package com.condado.newsletter.controller import com.condado.newsletter.model.VirtualEntity import com.condado.newsletter.repository.VirtualEntityRepository import com.condado.newsletter.scheduler.EntityScheduler import com.condado.newsletter.service.JwtService import com.fasterxml.jackson.databind.ObjectMapper import com.ninjasquad.springmockk.MockkBean import io.mockk.every import io.mockk.just import io.mockk.runs import io.mockk.verify import jakarta.servlet.http.Cookie import org.junit.jupiter.api.AfterEach 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.boot.test.context.SpringBootTest import org.springframework.http.MediaType import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status @SpringBootTest @AutoConfigureMockMvc class VirtualEntityControllerTest { @Autowired lateinit var mockMvc: MockMvc @Autowired lateinit var virtualEntityRepository: VirtualEntityRepository @Autowired lateinit var jwtService: JwtService @MockkBean lateinit var entityScheduler: EntityScheduler private val objectMapper = ObjectMapper() private fun authCookie() = Cookie("jwt", jwtService.generateToken()) @AfterEach fun cleanUp() { virtualEntityRepository.deleteAll() } @Test fun should_return201AndBody_when_postWithValidPayload() { val payload = mapOf("name" to "Fulano da Silva", "email" to "fulano@condado.com", "jobTitle" to "Diretor de Nada") mockMvc.perform(post("/api/v1/virtual-entities").cookie(authCookie()).contentType(MediaType.APPLICATION_JSON).content(objectMapper.writeValueAsString(payload))) .andExpect(status().isCreated).andExpect(jsonPath("$.name").value("Fulano da Silva")).andExpect(jsonPath("$.id").isNotEmpty) } @Test fun should_return400_when_postWithMissingRequiredField() { val payload = mapOf("name" to "Fulano") mockMvc.perform(post("/api/v1/virtual-entities").cookie(authCookie()).contentType(MediaType.APPLICATION_JSON).content(objectMapper.writeValueAsString(payload))) .andExpect(status().isBadRequest) } @Test fun should_return200AndList_when_getAllEntities() { virtualEntityRepository.save(VirtualEntity(name = "Test Entity", email = "test@condado.com", jobTitle = "Tester")) mockMvc.perform(get("/api/v1/virtual-entities").cookie(authCookie())) .andExpect(status().isOk).andExpect(jsonPath("$").isArray).andExpect(jsonPath("$[0].name").value("Test Entity")) } @Test fun should_returnOnlyActiveEntities_when_getAllEntities() { virtualEntityRepository.save(VirtualEntity(name = "Active Entity", email = "active@condado.com", jobTitle = "Tester", active = true)) virtualEntityRepository.save(VirtualEntity(name = "Inactive Entity", email = "inactive@condado.com", jobTitle = "Tester", active = false)) mockMvc.perform(get("/api/v1/virtual-entities").cookie(authCookie())) .andExpect(status().isOk) .andExpect(jsonPath("$.length()").value(1)) .andExpect(jsonPath("$[0].name").value("Active Entity")) } @Test fun should_return200AndEntity_when_getById() { val entity = virtualEntityRepository.save(VirtualEntity(name = "Test Entity", email = "entity@condado.com", jobTitle = "Test Job")) mockMvc.perform(get("/api/v1/virtual-entities/${entity.id}").cookie(authCookie())) .andExpect(status().isOk).andExpect(jsonPath("$.name").value("Test Entity")) } @Test fun should_return404_when_getByIdNotFound() { mockMvc.perform(get("/api/v1/virtual-entities/${java.util.UUID.randomUUID()}").cookie(authCookie())) .andExpect(status().isNotFound) } @Test fun should_return200_when_putWithValidPayload() { val entity = virtualEntityRepository.save(VirtualEntity(name = "Old Name", email = "old@condado.com", jobTitle = "Old Job")) mockMvc.perform(put("/api/v1/virtual-entities/${entity.id}").cookie(authCookie()).contentType(MediaType.APPLICATION_JSON).content("""{"name":"New Name"}""")) .andExpect(status().isOk).andExpect(jsonPath("$.name").value("New Name")).andExpect(jsonPath("$.email").value("old@condado.com")) } @Test fun should_return200AndDeactivated_when_delete() { val entity = virtualEntityRepository.save(VirtualEntity(name = "Active Entity", email = "active@condado.com", jobTitle = "Active Job")) mockMvc.perform(delete("/api/v1/virtual-entities/${entity.id}").cookie(authCookie())) .andExpect(status().isOk).andExpect(jsonPath("$.active").value(false)) } @Test fun should_return200_when_triggerEndpointCalled() { val entity = virtualEntityRepository.save(VirtualEntity(name = "Trigger Entity", email = "trigger@condado.com", jobTitle = "Trigger Job")) every { entityScheduler.runPipeline(any()) } just runs mockMvc.perform(post("/api/v1/virtual-entities/${entity.id}/trigger").cookie(authCookie())) .andExpect(status().isOk) verify(exactly = 1) { entityScheduler.runPipeline(any()) } } }