diff --git a/build.gradle.kts b/build.gradle.kts index e4c0a8d5..c2e66c6b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -52,6 +52,7 @@ dependencies { implementation("org.springframework.boot:spring-boot-starter-data-jpa") implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springframework.boot:spring-boot-starter-jdbc") + implementation("org.springframework.boot:spring-boot-starter-cache") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") implementation("org.jetbrains.kotlin:kotlin-reflect") implementation("com.ninja-squad:springmockk:4.0.2") diff --git a/docs/open-api.yaml b/docs/open-api.yaml index e327ddbd..b883770f 100644 --- a/docs/open-api.yaml +++ b/docs/open-api.yaml @@ -494,15 +494,15 @@ components: format: int32 sort: $ref: '#/components/schemas/SortObject' + first: + type: boolean + last: + type: boolean numberOfElements: type: integer format: int32 pageable: $ref: '#/components/schemas/PageableObject' - first: - type: boolean - last: - type: boolean empty: type: boolean PageableObject: @@ -519,10 +519,10 @@ components: pageSize: type: integer format: int32 - paged: - type: boolean unpaged: type: boolean + paged: + type: boolean Reservation: required: - address @@ -607,12 +607,12 @@ components: type: string isEnabled: type: boolean + username: + type: string authorities: type: array items: $ref: '#/components/schemas/GrantedAuthority' - username: - type: string isAccountNonExpired: type: boolean isAccountNonLocked: @@ -640,15 +640,15 @@ components: format: int32 sort: $ref: '#/components/schemas/SortObject' + first: + type: boolean + last: + type: boolean numberOfElements: type: integer format: int32 pageable: $ref: '#/components/schemas/PageableObject' - first: - type: boolean - last: - type: boolean empty: type: boolean EventResponse: @@ -703,14 +703,14 @@ components: format: int32 sort: $ref: '#/components/schemas/SortObject' + first: + type: boolean + last: + type: boolean numberOfElements: type: integer format: int32 pageable: $ref: '#/components/schemas/PageableObject' - first: - type: boolean - last: - type: boolean empty: type: boolean diff --git a/src/integrationTest/kotlin/com/group4/ticketingservice/Event/EventControllerTest.kt b/src/integrationTest/kotlin/com/group4/ticketingservice/Event/EventControllerTest.kt new file mode 100644 index 00000000..8d057a0e --- /dev/null +++ b/src/integrationTest/kotlin/com/group4/ticketingservice/Event/EventControllerTest.kt @@ -0,0 +1,33 @@ +package com.group4.ticketingservice.Event + +import com.group4.ticketingservice.AbstractIntegrationTest +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc +import org.springframework.cache.CacheManager +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders + +@AutoConfigureMockMvc +class EventControllerTest : AbstractIntegrationTest() { + @Autowired + private lateinit var mockMvc: MockMvc + + @Autowired + private lateinit var cacheManager: CacheManager + + @Test + fun `getEvents caches the result`() { + mockMvc.perform( + MockMvcRequestBuilders.get("/events") + .param("page", "0") + .param("size", "10") + + ) + + val cache = cacheManager.getCache("getEvents") + val cachedValue = cache!!.get("0-10-id: DESC-null") + + assert(cachedValue != null) + } +} diff --git a/src/main/kotlin/com/group4/ticketingservice/TicketingserviceApplication.kt b/src/main/kotlin/com/group4/ticketingservice/TicketingserviceApplication.kt index 35084a6b..537ca03c 100644 --- a/src/main/kotlin/com/group4/ticketingservice/TicketingserviceApplication.kt +++ b/src/main/kotlin/com/group4/ticketingservice/TicketingserviceApplication.kt @@ -2,10 +2,11 @@ package com.group4.ticketingservice import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.runApplication +import org.springframework.cache.annotation.EnableCaching @SpringBootApplication +@EnableCaching class TicketingserviceApplication - fun main(args: Array) { runApplication(*args) } diff --git a/src/main/kotlin/com/group4/ticketingservice/config/CacheConfig.kt b/src/main/kotlin/com/group4/ticketingservice/config/CacheConfig.kt new file mode 100644 index 00000000..23ac5d0e --- /dev/null +++ b/src/main/kotlin/com/group4/ticketingservice/config/CacheConfig.kt @@ -0,0 +1,33 @@ +package com.group4.ticketingservice.config + +import org.springframework.cache.CacheManager +import org.springframework.cache.annotation.CacheEvict +import org.springframework.cache.annotation.EnableCaching +import org.springframework.cache.concurrent.ConcurrentMapCache +import org.springframework.cache.support.SimpleCacheManager +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.scheduling.annotation.Scheduled + +@Configuration +@EnableCaching +class CacheConfig { + companion object { + private const val EVENT_CACHE = "getEvents" + } + + @Bean + fun cacheManager(): CacheManager { + val simpleCacheManager = SimpleCacheManager() + simpleCacheManager.setCaches( + listOf( + ConcurrentMapCache(EVENT_CACHE) + ) + ) + return simpleCacheManager + } + + @CacheEvict(allEntries = true, value = [EVENT_CACHE]) + @Scheduled(fixedDelay = 10 * 60 * 1000, initialDelay = 500) + fun cacheEvict() {} +} diff --git a/src/main/kotlin/com/group4/ticketingservice/controller/EventController.kt b/src/main/kotlin/com/group4/ticketingservice/controller/EventController.kt index 1904d7a3..8d61bbc7 100644 --- a/src/main/kotlin/com/group4/ticketingservice/controller/EventController.kt +++ b/src/main/kotlin/com/group4/ticketingservice/controller/EventController.kt @@ -8,6 +8,7 @@ import io.swagger.v3.oas.annotations.Hidden import jakarta.servlet.http.HttpServletRequest import jakarta.validation.Valid import org.springframework.beans.factory.annotation.Autowired +import org.springframework.cache.annotation.Cacheable import org.springframework.data.domain.Page import org.springframework.data.domain.Pageable import org.springframework.data.domain.Sort @@ -82,13 +83,14 @@ class EventController @Autowired constructor( } @GetMapping + @Cacheable(value = ["getEvents"], key = "#pageable.pageNumber+'-'+#pageable.pageSize+'-'+#pageable.sort.toString()+'-'+#name") fun getEvents( request: HttpServletRequest, @RequestParam(required = false) name: String?, @PageableDefault(size = 10, sort = ["id"], direction = Sort.Direction.DESC) pageable: Pageable ): ResponseEntity> { val page = eventService.getEvents(name, pageable) - + print(pageable.sort.toString()) val headers = HttpHeaders() headers.set("Content-Location", request.requestURI) diff --git a/src/test/kotlin/com/group4/ticketingservice/event/EventControllerTest.kt b/src/test/kotlin/com/group4/ticketingservice/event/EventControllerTest.kt index c5933162..405d9d31 100644 --- a/src/test/kotlin/com/group4/ticketingservice/event/EventControllerTest.kt +++ b/src/test/kotlin/com/group4/ticketingservice/event/EventControllerTest.kt @@ -14,6 +14,7 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest +import org.springframework.cache.CacheManager import org.springframework.context.annotation.ComponentScan import org.springframework.context.annotation.FilterType import org.springframework.data.domain.Page @@ -34,11 +35,12 @@ import java.time.OffsetDateTime @WebMvcTest( EventController::class, includeFilters = arrayOf( - ComponentScan.Filter(value = [(SecurityConfig::class), (TokenProvider::class), (JwtAuthorizationEntryPoint::class)], type = FilterType.ASSIGNABLE_TYPE) + ComponentScan.Filter(value = [(SecurityConfig::class), (TokenProvider::class), (JwtAuthorizationEntryPoint::class), (CacheManager::class)], type = FilterType.ASSIGNABLE_TYPE) ) ) class EventControllerTest( - @Autowired val mockMvc: MockMvc + @Autowired val mockMvc: MockMvc, + @Autowired val cacheManager: CacheManager ) { @MockkBean private lateinit var eventService: EventService @@ -178,6 +180,7 @@ class EventControllerTest( @Test fun `GET List of events should return list of events with pagination and sorting`() { // Given + every { eventService.getEvents(any(), any()) } returns page // When