package se.magnus.microservices.core.recommendation; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.stream.messaging.Sink; import org.springframework.http.HttpStatus; import org.springframework.integration.channel.AbstractMessageChannel; import org.springframework.messaging.MessagingException; import org.springframework.messaging.support.GenericMessage; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.reactive.server.WebTestClient; import se.magnus.api.core.product.Product; import se.magnus.api.core.recommendation.Recommendation; import se.magnus.api.event.Event; import se.magnus.microservices.core.recommendation.persistence.RecommendationRepository; import se.magnus.util.exceptions.InvalidInputException; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; import static org.springframework.http.HttpStatus.*; import static org.springframework.http.MediaType.APPLICATION_JSON_UTF8; import static se.magnus.api.event.Event.Type.CREATE; import static se.magnus.api.event.Event.Type.DELETE; @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment=RANDOM_PORT, properties = {"spring.data.mongodb.port: 0"}) public class RecommendationServiceApplicationTests { @Autowired private WebTestClient client; @Autowired private RecommendationRepository repository; @Autowired private Sink channels; private AbstractMessageChannel input = null; @Before public void setupDb() { input = (AbstractMessageChannel) channels.input(); repository.deleteAll().block(); } @Test public void getRecommendationsByProductId() { int productId = 1; sendCreateRecommendationEvent(productId, 1); sendCreateRecommendationEvent(productId, 2); sendCreateRecommendationEvent(productId, 3); assertEquals(3, (long)repository.findByProductId(productId).count().block()); getAndVerifyRecommendationsByProductId(productId, OK) .jsonPath("$.length()").isEqualTo(3) .jsonPath("$[2].productId").isEqualTo(productId) .jsonPath("$[2].recommendationId").isEqualTo(3); } @Test public void duplicateError() { int productId = 1; int recommendationId = 1; sendCreateRecommendationEvent(productId, recommendationId); assertEquals(1, (long)repository.count().block()); try { sendCreateRecommendationEvent(productId, recommendationId); fail("Expected a MessagingException here!"); } catch (MessagingException me) { if (me.getCause() instanceof InvalidInputException) { InvalidInputException iie = (InvalidInputException)me.getCause(); assertEquals("Duplicate key, Product Id: 1, Recommendation Id:1", iie.getMessage()); } else { fail("Expected a InvalidInputException as the root cause!"); } } assertEquals(1, (long)repository.count().block()); } @Test public void deleteRecommendations() { int productId = 1; int recommendationId = 1; sendCreateRecommendationEvent(productId, recommendationId); assertEquals(1, (long)repository.findByProductId(productId).count().block()); sendDeleteRecommendationEvent(productId); assertEquals(0, (long)repository.findByProductId(productId).count().block()); sendDeleteRecommendationEvent(productId); } @Test public void getRecommendationsMissingParameter() { getAndVerifyRecommendationsByProductId("", BAD_REQUEST) .jsonPath("$.path").isEqualTo("/recommendation") .jsonPath("$.message").isEqualTo("Required int parameter 'productId' is not present"); } @Test public void getRecommendationsInvalidParameter() { getAndVerifyRecommendationsByProductId("?productId=no-integer", BAD_REQUEST) .jsonPath("$.path").isEqualTo("/recommendation") .jsonPath("$.message").isEqualTo("Type mismatch."); } @Test public void getRecommendationsNotFound() { getAndVerifyRecommendationsByProductId("?productId=113", OK) .jsonPath("$.length()").isEqualTo(0); } @Test public void getRecommendationsInvalidParameterNegativeValue() { int productIdInvalid = -1; getAndVerifyRecommendationsByProductId("?productId=" + productIdInvalid, UNPROCESSABLE_ENTITY) .jsonPath("$.path").isEqualTo("/recommendation") .jsonPath("$.message").isEqualTo("Invalid productId: " + productIdInvalid); } private WebTestClient.BodyContentSpec getAndVerifyRecommendationsByProductId(int productId, HttpStatus expectedStatus) { return getAndVerifyRecommendationsByProductId("?productId=" + productId, expectedStatus); } private WebTestClient.BodyContentSpec getAndVerifyRecommendationsByProductId(String productIdQuery, HttpStatus expectedStatus) { return client.get() .uri("/recommendation" + productIdQuery) .accept(APPLICATION_JSON_UTF8) .exchange() .expectStatus().isEqualTo(expectedStatus) .expectHeader().contentType(APPLICATION_JSON_UTF8) .expectBody(); } private void sendCreateRecommendationEvent(int productId, int recommendationId) { Recommendation recommendation = new Recommendation(productId, recommendationId, "Author " + recommendationId, recommendationId, "Content " + recommendationId, "SA"); Event<Integer, Product> event = new Event(CREATE, productId, recommendation); input.send(new GenericMessage<>(event)); } private void sendDeleteRecommendationEvent(int productId) { Event<Integer, Product> event = new Event(DELETE, productId, null); input.send(new GenericMessage<>(event)); } }