package com.dalab.autoarchival.controller; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; import java.time.LocalDateTime; import java.util.Collections; import java.util.List; import java.util.UUID; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.data.domain.Pageable; import org.springframework.http.MediaType; import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.web.servlet.MockMvc; import com.dalab.autoarchival.dto.ArchivalTaskListResponse; import com.dalab.autoarchival.dto.ArchivalTaskRequest; import com.dalab.autoarchival.dto.ArchivalTaskResponse; import com.dalab.autoarchival.dto.ArchivalTaskStatusDTO; import com.dalab.autoarchival.dto.RestoreRequestDTO; import com.dalab.autoarchival.dto.RestoreResponseDTO; import com.dalab.autoarchival.service.IArchivalTaskService; import com.fasterxml.jackson.databind.ObjectMapper; @WebMvcTest(ArchivalTaskController.class) class ArchivalTaskControllerTest { @Autowired private MockMvc mockMvc; @MockBean private IArchivalTaskService taskService; @Autowired private ObjectMapper objectMapper; private ArchivalTaskRequest sampleTaskRequest; private ArchivalTaskResponse sampleTaskResponse; private ArchivalTaskStatusDTO sampleTaskStatusDTO; private String sampleTaskId; @BeforeEach void setUp() { sampleTaskId = UUID.randomUUID().toString(); ArchivalTaskRequest.ArchivalScope scope = ArchivalTaskRequest.ArchivalScope.builder() .assetIds(List.of("asset1", "asset2")) .build(); sampleTaskRequest = ArchivalTaskRequest.builder() .taskName("Test Archival Task") .scope(scope) .build(); sampleTaskResponse = ArchivalTaskResponse.builder() .taskId(sampleTaskId) .taskName("Test Archival Task") .status("SUBMITTED") .submittedAt(LocalDateTime.now()) .build(); sampleTaskStatusDTO = ArchivalTaskStatusDTO.builder() .taskId(sampleTaskId) .taskName("Test Archival Task") .status("SUBMITTED") .submittedAt(LocalDateTime.now()) .scope(scope) .totalAssetsInScope(2) .build(); } @Test @WithMockUser(authorities = "ROLE_ADMIN") void submitArchivalTask_AsAdmin_ShouldReturnAccepted() throws Exception { when(taskService.submitArchivalTask(any(ArchivalTaskRequest.class))).thenReturn(sampleTaskResponse); mockMvc.perform(post("/api/v1/archival/tasks") .with(csrf()) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(sampleTaskRequest))) .andExpect(status().isAccepted()) .andExpect(jsonPath("$.taskId").value(sampleTaskId)) .andExpect(jsonPath("$.status").value("SUBMITTED")); } @Test @WithMockUser(authorities = "ROLE_ADMIN") void submitArchivalTask_WithInvalidScope_ShouldReturnBadRequest() throws Exception { ArchivalTaskRequest invalidRequest = ArchivalTaskRequest.builder().taskName("Invalid Task").scope(null).build(); ArchivalTaskResponse validationResponse = ArchivalTaskResponse.builder() .status("FAILED_VALIDATION").message("Scope is null").build(); when(taskService.submitArchivalTask(any(ArchivalTaskRequest.class))).thenReturn(validationResponse); mockMvc.perform(post("/api/v1/archival/tasks") .with(csrf()) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(invalidRequest))) .andExpect(status().isBadRequest()); } @Test @WithMockUser(authorities = "ROLE_USER") // Assuming USER can get status void getArchivalTaskStatus_WhenTaskExists_ShouldReturnStatus() throws Exception { when(taskService.getTaskStatus(sampleTaskId)).thenReturn(sampleTaskStatusDTO); mockMvc.perform(get("/api/v1/archival/tasks/{taskId}", sampleTaskId)) .andExpect(status().isOk()) .andExpect(jsonPath("$.taskId").value(sampleTaskId)) .andExpect(jsonPath("$.status").value("SUBMITTED")); } @Test @WithMockUser(authorities = "ROLE_USER") void getArchivalTaskStatus_WhenTaskNotExists_ShouldReturnNotFound() throws Exception { when(taskService.getTaskStatus(sampleTaskId)).thenReturn(null); mockMvc.perform(get("/api/v1/archival/tasks/{taskId}", sampleTaskId)) .andExpect(status().isNotFound()); } @Test @WithMockUser(authorities = "ROLE_USER") void listArchivalTasks_ShouldReturnPageOfTasks() throws Exception { ArchivalTaskListResponse listResponse = ArchivalTaskListResponse.builder() .tasks(Collections.singletonList(sampleTaskStatusDTO)) .pageNumber(0).pageSize(20).totalElements(1).totalPages(1).last(true).first(true).numberOfElements(1) .build(); when(taskService.listTasks(any(Pageable.class))).thenReturn(listResponse); mockMvc.perform(get("/api/v1/archival/tasks").param("page", "0").param("size", "20")) .andExpect(status().isOk()) .andExpect(jsonPath("$.tasks[0].taskId").value(sampleTaskId)); } @Test @WithMockUser(authorities = "ROLE_ADMIN") void approveArchivalTask_AsAdmin_ShouldReturnOk() throws Exception { ArchivalTaskStatusDTO approvedStatus = ArchivalTaskStatusDTO.builder().taskId(sampleTaskId).status("APPROVED").build(); when(taskService.approveTask(eq(sampleTaskId), any())).thenReturn(approvedStatus); mockMvc.perform(post("/api/v1/archival/tasks/{taskId}/approve", sampleTaskId) .with(csrf())) .andExpect(status().isOk()) .andExpect(jsonPath("$.status").value("APPROVED")); } @Test @WithMockUser(authorities = "ROLE_ADMIN") void approveArchivalTask_NotApprovable_ShouldReturnConflict() throws Exception { ArchivalTaskStatusDTO conflictStatus = ArchivalTaskStatusDTO.builder().taskId(sampleTaskId).status("COMPLETED").build(); when(taskService.approveTask(eq(sampleTaskId), any())).thenReturn(conflictStatus); mockMvc.perform(post("/api/v1/archival/tasks/{taskId}/approve", sampleTaskId) .with(csrf())) .andExpect(status().isConflict()); } @Test @WithMockUser(authorities = "ROLE_ADMIN") void rejectArchivalTask_AsAdmin_ShouldReturnOk() throws Exception { ArchivalTaskStatusDTO rejectedStatus = ArchivalTaskStatusDTO.builder().taskId(sampleTaskId).status("REJECTED").build(); when(taskService.rejectTask(eq(sampleTaskId), any())).thenReturn(rejectedStatus); mockMvc.perform(post("/api/v1/archival/tasks/{taskId}/reject", sampleTaskId) .with(csrf())) .andExpect(status().isOk()) .andExpect(jsonPath("$.status").value("REJECTED")); } @Test @WithMockUser(authorities = "ROLE_ADMIN") void requestRestoreArchivalTask_AsAdmin_ShouldReturnAccepted() throws Exception { RestoreRequestDTO restoreRequest = RestoreRequestDTO.builder().restoreTier("STANDARD").retentionDays(7).build(); RestoreResponseDTO restoreResponse = RestoreResponseDTO.builder().archivalTaskId(sampleTaskId).status("RESTORATION_REQUESTED").build(); when(taskService.requestRestore(eq(sampleTaskId), any(RestoreRequestDTO.class))).thenReturn(restoreResponse); mockMvc.perform(post("/api/v1/archival/tasks/{taskId}/restore", sampleTaskId) .with(csrf()) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(restoreRequest))) .andExpect(status().isAccepted()) .andExpect(jsonPath("$.status").value("RESTORATION_REQUESTED")); } }