/* * Funambol is a mobile platform developed by Funambol, Inc. * Copyright (C) 2008 Funambol, Inc. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU Affero General Public License version 3 as published by * the Free Software Foundation with the addition of the following permission * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED * WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE * WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. * * 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 Affero General Public License * along with this program; if not, see http://www.gnu.org/licenses or write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA. * * You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite * 305, Redwood City, CA 94063, USA, or at email address info@funambol.com. * * The interactive user interfaces in modified source and object code versions * of this program must display Appropriate Legal Notices, as required under * Section 5 of the GNU Affero General Public License version 3. * * In accordance with Section 7(b) of the GNU Affero General Public License * version 3, these Appropriate Legal Notices must retain the display of the * "Powered by Funambol" logo. If the display of the logo is not reasonably * feasible for technical reasons, the Appropriate Legal Notices must display * the words "Powered by Funambol". */ package com.funambol.syncml.client; import java.io.IOException; import java.io.OutputStream; import java.io.InputStream; import java.io.ByteArrayOutputStream; import java.util.Vector; import java.util.Enumeration; import com.funambol.platform.FileAdapter; import com.funambol.storage.StringKeyValueStore; import com.funambol.storage.StringKeyValueFileStore; import com.funambol.syncml.spds.SourceConfig; import com.funambol.syncml.spds.SyncItem; import com.funambol.syncml.spds.SourceConfig; import com.funambol.syncml.spds.SyncException; import com.funambol.syncml.protocol.SyncML; import com.funambol.util.ConsoleAppender; import com.funambol.util.Base64; import com.funambol.util.Log; import com.funambol.util.StringUtil; import junit.framework.*; public class FileSyncSourceTest extends TestCase { private StringKeyValueStore store; private FileSyncSource source; private TestTracker tracker; private String directory; private SourceConfig config; private class TestTracker implements ChangesTracker { private Vector newItems = new Vector(); private Vector delItems = new Vector(); private Vector updItems = new Vector(); private Vector allItems = new Vector(); public TestTracker() { } public void setSyncSource(TrackableSyncSource ss) { } public void begin(int syncMode, boolean resume) throws TrackerException { } public void end() throws TrackerException { } public Enumeration getNewItems() throws TrackerException { return newItems.elements(); } public int getNewItemsCount() throws TrackerException { return newItems.size(); } public Enumeration getUpdatedItems() throws TrackerException { return updItems.elements(); } public int getUpdatedItemsCount() throws TrackerException { return updItems.size(); } public Enumeration getDeletedItems() throws TrackerException { return delItems.elements(); } public int getDeletedItemsCount() throws TrackerException { return delItems.size(); } public void setItemsStatus(Vector items) throws TrackerException { } public void reset() throws TrackerException { } public boolean removeItem(SyncItem item) throws TrackerException { return false; } public void addNewItem(SyncItem item) { newItems.addElement(item); } public void addUpdItem(SyncItem item) { updItems.addElement(item); } public void addDelItem(SyncItem item) { delItems.addElement(item); } public void addItem(SyncItem item) { allItems.addElement(item); } public void empty() throws TrackerException { } public boolean supportsResume() { return false; } public boolean hasChangedSinceLastSync(String key, long ts) { return true; } } public FileSyncSourceTest(String name) { super(name); Log.initLog(new ConsoleAppender()); Log.setLogLevel(Log.TRACE); // Depending on the running platform we have different values for the // "root" directory that we want to use directory = System.getProperty("java.io.tmpdir"); if (directory == null) { directory = "file:///root1"; } } public void setUp() { } private void prepareTestDirectory(String baseDir, String testDir) throws IOException { FileAdapter fa = new FileAdapter(baseDir + '/' + testDir); if (fa.exists()) { Enumeration files = fa.list(false); while(files.hasMoreElements()) { String file = (String)files.nextElement(); String fullFile = baseDir + '/' + testDir + '/' + file; FileAdapter fa1 = new FileAdapter(fullFile); try { fa1.delete(); } catch (Exception e) { Log.error("Exception while deleting: " + fullFile + " -- " + e.toString()); } fa1.close(); } } else { fa.mkdir(); } fa.close(); directory = baseDir + '/' + testDir + '/'; tracker = new TestTracker(); config = new SourceConfig(SourceConfig.BRIEFCASE,SourceConfig.FILE_OBJECT_TYPE , "briefcase"); if (Log.isLoggable(Log.DEBUG)) { Log.debug("directory = " + directory); } source = new FileSyncSource(config, tracker, directory); } public void testSlowSyncSimple() throws Throwable { prepareTestDirectory(directory, "test0"); // Populate the directory with one file String content = "This is a small file"; createFile("test-0.txt", content); tracker.addItem(new SyncItem("test-0.txt")); source.beginSync(SyncML.ALERT_CODE_SLOW, false); SyncItem item = source.getNextItem(); assertTrue(item != null); assertTrue(source.getNextItem() == null); InputStream is = item.getInputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream(); int value = is.read(); while (value != -1) { bos.write(value); value = is.read(); } String itemContent = bos.toString(); String expectedContent = new String(Base64.encode(content.getBytes())); String expectedItem = "<FILE>\n" + "<NAME>test-0.txt</NAME>\n" + "<MODIFIED>20090518T092027Z</MODIFIED>\n" + "<ATTRIBUTES>\n" + "<H>FALSE</H>\n" + "<S>FALSE</S>\n" + "<A>FALSE</A>\n" + "<D>FALSE</D>\n" + "<W>FALSE</W>\n" + "<R>FALSE</R>\n" + "<X>FALSE</X>\n" + "</ATTRIBUTES>\n" + "<BODY enc=\"base64\">" + expectedContent + "</BODY>\n" + "</FILE>"; // The date formatted depends on the current date, so we do not consider // it in the comparison String item1 = stripModified(expectedItem); String item2 = stripModified(itemContent); assertTrue(StringUtil.equalsIgnoreCase(item1, item2)); source.endSync(); } public void testRound1() throws Throwable { if (Log.isLoggable(Log.INFO)) { Log.info("################# FileSyncSourceTest.testRound1"); } prepareTestDirectory(directory, "test0"); // Populate the directory with one file String content = "This is a small file"; createFile("test-0.txt", content); tracker.addItem(new SyncItem("test-0.txt")); source.beginSync(SyncML.ALERT_CODE_SLOW, false); SyncItem item = source.getNextItem(); assertTrue(item != null); assertTrue(source.getNextItem() == null); InputStream is = item.getInputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream(); int value = is.read(); while (value != -1) { bos.write(value); value = is.read(); } String itemContent = bos.toString(); source.endSync(); // Now start another sync and add this item FileAdapter oldFile = new FileAdapter(directory+"test-0.txt"); try { oldFile.delete(); } catch (Exception e) { Log.error("Exception while deleting: " + directory+"test-0.txt" + " -- " + e.toString()); } source.beginSync(SyncML.ALERT_CODE_FAST, false); SyncItem sitem = source.createSyncItem("key0", SourceConfig.FILE_OBJECT_TYPE, SyncItem.STATE_NEW, "", 0); OutputStream os = sitem.getOutputStream(); os.write(itemContent.getBytes()); os.close(); source.addItem(sitem); source.endSync(); FileAdapter newFile = new FileAdapter(directory+"test-0.txt"); assertTrue(newFile.exists()); } public void testSyncSendLargeObject() throws Throwable { // Populate the directory with one file prepareTestDirectory(directory, "test1"); byte content[] = new byte[26*1024]; String fileContent = new String(content); createFile("test-0.txt", fileContent); tracker.addItem(new SyncItem("test-0.txt")); source.beginSync(SyncML.ALERT_CODE_SLOW, false); SyncItem chunk1 = source.getNextItem(); assertTrue(chunk1 != null); assertTrue(source.getNextItem() == null); source.endSync(); } private void createFile(String fileName, String content) throws Throwable { FileAdapter fa = new FileAdapter(directory + "/" + fileName); OutputStream os = fa.openOutputStream(false); os.write(content.getBytes()); os.close(); fa.close(); } private String stripModified(String item) { String loItem = item.toLowerCase(); int beginModified = loItem.indexOf("<modified>"); int endModified = loItem.indexOf("</modified>"); String prologue = item.substring(0, beginModified + "<modified>".length()); String epilogue = item.substring(endModified); return prologue + epilogue; } }