/* * Copyright (C) 2006-2016 DLR, Germany * * All rights reserved * * http://www.rcenvironment.de/ */ package de.rcenvironment.core.utils.incubator; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.io.File; import java.io.IOException; import java.nio.file.FileSystemException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.attribute.FileAttribute; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.junit.Before; import org.junit.Test; import de.rcenvironment.core.utils.common.OSFamily; import de.rcenvironment.core.utils.common.TempFileService; import de.rcenvironment.core.utils.common.TempFileServiceAccess; /** * Unit test for {@link FileSystemOperations} methods. * * @author Robert Mischke */ public class FileSystemOperationsTest { private static final String TEST_SUBDIR_NAME = "subdir"; private static final String TEST_FILENAME_2 = "file2.txt"; private static final String TEST_FILENAME_1 = "file1.txt"; private TempFileService tempFileService; private final Log log = LogFactory.getLog(getClass()); private File sandboxDir; private File testRootDir; /** * Common test setup. * * @throws IOException on setup errors */ @Before public void setup() throws IOException { TempFileServiceAccess.setupUnitTestEnvironment(); tempFileService = TempFileServiceAccess.getInstance(); testRootDir = tempFileService.createManagedTempDir(); sandboxDir = createAndVerifySubdir(testRootDir, "sandbox"); log.debug("Testing in temporary directory " + testRootDir.getAbsolutePath()); } /** * Test that a simple sandbox with a few files is properly deleted. * * @throws Exception on uncaught exceptions */ @Test public void testBasicSandboxDeletion() throws Exception { createAndVerifyFile(sandboxDir, TEST_FILENAME_1); File subDir = createAndVerifySubdir(sandboxDir, TEST_SUBDIR_NAME); createAndVerifyFile(subDir, TEST_FILENAME_2); assertEquals(2, sandboxDir.listFiles().length); FileSystemOperations.deleteSandboxDirectory(sandboxDir); assertFalse(sandboxDir.exists()); } /** * Tests that a symbolic link in the sandbox directory that points to another file in the sandbox directory is properly deleted. * * @throws Exception on uncaught exceptions */ @Test public void testInternalLinkDeletion() throws Exception { // Manipulating symlinks requires special permissions on Windows, so this cannot be tested out-of-the-box; // Current solution: check if symlinks can be created, else use junctions (for directories) and hard links (for files) instead. // create internal file link File targetFile = createAndVerifyFile(sandboxDir, TEST_FILENAME_1); File symLinkToTargetFile = new File(sandboxDir, "symLinkToFile"); createOSSpecificTestLink(symLinkToTargetFile, targetFile); // create internal directory link File subDir = createAndVerifySubdir(sandboxDir, TEST_SUBDIR_NAME); createAndVerifyFile(subDir, TEST_FILENAME_2); File symLinkToSubDir = new File(sandboxDir, "symlinkToSubDir"); createOSSpecificTestLink(symLinkToSubDir, subDir); assertEquals(4, sandboxDir.listFiles().length); // file+link, directory+link assertEquals(1, subDir.listFiles().length); assertEquals(1, symLinkToSubDir.listFiles().length); // should "look" like the actual external directory FileSystemOperations.deleteSandboxDirectory(sandboxDir); assertFalse(sandboxDir.exists()); } /** * Tests that a symbolic link in the sandbox directory that points to a file outside of the sandbox directory does *not* cause the * link's target to be deleted. * * @throws Exception on uncaught exceptions */ @Test // @Ignore("WIP; not complete yet") public void testExternalLinkTargetSurvival() throws Exception { // Manipulating symlinks requires special permissions on Windows, so this cannot be tested out-of-the-box; // Current solution: check if symlinks can be created, else use junctions (for directories) and hard links (for files) instead. // create link to external file File symLinkToFile = new File(sandboxDir, "toExternalFile"); File externalFile = createAndVerifyFile(testRootDir, "externalFile.txt"); createOSSpecificTestLink(symLinkToFile, externalFile); // create link to external directory File symLinkToDir = new File(sandboxDir, "toExternalDir"); File subDir = createAndVerifySubdir(sandboxDir, TEST_SUBDIR_NAME); createAndVerifyFile(subDir, TEST_FILENAME_1); File externalDir = createAndVerifySubdir(testRootDir, "externalDir"); File fileInExternalDir = createAndVerifyFile(externalDir, "fileInExternalDir"); createOSSpecificTestLink(symLinkToDir, externalDir); assertEquals(3, sandboxDir.listFiles().length); // normal directory, file symlink, and directory symlink assertEquals(1, externalDir.listFiles().length); assertEquals(1, symLinkToDir.listFiles().length); // should "look" like the actual external directory // verify external files' existence just before deletion assertTrue(externalDir.isDirectory()); assertTrue(fileInExternalDir.isFile()); assertTrue(externalFile.isFile()); FileSystemOperations.deleteSandboxDirectory(sandboxDir); assertFalse(sandboxDir.exists()); // check external files' "survival" assertTrue(externalDir.isDirectory()); assertTrue(fileInExternalDir.isFile()); assertTrue(externalFile.isFile()); } private File createAndVerifySubdir(File parentDir, String name) { File dir = new File(parentDir, name); dir.mkdir(); assertTrue(dir.isDirectory()); return dir; } private File createAndVerifyFile(File parentDir, String name) throws IOException { File file = new File(parentDir, name); file.createNewFile(); assertTrue(file.isFile() && file.canRead()); return file; } private void createOSSpecificTestLink(File linkDir, File linkTargetDir) throws IOException, InterruptedException { Path linkPath = linkDir.toPath(); Path linkTargetPath = linkTargetDir.toPath(); createOSSpecificTestLink(linkPath, linkTargetPath); } private void createOSSpecificTestLink(Path linkPath, Path linkTargetPath) throws IOException, InterruptedException { if (OSFamily.isLinux()) { // use Java 7 code to symlink on Linux Files.createSymbolicLink(linkPath, linkTargetPath, new FileAttribute<?>[0]); } else if (OSFamily.isWindows()) { // Windows requires a special permission to create symbolic links, so test with a NTFS Junction (for a directory) or a hardlink // (for a file) instead if creating symbolic link is not possible. try { //WARNING: This could not be tested yet due to missing permissions. Files.createSymbolicLink(linkPath, linkTargetPath, new FileAttribute<?>[0]); } catch (FileSystemException e) { log.debug("Symlink could not be created due to missing permissions. Creating junction/hardlink instead."); if (Files.isDirectory(linkTargetPath)) { Process process = Runtime.getRuntime().exec( new String[] { "cmd.exe", "/c", "mklink", "/j", linkPath.toString(), linkTargetPath.toString() }); assertEquals(0, process.waitFor()); } else { // Cannot use junctions for simple files, use hard link instead Process process = Runtime.getRuntime().exec( new String[] { "cmd.exe", "/c", "mklink", "/h", linkPath.toString(), linkTargetPath.toString() }); assertEquals(0, process.waitFor()); } } } else { throw new IllegalArgumentException(OSFamily.getLocal().toString()); } } }