package org.learning.by.example.reactive.microservices.services; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.learning.by.example.reactive.microservices.exceptions.GeoLocationNotFoundException; import org.learning.by.example.reactive.microservices.exceptions.GetGeoLocationException; import org.learning.by.example.reactive.microservices.exceptions.InvalidParametersException; import org.learning.by.example.reactive.microservices.model.GeoLocationResponse; import org.learning.by.example.reactive.microservices.model.GeographicCoordinates; import org.learning.by.example.reactive.microservices.test.tags.UnitTest; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.mock.mockito.SpyBean; import reactor.core.publisher.Mono; import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.core.Is.is; import static org.learning.by.example.reactive.microservices.test.RestServiceHelper.getMonoFromJsonPath; import static org.learning.by.example.reactive.microservices.test.RestServiceHelper.mockWebClient; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; @UnitTest @DisplayName("GeoLocationServiceImpl Unit Tests") class GeoLocationServiceImplTests { private static final String GOOGLE_ADDRESS = "1600 Amphitheatre Parkway, Mountain View, CA"; private static final String GOOGLE_ADDRESS_IN_PARAMS = "?address=" + GOOGLE_ADDRESS; private static final Mono<String> GOOGLE_ADDRESS_MONO = Mono.just(GOOGLE_ADDRESS); private static final String BAD_EXCEPTION = "bad exception"; private static final double GOOGLE_LAT = 37.4224082; private static final double GOOGLE_LNG = -122.0856086; private static final String OK_STATUS = "OK"; @SpyBean(GeoLocationService.class) private GeoLocationServiceImpl locationService; private static final String JSON_OK = "/json/GeoLocationResponse_OK.json"; private static final String JSON_NOT_FOUND = "/json/GeoLocationResponse_NOT_FOUND.json"; private static final String JSON_EMPTY = "/json/GeoLocationResponse_EMPTY.json"; private static final String JSON_WRONG_STATUS = "/json/GeoLocationResponse_WRONG_STATUS.json"; private static final Mono<GeoLocationResponse> LOCATION_OK = getMonoFromJsonPath(JSON_OK, GeoLocationResponse.class); private static final Mono<GeoLocationResponse> LOCATION_NOT_FOUND = getMonoFromJsonPath(JSON_NOT_FOUND, GeoLocationResponse.class); private static final Mono<GeoLocationResponse> LOCATION_EMPTY = getMonoFromJsonPath(JSON_EMPTY, GeoLocationResponse.class); private static final Mono<GeoLocationResponse> LOCATION_WRONG_STATUS = getMonoFromJsonPath(JSON_WRONG_STATUS, GeoLocationResponse.class); private static final Mono<GeoLocationResponse> LOCATION_EXCEPTION = Mono.error(new GetGeoLocationException(BAD_EXCEPTION)); private static final Mono<GeoLocationResponse> BIG_EXCEPTION = Mono.error(new RuntimeException(BAD_EXCEPTION)); @Value("${GeoLocationServiceImpl.endPoint}") private String endPoint; @Test void getBeamTest() { assertThat(locationService, is(notNullValue())); } @Test void getMockingWebClientTest() { locationService.webClient = mockWebClient(locationService.webClient, LOCATION_OK); final GeoLocationResponse location = GOOGLE_ADDRESS_MONO.transform(locationService::get).block(); assertThat(location.getStatus(), is(OK_STATUS)); reset(locationService.webClient); } @Test void fromAddressTest() { doReturn(LOCATION_OK).when(locationService).get(any()); final GeographicCoordinates geographicCoordinates = GOOGLE_ADDRESS_MONO.transform(locationService::fromAddress).block(); assertThat(geographicCoordinates, is(notNullValue())); assertThat(geographicCoordinates.getLatitude(), is(GOOGLE_LAT)); assertThat(geographicCoordinates.getLongitude(), is(GOOGLE_LNG)); verify(locationService, times(1)).fromAddress(any()); verify(locationService, times(1)).buildUrl(any()); verify(locationService, times(1)).get(any()); verify(locationService, times(1)).geometryLocation(any()); reset(locationService); } @Test void fromAddressNotFoundTest() { doReturn(LOCATION_NOT_FOUND).when(locationService).get(any()); final GeographicCoordinates geographicCoordinates = GOOGLE_ADDRESS_MONO.transform(locationService::fromAddress) .onErrorResume(throwable -> { assertThat(throwable, instanceOf(GeoLocationNotFoundException.class)); return Mono.empty(); }).block(); assertThat(geographicCoordinates, is(nullValue())); verify(locationService, times(1)).fromAddress(any()); verify(locationService, times(1)).buildUrl(any()); verify(locationService, times(1)).get(any()); verify(locationService, times(1)).geometryLocation(any()); reset(locationService); } @Test void fromAddressExceptionTest() { doReturn(LOCATION_EXCEPTION).when(locationService).get(any()); final GeographicCoordinates geographicCoordinates = GOOGLE_ADDRESS_MONO.transform(locationService::fromAddress) .onErrorResume(throwable -> { assertThat(throwable, instanceOf(GetGeoLocationException.class)); return Mono.empty(); }).block(); assertThat(geographicCoordinates, is(nullValue())); verify(locationService, times(1)).fromAddress(any()); verify(locationService, times(1)).buildUrl(any()); verify(locationService, times(1)).get(any()); verify(locationService, times(1)).geometryLocation(any()); reset(locationService); } @Test void fromAddressBigExceptionTest() { doReturn(BIG_EXCEPTION).when(locationService).get(any()); final GeographicCoordinates geographicCoordinates = GOOGLE_ADDRESS_MONO.transform(locationService::fromAddress) .onErrorResume(throwable -> { assertThat(throwable, instanceOf(GetGeoLocationException.class)); return Mono.empty(); }).block(); assertThat(geographicCoordinates, is(nullValue())); verify(locationService, times(1)).fromAddress(any()); verify(locationService, times(1)).buildUrl(any()); verify(locationService, times(1)).get(any()); verify(locationService, times(1)).geometryLocation(any()); reset(locationService); } @Test void fromAddressEmptyTest() { doReturn(LOCATION_EMPTY).when(locationService).get(any()); final GeographicCoordinates geographicCoordinates = GOOGLE_ADDRESS_MONO.transform(locationService::fromAddress) .onErrorResume(throwable -> { assertThat(throwable, instanceOf(GetGeoLocationException.class)); return Mono.empty(); }).block(); assertThat(geographicCoordinates, is(nullValue())); verify(locationService, times(1)).fromAddress(any()); verify(locationService, times(1)).buildUrl(any()); verify(locationService, times(1)).get(any()); verify(locationService, times(1)).geometryLocation(any()); reset(locationService); } @Test void fromAddressWrongStatusTest() { doReturn(LOCATION_WRONG_STATUS).when(locationService).get(any()); final GeographicCoordinates geographicCoordinates = GOOGLE_ADDRESS_MONO.transform(locationService::fromAddress) .onErrorResume(throwable -> { assertThat(throwable, instanceOf(GetGeoLocationException.class)); return Mono.empty(); }).block(); assertThat(geographicCoordinates, is(nullValue())); verify(locationService, times(1)).fromAddress(any()); verify(locationService, times(1)).buildUrl(any()); verify(locationService, times(1)).get(any()); verify(locationService, times(1)).geometryLocation(any()); reset(locationService); } @Test void buildUrlTest() { final String url = GOOGLE_ADDRESS_MONO.transform(locationService::buildUrl).block(); assertThat(url, is(notNullValue())); assertThat(url, is(endPoint.concat(GOOGLE_ADDRESS_IN_PARAMS))); } @Test void buildUrlEmptyAddressTest() { final String url = Mono.just("").transform(locationService::buildUrl) .onErrorResume(throwable -> { assertThat(throwable, instanceOf(InvalidParametersException.class)); return Mono.empty(); }).block(); assertThat(url, is(nullValue())); } }