package org.peerbox.watchservice.integration;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import org.junit.Ignore;
import org.junit.Test;
import org.peerbox.testutils.FileTestUtils;
/**
* @author Claudio Anliker
*
* This set of integration tests is designed to verify correct end-to-end execution of add
* and delete operations. Every test consists of two stages. In the first stage, files
* and/or folders are created. In the second stage, they are deleted again. At the end of
* both stages, the following checks are performed:
*
* - Do the two folders contain the same objects?
* - Are any pending executions left in the queue (this indicates a bug in the FileEventManager)?
* - Is the number of objects contained in both folders as expected (i.e. same file might be
* missing in both places)?
*
* Besides that, the test waits for a specified maximal amount of time after the first stage if
* files are missing. This is done to discover incorrect/incomplete synchronization.
*/
public class AddDelete extends FileIntegrationTest {
/**
* This test verifies the correct add and delete operations
* of a single empty folder.
* @throws IOException
*/
@Test
public void singleFolderTest() throws IOException {
Path folder = addFolder();
assertCleanedUpState(1);
deleteSingleFile(folder, true);
assertCleanedUpState(0);
}
/**
* This test verifies the correct add and delete operations
* of many empty folders.
* @throws IOException
*/
@Test
public void manyFoldersTest() throws IOException {
int numFolders = 20;
List<Path> folders = addFolders(numFolders);
assertCleanedUpState(numFolders);
deleteManyFiles(folders);
assertCleanedUpState(0);
}
/**
* This test verifies the correct add and delete operations
* of a single folder containing a single empty folder.
* @throws IOException
*/
@Test
public void singleFolderInFolderTest() throws IOException {
List<Path> folders = addSingleFolderInFolder();
assertCleanedUpState(2);
deleteSingleFileInFolder(folders);
assertCleanedUpState(0);
}
/**
* This test verifies the correct add and delete operations
* of a single folder containing many empty folders.
* @throws IOException
*/
@Test
public void manyFoldersInFolderTest() throws IOException {
int nrFolders = 20;
List<Path> folders = addManyFoldersInFolder(nrFolders);
assertCleanedUpState(nrFolders + 1);
deleteManyFoldersInFolder(folders);
assertCleanedUpState(1);
}
/**
* This test verifies the correct add and delete operations
* of a single file.
* @throws IOException
*/
@Test
public void singleFileTest() throws IOException {
Path file = addFile();
assertCleanedUpState(1);
deleteSingleFile(file, true);
assertCleanedUpState(0);
}
/**
* This test verifies the correct add and delete operations
* of a single large file.
* @throws IOException
*/
@Test
public void singleLargeFileTest() throws IOException {
Path file = addFile(1024);
assertCleanedUpState(1);
deleteSingleFile(file, true);
assertCleanedUpState(0);
}
/**
* This test verifies the correct add and delete operations
* of many files.
* @throws IOException
*/
@Test
public void manyFilesTest() throws IOException {
manyFilesTest(100, WAIT_TIME_LONG);
}
/**
* This test verifies the correct add and delete operations
* of a very high number of files. This test is used to verify
* stable execution under a huge load which implies high CPU time
* and memory consumption.
* @throws IOException
*/
@Test @Ignore
public void manyFilesStressTest() throws IOException {
manyFilesTest(1000, WAIT_TIME_STRESSTEST);
}
/**
* This test verifies the correct add and delete operations
* of a single folder containing a single file.
* @throws IOException
*/
@Test
public void singleFileInFolderTest() throws IOException {
List<Path> files = addSingleFileInFolder();
assertCleanedUpState(2);
deleteSingleFileInFolder(files);
assertCleanedUpState(0);
}
/**
* This test verifies the correct add and delete operations
* of a single folder containing many files.
* @throws IOException
*/
@Test
public void manyFilesInFolderTest() throws IOException {
int nrFiles = 20;
List<Path> files = addManyFilesInFolder(nrFiles);
assertCleanedUpState(nrFiles + 1);
deleteManyFilesInManyFolders(files);
assertCleanedUpState(0);
}
/**
* This test verifies the correct add and delete operations
* of many folders containing many files.
* @throws IOException
*/
@Test
public void manyFilesInManyFoldersTest() throws IOException {
int nrFolders = 10;
int nrFilesPerFolder = 10;
int allFiles = nrFolders + nrFolders * nrFilesPerFolder;
List<Path> files = addManyFilesInManyFolders(nrFolders, nrFilesPerFolder);
assertCleanedUpState(allFiles);
deleteManyFilesInManyFolders(files);
assertCleanedUpState(0);
}
/**
* This test verifies the correct add and delete operations
* of many folders containing each a single files. A fail of
* this test is mostly implied by incorrect execution order,
* i.e. a file cannot be synchronized as the parent folder was
* not yet synchronized.
* @throws IOException
*/
@Test
public void singleFileInManyFoldersTest() throws IOException{
int nrFolders = 100;
List<Path> allPathsInOne = addSingleFileInManyFolders(nrFolders);
assertCleanedUpState(nrFolders * 2);
deleteManyFilesInManyFolders(allPathsInOne);
assertCleanedUpState(0);
}
private void manyFilesTest(int nrFiles, int waitTime) throws IOException {
List<Path> files = addFiles(nrFiles, waitTime);
assertCleanedUpState(nrFiles);
deleteManyFiles(files);
assertCleanedUpState(0);
}
private List<Path> addSingleFolderInFolder() throws IOException {
Path folder = FileTestUtils.createRandomFolder(masterRootPath);
Path subFolder = FileTestUtils.createRandomFolder(folder);
List<Path> folders = new ArrayList<>();
folders.add(folder);
folders.add(subFolder);
waitForExists(folders, WAIT_TIME_LONG);
return folders;
}
private List<Path> addManyFoldersInFolder(int nrSubFolders) throws IOException {
List<Path> folders = new ArrayList<>();
Path folder = FileTestUtils.createRandomFolder(masterRootPath);
List<Path> subFolders = FileTestUtils.createRandomFolders(folder, nrSubFolders);
folders.addAll(subFolders);
waitForExists(folders, WAIT_TIME_LONG);
return folders;
}
private void deleteManyFoldersInFolder(List<Path> folders) throws IOException {
ListIterator<Path> it = folders.listIterator(folders.size());
while(it.hasPrevious()) {
Path f = it.previous();
deleteSingleFile(f);
}
waitForNotExists(folders, WAIT_TIME_LONG);
}
private void deleteSingleFileInFolder(List<Path> files) throws IOException {
ListIterator<Path> it = files.listIterator(files.size());
while(it.hasPrevious()) {
Path f = it.previous();
deleteSingleFile(f);
}
waitForNotExists(files, WAIT_TIME_SHORT);
}
public static void deleteManyFilesInManyFolders(List<Path> files) throws IOException {
List<Path> folders = new ArrayList<Path>();
// delete files
for(Path p : files) {
if(Files.isDirectory(p)) {
logger.debug("Directory: {}", p);
folders.add(p);
continue;
}
deleteSingleFile(p);
}
// delete (now empty) folders
for(Path p : folders) {
deleteSingleFile(p);
}
waitForNotExists(files, WAIT_TIME_LONG);
}
}