diff --git a/README.md b/README.md index da08665..14b8bdc 100644 --- a/README.md +++ b/README.md @@ -18,9 +18,10 @@ CRUD operations.Also is demonstrated how to return a Pageable responseGlobal exception handler for handle exception from the codebase and custom spring validator(example with annotation for field and class level).Demo of how to use CriteriaBuilder for data retrieving.Added configuration for collecting application metrics via Spring Boot Actuator and configuration for Injecting Git Information Into Spring. +In the project you can find implementation of Quartz scheduler using Cron Triggers and Expressions and Spring Custom Events. # GitHub actions pipelines integration -Added integration with GitHub actions for code analyzis with sonarcloud and codecov for code coverage report +Added integration with GitHub actions for code analyses with sonarcloud and codecov for code coverage report Added integration with Docker.On every push event to main branch this action generates a new docker image with the relevant image tag. - https://www.sonarsource.com/products/sonarcloud/ @@ -48,6 +49,7 @@ Added integration with Docker.On every push event to main branch this action gen - Spring Boot Actuator: https://www.baeldung.com/spring-boot-actuators - Injecting Git Information Into Spring: https://www.baeldung.com/spring-git-information - Quartz Job Scheduler with Cron Triggers and Expressions: https://www.quartz-scheduler.org/ +- Spring Custom Events: https://www.baeldung.com/spring-events # Branches: - Branch with name: "java11Version" is set up for JDK11 diff --git a/src/main/java/com/springpageable/dto/ProcessEventDto.java b/src/main/java/com/springpageable/dto/ProcessEventDto.java new file mode 100644 index 0000000..108e35b --- /dev/null +++ b/src/main/java/com/springpageable/dto/ProcessEventDto.java @@ -0,0 +1,20 @@ +package com.springpageable.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; +import java.util.UUID; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ProcessEventDto implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private UUID nextAutoPlanSubJobUuid; +} diff --git a/src/main/java/com/springpageable/event/ProcessEvent.java b/src/main/java/com/springpageable/event/ProcessEvent.java new file mode 100644 index 0000000..bb999c8 --- /dev/null +++ b/src/main/java/com/springpageable/event/ProcessEvent.java @@ -0,0 +1,20 @@ +package com.springpageable.event; + +import com.springpageable.dto.ProcessEventDto; +import com.springpageable.model.FutureDevice; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import org.springframework.context.ApplicationEvent; + +@Getter +@EqualsAndHashCode(callSuper = true) +public class ProcessEvent extends ApplicationEvent { + + private final ProcessEventDto processEventDto; + + public ProcessEvent(FutureDevice futureDevice, ProcessEventDto processEventDto) { + super(futureDevice); + this.processEventDto = processEventDto; + } + +} diff --git a/src/main/java/com/springpageable/event/ProcessEventListener.java b/src/main/java/com/springpageable/event/ProcessEventListener.java new file mode 100644 index 0000000..5c5e796 --- /dev/null +++ b/src/main/java/com/springpageable/event/ProcessEventListener.java @@ -0,0 +1,17 @@ +package com.springpageable.event; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.ApplicationListener; +import org.springframework.stereotype.Component; + +@Component +public class ProcessEventListener implements ApplicationListener { + + private static final Logger LOGGER = LoggerFactory.getLogger(ProcessEventListener.class); + + @Override + public void onApplicationEvent(ProcessEvent event) { + LOGGER.info("Received spring custom event - {}", event.getProcessEventDto()); + } +} diff --git a/src/main/java/com/springpageable/event/ProcessEventPublisher.java b/src/main/java/com/springpageable/event/ProcessEventPublisher.java new file mode 100644 index 0000000..2df1a6d --- /dev/null +++ b/src/main/java/com/springpageable/event/ProcessEventPublisher.java @@ -0,0 +1,24 @@ +package com.springpageable.event; + +import com.springpageable.dto.ProcessEventDto; +import com.springpageable.model.FutureDevice; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Component; + +import java.util.UUID; + +@Component +public class ProcessEventPublisher { + + private ApplicationEventPublisher applicationEventPublisher; + + public ProcessEventPublisher(ApplicationEventPublisher applicationEventPublisher) { + this.applicationEventPublisher = applicationEventPublisher; + } + + public void publishCustomEvent(FutureDevice futureDevice) { + ProcessEventDto processEventDto = new ProcessEventDto(UUID.randomUUID()); + var event = new ProcessEvent(futureDevice, processEventDto); + applicationEventPublisher.publishEvent(event); + } +} diff --git a/src/main/java/com/springpageable/service/FutureDeviceService.java b/src/main/java/com/springpageable/service/FutureDeviceService.java index c2f99fb..f3d365f 100644 --- a/src/main/java/com/springpageable/service/FutureDeviceService.java +++ b/src/main/java/com/springpageable/service/FutureDeviceService.java @@ -2,6 +2,7 @@ import com.springpageable.dto.FutureDeviceDTO; import com.springpageable.dto.GetFutureDeviceResponseDTO; +import com.springpageable.event.ProcessEventPublisher; import com.springpageable.exception.ConflictException; import com.springpageable.exception.ResourceNotFoundException; import com.springpageable.model.mapper.FutureDeviceMapper; @@ -15,87 +16,95 @@ import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; -import java.util.stream.Collectors; - @Service @Slf4j public class FutureDeviceService { - private final FutureDeviceRepository futureDeviceRepository; - private final UserRepository userRepository; + private final FutureDeviceRepository futureDeviceRepository; + private final UserRepository userRepository; + + private final FutureDeviceMapper futureDeviceMapper; - private final FutureDeviceMapper futureDeviceMapper; + private final ProcessEventPublisher applicationEventPublisher; - @Autowired - public FutureDeviceService( - FutureDeviceRepository futureDeviceRepository, FutureDeviceMapper futureDeviceMapper,UserRepository userRepository) { - this.futureDeviceRepository = futureDeviceRepository; - this.futureDeviceMapper = futureDeviceMapper; - this.userRepository=userRepository; - } + @Autowired + public FutureDeviceService( + FutureDeviceRepository futureDeviceRepository, FutureDeviceMapper futureDeviceMapper, + UserRepository userRepository, + ProcessEventPublisher applicationEventPublisher) { + this.futureDeviceRepository = futureDeviceRepository; + this.futureDeviceMapper = futureDeviceMapper; + this.userRepository = userRepository; + this.applicationEventPublisher = applicationEventPublisher; + } - /** - * Find all future devices - * - * @param p - pagination object containing page size, page number and sort parameters - * @param searchParameter - term to search by serialNumber, productId or customerName - * @return Page of {@link GetFutureDeviceResponseDTO} - */ - public Page retrieveFutureDevices( - Pageable p, String searchParameter) { - var futureDevices = futureDeviceRepository.findFutureDevices(p,searchParameter); - if (futureDevices.isEmpty()) { - return Page.empty(); + /** + * Find all future devices + * + * @param p + * - pagination object containing page size, page number and sort parameters + * @param searchParameter + * - term to search by serialNumber, productId or customerName + * @return Page of {@link GetFutureDeviceResponseDTO} + */ + public Page retrieveFutureDevices( + Pageable p, String searchParameter) { + var futureDevices = futureDeviceRepository.findFutureDevices(p, searchParameter); + if (futureDevices.isEmpty()) { + return Page.empty(); + } + var devices = + futureDevices.stream() + .map(futureDeviceMapper::futureDeviceToFutureDeviceResponseDTO) + .toList(); + // trigger custom spring event + applicationEventPublisher.publishCustomEvent(futureDevices.stream().findFirst().orElse(null)); + return new PageImpl<>(devices, p, devices.size()); } - var devices = - futureDevices.stream() - .map(futureDeviceMapper::futureDeviceToFutureDeviceResponseDTO) - .collect(Collectors.toList()); - return new PageImpl<>(devices, p, devices.size()); - } - /** - * Creates new record in device future table, containing combination between - * serialNumber,productId and customerId - * - * @param futureDeviceDTO - {@link FutureDeviceDTO} object containing the new data - */ - public void createFutureDevice(FutureDeviceDTO futureDeviceDTO) { - userRepository.findById(futureDeviceDTO.getCustomerId()).orElseThrow(() -> { - String errMsg = String.format("There is no customer with id %s", futureDeviceDTO.getCustomerId()); - log.error(errMsg); - throw new ResourceNotFoundException(errMsg); - }); - var futureDevice = futureDeviceMapper.futureDeviceDTOToFutureDevice(futureDeviceDTO); - try { - futureDeviceRepository.save(futureDevice); - } catch (DataIntegrityViolationException e) { - String errMsg = - String.format( - "Combination with serial number %s,productId %s and customerId %d already exists", - futureDeviceDTO.getSerialNumber(), - futureDeviceDTO.getProductId(), - futureDeviceDTO.getCustomerId()); - log.error(errMsg); - throw new ConflictException(errMsg); + /** + * Creates new record in device future table, containing combination between serialNumber,productId and customerId + * + * @param futureDeviceDTO + * - {@link FutureDeviceDTO} object containing the new data + */ + public void createFutureDevice(FutureDeviceDTO futureDeviceDTO) { + userRepository.findById(futureDeviceDTO.getCustomerId()).orElseThrow(() -> { + String errMsg = String.format("There is no customer with id %s", futureDeviceDTO.getCustomerId()); + log.error(errMsg); + throw new ResourceNotFoundException(errMsg); + }); + var futureDevice = futureDeviceMapper.futureDeviceDTOToFutureDevice(futureDeviceDTO); + try { + futureDeviceRepository.save(futureDevice); + } catch (DataIntegrityViolationException e) { + String errMsg = + String.format( + "Combination with serial number %s,productId %s and customerId %d already exists", + futureDeviceDTO.getSerialNumber(), + futureDeviceDTO.getProductId(), + futureDeviceDTO.getCustomerId()); + log.error(errMsg); + throw new ConflictException(errMsg); + } } - } - /** - * Deletes a future device - * - * @param id - id of the device to be deleted - */ - public void deleteFutureDevice(long id) { - var futureDevice = - futureDeviceRepository - .findById(id) - .orElseThrow( - () -> { - String errMsg = String.format("No future device found for id: %d", id); - log.error(errMsg); - throw new ResourceNotFoundException(errMsg); - }); - futureDeviceRepository.deleteById(futureDevice.getId()); - } + /** + * Deletes a future device + * + * @param id + * - id of the device to be deleted + */ + public void deleteFutureDevice(long id) { + var futureDevice = + futureDeviceRepository + .findById(id) + .orElseThrow( + () -> { + String errMsg = String.format("No future device found for id: %d", id); + log.error(errMsg); + throw new ResourceNotFoundException(errMsg); + }); + futureDeviceRepository.deleteById(futureDevice.getId()); + } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 628ca91..138203a 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -21,7 +21,6 @@ spring: sharedCache: mode: ENABLE_SELECTIVE hibernate: - dialect: org.hibernate.dialect.PostgreSQLDialect default_schema: dts jdbc.lob.non_contextual_creation: true hibernate.ddl-auto: none diff --git a/src/test/java/com/device/CountryStorageTest.java b/src/test/java/com/device/CountryStorageTest.java index 9e6abf7..63478b4 100644 --- a/src/test/java/com/device/CountryStorageTest.java +++ b/src/test/java/com/device/CountryStorageTest.java @@ -1,27 +1,26 @@ package com.device; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; import com.springpageable.storage.CountryStorage; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import java.io.IOException; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; import java.util.List; -import static com.device.mock.Constants.*; -import static com.springpageable.storage.CountryStorage.*; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.when; +import static com.device.mock.Constants.ALL_COUNTRIES_SIZE; +import static com.device.mock.Constants.COUNTRY_BG_KEY; +import static com.device.mock.Constants.COUNTRY_BG_VALUE; +import static com.device.mock.Constants.COUNTRY_DE_KEY; +import static com.device.mock.Constants.COUNTRY_DE_VALUE; +import static com.device.mock.Constants.EMPTY_STRING; +import static com.device.mock.Constants.NON_EXISTING_COUNTRY_CODE; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; @ExtendWith(MockitoExtension.class) class CountryStorageTest { @@ -42,7 +41,8 @@ void testThat_getCountriesByCountryCodes_returnsTheExpectedCountries() { assertFalse(result.isEmpty()); assertEquals(2, result.size()); assertEquals(2, result.stream() - .filter(country -> country.getName().equals(COUNTRY_BG_VALUE) || country.getName().equals(COUNTRY_DE_VALUE)) + .filter(country -> country.getName().equals(COUNTRY_BG_VALUE) || country.getName() + .equals(COUNTRY_DE_VALUE)) .count()); } @@ -107,7 +107,8 @@ void testThat_areAllCountryCodesSupported_validatesProperly() { // Act & Assert assertTrue(countryStorage.areAllCountryCodesSupported(List.of(COUNTRY_BG_KEY, COUNTRY_DE_KEY))); assertFalse( - countryStorage.areAllCountryCodesSupported(List.of(COUNTRY_BG_KEY, NON_EXISTING_COUNTRY_CODE, COUNTRY_DE_KEY))); + countryStorage.areAllCountryCodesSupported( + List.of(COUNTRY_BG_KEY, NON_EXISTING_COUNTRY_CODE, COUNTRY_DE_KEY))); } @Test diff --git a/src/test/java/com/device/event/ProcessEventListenerTest.java b/src/test/java/com/device/event/ProcessEventListenerTest.java new file mode 100644 index 0000000..e76cdb2 --- /dev/null +++ b/src/test/java/com/device/event/ProcessEventListenerTest.java @@ -0,0 +1,39 @@ +package com.device.event; + +import com.springpageable.dto.ProcessEventDto; +import com.springpageable.event.ProcessEvent; +import com.springpageable.event.ProcessEventListener; +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.util.UUID; + +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class ProcessEventListenerTest { + + @Mock + private ProcessEvent event; + + @InjectMocks + private ProcessEventListener eventListener; + + @Test + void onApplicationEventTest() { + // Arrange + ProcessEventDto processEventDto = new ProcessEventDto(UUID.randomUUID()); + when(event.getProcessEventDto()).thenReturn(processEventDto); + + // Act + eventListener.onApplicationEvent(event); + + // Assert + verify(event, times(1)).getProcessEventDto(); + } +} diff --git a/src/test/java/com/device/event/ProcessEventPublisherTest.java b/src/test/java/com/device/event/ProcessEventPublisherTest.java new file mode 100644 index 0000000..0cf5526 --- /dev/null +++ b/src/test/java/com/device/event/ProcessEventPublisherTest.java @@ -0,0 +1,49 @@ +package com.device.event; + +import com.springpageable.event.ProcessEvent; +import com.springpageable.event.ProcessEventPublisher; +import com.springpageable.model.FutureDevice; +import ie.corballis.fixtures.annotation.Fixture; +import ie.corballis.fixtures.annotation.FixtureAnnotations; +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.springframework.context.ApplicationEventPublisher; + +import java.util.List; + +import static com.device.mock.Constants.FIXTURE_FUTURE_DEVICE; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +@ExtendWith(MockitoExtension.class) +class ProcessEventPublisherTest { + + @Mock + private ApplicationEventPublisher applicationEventPublisher; + + @Fixture(FIXTURE_FUTURE_DEVICE) + private List futureDeviceList; + + @InjectMocks + private ProcessEventPublisher eventPublisher; + + @BeforeEach + void setUp() throws Exception { + FixtureAnnotations.initFixtures(this); + + } + + @Test + void publishCustomEventTest() { + // Act + eventPublisher.publishCustomEvent(futureDeviceList.get(0)); + + // Assert + verify(applicationEventPublisher, times(1)).publishEvent(any(ProcessEvent.class)); + } +} \ No newline at end of file diff --git a/src/test/java/com/device/service/FutureDeviceServiceTest.java b/src/test/java/com/device/service/FutureDeviceServiceTest.java index bd4b850..5fdea2f 100644 --- a/src/test/java/com/device/service/FutureDeviceServiceTest.java +++ b/src/test/java/com/device/service/FutureDeviceServiceTest.java @@ -2,6 +2,7 @@ import com.springpageable.dto.FutureDeviceDTO; import com.springpageable.dto.GetFutureDeviceResponseDTO; +import com.springpageable.event.ProcessEventPublisher; import com.springpageable.exception.BadRequestException; import com.springpageable.exception.ConflictException; import com.springpageable.exception.ResourceNotFoundException; @@ -25,147 +26,166 @@ import java.util.List; import java.util.Optional; -import static com.device.mock.Constants.*; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; +import static com.device.mock.Constants.FIXTURE_FUTURE_DEVICE; +import static com.device.mock.Constants.FIXTURE_FUTURE_DEVICE_DTO; +import static com.device.mock.Constants.FIXTURE_GET_FUTURE_DEVICE_RESPONSE_DTO; +import static com.device.mock.Constants.LIST_OF_USERS; +import static com.device.mock.Constants.SEARCH_PARAMETER_KEY; +import static com.device.mock.Constants.TEST_CUSTOMER_ID; +import static com.device.mock.Constants.TEST_SEARCH_PARAMETER; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class FutureDeviceServiceTest { - private FutureDeviceService underTest; - - @Mock private FutureDeviceRepository mockFutureDeviceRepository; - @Mock private UserRepository mockUserRepository; - @Mock private Pageable mockPageable; - - @Fixture(FIXTURE_FUTURE_DEVICE_DTO) - private FutureDeviceDTO futureDeviceDTO; - - @Fixture(FIXTURE_FUTURE_DEVICE) - private List futureDeviceList; - - @Fixture(LIST_OF_USERS) - private List users; - - @Fixture(FIXTURE_GET_FUTURE_DEVICE_RESPONSE_DTO) - private List getFutureDeviceResponseDtoList; - - @BeforeEach - void setUp() throws Exception { - FixtureAnnotations.initFixtures(this); - - underTest = - new FutureDeviceService( - mockFutureDeviceRepository, new FutureDeviceMapperImpl(), mockUserRepository); - } - - @Test - void testThat_deleteFutureDevice_returnsResult() throws BadRequestException { - // Arrange - when(mockFutureDeviceRepository.findById(anyLong())) - .thenReturn(Optional.of(futureDeviceList.get(0))); - - // Act - underTest.deleteFutureDevice(TEST_CUSTOMER_ID); - - // Assert - verify(mockFutureDeviceRepository).deleteById(anyLong()); - } - - @Test - void testThat_delete_throwsResourceNotFound_inCaseIdDoesNotExists() { - // Arrange - when(mockFutureDeviceRepository.findById(anyLong())).thenReturn(Optional.empty()); - - // Act - var thrown = - assertThrows( - ResourceNotFoundException.class, () -> underTest.deleteFutureDevice(TEST_CUSTOMER_ID)); - - // Assert - assertEquals("No future device found for id: 15", thrown.getMessage()); - } - - @Test - void testThat_createFutureDevice_throwsResourceNotFoundException_whenCustomer_notExists() { - // Arrange - when(mockUserRepository.findById(anyLong())).thenReturn(Optional.empty()); - - // Act - var thrown = - assertThrows( - ResourceNotFoundException.class, () -> underTest.createFutureDevice(futureDeviceDTO)); - - // Assert - assertEquals( - String.format("There is no customer with id %d", futureDeviceDTO.getCustomerId()), - thrown.getMessage()); - } - - @Test - void - testThat_createFutureDevice_throwsConflictException_whenCombinationAlreadyExistsInTheDatabase() { - // Arrange - when(mockUserRepository.findById(anyLong())).thenReturn(Optional.of(users.get(0))); - when(mockFutureDeviceRepository.save(any(FutureDevice.class))) - .thenThrow(new DataIntegrityViolationException("test")); - - // Act - var thrown = - assertThrows(ConflictException.class, () -> underTest.createFutureDevice(futureDeviceDTO)); - - // Assert - assertNotNull(thrown); - assertEquals( - String.format( - "Combination with serial number %s,productId %s and customerId %d already exists", - futureDeviceDTO.getSerialNumber(), - futureDeviceDTO.getProductId(), - futureDeviceDTO.getCustomerId()), - thrown.getMessage()); - } - - @Test - void testThat_createFutureDevice_passed_successfully() { - // Arrange - when(mockUserRepository.findById(anyLong())).thenReturn(Optional.of(users.get(0))); - when(mockFutureDeviceRepository.save(any(FutureDevice.class))) - .thenReturn(futureDeviceList.get(0)); - - // Act - underTest.createFutureDevice(futureDeviceDTO); - - // Assert - verify(mockFutureDeviceRepository).save(any()); - } - - @Test - void testThat_retrieveFutureDevices_returnsResult() throws BadRequestException { - // Arrange - when(mockFutureDeviceRepository.findFutureDevices(any(Pageable.class), anyString())) - .thenReturn(new PageImpl<>(futureDeviceList)); - // Act - var actualResult = - underTest.retrieveFutureDevices(mockPageable, TEST_SEARCH_PARAMETER).getContent(); - - // Assert - verify(mockFutureDeviceRepository).findFutureDevices(mockPageable, SEARCH_PARAMETER_KEY); - assertEquals(getFutureDeviceResponseDtoList.get(0).getId(), actualResult.get(0).getId()); - } - - @Test - void testThat_retrieveFutureDevices_whenNoResultFound() throws BadRequestException { - // Arrange - when(mockFutureDeviceRepository.findFutureDevices(any(Pageable.class), anyString())) - .thenReturn(new PageImpl<>(List.of())); - - //Act - var actualResult = underTest.retrieveFutureDevices(mockPageable, SEARCH_PARAMETER_KEY).getContent(); - - // Assert - assertNotNull(actualResult); - assertTrue(actualResult.isEmpty()); - } + private FutureDeviceService underTest; + + @Mock + private FutureDeviceRepository mockFutureDeviceRepository; + @Mock + private UserRepository mockUserRepository; + + @Mock + private ProcessEventPublisher mockApplicationEventPublisher; + + @Mock + private Pageable mockPageable; + + @Fixture(FIXTURE_FUTURE_DEVICE_DTO) + private FutureDeviceDTO futureDeviceDTO; + + @Fixture(FIXTURE_FUTURE_DEVICE) + private List futureDeviceList; + + @Fixture(LIST_OF_USERS) + private List users; + + @Fixture(FIXTURE_GET_FUTURE_DEVICE_RESPONSE_DTO) + private List getFutureDeviceResponseDtoList; + + @BeforeEach + void setUp() throws Exception { + FixtureAnnotations.initFixtures(this); + + underTest = + new FutureDeviceService( + mockFutureDeviceRepository, new FutureDeviceMapperImpl(), mockUserRepository, + mockApplicationEventPublisher); + } + + @Test + void testThat_deleteFutureDevice_returnsResult() throws BadRequestException { + // Arrange + when(mockFutureDeviceRepository.findById(anyLong())) + .thenReturn(Optional.of(futureDeviceList.get(0))); + + // Act + underTest.deleteFutureDevice(TEST_CUSTOMER_ID); + + // Assert + verify(mockFutureDeviceRepository).deleteById(anyLong()); + } + + @Test + void testThat_delete_throwsResourceNotFound_inCaseIdDoesNotExists() { + // Arrange + when(mockFutureDeviceRepository.findById(anyLong())).thenReturn(Optional.empty()); + + // Act + var thrown = + assertThrows( + ResourceNotFoundException.class, () -> underTest.deleteFutureDevice(TEST_CUSTOMER_ID)); + + // Assert + assertEquals("No future device found for id: 15", thrown.getMessage()); + } + + @Test + void testThat_createFutureDevice_throwsResourceNotFoundException_whenCustomer_notExists() { + // Arrange + when(mockUserRepository.findById(anyLong())).thenReturn(Optional.empty()); + + // Act + var thrown = + assertThrows( + ResourceNotFoundException.class, () -> underTest.createFutureDevice(futureDeviceDTO)); + + // Assert + assertEquals( + String.format("There is no customer with id %d", futureDeviceDTO.getCustomerId()), + thrown.getMessage()); + } + + @Test + void + testThat_createFutureDevice_throwsConflictException_whenCombinationAlreadyExistsInTheDatabase() { + // Arrange + when(mockUserRepository.findById(anyLong())).thenReturn(Optional.of(users.get(0))); + when(mockFutureDeviceRepository.save(any(FutureDevice.class))) + .thenThrow(new DataIntegrityViolationException("test")); + + // Act + var thrown = + assertThrows(ConflictException.class, () -> underTest.createFutureDevice(futureDeviceDTO)); + + // Assert + assertNotNull(thrown); + assertEquals( + String.format( + "Combination with serial number %s,productId %s and customerId %d already exists", + futureDeviceDTO.getSerialNumber(), + futureDeviceDTO.getProductId(), + futureDeviceDTO.getCustomerId()), + thrown.getMessage()); + } + + @Test + void testThat_createFutureDevice_passed_successfully() { + // Arrange + when(mockUserRepository.findById(anyLong())).thenReturn(Optional.of(users.get(0))); + when(mockFutureDeviceRepository.save(any(FutureDevice.class))) + .thenReturn(futureDeviceList.get(0)); + + // Act + underTest.createFutureDevice(futureDeviceDTO); + + // Assert + verify(mockFutureDeviceRepository).save(any()); + } + + @Test + void testThat_retrieveFutureDevices_returnsResult() throws BadRequestException { + // Arrange + when(mockFutureDeviceRepository.findFutureDevices(any(Pageable.class), anyString())) + .thenReturn(new PageImpl<>(futureDeviceList)); + // Act + var actualResult = + underTest.retrieveFutureDevices(mockPageable, TEST_SEARCH_PARAMETER).getContent(); + + // Assert + verify(mockFutureDeviceRepository).findFutureDevices(mockPageable, SEARCH_PARAMETER_KEY); + assertEquals(getFutureDeviceResponseDtoList.get(0).getId(), actualResult.get(0).getId()); + } + + @Test + void testThat_retrieveFutureDevices_whenNoResultFound() throws BadRequestException { + // Arrange + when(mockFutureDeviceRepository.findFutureDevices(any(Pageable.class), anyString())) + .thenReturn(new PageImpl<>(List.of())); + + //Act + var actualResult = underTest.retrieveFutureDevices(mockPageable, SEARCH_PARAMETER_KEY).getContent(); + + // Assert + assertNotNull(actualResult); + assertTrue(actualResult.isEmpty()); + } } diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml index 0918e41..df2f66a 100644 --- a/src/test/resources/application.yml +++ b/src/test/resources/application.yml @@ -21,7 +21,6 @@ spring: sharedCache: mode: ENABLE_SELECTIVE hibernate: - dialect: org.hibernate.dialect.PostgreSQLDialect default_schema: dts jdbc.lob.non_contextual_creation: true hibernate.ddl-auto: none