From fcb137de83eed7f78fc67cccf950e93a00c90429 Mon Sep 17 00:00:00 2001 From: boringAdam Date: Wed, 24 Apr 2024 23:46:24 +0200 Subject: [PATCH] added tests, modified start.sh to give right to created user --- Dockerfile | 30 +-- .../controller/FileTreeController.java | 202 +++++++-------- .../com/filetree/service/FileService.java | 238 +++++++++--------- .../controller/FileTreeControllerTest.java | 133 ++++++---- .../com/filetree/service/FileServiceTest.java | 69 ++++- .../filetree/service/LogEntryServiceTest.java | 54 +++- start.sh | 1 + 7 files changed, 441 insertions(+), 286 deletions(-) diff --git a/Dockerfile b/Dockerfile index 7bfe181..e10791f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,16 +1,16 @@ -FROM eclipse-temurin:17-jdk-alpine as builder - -WORKDIR /workspace/app -COPY . . -RUN chmod +x gradlew -RUN sh ./gradlew clean build - -FROM eclipse-temurin:17-jdk-alpine - -WORKDIR /app - -COPY --from=builder /workspace/app/build/libs/FileTree-0.0.1-SNAPSHOT.jar /app/app.jar -COPY start.sh /app/start.sh -RUN chmod +x /app/start.sh - +FROM eclipse-temurin:17-jdk-alpine as builder + +WORKDIR /workspace/app +COPY . . +RUN chmod +x gradlew +RUN sh ./gradlew clean bootJar + +FROM eclipse-temurin:17-jdk-alpine + +WORKDIR /app + +COPY --from=builder /workspace/app/build/libs/FileTree-0.0.1-SNAPSHOT.jar /app/app.jar +COPY start.sh /app/start.sh +RUN chmod +x /app/start.sh + ENTRYPOINT ["sh", "/app/start.sh"] \ No newline at end of file diff --git a/src/main/java/com/filetree/controller/FileTreeController.java b/src/main/java/com/filetree/controller/FileTreeController.java index 0361c9b..c59a2d3 100644 --- a/src/main/java/com/filetree/controller/FileTreeController.java +++ b/src/main/java/com/filetree/controller/FileTreeController.java @@ -1,101 +1,101 @@ -package com.filetree.controller; - -import com.filetree.dto.LogEntryDTO; -import com.filetree.service.FileService; -import com.filetree.service.LogEntryService; -import org.apache.commons.io.FileUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; - -import java.io.File; -import java.io.IOException; -import java.util.List; -import java.util.Set; - -/** - * The FileTreeController class handles all the endpoints - */ -@Controller -public class FileTreeController { - - private final FileService fileService; - private final LogEntryService logEntryService; - - /** - * Constructor to initialize the FileTreeController - * @param logEntryService The LogEntryService the to log the callings of the /getunique endpoint. - */ - @Autowired - public FileTreeController(LogEntryService logEntryService, FileService fileService) { - this.fileService = fileService; - this.logEntryService = logEntryService; - } - - /** - * Endpoint to retrieve a set of unique filenames matching the specified extension. - * @param rootFolder The root folder to search. - * @param extension The file extension to match. - * @return Returns with the list of the distinct filenames. - */ - @GetMapping("/getunique") - @ResponseBody - public Set findFiles(@RequestParam String rootFolder, @RequestParam String extension) { - - return fileService.findFiles(rootFolder, extension); - } - - /** - * Endpoint to get the /getunique endpoint's calling history - * @return Returns with a list of responses - */ - @GetMapping("/history") - @ResponseBody - public List getHistory() { - - return logEntryService.getAllLogEntries(); - } - - /** - * Endpoint to get the Application Documentation - * @return Redirects to the root folder, where the documentation is - */ - @GetMapping("/doc") - public String getDocumentation(){ - - return "redirect:/"; - } - - /** - * Endpoint to generate a random filesystem, to test the /getuniqe endpoint. - * @return Returns with a message if it was successful or not. - */ - @GetMapping("/gen") - @ResponseBody - public String generateFileStructure() { - - File rootFolder = new File("generated_root"); - - if (rootFolder.exists()) { - try { - FileUtils.deleteDirectory(rootFolder); - } catch (IOException e) { - e.printStackTrace(); - return "Failed to delete existing folder."; - } - } - - rootFolder.mkdirs(); - - try { - fileService.createFileStructure(rootFolder, 0); - return "File structure generated successfully."; - } catch (IOException e) { - e.printStackTrace(); - return "Failed to generate file structure."; - } - } - -} +package com.filetree.controller; + +import com.filetree.dto.LogEntryDTO; +import com.filetree.service.FileService; +import com.filetree.service.LogEntryService; +import org.apache.commons.io.FileUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Set; + +/** + * The FileTreeController class handles all the endpoints + */ +@Controller +public class FileTreeController { + + private final FileService fileService; + private final LogEntryService logEntryService; + + /** + * Constructor to initialize the FileTreeController + * @param logEntryService The LogEntryService the to log the callings of the /getunique endpoint. + */ + @Autowired + public FileTreeController(LogEntryService logEntryService, FileService fileService) { + this.fileService = fileService; + this.logEntryService = logEntryService; + } + + /** + * Endpoint to retrieve a set of unique filenames matching the specified extension. + * @param rootFolder The root folder to search. + * @param extension The file extension to match. + * @return Returns with the list of the distinct filenames. + */ + @GetMapping("/getunique") + @ResponseBody + public Set findFiles(@RequestParam String rootFolder, @RequestParam String extension) { + + return fileService.findFiles(rootFolder, extension); + } + + /** + * Endpoint to get the /getunique endpoint's calling history + * @return Returns with a list of the responses + */ + @GetMapping("/history") + @ResponseBody + public List getHistory() { + + return logEntryService.getAllLogEntries(); + } + + /** + * Endpoint to get the Application Documentation + * @return Redirects to the root folder, where the documentation is + */ + @GetMapping("/doc") + public String getDocumentation(){ + + return "redirect:/"; + } + + /** + * Endpoint to generate a random filesystem, to test the /getuniqe endpoint. + * @return Returns with a message if it was successful or not. + */ + @GetMapping("/gen") + @ResponseBody + public String generateFileStructure() { + + File rootFolder = new File("generated_root"); + + if (rootFolder.exists()) { + try { + FileUtils.deleteDirectory(rootFolder); + } catch (IOException e) { + e.printStackTrace(); + return "Failed to delete existing folder."; + } + } + + rootFolder.mkdirs(); + + try { + fileService.createFileStructure(rootFolder, 0); + return "File structure generated successfully."; + } catch (IOException e) { + e.printStackTrace(); + return "Failed to generate file structure."; + } + } + +} diff --git a/src/main/java/com/filetree/service/FileService.java b/src/main/java/com/filetree/service/FileService.java index aae6e1b..982eea6 100644 --- a/src/main/java/com/filetree/service/FileService.java +++ b/src/main/java/com/filetree/service/FileService.java @@ -1,119 +1,119 @@ -package com.filetree.service; - -import com.filetree.model.LogEntry; -import org.apache.commons.io.FileUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import java.io.File; -import java.io.IOException; -import java.time.LocalDateTime; -import java.util.HashSet; -import java.util.Random; -import java.util.Set; - -/** - * The FileService handles all the file operations - */ -@Service -public class FileService { - - private final LogEntryService logEntryService; - - @Autowired - public FileService(LogEntryService logEntryService) { - this.logEntryService = logEntryService; - } - - /** - * Searches for files with the specified extension in the given root folder. - * @param rootFolder The root folder to search. - * @param extension The file extension to match. - * @return Returns a set of filenames with the specified extension. - */ - public Set findFiles(String rootFolder, String extension) { - Set filenames = new HashSet<>(); - searchFiles(new File(rootFolder), extension, filenames); - - String user = executeWhoAmICommand(); - logRequest(user, LocalDateTime.now(), "root_older: " + rootFolder + ", extension: " + extension ,filenames.toString()); - - return filenames; - } - - /** - * Executes the "whoami" command to get the current user. - * @return Returns the username of the current user. - */ - private String executeWhoAmICommand() { - try { - Process process = new ProcessBuilder("whoami").start(); - process.waitFor(); - java.util.Scanner scanner = new java.util.Scanner(process.getInputStream()).useDelimiter("\\A"); - return scanner.hasNext() ? scanner.next().trim() : "Unknown"; - } catch (IOException | InterruptedException e) { - e.printStackTrace(); - return "Unknown"; - } - } - - /** - * Recursively searches for files with the specified extension in the given root folder. - * @param rootFolder The root folder to start searching. - * @param extension The file extension to match. - * @param filenames A set to store the filenames matching the extension. - */ - private void searchFiles(File rootFolder, String extension, Set filenames) { - File[] files = rootFolder.listFiles(); - - if (files != null) { - for (File file : files) { - if (file.isFile() && file.getName().endsWith(extension)) { - filenames.add(file.getName()); - } else if (file.isDirectory()) { - searchFiles(file, extension, filenames); - } - } - } - } - - /** - * Creates a random file structure within the specified folder with the maximum depth of 10. - * Every folder can have 0-3 sub folders, with a 25% chance. - * In every folder there is a 50% chance for a random txt file to spawn. - * @param folder The folder in which to create the file structure. - * @param depth The current depth of recursion to avoid infinite recursive calling. - * @throws IOException In case an IO error occurs while creating the files. - */ - public void createFileStructure(File folder, int depth) throws IOException { - Random random = new Random(); - - if (random.nextBoolean()) { - char fileNameLetter = (char) (random.nextInt(26) + 'a'); - File file = new File(folder, fileNameLetter + ".txt"); - file.createNewFile(); - } - - int numFolders = random.nextInt(4); - if (depth < 10 && numFolders > 0) { - for (int i = 1; i <= numFolders; i++) { - File subFolder = new File(folder, "Folder" + i); - subFolder.mkdirs(); - createFileStructure(subFolder, depth + 1); - } - } - } - - /** - * Logs the file search request and the results. - * @param user The user who made the request. - * @param time The timestamp of the request. - * @param data The search parameters. - * @param result The search result. - */ - private void logRequest(String user, LocalDateTime time, String data, String result) { - LogEntry logEntry = new LogEntry(user, time, data, result); - logEntryService.saveLogEntry(logEntry); - } - -} +package com.filetree.service; + +import com.filetree.model.LogEntry; +import org.apache.commons.io.FileUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.io.IOException; +import java.time.LocalDateTime; +import java.util.HashSet; +import java.util.Random; +import java.util.Set; + +/** + * The FileService handles all the file operations + */ +@Service +public class FileService { + + private final LogEntryService logEntryService; + + @Autowired + public FileService(LogEntryService logEntryService) { + this.logEntryService = logEntryService; + } + + /** + * Searches for files with the specified extension in the given root folder. + * @param rootFolder The root folder to search. + * @param extension The file extension to match. + * @return Returns a set of filenames with the specified extension. + */ + public Set findFiles(String rootFolder, String extension) { + Set filenames = new HashSet<>(); + searchFiles(new File(rootFolder), extension, filenames); + + String user = executeWhoAmICommand(); + logRequest(user, LocalDateTime.now(), "root_folder: " + rootFolder + ", extension: " + extension ,filenames.toString()); + + return filenames; + } + + /** + * Executes the "whoami" command to get the current user. + * @return Returns the username of the current user. + */ + private String executeWhoAmICommand() { + try { + Process process = new ProcessBuilder("whoami").start(); + process.waitFor(); + java.util.Scanner scanner = new java.util.Scanner(process.getInputStream()).useDelimiter("\\A"); + return scanner.hasNext() ? scanner.next().trim() : "Unknown"; + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + return "Unknown"; + } + } + + /** + * Recursively searches for files with the specified extension in the given root folder. + * @param rootFolder The root folder to start searching. + * @param extension The file extension to match. + * @param filenames A set to store the filenames matching the extension. + */ + private void searchFiles(File rootFolder, String extension, Set filenames) { + File[] files = rootFolder.listFiles(); + + if (files != null) { + for (File file : files) { + if (file.isFile() && file.getName().endsWith(extension)) { + filenames.add(file.getName()); + } else if (file.isDirectory()) { + searchFiles(file, extension, filenames); + } + } + } + } + + /** + * Creates a random file structure within the specified folder with the maximum depth of 10. + * Every folder can have 0-3 sub folders, with a 25% chance. + * In every folder there is a 50% chance for a random txt file to spawn. + * @param folder The folder in which to create the file structure. + * @param depth The current depth of recursion to avoid infinite recursive calling. + * @throws IOException In case an IO error occurs while creating the files. + */ + public void createFileStructure(File folder, int depth) throws IOException { + Random random = new Random(); + + if (random.nextBoolean()) { + char fileNameLetter = (char) (random.nextInt(26) + 'a'); + File file = new File(folder, fileNameLetter + ".txt"); + file.createNewFile(); + } + + int numFolders = random.nextInt(4); + if (depth < 10 && numFolders > 0) { + for (int i = 1; i <= numFolders; i++) { + File subFolder = new File(folder, "Folder" + i); + subFolder.mkdirs(); + createFileStructure(subFolder, depth + 1); + } + } + } + + /** + * Logs the file search request and the results. + * @param user The user who made the request. + * @param time The timestamp of the request. + * @param data The search parameters. + * @param result The search result. + */ + private void logRequest(String user, LocalDateTime time, String data, String result) { + LogEntry logEntry = new LogEntry(user, time, data, result); + logEntryService.saveLogEntry(logEntry); + } + +} diff --git a/src/test/java/com/filetree/controller/FileTreeControllerTest.java b/src/test/java/com/filetree/controller/FileTreeControllerTest.java index ea8d56e..a192063 100644 --- a/src/test/java/com/filetree/controller/FileTreeControllerTest.java +++ b/src/test/java/com/filetree/controller/FileTreeControllerTest.java @@ -1,44 +1,91 @@ -package com.filetree.controller; - -import com.filetree.controller.FileTreeController; -import com.filetree.dto.LogEntryDTO; -import com.filetree.model.LogEntry; -import com.filetree.service.FileService; -import com.filetree.service.LogEntryService; -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -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.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.result.MockMvcResultMatchers; -import static org.mockito.Mockito.when; - -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - - -@SpringBootTest -@AutoConfigureMockMvc -public class FileTreeControllerTest { - - @Autowired - private MockMvc mockMvc; - - @Mock - private FileService fileService; - - @Mock - private LogEntryService logEntryService; - - @InjectMocks - private FileTreeController fileTreeController; - - - +package com.filetree.controller; + +import com.filetree.dto.LogEntryDTO; +import com.filetree.service.FileService; +import com.filetree.service.LogEntryService; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.when; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + + +@SpringBootTest +@AutoConfigureMockMvc +@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class}) +public class FileTreeControllerTest { + + @Autowired + private MockMvc mockMvc; + + @MockBean + private FileService fileService; + + @MockBean + private LogEntryService logEntryService; + + @Test + public void testGetUniqueFiles() throws Exception { + Set files = new HashSet<>(); + files.add("file1.txt"); + files.add("file2.txt"); + + when(fileService.findFiles("rootFolder", "txt")).thenReturn(files); + + mockMvc.perform(MockMvcRequestBuilders.get("/getunique") + .param("rootFolder", "rootFolder") + .param("extension", "txt")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$").isArray()) + .andExpect(MockMvcResultMatchers.jsonPath("$.length()").value(files.size())); + } + + @Test + public void testGetHistory() throws Exception { + List logEntries = new ArrayList<>(); + LogEntryDTO logEntry1 = new LogEntryDTO("user1", LocalDateTime.now(), null, null); + LogEntryDTO logEntry2 = new LogEntryDTO("user2", LocalDateTime.now(), null, null); + logEntries.add(logEntry1); + logEntries.add(logEntry2); + + when(logEntryService.getAllLogEntries()).thenReturn(logEntries); + + mockMvc.perform(MockMvcRequestBuilders.get("/history")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$").isArray()) + .andExpect(MockMvcResultMatchers.jsonPath("$.length()").value(logEntries.size())); + } + + @Test + public void testGenerateFileStructure() throws Exception { + doNothing().when(fileService).createFileStructure(any(), anyInt()); + + mockMvc.perform(MockMvcRequestBuilders.get("/gen")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().string("File structure generated successfully.")); + } + + @Test + public void testGetDocumentation() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/doc")) + .andExpect(MockMvcResultMatchers.status().is3xxRedirection()) + .andExpect(MockMvcResultMatchers.redirectedUrl("/")); + } + } \ No newline at end of file diff --git a/src/test/java/com/filetree/service/FileServiceTest.java b/src/test/java/com/filetree/service/FileServiceTest.java index a31aeb5..0e52e66 100644 --- a/src/test/java/com/filetree/service/FileServiceTest.java +++ b/src/test/java/com/filetree/service/FileServiceTest.java @@ -1,4 +1,65 @@ -package com.filetree.service; - -public class FileServiceTest { -} +package com.filetree.service; + +import com.filetree.repository.LogEntryRepository; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.io.File; +import java.io.IOException; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; + +@ExtendWith(MockitoExtension.class) +public class FileServiceTest { + + @InjectMocks + FileService fileService; + @Mock + LogEntryService logEntryService; + + @Test + public void testFindFiles() throws IOException { + File tempDir = createTemporaryDirectory(); + createTestFiles(tempDir); + + Set filenames = fileService.findFiles(tempDir.getPath(), ".txt"); + + assertEquals(3, filenames.size()); + + Mockito.verify(logEntryService).saveLogEntry(any()); + } + + @Test + public void testCreateFileStructure() throws IOException { + File tempDir = createTemporaryDirectory(); + + fileService.createFileStructure(tempDir, 0); + } + + private File createTemporaryDirectory() throws IOException { + File tempDir = File.createTempFile("temp", Long.toString(System.nanoTime())); + tempDir.delete(); + tempDir.mkdir(); + return tempDir; + } + + private void createTestFiles(File directory) throws IOException { + File txtFile1 = new File(directory, "file1.txt"); + txtFile1.createNewFile(); + File txtFile2 = new File(directory, "file2.txt"); + txtFile2.createNewFile(); + File txtFile3 = new File(directory, "file3.txt"); + txtFile3.createNewFile(); + File otherFile1 = new File(directory, "file4.doc"); + otherFile1.createNewFile(); + File otherFile2 = new File(directory, "file5.xml"); + otherFile2.createNewFile(); + } +} + diff --git a/src/test/java/com/filetree/service/LogEntryServiceTest.java b/src/test/java/com/filetree/service/LogEntryServiceTest.java index 7cac3a6..450b32c 100644 --- a/src/test/java/com/filetree/service/LogEntryServiceTest.java +++ b/src/test/java/com/filetree/service/LogEntryServiceTest.java @@ -1,4 +1,50 @@ -package com.filetree.service; - -public class LogEntryServiceTest { -} +package com.filetree.service; + +import com.filetree.dto.LogEntryDTO; +import com.filetree.model.LogEntry; +import com.filetree.repository.LogEntryRepository; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.boot.test.context.SpringBootTest; + +import java.time.LocalDateTime; +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +public class LogEntryServiceTest { + @InjectMocks + LogEntryService logEntryService; + @Mock + LogEntryRepository logEntryRepository; + @Test + public void testGetAllLogEntries() { + LogEntry logEntry1 = new LogEntry("user1", LocalDateTime.now(), "root_folder: folder1 extension: .txt", "result1"); + LogEntry logEntry2 = new LogEntry("user2", LocalDateTime.now(), "root_folder: folder2 extension: .java", "result2"); + List mockEntries = Arrays.asList(logEntry1, logEntry2); + + when(logEntryRepository.findAll()).thenReturn(mockEntries); + + List logEntryDTOs = logEntryService.getAllLogEntries(); + + assertEquals(2, logEntryDTOs.size()); + } + + @Test + public void testSaveLogEntry() { + LogEntryService logEntryService = new LogEntryService(logEntryRepository); + LogEntry logEntry = new LogEntry("user1", LocalDateTime.now(), "data1", "result1"); + + logEntryService.saveLogEntry(logEntry); + + verify(logEntryRepository).save(logEntry); + } +} \ No newline at end of file diff --git a/start.sh b/start.sh index 83ef0f4..9acdb7e 100644 --- a/start.sh +++ b/start.sh @@ -1,4 +1,5 @@ #!/bin/sh adduser -DH -G root $USERNAME +chmod -R 775 /app su -c "java -jar app.jar" "$USERNAME"