diff --git a/src/main/java/hng_java_boilerplate/Program.java b/src/main/java/hng_java_boilerplate/Program.java index 8a2f56dd..cfa225d7 100644 --- a/src/main/java/hng_java_boilerplate/Program.java +++ b/src/main/java/hng_java_boilerplate/Program.java @@ -2,8 +2,10 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication +@EnableScheduling public class Program { public static void main(String[] args) { diff --git a/src/main/java/hng_java_boilerplate/statusPage/controller/ApiStatusController.java b/src/main/java/hng_java_boilerplate/statusPage/controller/ApiStatusController.java deleted file mode 100644 index 849a9f18..00000000 --- a/src/main/java/hng_java_boilerplate/statusPage/controller/ApiStatusController.java +++ /dev/null @@ -1,27 +0,0 @@ -package hng_java_boilerplate.statusPage.controller; - -import hng_java_boilerplate.statusPage.entity.ApiStatus; -import hng_java_boilerplate.statusPage.service.ApiStatusService; -import lombok.RequiredArgsConstructor; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import java.util.List; - -@RestController -@RequiredArgsConstructor -@RequestMapping("/api/v1/api-status") -public class ApiStatusController { - - private final ApiStatusService apiStatusService; - - @GetMapping - public ResponseEntity> getAllApiStatuses() { - return ResponseEntity.ok(apiStatusService.getAllApiStatuses()); - } - - @PostMapping - public ResponseEntity updateApiStatus(@RequestBody ApiStatus apiStatus) { - return ResponseEntity.ok(apiStatusService.updateApiStatus(apiStatus)); - } -} \ No newline at end of file diff --git a/src/main/java/hng_java_boilerplate/statusPage/controller/StatusPageController.java b/src/main/java/hng_java_boilerplate/statusPage/controller/StatusPageController.java new file mode 100644 index 00000000..b21fed12 --- /dev/null +++ b/src/main/java/hng_java_boilerplate/statusPage/controller/StatusPageController.java @@ -0,0 +1,29 @@ +package hng_java_boilerplate.statusPage.controller; + +import hng_java_boilerplate.statusPage.entity.StatusPage; +import hng_java_boilerplate.statusPage.service.StatusPageService; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/v1/api-status") +public class StatusPageController { + + private final StatusPageService statusPageService; + + @GetMapping + public List getAllApiStatuses() { + return statusPageService.getAllApiStatuses(); + } + + @PostMapping + public void updateApiStatus() { + statusPageService.updateApiStatus(); + } +} diff --git a/src/main/java/hng_java_boilerplate/statusPage/entity/ApiStatus.java b/src/main/java/hng_java_boilerplate/statusPage/entity/StatusPage.java similarity index 96% rename from src/main/java/hng_java_boilerplate/statusPage/entity/ApiStatus.java rename to src/main/java/hng_java_boilerplate/statusPage/entity/StatusPage.java index 1be5784f..721230f8 100644 --- a/src/main/java/hng_java_boilerplate/statusPage/entity/ApiStatus.java +++ b/src/main/java/hng_java_boilerplate/statusPage/entity/StatusPage.java @@ -10,7 +10,7 @@ @Getter @Setter @Table(name = "api_status") -public class ApiStatus { +public class StatusPage { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; diff --git a/src/main/java/hng_java_boilerplate/statusPage/repository/ApiStatusRepository.java b/src/main/java/hng_java_boilerplate/statusPage/repository/ApiStatusRepository.java deleted file mode 100644 index f82ed812..00000000 --- a/src/main/java/hng_java_boilerplate/statusPage/repository/ApiStatusRepository.java +++ /dev/null @@ -1,8 +0,0 @@ -package hng_java_boilerplate.statusPage.repository; - -import hng_java_boilerplate.statusPage.entity.ApiStatus; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface ApiStatusRepository extends JpaRepository { - ApiStatus findByApiGroup(String apiGroup); -} \ No newline at end of file diff --git a/src/main/java/hng_java_boilerplate/statusPage/repository/StatusPageRepository.java b/src/main/java/hng_java_boilerplate/statusPage/repository/StatusPageRepository.java new file mode 100644 index 00000000..f4b6cbc6 --- /dev/null +++ b/src/main/java/hng_java_boilerplate/statusPage/repository/StatusPageRepository.java @@ -0,0 +1,7 @@ +package hng_java_boilerplate.statusPage.repository; + +import hng_java_boilerplate.statusPage.entity.StatusPage; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface StatusPageRepository extends JpaRepository { +} \ No newline at end of file diff --git a/src/main/java/hng_java_boilerplate/statusPage/service/ApiStatusService.java b/src/main/java/hng_java_boilerplate/statusPage/service/ApiStatusService.java deleted file mode 100644 index 486350d0..00000000 --- a/src/main/java/hng_java_boilerplate/statusPage/service/ApiStatusService.java +++ /dev/null @@ -1,12 +0,0 @@ -package hng_java_boilerplate.statusPage.service; - -import hng_java_boilerplate.statusPage.entity.ApiStatus; -import org.springframework.stereotype.Service; - -import java.util.List; - -@Service -public interface ApiStatusService { - List getAllApiStatuses(); - ApiStatus updateApiStatus(ApiStatus apiStatus); -} \ No newline at end of file diff --git a/src/main/java/hng_java_boilerplate/statusPage/service/ApiStatusServiceImpl.java b/src/main/java/hng_java_boilerplate/statusPage/service/ApiStatusServiceImpl.java deleted file mode 100644 index 91e702ab..00000000 --- a/src/main/java/hng_java_boilerplate/statusPage/service/ApiStatusServiceImpl.java +++ /dev/null @@ -1,31 +0,0 @@ -package hng_java_boilerplate.statusPage.service; - -import hng_java_boilerplate.statusPage.entity.ApiStatus; -import hng_java_boilerplate.statusPage.repository.ApiStatusRepository; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; - -import java.util.List; - -@Service -@RequiredArgsConstructor -public class ApiStatusServiceImpl implements ApiStatusService { - - private final ApiStatusRepository apiStatusRepository; - - public List getAllApiStatuses() { - return apiStatusRepository.findAll(); - } - - public ApiStatus updateApiStatus(ApiStatus apiStatus) { - ApiStatus existingStatus = apiStatusRepository.findByApiGroup(apiStatus.getApiGroup()); - if (existingStatus != null) { - existingStatus.setStatus(apiStatus.getStatus()); - existingStatus.setLastChecked(apiStatus.getLastChecked()); - existingStatus.setResponseTime(apiStatus.getResponseTime()); - existingStatus.setDetails(apiStatus.getDetails()); - return apiStatusRepository.save(existingStatus); - } - return apiStatusRepository.save(apiStatus); - } -} \ No newline at end of file diff --git a/src/main/java/hng_java_boilerplate/statusPage/service/StatusPageService.java b/src/main/java/hng_java_boilerplate/statusPage/service/StatusPageService.java new file mode 100644 index 00000000..3b40ecb2 --- /dev/null +++ b/src/main/java/hng_java_boilerplate/statusPage/service/StatusPageService.java @@ -0,0 +1,12 @@ +package hng_java_boilerplate.statusPage.service; + +import com.fasterxml.jackson.databind.JsonNode; +import hng_java_boilerplate.statusPage.entity.StatusPage; + +import java.util.List; + +public interface StatusPageService { + void updateApiStatus(); + void processJsonData(JsonNode jsonNode); + List getAllApiStatuses(); +} diff --git a/src/main/java/hng_java_boilerplate/statusPage/service/StatusPageServiceImpl.java b/src/main/java/hng_java_boilerplate/statusPage/service/StatusPageServiceImpl.java new file mode 100644 index 00000000..f3cd4793 --- /dev/null +++ b/src/main/java/hng_java_boilerplate/statusPage/service/StatusPageServiceImpl.java @@ -0,0 +1,71 @@ +package hng_java_boilerplate.statusPage.service; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import hng_java_boilerplate.statusPage.entity.StatusPage; +import hng_java_boilerplate.statusPage.entity.StatusPage.Status; +import hng_java_boilerplate.statusPage.repository.StatusPageRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.io.IOException; +import java.time.LocalDateTime; +import java.util.List; + +@Service +@RequiredArgsConstructor +public class StatusPageServiceImpl implements StatusPageService { + + private final StatusPageRepository statusPageRepository; + private final ObjectMapper objectMapper; + private static final String RESULT_JSON_PATH = "/home/${{ secrets.USERNAME }}/hng_boilerplate_java_web/result.json"; + + @Override + @Scheduled(fixedRate = 900000) + public void updateApiStatus() { + try { + File jsonFile = new File(RESULT_JSON_PATH); + JsonNode jsonNode = objectMapper.readTree(jsonFile); + processJsonData(jsonNode); + } catch (IOException e) { + e.printStackTrace(); + } + } + + @Override + public void processJsonData(JsonNode jsonNode) { + JsonNode executions = jsonNode.get("run").get("executions"); + + for (JsonNode execution : executions) { + String apiGroup = execution.get("item").get("name").asText(); + int responseTime = execution.get("response").get("responseTime").asInt(); + int statusCode = execution.get("response").get("code").asInt(); + String statusMessage = execution.get("response").get("status").asText(); + + StatusPage statusPage = new StatusPage(); + statusPage.setApiGroup(apiGroup); + statusPage.setResponseTime(responseTime); + statusPage.setLastChecked(LocalDateTime.now()); + + if (statusCode >= 200 && statusCode < 300) { + statusPage.setStatus(Status.OPERATIONAL); + } else if (statusCode >= 500) { + statusPage.setStatus(Status.DEGRADED); + } else { + statusPage.setStatus(Status.DOWN); + } + + statusPage.setDetails(statusMessage); + + statusPageRepository.save(statusPage); + } + } + + @Override + public List getAllApiStatuses() { + return statusPageRepository.findAll(); + } +} diff --git a/src/main/java/hng_java_boilerplate/statusPage/util/NewmanResultParser.java b/src/main/java/hng_java_boilerplate/statusPage/util/NewmanResultParser.java deleted file mode 100644 index 54573347..00000000 --- a/src/main/java/hng_java_boilerplate/statusPage/util/NewmanResultParser.java +++ /dev/null @@ -1,39 +0,0 @@ -package hng_java_boilerplate.statusPage.util; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import hng_java_boilerplate.statusPage.entity.ApiStatus; - -import java.io.File; -import java.io.IOException; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; - -public class NewmanResultParser { - - public static List parseNewmanResults(String filePath) throws IOException { - ObjectMapper objectMapper = new ObjectMapper(); - JsonNode rootNode = objectMapper.readTree(new File(filePath)); - - List apiStatuses = new ArrayList<>(); - - JsonNode executions = rootNode.path("run").path("executions"); - for (JsonNode execution : executions) { - String apiGroup = execution.path("item").path("name").asText(); - boolean passed = execution.path("response").path("code").asInt() == 200; - int responseTime = execution.path("response").path("responseTime").asInt(); - - ApiStatus apiStatus = new ApiStatus(); - apiStatus.setApiGroup(apiGroup); - apiStatus.setStatus(passed ? ApiStatus.Status.OPERATIONAL : ApiStatus.Status.DOWN); - apiStatus.setLastChecked(LocalDateTime.now()); - apiStatus.setResponseTime(responseTime); - apiStatus.setDetails(passed ? "All tests passed" : "API not responding"); - - apiStatuses.add(apiStatus); - } - - return apiStatuses; - } -} diff --git a/src/test/java/hng_java_boilerplate/statusPage/controller/ApiStatusControllerTest.java b/src/test/java/hng_java_boilerplate/statusPage/controller/ApiStatusControllerTest.java deleted file mode 100644 index 51eaa99f..00000000 --- a/src/test/java/hng_java_boilerplate/statusPage/controller/ApiStatusControllerTest.java +++ /dev/null @@ -1,79 +0,0 @@ -package hng_java_boilerplate.statusPage.controller; - -import hng_java_boilerplate.statusPage.entity.ApiStatus; -import hng_java_boilerplate.statusPage.service.ApiStatusServiceImpl; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.springframework.http.MediaType; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; - -import java.time.LocalDateTime; -import java.util.Collections; -import java.util.List; - -import static org.mockito.Mockito.when; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import static org.mockito.ArgumentMatchers.any; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.hamcrest.Matchers.is; - -public class ApiStatusControllerTest { - - private MockMvc mockMvc; - - @Mock - private ApiStatusServiceImpl apiStatusService; - - @InjectMocks - private ApiStatusController apiStatusController; - - @BeforeEach - public void setUp() { - MockitoAnnotations.openMocks(this); - mockMvc = MockMvcBuilders.standaloneSetup(apiStatusController).build(); - } - - @Test - public void testGetAllApiStatuses() throws Exception { - ApiStatus apiStatus = new ApiStatus(); - apiStatus.setApiGroup("Test API"); - apiStatus.setStatus(ApiStatus.Status.OPERATIONAL); - apiStatus.setLastChecked(LocalDateTime.now()); - - List apiStatuses = Collections.singletonList(apiStatus); - - when(apiStatusService.getAllApiStatuses()).thenReturn(apiStatuses); - - mockMvc.perform(get("/api/v1/api-status")) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$[0].apiGroup", is("Test API"))) - .andExpect(jsonPath("$[0].status", is("OPERATIONAL"))); - } - - @Test - public void testUpdateApiStatus() throws Exception { - ApiStatus apiStatus = new ApiStatus(); - apiStatus.setApiGroup("Test API"); - apiStatus.setStatus(ApiStatus.Status.OPERATIONAL); - apiStatus.setLastChecked(LocalDateTime.now()); - - when(apiStatusService.updateApiStatus(any(ApiStatus.class))).thenReturn(apiStatus); - - mockMvc.perform(post("/api/v1/api-status") - .contentType(MediaType.APPLICATION_JSON) - .content("{\"apiGroup\":\"Test API\",\"status\":\"OPERATIONAL\"}")) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.apiGroup", is("Test API"))) - .andExpect(jsonPath("$.status", is("OPERATIONAL"))); - } -} diff --git a/src/test/java/hng_java_boilerplate/statusPage/controller/StatusPageControllerTest.java b/src/test/java/hng_java_boilerplate/statusPage/controller/StatusPageControllerTest.java new file mode 100644 index 00000000..e2f39927 --- /dev/null +++ b/src/test/java/hng_java_boilerplate/statusPage/controller/StatusPageControllerTest.java @@ -0,0 +1,66 @@ +package hng_java_boilerplate.statusPage.controller; + +import hng_java_boilerplate.statusPage.entity.StatusPage; +import hng_java_boilerplate.statusPage.service.StatusPageService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import java.util.Arrays; +import java.util.List; + +import static org.mockito.Mockito.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +class StatusPageControllerTest { + + @Mock + private StatusPageService statusPageService; + + @InjectMocks + private StatusPageController statusPageController; + + private MockMvc mockMvc; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + mockMvc = MockMvcBuilders.standaloneSetup(statusPageController).build(); + } + + @Test + void testGetAllApiStatuses() throws Exception { + // Prepare test data + List mockStatusPages = Arrays.asList(new StatusPage(), new StatusPage()); + when(statusPageService.getAllApiStatuses()).thenReturn(mockStatusPages); + + // Perform GET request and verify the response + mockMvc.perform(get("/api/v1/api-status") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("$").isArray()) + .andExpect(jsonPath("$.length()").value(mockStatusPages.size())); + + // Verify that the service method was called + verify(statusPageService, times(1)).getAllApiStatuses(); + } + + @Test + void testUpdateApiStatus() throws Exception { + // Perform POST request and verify the response + mockMvc.perform(post("/api/v1/api-status") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + + // Verify that the service method was called + verify(statusPageService, times(1)).updateApiStatus(); + } +} \ No newline at end of file diff --git a/src/test/java/hng_java_boilerplate/statusPage/service/ApiStatusServiceTest.java b/src/test/java/hng_java_boilerplate/statusPage/service/ApiStatusServiceTest.java deleted file mode 100644 index 4cd58d53..00000000 --- a/src/test/java/hng_java_boilerplate/statusPage/service/ApiStatusServiceTest.java +++ /dev/null @@ -1,85 +0,0 @@ -package hng_java_boilerplate.statusPage.service; - -import hng_java_boilerplate.statusPage.entity.ApiStatus; -import hng_java_boilerplate.statusPage.repository.ApiStatusRepository; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import java.time.LocalDateTime; -import java.util.Collections; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; - -public class ApiStatusServiceTest { - - @Mock - private ApiStatusRepository apiStatusRepository; - - @InjectMocks - private ApiStatusServiceImpl apiStatusService; - - @BeforeEach - public void setUp() { - MockitoAnnotations.openMocks(this); - } - - @Test - public void testGetAllApiStatuses() { - ApiStatus apiStatus = new ApiStatus(); - apiStatus.setApiGroup("Test API"); - apiStatus.setStatus(ApiStatus.Status.OPERATIONAL); - apiStatus.setLastChecked(LocalDateTime.now()); - - when(apiStatusRepository.findAll()).thenReturn(Collections.singletonList(apiStatus)); - - List result = apiStatusService.getAllApiStatuses(); - - assertEquals(1, result.size()); - assertEquals("Test API", result.get(0).getApiGroup()); - assertEquals(ApiStatus.Status.OPERATIONAL, result.get(0).getStatus()); - } - - @Test - public void testUpdateApiStatus_ExistingStatus() { - ApiStatus existingStatus = new ApiStatus(); - existingStatus.setApiGroup("Existing API"); - existingStatus.setStatus(ApiStatus.Status.OPERATIONAL); - existingStatus.setLastChecked(LocalDateTime.now()); - - when(apiStatusRepository.findByApiGroup("Existing API")).thenReturn(existingStatus); - when(apiStatusRepository.save(any(ApiStatus.class))).thenReturn(existingStatus); - - ApiStatus newStatus = new ApiStatus(); - newStatus.setApiGroup("Existing API"); - newStatus.setStatus(ApiStatus.Status.DOWN); - newStatus.setLastChecked(LocalDateTime.now()); - - ApiStatus result = apiStatusService.updateApiStatus(newStatus); - - assertEquals(ApiStatus.Status.DOWN, result.getStatus()); - verify(apiStatusRepository, times(1)).save(existingStatus); - } - - @Test - public void testUpdateApiStatus_NewStatus() { - ApiStatus newStatus = new ApiStatus(); - newStatus.setApiGroup("New API"); - newStatus.setStatus(ApiStatus.Status.OPERATIONAL); - newStatus.setLastChecked(LocalDateTime.now()); - - when(apiStatusRepository.findByApiGroup("New API")).thenReturn(null); - when(apiStatusRepository.save(any(ApiStatus.class))).thenReturn(newStatus); - - ApiStatus result = apiStatusService.updateApiStatus(newStatus); - - assertEquals("New API", result.getApiGroup()); - assertEquals(ApiStatus.Status.OPERATIONAL, result.getStatus()); - verify(apiStatusRepository, times(1)).save(newStatus); - } -} diff --git a/src/test/java/hng_java_boilerplate/statusPage/service/StatusPageServiceTest.java b/src/test/java/hng_java_boilerplate/statusPage/service/StatusPageServiceTest.java new file mode 100644 index 00000000..1ec8a083 --- /dev/null +++ b/src/test/java/hng_java_boilerplate/statusPage/service/StatusPageServiceTest.java @@ -0,0 +1,89 @@ +package hng_java_boilerplate.statusPage.service; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import hng_java_boilerplate.statusPage.entity.StatusPage; +import hng_java_boilerplate.statusPage.repository.StatusPageRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.*; + +class StatusPageServiceTest { + + @Mock + private StatusPageRepository statusPageRepository; + + @Mock + private ObjectMapper objectMapper; + + @InjectMocks + private StatusPageServiceImpl statusPageService; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + } + + @Test + void testUpdateApiStatus() throws IOException { + // Prepare test data + JsonNode mockJsonNode = mock(JsonNode.class); + JsonNode mockRunNode = mock(JsonNode.class); + JsonNode mockExecutionsNode = mock(JsonNode.class); + JsonNode mockExecutionNode = mock(JsonNode.class); + JsonNode mockItemNode = mock(JsonNode.class); + JsonNode mockResponseNode = mock(JsonNode.class); + + when(objectMapper.readTree(any(File.class))).thenReturn(mockJsonNode); + when(mockJsonNode.get("run")).thenReturn(mockRunNode); + when(mockRunNode.get("executions")).thenReturn(mockExecutionsNode); + when(mockExecutionsNode.iterator()).thenReturn(Arrays.asList(mockExecutionNode).iterator()); + + // Mock the structure for a single execution + when(mockExecutionNode.get("item")).thenReturn(mockItemNode); + when(mockExecutionNode.get("response")).thenReturn(mockResponseNode); + when(mockItemNode.get("name")).thenReturn(mock(JsonNode.class)); + when(mockItemNode.get("name").asText()).thenReturn("Test API"); + when(mockResponseNode.get("responseTime")).thenReturn(mock(JsonNode.class)); + when(mockResponseNode.get("responseTime").asInt()).thenReturn(100); + when(mockResponseNode.get("code")).thenReturn(mock(JsonNode.class)); + when(mockResponseNode.get("code").asInt()).thenReturn(200); + when(mockResponseNode.get("status")).thenReturn(mock(JsonNode.class)); + when(mockResponseNode.get("status").asText()).thenReturn("OK"); + + // Call the method + statusPageService.updateApiStatus(); + + // Verify that processJsonData was called and a StatusPage was saved + verify(statusPageRepository, times(1)).save(argThat(statusPage -> + statusPage.getApiGroup().equals("Test API") && + statusPage.getResponseTime() == 100 && + statusPage.getStatus() == StatusPage.Status.OPERATIONAL && + statusPage.getDetails().equals("OK") + )); + } + + @Test + void testGetAllApiStatuses() { + // Prepare test data + List mockStatusPages = Arrays.asList(new StatusPage(), new StatusPage()); + when(statusPageRepository.findAll()).thenReturn(mockStatusPages); + + // Call the method + List result = statusPageService.getAllApiStatuses(); + + // Verify the result + assertEquals(mockStatusPages, result); + verify(statusPageRepository, times(1)).findAll(); + } +} \ No newline at end of file