From f7d00278becdd339a74c5d079a522292fa9e808c Mon Sep 17 00:00:00 2001 From: dcarello Date: Sun, 9 Nov 2025 20:20:27 -0800 Subject: [PATCH 1/6] EI-11 GET batches/{id} endpoint Connected the batches/{id} endpoint to the database. Tested that it works using Postman. Updated Unit Tests also --- .../controller/BatchesController.java | 72 +++++++++++--- .../dto/BatchRequestDTO.java | 6 +- .../dto/BatchResponseDTO.java | 21 +++-- .../exception/BatchNotFoundException.java | 14 +++ .../repository/TestBatchRepository.java | 11 +++ .../service/BatchService.java | 47 ++++++++++ .../controller/BatchesControllerUnitTest.java | 93 +++++++++++++------ .../service/BatchServiceTest.java | 57 ++++++++++++ 8 files changed, 273 insertions(+), 48 deletions(-) create mode 100644 endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/exception/BatchNotFoundException.java create mode 100644 endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/repository/TestBatchRepository.java create mode 100644 endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/service/BatchService.java create mode 100644 endpoint-insights-api/src/test/java/com/vsp/endpointinsightsapi/service/BatchServiceTest.java diff --git a/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/controller/BatchesController.java b/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/controller/BatchesController.java index 70d46da..fbef2fb 100644 --- a/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/controller/BatchesController.java +++ b/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/controller/BatchesController.java @@ -2,45 +2,89 @@ import com.vsp.endpointinsightsapi.dto.BatchRequestDTO; import com.vsp.endpointinsightsapi.dto.BatchResponseDTO; +import com.vsp.endpointinsightsapi.service.BatchService; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import java.time.LocalDate; +import java.util.Collections; import java.util.List; +import java.util.UUID; @RestController @RequestMapping("/api/batches") public class BatchesController { + private final BatchService batchService; + + public BatchesController(BatchService batchService){ + this.batchService = batchService; + } + @GetMapping public ResponseEntity> listBatches() { - List batches = List.of( - new BatchResponseDTO(1L, "Daily API Tests", "ACTIVE"), - new BatchResponseDTO(2L, "Weekly Regression", "INACTIVE") - ); - return ResponseEntity.ok(batches); + List batches = List.of( + BatchResponseDTO.builder() + .id(UUID.randomUUID()) + .batchName("Daily API Tests") + .scheduleId(334523453L) + .startTime(LocalDate.now().minusDays(1)) + .lastTimeRun(LocalDate.now()) + .active(true) +// .jobs(Collections.emptyList()) + .build(), + BatchResponseDTO.builder() + .id(UUID.randomUUID()) + .batchName("Weekly Regression") + .scheduleId(42L) + .startTime(LocalDate.now().minusWeeks(1)) + .lastTimeRun(LocalDate.now().minusDays(3)) + .active(false) +// .jobs(Collections.emptyList()) + .build() + ); + return ResponseEntity.ok(batches); } @GetMapping("/{id}") - public ResponseEntity getBatch(@PathVariable Long id) { - BatchResponseDTO batch = new BatchResponseDTO(id, "Example Batch " + id, "ACTIVE"); - return ResponseEntity.ok(batch); + public ResponseEntity getBatch(@PathVariable UUID id) { + BatchResponseDTO batch = batchService.getBatchById(id); + return ResponseEntity.ok(batch); } @PostMapping public ResponseEntity createBatch(@RequestBody BatchRequestDTO request) { - BatchResponseDTO created = new BatchResponseDTO(99L, request.getName(), "CREATED"); - return ResponseEntity.status(HttpStatus.CREATED).body(created); + BatchResponseDTO created = BatchResponseDTO.builder() + .id(UUID.randomUUID()) + .batchName(request.getName()) + .scheduleId(request.getScheduleId()) + .startTime(LocalDate.now()) + .lastTimeRun(null) + .active(true) +// .jobs(Collections.emptyList()) + .build(); + + return ResponseEntity.status(HttpStatus.CREATED).body(created); } @PutMapping("/{id}") - public ResponseEntity updateBatch(@PathVariable Long id, @RequestBody BatchRequestDTO request) { - BatchResponseDTO updated = new BatchResponseDTO(id, request.getName(), "UPDATED"); - return ResponseEntity.ok(updated); + public ResponseEntity updateBatch(@PathVariable UUID id, @RequestBody BatchRequestDTO request) { + BatchResponseDTO updated = BatchResponseDTO.builder() + .id(id) + .batchName(request.getName()) + .scheduleId(request.getScheduleId()) + .startTime(request.getStartTime()) + .lastTimeRun(LocalDate.now()) + .active(request.getActive()) +// .jobs(Collections.emptyList()) + .build(); + + return ResponseEntity.ok(updated); } @DeleteMapping("/{id}") - public ResponseEntity deleteBatch(@PathVariable Long id) { + public ResponseEntity deleteBatch(@PathVariable UUID id) { return ResponseEntity.noContent().build(); } } diff --git a/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/dto/BatchRequestDTO.java b/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/dto/BatchRequestDTO.java index 7ead13b..e7eb9c1 100644 --- a/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/dto/BatchRequestDTO.java +++ b/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/dto/BatchRequestDTO.java @@ -5,6 +5,8 @@ import lombok.NoArgsConstructor; import lombok.Setter; +import java.time.LocalDate; + @Getter @Setter @@ -12,5 +14,7 @@ @AllArgsConstructor public class BatchRequestDTO { private String name; - private String description; + private Long scheduleId; + private LocalDate startTime; + private Boolean active; } diff --git a/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/dto/BatchResponseDTO.java b/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/dto/BatchResponseDTO.java index 5e5ebea..6e1c314 100644 --- a/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/dto/BatchResponseDTO.java +++ b/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/dto/BatchResponseDTO.java @@ -1,17 +1,24 @@ package com.vsp.endpointinsightsapi.dto; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; +import com.vsp.endpointinsightsapi.model.Job; +import lombok.*; + +import java.time.LocalDate; +import java.util.List; +import java.util.UUID; @Getter @Setter +@Builder @NoArgsConstructor @AllArgsConstructor public class BatchResponseDTO { - private Long id; - private String name; - private String status; + private UUID id; + private String batchName; + private Long scheduleId; + private LocalDate startTime; + private LocalDate lastTimeRun; + private Boolean active; +// private List jobs; Jobs Table not created yet } diff --git a/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/exception/BatchNotFoundException.java b/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/exception/BatchNotFoundException.java new file mode 100644 index 0000000..e0c40b6 --- /dev/null +++ b/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/exception/BatchNotFoundException.java @@ -0,0 +1,14 @@ +package com.vsp.endpointinsightsapi.exception; + +import org.springframework.http.HttpStatus; + +/** + * Thrown when a batch with the given ID does not exist in the database. + */ +public class BatchNotFoundException extends CustomException { + + public BatchNotFoundException(String batchId) { + super(HttpStatus.NOT_FOUND, + new ErrorResponse("BATCH_NOT_FOUND", "Batch not found with ID: " + batchId, null)); + } +} diff --git a/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/repository/TestBatchRepository.java b/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/repository/TestBatchRepository.java new file mode 100644 index 0000000..4559307 --- /dev/null +++ b/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/repository/TestBatchRepository.java @@ -0,0 +1,11 @@ +package com.vsp.endpointinsightsapi.repository; + +import com.vsp.endpointinsightsapi.model.TestBatch; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.UUID; + +@Repository +public interface TestBatchRepository extends JpaRepository { +} \ No newline at end of file diff --git a/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/service/BatchService.java b/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/service/BatchService.java new file mode 100644 index 0000000..0460289 --- /dev/null +++ b/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/service/BatchService.java @@ -0,0 +1,47 @@ +package com.vsp.endpointinsightsapi.service; + +import com.vsp.endpointinsightsapi.dto.BatchResponseDTO; +import com.vsp.endpointinsightsapi.exception.BatchNotFoundException; +import com.vsp.endpointinsightsapi.model.TestBatch; +import com.vsp.endpointinsightsapi.repository.TestBatchRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + + +import java.util.Optional; +import java.util.UUID; + +@Service +public class BatchService { + + private final Logger LOG = LoggerFactory.getLogger(BatchService.class); + private TestBatchRepository testBatchRepository = null; + + public BatchService(TestBatchRepository testBatchRepository) { + this.testBatchRepository = testBatchRepository; + } + + public BatchResponseDTO getBatchById(UUID batchId) { + TestBatch b = testBatchRepository.findById(batchId) + .orElseThrow(() -> { + LOG.debug("Batch {} not found", batchId); + return new BatchNotFoundException(batchId.toString()); + }); + + return mapToDto(b); + + } + + private BatchResponseDTO mapToDto(TestBatch b) { + return new BatchResponseDTO( + b.getBatch_id(), + b.getBatchName(), + b.getScheduleId(), + b.getStartTime(), + b.getLastTimeRun(), + b.getActive() +// b.getJobs() Jobs table not created yet + ); + } +} diff --git a/endpoint-insights-api/src/test/java/com/vsp/endpointinsightsapi/controller/BatchesControllerUnitTest.java b/endpoint-insights-api/src/test/java/com/vsp/endpointinsightsapi/controller/BatchesControllerUnitTest.java index f393dd6..04aaf2c 100644 --- a/endpoint-insights-api/src/test/java/com/vsp/endpointinsightsapi/controller/BatchesControllerUnitTest.java +++ b/endpoint-insights-api/src/test/java/com/vsp/endpointinsightsapi/controller/BatchesControllerUnitTest.java @@ -1,19 +1,24 @@ package com.vsp.endpointinsightsapi.controller; -import com.fasterxml.jackson.databind.ObjectMapper; +import tools.jackson.databind.ObjectMapper; import com.vsp.endpointinsightsapi.dto.BatchRequestDTO; +import com.vsp.endpointinsightsapi.dto.BatchResponseDTO; +import com.vsp.endpointinsightsapi.exception.BatchNotFoundException; +import com.vsp.endpointinsightsapi.service.BatchService; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.context.annotation.Bean; import org.springframework.http.MediaType; import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.context.ActiveProfiles; +import java.time.LocalDate; +import java.util.UUID; import static org.hamcrest.Matchers.*; +import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; @@ -28,13 +33,9 @@ class BatchesControllerUnitTest { @Autowired private ObjectMapper objectMapper; - @TestConfiguration - static class TestConfig { - @Bean - public ObjectMapper objectMapper() { - return new ObjectMapper(); - } - } + @MockitoBean + private BatchService batchService; + @Test void shouldReturnListOfBatches() throws Exception { @@ -42,48 +43,88 @@ void shouldReturnListOfBatches() throws Exception { .andExpect(status().isOk()) .andExpect(jsonPath("$", hasSize(greaterThan(0)))) .andExpect(jsonPath("$[0].id", notNullValue())) - .andExpect(jsonPath("$[0].name", not(emptyString()))) - .andExpect(jsonPath("$[0].status", not(emptyString()))); + .andExpect(jsonPath("$[0].batchName", not(emptyString()))) + .andExpect(jsonPath("$[0].scheduleId", notNullValue())) + .andExpect(jsonPath("$[0].active", anyOf(is(true), is(false)))); } @Test void shouldReturnBatchById() throws Exception { - mockMvc.perform(get("/api/batches/1")) + UUID id = UUID.randomUUID(); + + BatchResponseDTO dto = BatchResponseDTO.builder() + .id(id) + .batchName("Daily API Tests") + .scheduleId(1001L) + .startTime(LocalDate.parse("2025-11-08")) + .lastTimeRun(LocalDate.parse("2025-11-09")) + .active(true) +// .jobs(Collections.emptyList()) Jobs not implemented yet + .build(); + + when(batchService.getBatchById(id)).thenReturn(dto); + + mockMvc.perform(get("/api/batches/{id}", id)) .andExpect(status().isOk()) - .andExpect(jsonPath("$.id", is(1))) - .andExpect(jsonPath("$.name", containsString("Example Batch"))) - .andExpect(jsonPath("$.status", is("ACTIVE"))); + .andExpect(jsonPath("$.id").value(id.toString())) + .andExpect(jsonPath("$.batchName").value("Daily API Tests")) + .andExpect(jsonPath("$.scheduleId").value(1001)) + .andExpect(jsonPath("$.active").value(true)); + } + + @Test + void getBatchById_notFound_shouldReturn404() throws Exception { + UUID id = UUID.randomUUID(); + when(batchService.getBatchById(id)).thenThrow(new BatchNotFoundException(id.toString())); + + mockMvc.perform(get("/api/batches/{id}", id)) + .andExpect(status().isNotFound()); } @Test void shouldCreateBatch() throws Exception { - BatchRequestDTO request = new BatchRequestDTO("New Batch", "Test batch description"); + BatchRequestDTO request = new BatchRequestDTO( + "New Batch", + 5001L, + LocalDate.now(), + true + ); mockMvc.perform(post("/api/batches") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(request))) .andExpect(status().isCreated()) - .andExpect(jsonPath("$.id", is(99))) - .andExpect(jsonPath("$.name", is("New Batch"))) - .andExpect(jsonPath("$.status", is("CREATED"))); + .andExpect(jsonPath("$.id", notNullValue())) + .andExpect(jsonPath("$.batchName", is("New Batch"))) + .andExpect(jsonPath("$.scheduleId", is(5001))) + .andExpect(jsonPath("$.active", is(true))); } @Test void shouldUpdateBatch() throws Exception { - BatchRequestDTO request = new BatchRequestDTO("Updated Batch", "Updated description"); + BatchRequestDTO request = new BatchRequestDTO( + "Updated Batch", + 7002L, + LocalDate.now(), + false + ); + + UUID id = UUID.randomUUID(); - mockMvc.perform(put("/api/batches/2") + mockMvc.perform(put("/api/batches/{id}", id) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(request))) .andExpect(status().isOk()) - .andExpect(jsonPath("$.id", is(2))) - .andExpect(jsonPath("$.name", is("Updated Batch"))) - .andExpect(jsonPath("$.status", is("UPDATED"))); + .andExpect(jsonPath("$.id", is(id.toString()))) + .andExpect(jsonPath("$.batchName", is("Updated Batch"))) + .andExpect(jsonPath("$.scheduleId", is(7002))) + .andExpect(jsonPath("$.active", is(false))); } @Test void shouldDeleteBatch() throws Exception { - mockMvc.perform(delete("/api/batches/1")) + UUID id = UUID.randomUUID(); + mockMvc.perform(delete("/api/batches/{id}", id)) .andExpect(status().isNoContent()); } } diff --git a/endpoint-insights-api/src/test/java/com/vsp/endpointinsightsapi/service/BatchServiceTest.java b/endpoint-insights-api/src/test/java/com/vsp/endpointinsightsapi/service/BatchServiceTest.java new file mode 100644 index 0000000..1c48742 --- /dev/null +++ b/endpoint-insights-api/src/test/java/com/vsp/endpointinsightsapi/service/BatchServiceTest.java @@ -0,0 +1,57 @@ +// BatchServiceTest.java +package com.vsp.endpointinsightsapi.service; + +import com.vsp.endpointinsightsapi.dto.BatchResponseDTO; +import com.vsp.endpointinsightsapi.exception.BatchNotFoundException; +import com.vsp.endpointinsightsapi.model.TestBatch; +import com.vsp.endpointinsightsapi.repository.TestBatchRepository; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.time.LocalDate; +import java.util.Optional; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class BatchServiceTest { + + @Mock TestBatchRepository repo; + @InjectMocks BatchService service; + + @Test + void getBatchById_returnsDto() { + UUID id = UUID.randomUUID(); + TestBatch entity = new TestBatch(); + // adjust getters/setters to your model + entity.setBatch_id(id); + entity.setBatchName("Example"); + entity.setScheduleId(1001L); + entity.setStartTime(LocalDate.parse("2025-11-08")); + entity.setLastTimeRun(LocalDate.parse("2025-11-09")); + entity.setActive(true); + + when(repo.findById(id)).thenReturn(Optional.of(entity)); + + BatchResponseDTO dto = service.getBatchById(id); + + assertThat(dto.getId()).isEqualTo(id); + assertThat(dto.getBatchName()).isEqualTo("Example"); + assertThat(dto.getScheduleId()).isEqualTo(1001L); + assertThat(dto.getActive()).isTrue(); + } + + @Test + void getBatchById_notFound_throws() { + UUID id = UUID.randomUUID(); + when(repo.findById(id)).thenReturn(Optional.empty()); + + assertThrows(BatchNotFoundException.class, () -> service.getBatchById(id)); + } +} From 141248e916e81f8b7e22702d9ea3efa16aca75bb Mon Sep 17 00:00:00 2001 From: dcarello <64613016+dcarello@users.noreply.github.com> Date: Sun, 16 Nov 2025 18:02:09 -0800 Subject: [PATCH 2/6] EI-18: Connected Delete batches/{id} to DB (#50) --- .../controller/BatchesController.java | 3 +- .../service/BatchService.java | 11 ++++++- .../controller/BatchesControllerUnitTest.java | 16 ++++++++++ .../service/BatchServiceTest.java | 31 +++++++++++++++---- 4 files changed, 53 insertions(+), 8 deletions(-) diff --git a/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/controller/BatchesController.java b/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/controller/BatchesController.java index fbef2fb..84032e4 100644 --- a/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/controller/BatchesController.java +++ b/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/controller/BatchesController.java @@ -85,6 +85,7 @@ public ResponseEntity updateBatch(@PathVariable UUID id, @Requ @DeleteMapping("/{id}") public ResponseEntity deleteBatch(@PathVariable UUID id) { - return ResponseEntity.noContent().build(); + batchService.deleteBatchById(id); + return ResponseEntity.noContent().build(); } } diff --git a/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/service/BatchService.java b/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/service/BatchService.java index 0460289..341d02d 100644 --- a/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/service/BatchService.java +++ b/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/service/BatchService.java @@ -28,11 +28,20 @@ public BatchResponseDTO getBatchById(UUID batchId) { LOG.debug("Batch {} not found", batchId); return new BatchNotFoundException(batchId.toString()); }); - return mapToDto(b); + } + public void deleteBatchById(UUID batchId) { + if (!testBatchRepository.existsById(batchId)) { + LOG.debug("Batch {} not found", batchId); + throw new BatchNotFoundException(batchId.toString()); + } + + testBatchRepository.deleteById(batchId); + LOG.info("Deleted batch {}", batchId); } + private BatchResponseDTO mapToDto(TestBatch b) { return new BatchResponseDTO( b.getBatch_id(), diff --git a/endpoint-insights-api/src/test/java/com/vsp/endpointinsightsapi/controller/BatchesControllerUnitTest.java b/endpoint-insights-api/src/test/java/com/vsp/endpointinsightsapi/controller/BatchesControllerUnitTest.java index 04aaf2c..ee4f361 100644 --- a/endpoint-insights-api/src/test/java/com/vsp/endpointinsightsapi/controller/BatchesControllerUnitTest.java +++ b/endpoint-insights-api/src/test/java/com/vsp/endpointinsightsapi/controller/BatchesControllerUnitTest.java @@ -18,6 +18,7 @@ import java.util.UUID; import static org.hamcrest.Matchers.*; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; @@ -124,7 +125,22 @@ void shouldUpdateBatch() throws Exception { @Test void shouldDeleteBatch() throws Exception { UUID id = UUID.randomUUID(); + + org.mockito.Mockito.doNothing() + .when(batchService).deleteBatchById(id); + mockMvc.perform(delete("/api/batches/{id}", id)) .andExpect(status().isNoContent()); } + + @Test + void shouldReturn404WhenDeletingNonexistentBatch() throws Exception { + UUID id = UUID.randomUUID(); + + org.mockito.Mockito.doThrow(new BatchNotFoundException(id.toString())) + .when(batchService).deleteBatchById(id); + + mockMvc.perform(delete("/api/batches/{id}", id)) + .andExpect(status().isNotFound()); + } } diff --git a/endpoint-insights-api/src/test/java/com/vsp/endpointinsightsapi/service/BatchServiceTest.java b/endpoint-insights-api/src/test/java/com/vsp/endpointinsightsapi/service/BatchServiceTest.java index 1c48742..8ce49d4 100644 --- a/endpoint-insights-api/src/test/java/com/vsp/endpointinsightsapi/service/BatchServiceTest.java +++ b/endpoint-insights-api/src/test/java/com/vsp/endpointinsightsapi/service/BatchServiceTest.java @@ -17,13 +17,14 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class BatchServiceTest { - @Mock TestBatchRepository repo; - @InjectMocks BatchService service; + @Mock TestBatchRepository testBatchRepository; + @InjectMocks BatchService batchService; @Test void getBatchById_returnsDto() { @@ -37,9 +38,9 @@ void getBatchById_returnsDto() { entity.setLastTimeRun(LocalDate.parse("2025-11-09")); entity.setActive(true); - when(repo.findById(id)).thenReturn(Optional.of(entity)); + when(testBatchRepository.findById(id)).thenReturn(Optional.of(entity)); - BatchResponseDTO dto = service.getBatchById(id); + BatchResponseDTO dto = batchService.getBatchById(id); assertThat(dto.getId()).isEqualTo(id); assertThat(dto.getBatchName()).isEqualTo("Example"); @@ -50,8 +51,26 @@ void getBatchById_returnsDto() { @Test void getBatchById_notFound_throws() { UUID id = UUID.randomUUID(); - when(repo.findById(id)).thenReturn(Optional.empty()); + when(testBatchRepository.findById(id)).thenReturn(Optional.empty()); - assertThrows(BatchNotFoundException.class, () -> service.getBatchById(id)); + assertThrows(BatchNotFoundException.class, () -> batchService.getBatchById(id)); + } + + @Test + void deleteBatchById_Exists() { + UUID id = UUID.randomUUID(); + when(testBatchRepository.existsById(id)).thenReturn(true); + + batchService.deleteBatchById(id); + + verify(testBatchRepository).deleteById(id); + } + + @Test + void deleteBatchById_NotFound() { + UUID id = UUID.randomUUID(); + when(testBatchRepository.existsById(id)).thenReturn(false); + + assertThrows(BatchNotFoundException.class, () -> batchService.deleteBatchById(id)); } } From c572d4315e1d4d6151722a3b093c62a249419767 Mon Sep 17 00:00:00 2001 From: dcarello Date: Tue, 18 Nov 2025 23:14:07 -0800 Subject: [PATCH 3/6] Updated where DTO is Put DTO in its own class and used mapStruct so it can auto generated the mapping. --- endpoint-insights-api/pom.xml | 31 ++++++++++++++++++- .../dto/BatchResponseDTO.java | 1 - .../mapper/BatchMapper.java | 12 +++++++ .../service/BatchService.java | 22 ++++--------- 4 files changed, 48 insertions(+), 18 deletions(-) create mode 100644 endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/mapper/BatchMapper.java diff --git a/endpoint-insights-api/pom.xml b/endpoint-insights-api/pom.xml index 92a3067..7e9d679 100644 --- a/endpoint-insights-api/pom.xml +++ b/endpoint-insights-api/pom.xml @@ -100,7 +100,26 @@ 3.5.7 - + + org.mapstruct + mapstruct + 1.5.5.Final + + + + org.mapstruct + mapstruct-processor + 1.5.5.Final + provided + + + + org.projectlombok + lombok-mapstruct-binding + 0.2.0 + + + @@ -164,6 +183,16 @@ lombok 1.18.42 + + org.mapstruct + mapstruct-processor + 1.5.5.Final + + + org.projectlombok + lombok-mapstruct-binding + 0.2.0 + diff --git a/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/dto/BatchResponseDTO.java b/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/dto/BatchResponseDTO.java index 6e1c314..0057393 100644 --- a/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/dto/BatchResponseDTO.java +++ b/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/dto/BatchResponseDTO.java @@ -20,5 +20,4 @@ public class BatchResponseDTO { private LocalDate startTime; private LocalDate lastTimeRun; private Boolean active; -// private List jobs; Jobs Table not created yet } diff --git a/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/mapper/BatchMapper.java b/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/mapper/BatchMapper.java new file mode 100644 index 0000000..069761d --- /dev/null +++ b/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/mapper/BatchMapper.java @@ -0,0 +1,12 @@ +package com.vsp.endpointinsightsapi.mapper; + +import com.vsp.endpointinsightsapi.dto.BatchResponseDTO; +import com.vsp.endpointinsightsapi.model.TestBatch; +import org.mapstruct.Mapper; + +@Mapper(componentModel = "spring") +public interface BatchMapper { + + // MapStruct will generate the implementation automatically + BatchResponseDTO toDto(TestBatch entity); +} diff --git a/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/service/BatchService.java b/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/service/BatchService.java index 341d02d..819d730 100644 --- a/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/service/BatchService.java +++ b/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/service/BatchService.java @@ -2,14 +2,15 @@ import com.vsp.endpointinsightsapi.dto.BatchResponseDTO; import com.vsp.endpointinsightsapi.exception.BatchNotFoundException; +import com.vsp.endpointinsightsapi.mapper.BatchMapper; import com.vsp.endpointinsightsapi.model.TestBatch; import com.vsp.endpointinsightsapi.repository.TestBatchRepository; +import lombok.RequiredArgsConstructor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; -import java.util.Optional; import java.util.UUID; @Service @@ -17,9 +18,11 @@ public class BatchService { private final Logger LOG = LoggerFactory.getLogger(BatchService.class); private TestBatchRepository testBatchRepository = null; + private final BatchMapper batchMapper; - public BatchService(TestBatchRepository testBatchRepository) { + public BatchService(TestBatchRepository testBatchRepository, BatchMapper batchMapper) { this.testBatchRepository = testBatchRepository; + this.batchMapper = batchMapper; } public BatchResponseDTO getBatchById(UUID batchId) { @@ -28,7 +31,7 @@ public BatchResponseDTO getBatchById(UUID batchId) { LOG.debug("Batch {} not found", batchId); return new BatchNotFoundException(batchId.toString()); }); - return mapToDto(b); + return batchMapper.toDto(b); } public void deleteBatchById(UUID batchId) { @@ -40,17 +43,4 @@ public void deleteBatchById(UUID batchId) { testBatchRepository.deleteById(batchId); LOG.info("Deleted batch {}", batchId); } - - - private BatchResponseDTO mapToDto(TestBatch b) { - return new BatchResponseDTO( - b.getBatch_id(), - b.getBatchName(), - b.getScheduleId(), - b.getStartTime(), - b.getLastTimeRun(), - b.getActive() -// b.getJobs() Jobs table not created yet - ); - } } From 09ed898e7264533c8ac697b1f3bebe32084ac304 Mon Sep 17 00:00:00 2001 From: dcarello Date: Wed, 19 Nov 2025 00:09:00 -0800 Subject: [PATCH 4/6] Update BatchServiceTest.java Mocked the mapper in the testing --- .../service/BatchServiceTest.java | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/endpoint-insights-api/src/test/java/com/vsp/endpointinsightsapi/service/BatchServiceTest.java b/endpoint-insights-api/src/test/java/com/vsp/endpointinsightsapi/service/BatchServiceTest.java index 8ce49d4..c652930 100644 --- a/endpoint-insights-api/src/test/java/com/vsp/endpointinsightsapi/service/BatchServiceTest.java +++ b/endpoint-insights-api/src/test/java/com/vsp/endpointinsightsapi/service/BatchServiceTest.java @@ -3,6 +3,7 @@ import com.vsp.endpointinsightsapi.dto.BatchResponseDTO; import com.vsp.endpointinsightsapi.exception.BatchNotFoundException; +import com.vsp.endpointinsightsapi.mapper.BatchMapper; import com.vsp.endpointinsightsapi.model.TestBatch; import com.vsp.endpointinsightsapi.repository.TestBatchRepository; import org.junit.jupiter.api.Test; @@ -15,8 +16,7 @@ import java.util.Optional; import java.util.UUID; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -24,6 +24,7 @@ class BatchServiceTest { @Mock TestBatchRepository testBatchRepository; + @Mock BatchMapper batchMapper; @InjectMocks BatchService batchService; @Test @@ -40,12 +41,22 @@ void getBatchById_returnsDto() { when(testBatchRepository.findById(id)).thenReturn(Optional.of(entity)); - BatchResponseDTO dto = batchService.getBatchById(id); - - assertThat(dto.getId()).isEqualTo(id); - assertThat(dto.getBatchName()).isEqualTo("Example"); - assertThat(dto.getScheduleId()).isEqualTo(1001L); - assertThat(dto.getActive()).isTrue(); + BatchResponseDTO dto = BatchResponseDTO.builder() + .id(id) + .batchName("Example") + .scheduleId(1001L) + .startTime(LocalDate.parse("2025-11-08")) + .lastTimeRun(LocalDate.parse("2025-11-09")) + .active(true) + .build(); + when(batchMapper.toDto(entity)).thenReturn(dto); + + BatchResponseDTO out = batchService.getBatchById(id); + + assertEquals(id, out.getId()); + assertEquals("Example", out.getBatchName()); + verify(testBatchRepository).findById(id); + verify(batchMapper).toDto(entity); } @Test From 3c0b2a0d27e5411453005143bdc84e05b6690ac1 Mon Sep 17 00:00:00 2001 From: dcarello Date: Thu, 20 Nov 2025 10:43:28 -0800 Subject: [PATCH 5/6] Update BatchService.java Code rabbit suggestions inputted --- .../endpointinsightsapi/service/BatchService.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/service/BatchService.java b/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/service/BatchService.java index 819d730..7b284a0 100644 --- a/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/service/BatchService.java +++ b/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/service/BatchService.java @@ -5,24 +5,22 @@ import com.vsp.endpointinsightsapi.mapper.BatchMapper; import com.vsp.endpointinsightsapi.model.TestBatch; import com.vsp.endpointinsightsapi.repository.TestBatchRepository; -import lombok.RequiredArgsConstructor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; - - +import java.util.Objects; import java.util.UUID; @Service public class BatchService { - private final Logger LOG = LoggerFactory.getLogger(BatchService.class); - private TestBatchRepository testBatchRepository = null; + private static final Logger LOG = LoggerFactory.getLogger(BatchService.class); + private final TestBatchRepository testBatchRepository; private final BatchMapper batchMapper; public BatchService(TestBatchRepository testBatchRepository, BatchMapper batchMapper) { - this.testBatchRepository = testBatchRepository; - this.batchMapper = batchMapper; + this.testBatchRepository = Objects.requireNonNull(testBatchRepository, "testBatchRepository must not be null"); + this.batchMapper = Objects.requireNonNull(batchMapper, "batchMapper must not be null"); } public BatchResponseDTO getBatchById(UUID batchId) { From 34ea5687d3115f914b90839884a9a7b1d02125ce Mon Sep 17 00:00:00 2001 From: dcarello Date: Thu, 20 Nov 2025 13:00:19 -0800 Subject: [PATCH 6/6] Unit Test/Mapping fix Fixed small bug with mapping for getting batch by id. And fixed unit test problems --- .../endpointinsightsapi/controller/BatchesController.java | 3 --- .../java/com/vsp/endpointinsightsapi/mapper/BatchMapper.java | 2 ++ .../controller/BatchesControllerUnitTest.java | 4 +--- .../vsp/endpointinsightsapi/service/BatchServiceTest.java | 5 +---- 4 files changed, 4 insertions(+), 10 deletions(-) diff --git a/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/controller/BatchesController.java b/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/controller/BatchesController.java index 5faa121..3b46bfc 100644 --- a/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/controller/BatchesController.java +++ b/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/controller/BatchesController.java @@ -73,10 +73,7 @@ public ResponseEntity updateBatch(@PathVariable UUID id, @Requ BatchResponseDTO updated = BatchResponseDTO.builder() .id(id) .batchName(request.getName()) - .scheduleId(request.getScheduleId()) - .startTime(request.getStartTime()) .lastTimeRun(LocalDate.now()) - .active(request.getActive()) .build(); return ResponseEntity.ok(updated); diff --git a/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/mapper/BatchMapper.java b/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/mapper/BatchMapper.java index 069761d..72ad45b 100644 --- a/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/mapper/BatchMapper.java +++ b/endpoint-insights-api/src/main/java/com/vsp/endpointinsightsapi/mapper/BatchMapper.java @@ -3,10 +3,12 @@ import com.vsp.endpointinsightsapi.dto.BatchResponseDTO; import com.vsp.endpointinsightsapi.model.TestBatch; import org.mapstruct.Mapper; +import org.mapstruct.Mapping; @Mapper(componentModel = "spring") public interface BatchMapper { // MapStruct will generate the implementation automatically + @Mapping(source = "batch_id", target = "id") BatchResponseDTO toDto(TestBatch entity); } diff --git a/endpoint-insights-api/src/test/java/com/vsp/endpointinsightsapi/controller/BatchesControllerUnitTest.java b/endpoint-insights-api/src/test/java/com/vsp/endpointinsightsapi/controller/BatchesControllerUnitTest.java index 9272d92..bc8b01a 100644 --- a/endpoint-insights-api/src/test/java/com/vsp/endpointinsightsapi/controller/BatchesControllerUnitTest.java +++ b/endpoint-insights-api/src/test/java/com/vsp/endpointinsightsapi/controller/BatchesControllerUnitTest.java @@ -106,9 +106,7 @@ void shouldUpdateBatch() throws Exception { .content(objectMapper.writeValueAsString(request))) .andExpect(status().isOk()) .andExpect(jsonPath("$.id", is(id.toString()))) - .andExpect(jsonPath("$.batchName", is("Updated Batch"))) - .andExpect(jsonPath("$.scheduleId", is(7002))) - .andExpect(jsonPath("$.active", is(false))); + .andExpect(jsonPath("$.batchName", is("Updated Batch"))); } @Test diff --git a/endpoint-insights-api/src/test/java/com/vsp/endpointinsightsapi/service/BatchServiceTest.java b/endpoint-insights-api/src/test/java/com/vsp/endpointinsightsapi/service/BatchServiceTest.java index 465a6e6..1951368 100644 --- a/endpoint-insights-api/src/test/java/com/vsp/endpointinsightsapi/service/BatchServiceTest.java +++ b/endpoint-insights-api/src/test/java/com/vsp/endpointinsightsapi/service/BatchServiceTest.java @@ -7,13 +7,11 @@ import com.vsp.endpointinsightsapi.model.TestBatch; import com.vsp.endpointinsightsapi.repository.JobRepository; import com.vsp.endpointinsightsapi.repository.TestBatchRepository; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import org.mockito.Mockito; import java.time.LocalDate; import java.util.Optional; @@ -21,7 +19,6 @@ import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.verify; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) @@ -29,7 +26,7 @@ class BatchServiceTest { @Mock TestBatchRepository testBatchRepository; @Mock BatchMapper batchMapper; - @Mock BatchService batchService; + @InjectMocks BatchService batchService; @Mock JobRepository jobRepository; @Test