package cloudsync; import cloudsync.exceptions.CloudsyncException; import cloudsync.exceptions.FileIOException; import cloudsync.exceptions.InfoException; import cloudsync.exceptions.UsageException; import cloudsync.helper.CmdOptions; import cloudsync.helper.Crypt; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.StandardOpenOption; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.Random; import org.apache.commons.cli.ParseException; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; public class RemoteLocalFilesystemTest { public RemoteLocalFilesystemTest() { } @BeforeClass public static void setUpClass() { } @AfterClass public static void tearDownClass() { } @Before public void setUp() throws IOException { } @After public void tearDown() throws IOException { } /** * Generate a random hierarchy, backup then restore it. * Check for equality between the origin hierarchy and restored one. */ @Test public void test1() throws IOException, ParseException { File rootFolder = createRandomHierarchie(); File targetLocalRemoteFolder = Files.createTempDirectory("targetRemoteFolder").toFile(); File restoreFolder = new File(rootFolder.getParent(),rootFolder.getName()+"_restore"); File configFile = Files.createTempFile("test1Config", ".config").toFile(); String targetLocalRemoteFolderPath = FilesystemHelper.fixPathSeparators(targetLocalRemoteFolder.getAbsolutePath()); String config = "REMOTE_CONNECTOR=LocalFilesystem"; config += "\n"+ "PASSPHRASE=1234567"; config += "\n"+ "TARGET_DIR=" + targetLocalRemoteFolderPath; config += "\n"+ "CACHEFILE=" + targetLocalRemoteFolderPath + File.separator + ".cloudsync.cache"; config += "\n"+ "LOGFILE=" + targetLocalRemoteFolderPath + File.separator + ".cloudsync.log"; Files.write(configFile.toPath(), config.getBytes(), StandardOpenOption.CREATE); System.out.println("RootFolder: " + rootFolder.getAbsolutePath()); System.out.println("TargetFolder: " + targetLocalRemoteFolder.getAbsolutePath()); String[] args = new String[]{ "--nocache", "--backup", rootFolder.getAbsolutePath(), "--name", "Test1Backup", "--config", configFile.getAbsolutePath() }; Cloudsync.main(args); restoreFolder.mkdir(); args = new String[]{ "--nocache", "--restore", restoreFolder.getAbsolutePath(), "--name", "Test1Backup", "--config", configFile.getAbsolutePath() }; Cloudsync.main(args); assertTrue(hierarchieEquals(rootFolder, restoreFolder)); FileUtils.deleteDirectory(rootFolder); } /** * Create a specific hierarchy * Modify files * Check if file is in history. */ @Test public void test2() throws IOException, ParseException, CloudsyncException, FileIOException, UsageException, InfoException { File rootFolder = Files.createTempDirectory("srcTest2").toFile(); File targetLocalRemoteFolder = Files.createTempDirectory("targetRemoteFolder").toFile(); File restoreFolder = new File(rootFolder.getParent(),rootFolder.getName()+"_restore"); File configFile = Files.createTempFile("test2Config", ".config").toFile(); System.out.println("Test2"); System.out.println("RootFolder: " + rootFolder.getAbsolutePath()); System.out.println("TargetFolder: " + targetLocalRemoteFolder.getAbsolutePath()); String targetLocalRemoteFolderPath = FilesystemHelper.fixPathSeparators(targetLocalRemoteFolder.getAbsolutePath()); String config = "REMOTE_CONNECTOR=LocalFilesystem"; config += "\n"+ "PASSPHRASE=1234567"; config += "\n"+ "TARGET_DIR=" + targetLocalRemoteFolderPath; config += "\n"+ "CACHEFILE=" + targetLocalRemoteFolderPath + File.separator + ".cloudsync.cache"; config += "\n"+ "LOGFILE=" + targetLocalRemoteFolderPath + File.separator + ".cloudsync.log"; config += "\n"+ "HISTORY=3"; Files.write(configFile.toPath(), config.getBytes(), StandardOpenOption.CREATE); /** * rootFolder * /file1 * /subfolder1 * /file2 * /subfolder2 * /file3 */ File file1 = new File(rootFolder,"file1"); File subfolder1 = new File(rootFolder,"subfolder1"); File file2 = new File(subfolder1,"file2"); File subfolder2 = new File(subfolder1,"subfolder2"); File file3 = new File(subfolder2,"file3"); subfolder1.mkdirs(); subfolder2.mkdirs(); Files.write(file1.toPath(), "file 1 content".getBytes("UTF-8"), StandardOpenOption.CREATE_NEW); Files.write(file2.toPath(), "file 2 content".getBytes("UTF-8"), StandardOpenOption.CREATE_NEW); Files.write(file3.toPath(), "file 3 content".getBytes("UTF-8"), StandardOpenOption.CREATE_NEW); String[] args = new String[]{ "--nocache", "--backup", rootFolder.getAbsolutePath(), "--name", "Test2Backup", "--config", configFile.getAbsolutePath() }; Cloudsync.main(args); // Update files content Files.write(file1.toPath(), "new file 1 content updated".getBytes("UTF-8"), StandardOpenOption.TRUNCATE_EXISTING); Files.write(file2.toPath(), "new file 2 content updated".getBytes("UTF-8"), StandardOpenOption.TRUNCATE_EXISTING); Files.write(file3.toPath(), "new file 3 content updated".getBytes("UTF-8"), StandardOpenOption.TRUNCATE_EXISTING); Cloudsync.main(args); // Check if history exist for updated files SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd"); File historyFolder = new File(targetLocalRemoteFolder,"Test2Backup"+"_history_"+sdf.format(new Date())); CmdOptions cmdOptions = new CmdOptions(args); cmdOptions.parse(); Crypt crypt = new Crypt(cmdOptions); assertEquals(historyFolder.listFiles().length,3); for(File f1 : historyFolder.listFiles()) { if(f1.getName().endsWith(".metadata")) { //TODO } else if(f1.isFile()) { assertEquals(crypt.decryptText(f1.getName()), "file1"); _assertEncryptedFileContentEquals(f1,crypt,"file 1 content"); } else { assertEquals(crypt.decryptText(f1.getName()), "subfolder1"); assertEquals(f1.listFiles().length,3); for(File f2 : f1.listFiles()) { if(f2.getName().endsWith(".metadata")) { //TODO } else if(f2.isFile()) { assertEquals(crypt.decryptText(f2.getName()), "file2"); _assertEncryptedFileContentEquals(f2,crypt,"file 2 content"); } else { assertEquals(f2.listFiles().length,2); assertEquals(crypt.decryptText(f2.getName()), "subfolder2"); for(File f3 : f2.listFiles()) { if(f3.getName().endsWith(".metadata")) { //TODO } else { assertEquals(crypt.decryptText(f3.getName()), "file3"); _assertEncryptedFileContentEquals(f3,crypt,"file 3 content"); } } } } } } restoreFolder.mkdir(); args = new String[]{ "--nocache", "--restore", restoreFolder.getAbsolutePath(), "--name", "Test2Backup", "--config", configFile.getAbsolutePath() }; Cloudsync.main(args); assertTrue(hierarchieEquals(rootFolder, restoreFolder)); FileUtils.deleteDirectory(rootFolder); } private void _assertEncryptedFileContentEquals(File file, Crypt crypt, String content) throws IOException, CloudsyncException { byte[] encryptedFileContent = Files.readAllBytes(file.toPath()); ByteArrayInputStream bais = new ByteArrayInputStream(encryptedFileContent); byte[] fileContent = IOUtils.toByteArray(crypt.decryptData(bais)); String s = new String(fileContent, "UTF-8"); assertEquals(s,content); } public static File createRandomHierarchie() throws IOException { Random random = new Random(); int prefixLength = random.nextInt(10)+1; String prefix = "src"+org.apache.commons.lang3.RandomStringUtils.randomAlphanumeric(prefixLength); File root = Files.createTempDirectory(prefix).toFile(); root.mkdirs(); createRandomHierarchie(root,(random.nextDouble()+1.)*3.); return root; } public static void createRandomHierarchie(File parent, double nbFolderProba) throws IOException { Random random = new Random(); double r = random.nextDouble(); while(r < nbFolderProba) { nbFolderProba = nbFolderProba / (random.nextDouble() + 1.); File folder = createRandomFolder(parent,random.nextInt(20)); createRandomHierarchie(folder,nbFolderProba); r = random.nextDouble(); } } public static void createRandomFile(File inFolder) throws IOException { Random random = new Random(); int prefixLength = random.nextInt(10)+3; String prefix = org.apache.commons.lang3.RandomStringUtils.randomAlphanumeric(prefixLength); String suffix = org.apache.commons.lang3.RandomStringUtils.randomAlphanumeric(3); File f = File.createTempFile(prefix, suffix, inFolder); int n = random.nextInt(50); while(n != 0) { int l = random.nextInt(1000); byte[] data = new byte[l]; random.nextBytes(data); Files.write(f.toPath(), data, StandardOpenOption.CREATE,StandardOpenOption.APPEND); n = n - 1; } } public static File createRandomFolder(File inFolder, int nbFile) throws IOException { Random random = new Random(); int prefixLength = random.nextInt(10)+1; String prefix = org.apache.commons.lang3.RandomStringUtils.randomAlphanumeric(prefixLength); File result = Files.createTempDirectory(inFolder.toPath(), prefix).toFile(); result.mkdirs(); for(int i = 0;i<nbFile;i++) { createRandomFile(result); } return result; } public static boolean hierarchieEquals(File root1,File root2) throws IOException { File[] files1 = root1.listFiles(); File[] files2 = root2.listFiles(); if(files1.length != files2.length) { return false; } Map<String,File> mapFiles2 = new HashMap<>(); for(File f : files2) { mapFiles2.put(f.getName(), f); } for(File f1 : files1) { if(!mapFiles2.containsKey(f1.getName())) { return false; } File f2 = mapFiles2.get(f1.getName()); if(f1.isDirectory() && f2.isDirectory()) { if(!hierarchieEquals(f1,f2)) { return false; } } else if(f1.isFile() && f2.isFile()) { if(!FileUtils.contentEquals(f1, f2)) { return false; } } else { return false; } mapFiles2.remove(f1.getName()); } if(!mapFiles2.isEmpty()) { return false; } return true; } }