Skip to content

Commit

Permalink
Added 2nd level cache tests
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisgleissner committed Jun 16, 2024
1 parent 2612282 commit 0345818
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 24 deletions.
6 changes: 1 addition & 5 deletions src/main/java/uk/gleissner/loomwebflux/LoomWebfluxApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,15 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.scheduling.annotation.EnableScheduling;
import uk.gleissner.loomwebflux.config.AppProperties;

@SpringBootApplication
@ConfigurationPropertiesScan(basePackageClasses = AppProperties.class)
@EnableScheduling
@EnableCaching
public class LoomWebfluxApp {
static ConfigurableApplicationContext ctx;

public static void main(String[] args) {
ctx = SpringApplication.run(LoomWebfluxApp.class, args);
SpringApplication.run(LoomWebfluxApp.class, args);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;
import uk.gleissner.loomwebflux.config.AppProperties;
import uk.gleissner.loomwebflux.movie.domain.Movie;
Expand All @@ -24,7 +23,7 @@ public class AppPropertiesAwareMovieRepo {
this.moviesByDirectorNameCache = cacheManager.getCache(MOVIES_BY_DIRECTOR_NAME_CACHE_NAME);
}

@Cacheable("moviesByDirectorName")
// @Cacheable("moviesByDirectorName")
public Set<Movie> findByDirectorName(String directorName) {
return underlying.findByDirectorName(directorName);
}
Expand All @@ -33,17 +32,15 @@ public Movie save(Movie movie) {
if (appProperties.repoReadOnly()) {
return movie;
} else {
// TODO cg Save new movie to cache
moviesByDirectorNameCache.invalidate();
// movie.getDirectors().forEach(director -> moviesByDirectorNameCache.put(director.getLastName(), movie));
return underlying.save(movie);
}
}

public void deleteById(Long id) {
if (!appProperties.repoReadOnly()) {
// underlying.findById(id).ifPresent(movie -> movie.getDirectors().forEach(director -> moviesByDirectorNameCache.evict(director.getLastName())));
underlying.deleteById(id);
// TODO cg Expire deleted movie from cache
moviesByDirectorNameCache.invalidate();
}
}
}
6 changes: 0 additions & 6 deletions src/main/resources/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,6 @@ spring:
threads:
virtual:
enabled: true
cache:
# TODO cg Examine why this Hibernate query cache is not used. Instead, only the Spring Boot cache (Caffeine) is used.
jcache:
provider: org.ehcache.jsr107.EhcacheCachingProvider
cache-names: moviesByDirectorName
jpa:
open-in-view: false
properties:
Expand All @@ -21,7 +16,6 @@ spring:
cache:
region:
factory_class: jcache
# TODO cg Examine why the Hibernate query cache is not used. Instead, only the Spring Boot cache (Caffeine) is used.
use_query_cache: true
use_second_level_cache: true
hibernate:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package uk.gleissner.loomwebflux.fixture

import io.github.oshai.kotlinlogging.KotlinLogging
import nl.altindag.log.LogCaptor
import org.junit.jupiter.api.BeforeEach
import org.junitpioneer.jupiter.cartesian.ArgumentSets
Expand Down Expand Up @@ -27,6 +28,7 @@ abstract class AbstractIntegrationTest {
}

companion object {
val log = KotlinLogging.logger { }

@JvmStatic
fun approaches(): List<String> = listOf(PLATFORM_TOMCAT, LOOM_TOMCAT, LOOM_NETTY, WEBFLUX_NETTY)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package uk.gleissner.loomwebflux.movie

import nl.altindag.log.LogCaptor
import org.assertj.core.api.Assertions.assertThat
import org.junitpioneer.jupiter.cartesian.CartesianTest
import org.springframework.beans.factory.annotation.Autowired
Expand All @@ -16,6 +17,10 @@ import uk.gleissner.loomwebflux.movie.repo.MovieRepo
import java.time.Duration
import java.time.Instant.now

private const val HIBERNATE_ORM_CACHE_LOG_NAME = "org.hibernate.orm.cache"
private const val RETURNING_CACHED_QUERY_RESULTS = "Returning cached query results"
private const val CACHED_QUERY_RESULTS_WERE_NOT_UP_TO_DATE = "Cached query results were not up-to-date"

internal class MovieControllerIntegrationTest : AbstractIntegrationTest() {

@Autowired
Expand All @@ -35,7 +40,8 @@ internal class MovieControllerIntegrationTest : AbstractIntegrationTest() {
@CartesianTestApproachesAndDelayCallDepths
fun `save and delete movies`(approach: String, delayCallDepth: Int) {
val movies = listOf(mulhollandDrive, theStraightStory)
assertThat(getMovies(approach, directorLastName = davidLynch.lastName, delayCallDepth = delayCallDepth)).isEmpty()
fun getMovies() = getMovies(approach, directorLastName = davidLynch.lastName, delayCallDepth = delayCallDepth)
assertThat(getMovies()).isEmpty()

val savedMovies = saveMovies(approach, movies, delayCallDepth = delayCallDepth)
assertThat(savedMovies).hasSize(movies.size)
Expand All @@ -44,14 +50,35 @@ internal class MovieControllerIntegrationTest : AbstractIntegrationTest() {
}
assertThat(savedMovies).usingRecursiveComparison().ignoringFieldsMatchingRegexes(".*id").isEqualTo(movies)

assertThat(getMovies(approach, directorLastName = davidLynch.lastName, delayCallDepth = delayCallDepth)).containsExactlyElementsOf(savedMovies)
secondLevelCacheLogCaptor().use { logCaptor ->
assertThat(getMovies()).containsExactlyElementsOf(savedMovies)
logCaptor.assertThatCached(false)
}

savedMovies.forEach {
deleteMovie(approach, movieId = it.id, delayCallDepth = delayCallDepth)
secondLevelCacheLogCaptor().use { logCaptor ->
assertThat(getMovies()).containsExactlyElementsOf(savedMovies)
logCaptor.assertThatCached(true)
}

secondLevelCacheLogCaptor().use { logCaptor ->
savedMovies.forEach { savedMovie ->
deleteMovie(approach, movieId = savedMovie.id, delayCallDepth = delayCallDepth)
}
assertThat(getMovies()).isEmpty()
logCaptor.assertThatCached(false)
}

assertThat(getMovies(approach, directorLastName = davidLynch.lastName, delayCallDepth = delayCallDepth)).isEmpty()
logCaptor.assertCorrectThreadType(approach, expectedLogCount = (delayCallDepth + 1) * 6)
logCaptor.assertCorrectThreadType(approach, expectedLogCount = (delayCallDepth + 1) * 7)
}

private fun secondLevelCacheLogCaptor() = LogCaptor.forName(HIBERNATE_ORM_CACHE_LOG_NAME)

private fun LogCaptor.assertThatCached(cached: Boolean) {
if (cached) {
assertThat(debugLogs).contains(RETURNING_CACHED_QUERY_RESULTS).doesNotContain(CACHED_QUERY_RESULTS_WERE_NOT_UP_TO_DATE)
} else {
assertThat(debugLogs).doesNotContain(RETURNING_CACHED_QUERY_RESULTS).contains(CACHED_QUERY_RESULTS_WERE_NOT_UP_TO_DATE)
}
}

private fun getMovies(
Expand Down
3 changes: 2 additions & 1 deletion src/test/resources/application-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ loom-webflux:
logging:
level:
uk.gleissner.loomwebflux: debug
#org.hibernate: trace
org.hibernate.orm.cache: debug

0 comments on commit 0345818

Please sign in to comment.