backend/src/test/java/ai/decompile/workspace/service/BinaryServiceTest.java

176 lines
6.2 KiB
Java

package ai.decompile.workspace.service;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import ai.decompile.common.exception.NotFoundException;
import ai.decompile.workspace.event.BinaryUploadedEvent;
import ai.decompile.workspace.model.dto.BinaryResponse;
import ai.decompile.workspace.model.entity.Binary;
import ai.decompile.workspace.model.entity.Project;
import ai.decompile.workspace.model.entity.Workspace;
import ai.decompile.workspace.model.repository.BinaryRepository;
import ai.decompile.workspace.service.storage.FileStorage;
import java.io.IOException;
import java.time.Instant;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.mock.web.MockMultipartFile;
@ExtendWith(MockitoExtension.class)
class BinaryServiceTest {
@Mock private ProjectService projectService;
@Mock private BinaryRepository binaryRepository;
@Mock private FileStorage fileStorage;
@Mock private ApplicationEventPublisher eventPublisher;
@InjectMocks private BinaryService binaryService;
private UUID projectId;
private UUID binaryId;
private Project project;
private Binary binary;
private byte[] fileContent;
@BeforeEach
void setUp() {
projectId = UUID.randomUUID();
binaryId = UUID.randomUUID();
var workspace =
Workspace.builder()
.id(UUID.randomUUID())
.name("WS")
.createdAt(Instant.now())
.updatedAt(Instant.now())
.build();
project =
Project.builder()
.id(projectId)
.name("Test Project")
.workspace(workspace)
.createdAt(Instant.now())
.updatedAt(Instant.now())
.build();
binary =
Binary.builder()
.id(binaryId)
.filename("test.bin")
.fileSize(100L)
.filePath("abc_test.bin")
.project(project)
.createdAt(Instant.now())
.updatedAt(Instant.now())
.build();
fileContent = new byte[] {1, 2, 3, 4};
project.setBinaries(List.of(binary));
}
@Test
void getBinariesShouldReturnEmptyList() {
when(projectService.getProject(projectId)).thenReturn(project);
when(binaryRepository.findAll(any(Specification.class))).thenReturn(List.of());
List<BinaryResponse> result = binaryService.getBinaries(projectId, null);
assertTrue(result.isEmpty());
verify(projectService).getProject(projectId);
verify(binaryRepository).findAll(any(Specification.class));
}
@Test
void getBinariesShouldReturnList() {
when(projectService.getProject(projectId)).thenReturn(project);
when(binaryRepository.findAll(any(Specification.class))).thenReturn(List.of(binary));
List<BinaryResponse> result = binaryService.getBinaries(projectId, null);
assertEquals(1, result.size());
assertEquals(binaryId, result.getFirst().id());
assertEquals("test.bin", result.getFirst().filename());
assertEquals(projectId, result.getFirst().projectId());
assertEquals(100L, result.getFirst().fileSize());
}
@Test
void getBinariesShouldFilterByFilename() {
when(projectService.getProject(projectId)).thenReturn(project);
when(binaryRepository.findAll(any(Specification.class))).thenReturn(List.of(binary));
List<BinaryResponse> result = binaryService.getBinaries(projectId, "test");
assertEquals(1, result.size());
assertEquals("test.bin", result.getFirst().filename());
verify(binaryRepository).findAll(any(Specification.class));
}
@Test
void getBinariesShouldThrowNotFoundWhenProjectDoesNotExist() {
when(projectService.getProject(projectId))
.thenThrow(new NotFoundException("Project with id '" + projectId + "' not found"));
assertThrows(NotFoundException.class, () -> binaryService.getBinaries(projectId, null));
verify(binaryRepository, never()).findAll(any(Specification.class));
}
@Test
void uploadBinaryShouldSucceed() throws IOException {
var file = new MockMultipartFile("file", "test.exe", "application/octet-stream", fileContent);
when(projectService.getProject(projectId)).thenReturn(project);
when(fileStorage.store(any(), eq("test.exe"))).thenReturn("stored_test.exe");
when(binaryRepository.save(any(Binary.class))).thenReturn(binary);
BinaryResponse result = binaryService.uploadBinary(projectId, file, null);
assertEquals(binaryId, result.id());
assertEquals("test.bin", result.filename());
verify(projectService).getProject(projectId);
verify(fileStorage).store(any(), eq("test.exe"));
verify(binaryRepository).save(any(Binary.class));
verify(eventPublisher).publishEvent(any(BinaryUploadedEvent.class));
}
@Test
void uploadBinaryShouldThrowRuntimeExceptionOnStorageFailure() throws IOException {
var file = new MockMultipartFile("file", "test.exe", "application/octet-stream", fileContent);
when(projectService.getProject(projectId)).thenReturn(project);
when(fileStorage.store(any(), eq("test.exe"))).thenThrow(new IOException("disk full"));
assertThrows(RuntimeException.class, () -> binaryService.uploadBinary(projectId, file, null));
verify(binaryRepository, never()).save(any());
verify(eventPublisher, never()).publishEvent(any());
}
@Test
void deleteBinaryShouldSucceed() throws IOException {
when(binaryRepository.findById(binaryId)).thenReturn(Optional.of(binary));
binaryService.deleteBinary(binaryId);
verify(fileStorage).delete(binary.getFilePath());
verify(binaryRepository).delete(binary);
}
@Test
void deleteBinaryShouldThrowNotFound() throws IOException {
when(binaryRepository.findById(binaryId)).thenReturn(Optional.empty());
assertThrows(NotFoundException.class, () -> binaryService.deleteBinary(binaryId));
verify(fileStorage, never()).delete(any());
verify(binaryRepository, never()).delete((Binary) any());
}
}