/* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * * For information about the authors of this project Have a look * at the AUTHORS file in the root of this project. */ package net.sourceforge.fullsync; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; import java.net.URI; import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.TimeZone; import net.sourceforge.fullsync.impl.SimplyfiedRuleSetDescriptor; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameter; import org.mockftpserver.fake.FakeFtpServer; import org.mockftpserver.fake.UserAccount; import org.mockftpserver.fake.filesystem.DirectoryEntry; import org.mockftpserver.fake.filesystem.FileEntry; import org.mockftpserver.fake.filesystem.FileSystem; import org.mockftpserver.fake.filesystem.UnixFakeFileSystem; import com.mindtree.techworks.infix.pluginscommon.test.ssh.SSHServerResource; @RunWith(Parameterized.class) public class FilesystemTest { protected static final int MILLI_SECONDS_PER_DAY = 86400000; private static final int TEST_FTP_PORT = 16131; @Parameterized.Parameters public static Iterable<Object[]> data() { return Arrays.asList(new Object[][] { { "file" }, { "ftp" }, { "sftp" }, //{"smb"}, // no server for smb/cifs }); } @Parameter public String filesystem; @Rule public TemporaryFolder tmpFolder = new TemporaryFolder(); protected File testingDst; protected File testingSrc; protected Synchronizer synchronizer; protected Profile profile; private FakeFtpServer m_fakeServer; @Rule public SSHServerResource m_sshServer = new SSHServerResource("SampleUser", 2222, "127.0.0.1"); @Before public void setUp() throws Exception { testingDst = null; testingSrc = null; synchronizer = null; profile = null; m_fakeServer = null; } @After public void tearDown() throws Exception { if (null != m_fakeServer) { m_fakeServer.stop(); } //FIXME: disconnect source and destination! tmpFolder.delete(); } void prepareProfile(String syncType) throws Exception { testingDst = tmpFolder.newFolder("destination"); testingDst.mkdirs(); testingSrc = tmpFolder.newFolder("source"); testingSrc.mkdirs(); synchronizer = new Synchronizer(); ConnectionDescription src = new ConnectionDescription(testingSrc.toURI()); src.setParameter("bufferStrategy", ""); String dstUrl = null; if ("file".equals(filesystem)) { dstUrl = testingDst.toURI().toString(); } if ("ftp".equals(filesystem)) { m_fakeServer = new FakeFtpServer(); m_fakeServer.setServerControlPort(TEST_FTP_PORT); clearDirectory(testingDst); m_fakeServer.addUserAccount(new UserAccount("SampleUser", "Sample", "/sampleuser")); m_fakeServer.start(); dstUrl = "ftp://127.0.0.1:" + TEST_FTP_PORT + "/sampleuser"; } if ("sftp".equals(filesystem)) { System.setProperty("vfs.sftp.sshdir", new File("./tests/sshd-config/").getAbsolutePath()); testingDst.delete(); testingDst = m_sshServer.getUserHome(); dstUrl = "sftp://127.0.0.1:2222/"; } ConnectionDescription dst = new ConnectionDescription(new URI(dstUrl)); dst.setParameter("bufferStrategy", ""); dst.setParameter("username", "SampleUser"); dst.setSecretParameter("password", "Sample"); profile = new Profile("TestProfile", src, dst, new SimplyfiedRuleSetDescriptor(true, null, false, null)); profile.setSynchronizationType(syncType); profile.setDestination(dst); } /** * recursively delete directory and all contained files. * * @param dir directory to clear */ protected void clearDirectory(final File dir) { if ((testingDst == dir) && "ftp".equals(filesystem)) { FileSystem fs = new UnixFakeFileSystem(); fs.add(new DirectoryEntry("/sampleuser")); m_fakeServer.setFileSystem(fs); } else { File[] children = dir.listFiles(); if (null != children) { for (File file : children) { if (file.isDirectory()) { clearDirectory(file); } assertTrue("File.delete failed for: " + file.getAbsolutePath(), file.delete()); } } } } protected void createNewDir(File dir, String dirname, long lastModified) { File d = new File(dir, dirname); d.mkdir(); setLastModified(dir, dirname, lastModified); } protected long getLastModified() { Calendar cal = Calendar.getInstance(TimeZone.getDefault()); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); Date d = cal.getTime(); return d.getTime(); } protected void setLastModified(File dir, String filename, long lm) { File file = new File(dir, filename); if (!file.setLastModified(lm)) { throw new RuntimeException("file.setLastModified(" + dir.getAbsolutePath() + "/" + filename + ") FAILED"); } } protected void delete(File dir, String filename) { if (!(new File(dir, filename).delete())) { throw new RuntimeException("file.delete(" + dir.getAbsolutePath() + "/" + filename + ") FAILED"); } } protected void fileToDir(File dir, String filename, long lm) { File file = new File(dir, filename); if (!file.delete()) { throw new RuntimeException("file.delete(" + dir.getAbsolutePath() + "/" + filename + ") FAILED"); } if (!file.mkdir()) { throw new RuntimeException("file.mkdir(" + dir.getAbsolutePath() + "/" + filename + ") FAILED"); } setLastModified(dir, filename, lm); } protected void dirToFile(File dir, String filename, long lm) throws IOException { File file = new File(dir, filename); if (!file.delete()) { throw new RuntimeException("file.delete(" + dir.getAbsolutePath() + "/" + filename + ") FAILED"); } if (!file.createNewFile()) { throw new RuntimeException("file.createNewFile(" + dir.getAbsolutePath() + "/" + filename + ") FAILED"); } setLastModified(dir, filename, lm); } protected PrintStream createNewFile(final File dir, final String filename) throws IOException { File file = new File(dir, filename); File d = file.getParentFile(); assertTrue("File.mkdirs failed for: " + file.getParentFile().getAbsolutePath(), d.mkdirs() || d.exists()); assertTrue("File.createNewFile failed for: " + file.getAbsolutePath(), file.createNewFile()); PrintStream out = new PrintStream(new FileOutputStream(file)); return out; } protected void createNewFileWithContents(File dir, String filename, long lm, String content) throws IOException { if ((dir == testingDst) && "ftp".equals(filesystem)) { FileEntry file = new FileEntry("/sampleuser/" + filename, content); file.setLastModified(new Date(lm)); m_fakeServer.getFileSystem().add(file); } else { try (PrintStream out = createNewFile(dir, filename)) { out.print(content); } File f = new File(dir, filename); assertTrue("File.setLastModified failed for: " + f.getAbsolutePath(), f.setLastModified(lm)); } } protected TaskTree assertPhaseOneActions(final Map<String, Action> expectation) throws Exception { TaskGenerationListener list = new TaskGenerationListener() { @Override public void taskGenerationFinished(final Task task) { Object ex = expectation.get(task.getSource().getName()); assertNotNull("Unexpected generated Task for file: " + task.getSource().getName(), ex); assertTrue("Action was " + task.getCurrentAction() + ", expected: " + ex + " for File " + task.getSource().getName(), task.getCurrentAction().equalsExceptExplanation((Action) ex)); } @Override public void taskGenerationStarted(final net.sourceforge.fullsync.fs.File source, final net.sourceforge.fullsync.fs.File destination) { } @Override public void taskTreeFinished(final TaskTree tree) { } @Override public void taskTreeStarted(final TaskTree tree) { } }; TaskGenerator processor = synchronizer.getTaskGenerator(); processor.addTaskGenerationListener(list); TaskTree tree = processor.execute(profile, false); processor.removeTaskGenerationListener(list); return tree; } private long prepareForTest() { clearDirectory(testingSrc); clearDirectory(testingDst); return getLastModified(); } private void verifyExpectations(Map<String, Action> expectation) throws Exception { TaskTree tree = assertPhaseOneActions(expectation); synchronizer.performActions(tree); } @Test public void testPublishUpdate() throws Exception { prepareProfile("Publish/Update"); Map<String, Action> expectation = new HashMap<String, Action>(); long lm; lm = prepareForTest(); createNewFileWithContents(testingSrc, "sourceFile1.txt", lm, "this is a test\ncontent1"); createNewFileWithContents(testingSrc, "sourceFile2.txt", lm, "this is a test\ncontent2"); createNewFileWithContents(testingDst, "sourceFile1.txt", lm, "this is a test\ncontent1"); createNewFileWithContents(testingSrc, "-strangeFolder/sub folder/sourceFile3.txt", lm, "this is a test\ncontent3"); createNewFileWithContents(testingDst, "-strangeFolder/sub folder/sourceFile3.txt", lm, "this is a test\ncontent3"); expectation.clear(); expectation.put("sourceFile1.txt", new Action(ActionType.Nothing, Location.None, BufferUpdate.None, "")); expectation.put("sourceFile2.txt", new Action(ActionType.Add, Location.Destination, BufferUpdate.Destination, "")); expectation.put("sourceFile3.txt", new Action(ActionType.Nothing, Location.None, BufferUpdate.None, "")); expectation.put("-strangeFolder", new Action(ActionType.Nothing, Location.None, BufferUpdate.None, "")); expectation.put("sub folder", new Action(ActionType.Nothing, Location.None, BufferUpdate.None, "")); verifyExpectations(expectation); lm = prepareForTest(); createNewFileWithContents(testingSrc, "sub - folder/sub2 - folder/sourceFile1.txt", lm, "this is a test\ncontent1"); createNewFileWithContents(testingSrc, "sub - folder/sourceFile2.txt", lm, "this is a test\ncontent2"); createNewFileWithContents(testingSrc, "-strangeFolder/sub folder/sourceFile3.txt", lm, "this is a test\ncontent3"); createNewFileWithContents(testingDst, "-strangeFolder2/sub2 folder/sourceFile4.txt", lm, "this is a test\ncontent4"); expectation.clear(); expectation.put("sub - folder", new Action(ActionType.Add, Location.Destination, BufferUpdate.Destination, "")); expectation.put("sub2 - folder", new Action(ActionType.Add, Location.Destination, BufferUpdate.Destination, "")); expectation.put("sourceFile1.txt", new Action(ActionType.Add, Location.Destination, BufferUpdate.Destination, "")); expectation.put("sourceFile2.txt", new Action(ActionType.Add, Location.Destination, BufferUpdate.Destination, "")); expectation.put("-strangeFolder", new Action(ActionType.Add, Location.Destination, BufferUpdate.Destination, "")); expectation.put("sub folder", new Action(ActionType.Add, Location.Destination, BufferUpdate.Destination, "")); expectation.put("sourceFile3.txt", new Action(ActionType.Add, Location.Destination, BufferUpdate.Destination, "")); expectation.put("-strangeFolder2", new Action(ActionType.Nothing, Location.None, BufferUpdate.None, "")); expectation.put("sub2 folder", new Action(ActionType.Nothing, Location.None, BufferUpdate.None, "")); expectation.put("sourceFile4.txt", new Action(ActionType.Nothing, Location.None, BufferUpdate.None, "")); verifyExpectations(expectation); lm = prepareForTest(); createNewFileWithContents(testingSrc, "sourceFile1.txt", lm, "this is a test\ncontent2"); createNewFileWithContents(testingDst, "sourceFile1.txt", lm, "this is a test\ncontent2 bla"); createNewFileWithContents(testingSrc, "sourceFile2.txt", lm + MILLI_SECONDS_PER_DAY, "this is a test\ncontent2"); createNewFileWithContents(testingDst, "sourceFile2.txt", lm, "this is a test\ncontent2"); expectation.clear(); expectation.put("sourceFile1.txt", new Action(ActionType.Nothing, Location.None, BufferUpdate.None, "")); expectation.put("sourceFile2.txt", new Action(ActionType.Update, Location.Destination, BufferUpdate.Destination, "")); verifyExpectations(expectation); } }