From 429255fc04976310f2f9ce2666028c54eaea3227 Mon Sep 17 00:00:00 2001 From: Raja Kolli Date: Thu, 22 Aug 2024 17:31:44 +0530 Subject: [PATCH] feat : adds negative tests and labels (#1385) * feat : adds negative tests and labels * adds auto connection pooling --- .github/labeler.yml | 2 + r2dbc/boot-reactive-cache/pom.xml | 7 +++ .../example/cache/services/MovieService.java | 28 +++++----- .../com/example/cache/utils/AppConstants.java | 10 ++-- .../web/controllers/MovieControllerIT.java | 52 +++++++++++++++---- 5 files changed, 70 insertions(+), 29 deletions(-) diff --git a/.github/labeler.yml b/.github/labeler.yml index d353f5e7a..0cf4a8174 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -99,6 +99,7 @@ - any-glob-to-any-file: - r2dbc/boot-jooq-r2dbc-sample/**/* - r2dbc/boot-r2dbc-sample/**/* + - r2dbc/boot-reactive-cache/**/* "component: jobrunr": - changed-files: - any-glob-to-any-file: @@ -150,6 +151,7 @@ - open-api-spring-boot/pom.xml - r2dbc/boot-jooq-r2dbc-sample/pom.xml - r2dbc/boot-r2dbc-sample/pom.xml + - r2dbc/boot-reactive-cache/pom.xml - scheduler/boot-jobrunr-sample/pom.xml - scheduler/boot-scheduler-quartz/pom.xml - scheduler/boot-shedlock-sample/pom.xml diff --git a/r2dbc/boot-reactive-cache/pom.xml b/r2dbc/boot-reactive-cache/pom.xml index ada2f2519..c29670e33 100644 --- a/r2dbc/boot-reactive-cache/pom.xml +++ b/r2dbc/boot-reactive-cache/pom.xml @@ -56,6 +56,7 @@ org.springframework.boot spring-boot-starter-webflux + org.springframework.boot spring-boot-devtools @@ -78,10 +79,15 @@ org.springframework.boot spring-boot-starter-data-redis-reactive + + org.apache.commons + commons-pool2 + org.springframework.boot spring-boot-starter-data-r2dbc + org.postgresql postgresql @@ -92,6 +98,7 @@ r2dbc-postgresql runtime + org.flywaydb flyway-core diff --git a/r2dbc/boot-reactive-cache/src/main/java/com/example/cache/services/MovieService.java b/r2dbc/boot-reactive-cache/src/main/java/com/example/cache/services/MovieService.java index d2f30115e..11e06a2de 100644 --- a/r2dbc/boot-reactive-cache/src/main/java/com/example/cache/services/MovieService.java +++ b/r2dbc/boot-reactive-cache/src/main/java/com/example/cache/services/MovieService.java @@ -5,6 +5,7 @@ import com.example.cache.model.request.MovieRequest; import com.example.cache.model.response.MovieResponse; import com.example.cache.repositories.MovieRepository; +import com.example.cache.utils.AppConstants; import org.springframework.data.redis.core.ReactiveRedisTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -37,22 +38,25 @@ public Flux findAll() { .switchIfEmpty(movieRepository .findAll() // Persisting the fetched movies in the cache. - .flatMap(movie -> reactiveRedisTemplate.opsForValue().set("movie:" + movie.id(), movie)) + .flatMap(movie -> + reactiveRedisTemplate.opsForValue().set(AppConstants.MOVIE_KEY + movie.id(), movie)) // Fetching the movies from the updated cache. - .thenMany(reactiveRedisTemplate.keys("movie:*").flatMap(key -> reactiveRedisTemplate - .opsForValue() - .get(key)))) + .thenMany(reactiveRedisTemplate + .keys(AppConstants.MOVIE_KEY + "*") + .flatMap(key -> + reactiveRedisTemplate.opsForValue().get(key)))) .map(movieMapper::toResponse); } public Mono findMovieById(Long id) { return reactiveRedisTemplate .opsForValue() - .get("movie:" + id) + .get(AppConstants.MOVIE_KEY + id) .switchIfEmpty(movieRepository .findById(id) - .flatMap(movie -> reactiveRedisTemplate.opsForValue().set("movie:" + movie.id(), movie)) - .then(reactiveRedisTemplate.opsForValue().get("movie:" + id))) + .flatMap(movie -> + reactiveRedisTemplate.opsForValue().set(AppConstants.MOVIE_KEY + movie.id(), movie)) + .then(reactiveRedisTemplate.opsForValue().get(AppConstants.MOVIE_KEY + id))) .map(movieMapper::toResponse); } @@ -62,8 +66,8 @@ public Mono saveMovie(MovieRequest movieRequest) { .flatMap(movieRepository::save) .flatMap(movie -> reactiveRedisTemplate .opsForValue() - .set("movie:" + movie.id(), movie) - .then(reactiveRedisTemplate.opsForValue().get("movie:" + movie.id()))) + .set(AppConstants.MOVIE_KEY + movie.id(), movie) + .then(reactiveRedisTemplate.opsForValue().get(AppConstants.MOVIE_KEY + movie.id()))) .map(movieMapper::toResponse); } @@ -75,13 +79,13 @@ public Mono updateMovie(Long id, MovieRequest movieRequest) { .flatMap(movieRepository::save) .flatMap(movie -> reactiveRedisTemplate .opsForValue() - .set("movie:" + movie.id(), movie) - .then(reactiveRedisTemplate.opsForValue().get("movie:" + movie.id()))) + .set(AppConstants.MOVIE_KEY + movie.id(), movie) + .then(reactiveRedisTemplate.opsForValue().get(AppConstants.MOVIE_KEY + movie.id()))) .map(movieMapper::toResponse); } @Transactional public Mono deleteMovieById(Long id) { - return movieRepository.deleteById(id).then(reactiveRedisTemplate.delete("movie:" + id)); + return movieRepository.deleteById(id).then(reactiveRedisTemplate.delete(AppConstants.MOVIE_KEY + id)); } } diff --git a/r2dbc/boot-reactive-cache/src/main/java/com/example/cache/utils/AppConstants.java b/r2dbc/boot-reactive-cache/src/main/java/com/example/cache/utils/AppConstants.java index 9d618c5d7..c8f425133 100644 --- a/r2dbc/boot-reactive-cache/src/main/java/com/example/cache/utils/AppConstants.java +++ b/r2dbc/boot-reactive-cache/src/main/java/com/example/cache/utils/AppConstants.java @@ -1,12 +1,8 @@ package com.example.cache.utils; public final class AppConstants { - public static final String PROFILE_PROD = "prod"; - public static final String PROFILE_NOT_PROD = "!" + PROFILE_PROD; public static final String PROFILE_TEST = "test"; - public static final String PROFILE_NOT_TEST = "!" + PROFILE_TEST; - public static final String DEFAULT_PAGE_NUMBER = "0"; - public static final String DEFAULT_PAGE_SIZE = "10"; - public static final String DEFAULT_SORT_BY = "id"; - public static final String DEFAULT_SORT_DIRECTION = "asc"; + public static final String MOVIE_KEY = "movie:"; + private static final String PROFILE_PROD = "prod"; + public static final String PROFILE_NOT_PROD = "!" + PROFILE_PROD; } diff --git a/r2dbc/boot-reactive-cache/src/test/java/com/example/cache/web/controllers/MovieControllerIT.java b/r2dbc/boot-reactive-cache/src/test/java/com/example/cache/web/controllers/MovieControllerIT.java index 538cd344b..5bed47b2c 100644 --- a/r2dbc/boot-reactive-cache/src/test/java/com/example/cache/web/controllers/MovieControllerIT.java +++ b/r2dbc/boot-reactive-cache/src/test/java/com/example/cache/web/controllers/MovieControllerIT.java @@ -43,13 +43,6 @@ void shouldFetchAllMovies() { .isOk() .expectBodyList(MovieResponse.class) .hasSize(movieFlux.collectList().block().size()); - // .andExpect(jsonPath("$.totalElements", is(3))) - // .andExpect(jsonPath("$.pageNumber", is(1))) - // .andExpect(jsonPath("$.totalPages", is(1))) - // .andExpect(jsonPath("$.isFirst", is(true))) - // .andExpect(jsonPath("$.isLast", is(true))) - // .andExpect(jsonPath("$.hasNext", is(false))) - // .andExpect(jsonPath("$.hasPrevious", is(false))); } @Test @@ -73,6 +66,24 @@ void shouldFindMovieById() { .isEqualTo(movie.title()); } + @Test + void shouldReturn404WhenFetchingNonExistingMovie() { + this.webTestClient + .get() + .uri("/api/movies/{id}", 10000) + .accept(MediaType.APPLICATION_JSON) + .exchange() + .expectStatus() + .isNotFound() + .expectHeader() + .contentType(MediaType.APPLICATION_PROBLEM_JSON) + .expectBody() + .json( + """ + {"type":"https://api.boot-reactive-cache.com/errors/not-found","title":"Not Found","status":404,"detail":"Movie with Id '10000' not found","instance":"/api/movies/10000","errorCategory":"Generic"} + """); + } + @Test void shouldCreateNewMovie() { MovieRequest movieRequest = new MovieRequest("New Movie"); @@ -87,6 +98,10 @@ void shouldCreateNewMovie() { .isCreated() .expectHeader() .contentType(MediaType.APPLICATION_JSON) + .expectHeader() + .contentLength(29) + .expectHeader() + .exists("Location") .expectBody(MovieResponse.class) .value(movieResponse -> { assertThat(movieResponse.id()).isNotNull(); @@ -95,7 +110,7 @@ void shouldCreateNewMovie() { } @Test - void shouldReturn400WhenCreateNewMovieWithoutText() throws Exception { + void shouldReturn400WhenCreateNewMovieWithoutTitle() { MovieRequest movieRequest = new MovieRequest(null); this.webTestClient @@ -118,7 +133,7 @@ void shouldReturn400WhenCreateNewMovieWithoutText() throws Exception { } @Test - void shouldUpdateMovie() throws Exception { + void shouldUpdateMovie() { Long movieId = movieFlux.blockLast().id(); MovieRequest movieRequest = new MovieRequest("Updated Movie"); @@ -157,6 +172,23 @@ void shouldDeleteMovie() { .isEqualTo(movie.id()) .jsonPath("$.title") .isEqualTo(movie.title()); - ; + } + + @Test + void shouldReturn404WhenDeletingNonExistingMovie() { + this.webTestClient + .delete() + .uri("/api/movies/{id}", 10000) + .accept(MediaType.APPLICATION_JSON) + .exchange() + .expectStatus() + .isNotFound() + .expectHeader() + .contentType(MediaType.APPLICATION_PROBLEM_JSON) + .expectBody() + .json( + """ + {"type":"https://api.boot-reactive-cache.com/errors/not-found","title":"Not Found","status":404,"detail":"Movie with Id '10000' not found","instance":"/api/movies/10000","errorCategory":"Generic"} + """); } }