/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.core.utils.common;
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.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.LogFactory;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import de.rcenvironment.core.utils.common.TempFileManager.TempFileServiceImpl;
/**
* Tests for {@link TempFileManager}.
*
* @author Robert Mischke
*/
public class TempFileManagerTest {
private static final int COLLISION_TEST_ITERATIONS = 100;
private static final int PARALLEL_TEST_TIMEOUT_MSEC = 30000;
/**
* Expected exception.
*/
@Rule
public ExpectedException expectedException = ExpectedException.none();
private TempFileServiceImpl defaultInstance;
/**
* Creates the test instance.
*
* @throws IOException on setup errors
*/
@Before
public void setUp() throws IOException {
TempFileServiceAccess.setupUnitTestEnvironment();
defaultInstance = (TempFileServiceImpl) TempFileServiceAccess.getInstance();
}
/**
* Fixture teardown. Discards/resets the default {@link TempFileManager} instance.
*/
@After
public void tearDown() {
TempFileServiceAccess.discardCurrentSetup();
}
/**
* Tests that {@link TempFileServiceAccess#getDefaultTestRootDir()} is set after {@link TempFileServiceAccess#setupTestEnvironment()}
* was called.
*/
@Test
public void testDefaultTestRootDir() {
File globalRootDir = ((TempFileServiceImpl) TempFileServiceAccess.getInstance()).getGlobalRootDir();
assertEquals(globalRootDir, TempFileServiceAccess.getDefaultTestRootDir());
}
/**
* Basic Test: Checks that createManagedTempDir returns different directories on repeated calls.
*
* @throws IOException on I/O errors
*/
@Test
public void testCreateManagedTempDir() throws IOException {
File dir1 = defaultInstance.createManagedTempDir();
File dir2 = defaultInstance.createManagedTempDir();
Assert.assertTrue(dir1.isDirectory());
Assert.assertTrue(dir2.isDirectory());
Assert.assertFalse(dir1.getAbsolutePath().equals(dir2.getAbsolutePath()));
}
/**
* Checks that createTempFileWithFixedFilename returns different files on repeated calls, and that the expected filename is met.
*
* @throws IOException on I/O errors
*/
@Test
public void testCreateTempFileWithFixedFilename() throws IOException {
String filename = "fixedNameTest.ext";
File file1 = defaultInstance.createTempFileWithFixedFilename(filename);
File file2 = defaultInstance.createTempFileWithFixedFilename(filename);
Assert.assertTrue(file1.isFile());
Assert.assertTrue(file2.isFile());
Assert.assertFalse(file1.getAbsolutePath().equals(file2.getAbsolutePath()));
Assert.assertTrue(file1.getName().equals(filename));
Assert.assertTrue(file2.getName().equals(filename));
// test that a collision with an externally-created directory of the same name does not fail
String testDirName = "dir";
File collidingDir = new File(file2.getParentFile(), testDirName);
collidingDir.mkdir();
File collidingFile = defaultInstance.createTempFileWithFixedFilename(testDirName);
assertTrue(collidingDir.isDirectory());
assertEquals(testDirName, collidingDir.getName());
assertTrue(collidingFile.isFile());
assertEquals(testDirName, collidingFile.getName());
}
/**
* Test if invalid filenames are properly rejected.
*
* @throws IOException expected
*/
@Test
@Ignore
public void testCreateTempFileWithInvalidFilename() throws IOException {
String filename = "te*st.exe";
expectedException.expect(IOException.class);
expectedException.expectMessage(StringUtils.format("The filename %s is not valid on all supported platforms.", filename));
defaultInstance.createTempFileWithFixedFilename(filename);
}
/**
* Tests that concurrent calls to {@link TempFileService#createTempFileWithFixedFilename(String)} work as intended.
*
* Note that with the current service implementation, the test is somewhat pointless, as the tested method is synchronized, so it is not
* actually parallelized. The test still guards against regressions by future changes.
*
* @throws IOException on I/O errors
* @throws InterruptedException on test interruption
*/
@Test
public void testCreateTempFileWithFixedFilenameCollisions() throws IOException, InterruptedException {
final String filename = "fixedNameTest.ext";
ExecutorService executor = Executors.newFixedThreadPool(COLLISION_TEST_ITERATIONS); // ensure maximum parallelity
final Set<String> absolutePaths = Collections.synchronizedSet(new HashSet<String>());
for (int i = 1; i <= COLLISION_TEST_ITERATIONS; i++) {
executor.submit(new Runnable() {
@Override
public void run() {
File file;
try {
file = defaultInstance.createTempFileWithFixedFilename(filename);
Assert.assertTrue(file.isFile());
Assert.assertTrue(file.getName().equals(filename));
absolutePaths.add(file.getAbsolutePath());
} catch (IOException e) {
// will fail the test as no path is added to the global set
LogFactory.getLog(getClass()).error("Failed to create temp file", e);
}
}
});
}
executor.shutdown();
executor.awaitTermination(PARALLEL_TEST_TIMEOUT_MSEC, TimeUnit.MILLISECONDS);
// test that all generated paths were unique
assertEquals(COLLISION_TEST_ITERATIONS, absolutePaths.size());
}
/**
* Test for {@link TempFileUtils#disposeManagedTempDirOrFile(File)}.
*
* @throws IOException on internal test errors
*/
@Test
public void testDisposeManagedTempDirOrFile() throws IOException {
File dir1 = defaultInstance.createManagedTempDir();
File dir2 = defaultInstance.createManagedTempDir("123asd()_-");
File file1 = defaultInstance.createTempFileFromPattern("dummy*file.txt");
// should succeed
defaultInstance.disposeManagedTempDirOrFile(dir1);
// test deleting some other temp file or directory; should fail
try {
String tempDir = System.getProperty("java.io.tmpdir");
Assert.assertNotNull(tempDir);
defaultInstance.disposeManagedTempDirOrFile(new File(tempDir, "deleteme.txt"));
Assert.fail("Exception expected");
} catch (IOException e) {
// expected: an exception text about the root directory mismatch
Assert.assertTrue(e.getMessage().contains("root"));
}
// should succeed
defaultInstance.disposeManagedTempDirOrFile(dir2);
// test deleting a file (instead of a directory)
defaultInstance.disposeManagedTempDirOrFile(file1);
}
/**
* Tests that the garbage collection does not delete currently-used managed temp directories.
*
* @throws IOException on I/O errors
*/
@Test
@Ignore("target code not implemented yet")
public void testGCDoesNotDeleteLiveInstanceRootDirs() throws IOException {
TempFileManager instance2 = createNewInstanceWithSameGlobalRootDir();
instance2.runGCOnGlobalRootDir();
assertTrue("Own instance root dir should still exist after GC",
defaultInstance.getInstanceRootDir().isDirectory());
assertTrue("External instance root dir should still exist after GC",
// TODO review: correct instance?
defaultInstance.getInstanceRootDir().isDirectory());
}
/**
* Tests that the garbage collection deletes all "instance root" directories except the ones that are currently in use (by this test).
*
* @throws IOException on I/O errors
*/
@Test
@Ignore("target code not implemented yet")
public void testGCDeletesAllNonLiveInstanceRootDirs() throws IOException {
TempFileManager instance2 = createNewInstanceWithSameGlobalRootDir();
instance2.runGCOnGlobalRootDir();
File globalRootDir = instance2.getGlobalRootDir();
List<File> content = TempFileManager.getActualDirectoryContent(globalRootDir);
assertEquals("Global root dir " + globalRootDir.getAbsolutePath() + " should only contain two directories after GC test", 2,
content.size());
assertTrue("Fresh instance root dir should still exist after external GC",
defaultInstance.getInstanceRootDir().isDirectory());
}
private TempFileManager createNewInstanceWithSameGlobalRootDir() throws IOException {
// verify implicit creation of instance root
assertTrue("Default instance should have created its instance root dir",
defaultInstance.getInstanceRootDir().isDirectory());
TempFileManager instance2 = new TempFileManager(defaultInstance.getGlobalRootDir(), null);
// verify *global* root dir equality
assertTrue(defaultInstance.getGlobalRootDir().equals(instance2.getGlobalRootDir()));
// verify *instance* root dir *in*equality
assertFalse(defaultInstance.getInstanceRootDir().equals(instance2.getServiceImplementation().getInstanceRootDir()));
return instance2;
}
}