package org.learning.by.example.reactive.microservices.routers; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; 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.handlers.ApiHandler; import org.learning.by.example.reactive.microservices.handlers.ErrorHandler; import org.learning.by.example.reactive.microservices.model.*; import org.learning.by.example.reactive.microservices.services.GeoLocationService; import org.learning.by.example.reactive.microservices.services.SunriseSunsetService; import org.learning.by.example.reactive.microservices.test.BasicIntegrationTest; import org.learning.by.example.reactive.microservices.test.tags.IntegrationTest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.http.HttpStatus; import reactor.core.publisher.Mono; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.isEmptyOrNullString; import static org.hamcrest.core.IsNot.not; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.reset; @IntegrationTest @DisplayName("ApiRouter Integration Tests") class ApiRouterTests extends BasicIntegrationTest { private static final String LOCATION_PATH = "/api/location"; private static final String ADDRESS_ARG = "{address}"; private static final String WRONG_PATH = "/api/wrong"; private static final String GOOGLE_ADDRESS = "1600 Amphitheatre Parkway, Mountain View, CA"; private static final double GOOGLE_LAT = 37.4224082; private static final double GOOGLE_LNG = -122.0856086; private static final String NOT_FOUND = "not found"; private static final String BIG_ERROR = "big error"; private static final String SUNRISE_TIME = "12:55:17 PM"; private static final String SUNSET_TIME = "3:14:28 AM"; private static final Mono<GeographicCoordinates> GOOGLE_LOCATION = Mono.just(new GeographicCoordinates(GOOGLE_LAT, GOOGLE_LNG)); private static final Mono<GeographicCoordinates> LOCATION_NOT_FOUND = Mono.error(new GeoLocationNotFoundException(NOT_FOUND)); private static final Mono<GeographicCoordinates> GENERIC_ERROR = Mono.error(new RuntimeException(BIG_ERROR)); private static final Mono<SunriseSunset> SUNRISE_SUNSET = Mono.just(new SunriseSunset(SUNRISE_TIME, SUNSET_TIME)); @Autowired private ApiHandler apiHandler; @Autowired private ErrorHandler errorHandler; @SpyBean private GeoLocationService geoLocationService; @SpyBean private SunriseSunsetService sunriseSunsetService; @BeforeEach void setup() { super.bindToRouterFunction(ApiRouter.doRoute(apiHandler, errorHandler)); } @BeforeAll static void setupAll() { final ApiRouter apiRouter = new ApiRouter(); } @Test void getWrongPath() { final ErrorResponse response = get( builder -> builder.path(WRONG_PATH).build(), HttpStatus.NOT_FOUND, ErrorResponse.class); assertThat(response.getError(), not(isEmptyOrNullString())); } @Test void postWrongPath() { final ErrorResponse response = post( builder -> builder.path(WRONG_PATH).build(), HttpStatus.NOT_FOUND, new LocationRequest(GOOGLE_ADDRESS), ErrorResponse.class); assertThat(response.getError(), not(isEmptyOrNullString())); } @Test void postWrongObject() { final ErrorResponse response = post( builder -> builder.path(LOCATION_PATH).build(), HttpStatus.BAD_REQUEST, new WrongRequest(GOOGLE_ADDRESS), ErrorResponse.class); assertThat(response.getError(), not(isEmptyOrNullString())); } @Test void postLocationWrongObject() { final ErrorResponse response = post( builder -> builder.path(LOCATION_PATH).build(), HttpStatus.BAD_REQUEST, new WrongRequest(GOOGLE_ADDRESS), ErrorResponse.class); assertThat(response.getError(), not(isEmptyOrNullString())); } @Test void getLocationTest() { doReturn(GOOGLE_LOCATION).when(geoLocationService).fromAddress(any()); doReturn(SUNRISE_SUNSET).when(sunriseSunsetService).fromGeographicCoordinates(any()); final LocationResponse location = get( builder -> builder.path(LOCATION_PATH).path("/").path(ADDRESS_ARG).build(GOOGLE_ADDRESS), LocationResponse.class); assertThat(location.getGeographicCoordinates().getLatitude(), is(GOOGLE_LAT)); assertThat(location.getGeographicCoordinates().getLongitude(), is(GOOGLE_LNG)); reset(geoLocationService); reset(sunriseSunsetService); } @Test void postLocationTest() { doReturn(GOOGLE_LOCATION).when(geoLocationService).fromAddress(any()); doReturn(SUNRISE_SUNSET).when(sunriseSunsetService).fromGeographicCoordinates(any()); final LocationResponse location = post( builder -> builder.path(LOCATION_PATH).build(), new LocationRequest(GOOGLE_ADDRESS), LocationResponse.class); assertThat(location.getGeographicCoordinates().getLatitude(), is(GOOGLE_LAT)); assertThat(location.getGeographicCoordinates().getLongitude(), is(GOOGLE_LNG)); reset(geoLocationService); reset(sunriseSunsetService); } @Test void getLocationNotFoundTest() { doReturn(LOCATION_NOT_FOUND).when(geoLocationService).fromAddress(any()); doReturn(SUNRISE_SUNSET).when(sunriseSunsetService).fromGeographicCoordinates(any()); final ErrorResponse errorResponse = get( builder -> builder.path(LOCATION_PATH).path("/").path(ADDRESS_ARG).build(GOOGLE_ADDRESS), HttpStatus.NOT_FOUND, ErrorResponse.class); assertThat(errorResponse.getError(), is(NOT_FOUND)); reset(geoLocationService); reset(sunriseSunsetService); } @Test void getLocationExceptionTest() { doReturn(GENERIC_ERROR).when(geoLocationService).fromAddress(any()); doReturn(SUNRISE_SUNSET).when(sunriseSunsetService).fromGeographicCoordinates(any()); final ErrorResponse errorResponse = get( builder -> builder.path(LOCATION_PATH).path("/").path(ADDRESS_ARG).build(GOOGLE_ADDRESS), HttpStatus.INTERNAL_SERVER_ERROR, ErrorResponse.class); assertThat(errorResponse.getError(), is(BIG_ERROR)); reset(geoLocationService); reset(sunriseSunsetService); } @Test void getLocationSunriseSunsetExceptionTest() { doReturn(GOOGLE_LOCATION).when(geoLocationService).fromAddress(any()); doReturn(GENERIC_ERROR).when(sunriseSunsetService).fromGeographicCoordinates(any()); final ErrorResponse errorResponse = get( builder -> builder.path(LOCATION_PATH).path("/").path(ADDRESS_ARG).build(GOOGLE_ADDRESS), HttpStatus.INTERNAL_SERVER_ERROR, ErrorResponse.class); assertThat(errorResponse.getError(), is(BIG_ERROR)); reset(geoLocationService); reset(sunriseSunsetService); } @Test void getLocationBothServiceExceptionTest() { doReturn(GENERIC_ERROR).when(geoLocationService).fromAddress(any()); doReturn(GENERIC_ERROR).when(sunriseSunsetService).fromGeographicCoordinates(any()); final ErrorResponse errorResponse = get( builder -> builder.path(LOCATION_PATH).path("/").path(ADDRESS_ARG).build(GOOGLE_ADDRESS), HttpStatus.INTERNAL_SERVER_ERROR, ErrorResponse.class); assertThat(errorResponse.getError(), is(BIG_ERROR)); reset(geoLocationService); reset(sunriseSunsetService); } }