package hudson.plugins.filesystem_scm; import static org.junit.Assert.*; import org.junit.*; import java.io.*; import java.util.*; import org.apache.commons.io.*; public class FolderDiffTest { File src; File dst; long modifiedTime; long checkTime; final static long diff = 60*60*2*1000L; @Before public void setupSrcAndDst() throws IOException { src = getTempDir(); for(int i=0; i<50; i++) createRandomFile(src); dst = getTempDir(); FileUtils.copyDirectory(src, dst); checkTime = System.currentTimeMillis() - 60*60*1000L; modifiedTime = System.currentTimeMillis() - diff; } private static File createRandomFile(File dir) { while(true) { String name = getRandomName(); File tmp = new File(dir, name); if ( !tmp.exists() ) { try { FileUtils.touch(tmp); tmp.setLastModified(System.currentTimeMillis()-2*diff); return tmp; } catch ( IOException e ) { continue; } } } } private static String getRandomName() { String[] names = { "Apple", "Banana", "Cherry", "Durian", "Eggfruit", "Figs", "Grapes", "Honeydew", "Melon", "Jujube", "Kiwi", "Lemon", "Mango", "Nectarine", "Orange", "Pineapple", "Raisins", "Strawberries", "Tangerine", "Watermelon" }; String[] exts = {"cpp", "jsp", "java", "tmp", "$$$", "txt", "xml", "exe", "dll", "", "html", "css", "js"}; StringBuffer buf = new StringBuffer(); buf.append(names[new Random().nextInt(names.length)]); int count = new Random().nextInt(4); for(int i=0; i<count; i++) { if ( new Random().nextInt(3) == 0 ) buf.append("/"); buf.append(names[new Random().nextInt(names.length)]); } String name = buf.toString(); String ext = exts[new Random().nextInt(exts.length)]; if ( 0 == ext.length() ) return name; else return name + "." + ext; } private static File getTempDir() { for(int i=0; i<20; i++) { try { File file = File.createTempFile("fsscm", null); file.delete(); file.mkdir(); return file; } catch ( IOException e ) { continue; } } throw new RuntimeException("Can't creat temp directory"); } @After public void deleteSrcAndDst() throws IOException { FileUtils.forceDelete(src); FileUtils.forceDelete(dst); } @Test public void testModifiedFiles() throws IOException { Set<FolderDiff.Entry> expected = processFiles(src, new FileCallable() { public void process(File file, Set<FolderDiff.Entry> expected) throws IOException { file.setLastModified(modifiedTime); String relativeName = FolderDiff.getRelativeName(file.getAbsolutePath(), src.getAbsolutePath()); expected.add(new FolderDiff.Entry(relativeName, FolderDiff.Entry.Type.MODIFIED)); } }); FolderDiff diff = getFolderDiff(); List<FolderDiff.Entry> result = diff.getNewOrModifiedFiles(checkTime, false, true); assertEquals(expected, new HashSet<FolderDiff.Entry>(result)); } @Test public void testCopiedFiles() throws IOException { Set<FolderDiff.Entry> expected = processFiles(src, new FileCallable() { public void process(File file, Set<FolderDiff.Entry> expected) throws IOException { File newFile = createNewFile(file, true); String relativeName = FolderDiff.getRelativeName(newFile.getAbsolutePath(), src.getAbsolutePath()); expected.add(new FolderDiff.Entry(relativeName, FolderDiff.Entry.Type.NEW)); } }); FolderDiff diff = getFolderDiff(); List<FolderDiff.Entry> result = diff.getNewOrModifiedFiles(checkTime, false, true); assertEquals(expected, new HashSet<FolderDiff.Entry>(result)); } @Test public void testCreatedFiles() throws IOException { Set<FolderDiff.Entry> expected = processFiles(src, new FileCallable() { public void process(File file, Set<FolderDiff.Entry> expected) throws IOException { File newFile = createNewFile(file, false); String relativeName = FolderDiff.getRelativeName(newFile.getAbsolutePath(), src.getAbsolutePath()); expected.add(new FolderDiff.Entry(relativeName, FolderDiff.Entry.Type.NEW)); } }); FolderDiff diff = getFolderDiff(); List<FolderDiff.Entry> result = diff.getNewOrModifiedFiles(checkTime, false, true); assertEquals(expected, new HashSet<FolderDiff.Entry>(result)); } @Test public void testDeletedFiles() throws IOException { Set<FolderDiff.Entry> expected = processFiles(src, new FileCallable() { public void process(File file, Set<FolderDiff.Entry> expected) throws IOException { if ( file.delete() ) { String relativeName = FolderDiff.getRelativeName(file.getAbsolutePath(), src.getAbsolutePath()); expected.add(new FolderDiff.Entry(relativeName, FolderDiff.Entry.Type.DELETED)); } } }); FolderDiff diff = getFolderDiff(); List<FolderDiff.Entry> result = diff.getDeletedFiles(checkTime, false, true); assertEquals(expected, new HashSet<FolderDiff.Entry>(result)); } @Test public void testNewFilesInDst() throws IOException { Set<FolderDiff.Entry> expected = processFiles(dst, new FileCallable() { public void process(File file, Set<FolderDiff.Entry> expected) throws IOException { // the file is newly created in dst, we shouldn't delete this file // therefore, we don't need to add to expected File newFile = createNewFile(file, false); String relativeName = FolderDiff.getRelativeName(newFile.getAbsolutePath(), dst.getAbsolutePath()); expected.add(new FolderDiff.Entry(relativeName, FolderDiff.Entry.Type.DELETED)); } }); FolderDiff diff = getFolderDiff(); List<FolderDiff.Entry> result = diff.getDeletedFiles(checkTime, false, true); assertEquals(expected, new HashSet<FolderDiff.Entry>(result)); } @Test public void testCopiedFilesInDst() throws IOException { Set<FolderDiff.Entry> expected = processFiles(dst, new FileCallable() { public void process(File file, Set<FolderDiff.Entry> expected) throws IOException { // the file is copied in dst, the last modified time should be same as the original one // we should delete this file File newFile = createNewFile(file, true); String relativeName = FolderDiff.getRelativeName(newFile.getAbsolutePath(), dst.getAbsolutePath()); expected.add(new FolderDiff.Entry(relativeName, FolderDiff.Entry.Type.DELETED)); } }); FolderDiff diff = getFolderDiff(); List<FolderDiff.Entry> result = diff.getDeletedFiles(checkTime, false, true); assertEquals(expected, new HashSet<FolderDiff.Entry>(result)); } @Test public void testCopiedFilesInDstWithAllowDeleteList() throws IOException { Collection<File> list = FileUtils.listFiles(dst, null, true); Set<String> allowDeleteList = new HashSet<String>(); for(File file : list) { String relativePath = FolderDiff.getRelativeName(file.getAbsolutePath(), dst.getAbsolutePath()); allowDeleteList.add(relativePath); } Set<FolderDiff.Entry> expected = processFiles(dst, new FileCallable() { public void process(File file, Set<FolderDiff.Entry> expected) throws IOException { // the file is copied in dst, the last modified time should be same as the original one // we should delete this file File newFile = createNewFile(file, true); } }); FolderDiff diff = getFolderDiff(); diff.setAllowDeleteList(allowDeleteList); List<FolderDiff.Entry> result = diff.getDeletedFiles(checkTime, false, true); assertEquals(expected, new HashSet<FolderDiff.Entry>(result)); } private File createNewFile(File srcFile, boolean copyFile) throws IOException { String ext = FilenameUtils.getExtension(srcFile.getAbsolutePath()); if ( null != ext && ext.length() > 0 ) ext = "." + ext; String base = FilenameUtils.removeExtension(srcFile.getAbsolutePath()); for(int i=0; ; i++) { String newName = null; if ( 0 == i ) newName = base + "New" + ext; else newName = base + "New" + i + ext; File newFile = new File(newName); if ( !newFile.exists() ) { if ( copyFile ) { FileUtils.copyFile(srcFile, newFile); // newFile.setLastModified(System.currentTimeMillis()); } else { PrintWriter writer = new PrintWriter(newFile); writer.println("This is a FolderDiff Test File"); writer.flush(); writer.close(); } return newFile; } } } private FolderDiff getFolderDiff() { FolderDiff folderDiff = new FolderDiff(); folderDiff.setSrcPath(src.getAbsolutePath()); folderDiff.setDstPath(dst.getAbsolutePath()); return folderDiff; } private Set<FolderDiff.Entry> processFiles(File folder, FileCallable call) throws IOException { ArrayList<File> files = new ArrayList<File>(FileUtils.listFiles(folder, null, true)); Collections.shuffle(files); Set<FolderDiff.Entry> expected = new HashSet<FolderDiff.Entry>(); for(int i=0; i<Math.min(10, files.size()/2); i++) { File file = (File)files.get(i); call.process(file, expected); } return expected; } private interface FileCallable { public void process(File file, Set<FolderDiff.Entry> result) throws IOException ; } }