/** * Funambol is a mobile platform developed by Funambol, Inc. * Copyright (C) 2010 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.spds; import com.funambol.sync.SourceConfig; import com.funambol.sync.SyncConfig; import com.funambol.util.Log; import com.funambol.util.ConsoleAppender; import com.funambol.util.StringUtil; import junit.framework.*; /** * Test the SyncManager performance */ public class SyncManagerDevInfTest extends TestCase { private static final String TAG_LOG = "SyncManagerDevInfTest"; private final String TEST_SERVER_URL = "http://test.server.url"; private final String TEST_USERNAME = "test"; private final String TEST_PASSWORD = "test"; private SyncManager syncManager = null; private SyncConfig syncConfig = null; private DeviceConfig deviceConfig = null; private SourceConfig syncSourceConfig = null; private TestSyncSource testSyncSource = null; private final String JSESSION_ID = ";jsessionid=F2EA56F802D65950FAC3E37336BE1EEA.NODE01"; private int sentMessagesCount; public SyncManagerDevInfTest(String name) { super(name); } /** * Set up all of the tests */ public void setUp() { syncConfig = new SyncConfig(); syncConfig.syncUrl = TEST_SERVER_URL; syncConfig.userName = TEST_USERNAME; syncConfig.password = TEST_PASSWORD; deviceConfig = new DeviceConfig(); syncSourceConfig = new SyncMLSourceConfig("briefcase", SourceConfig.BRIEFCASE_TYPE, "briefcase"); SyncMLAnchor anchor = new SyncMLAnchor(); syncSourceConfig.setSyncAnchor(anchor); syncManager = new SyncManager(syncConfig, deviceConfig); testSyncSource = new TestSyncSource(syncSourceConfig); sentMessagesCount = 0; // Log.initLog(new ConsoleAppender(), Log.ERROR); Log.initLog(new ConsoleAppender(), Log.TRACE); } /** * Tear down all of the tests */ public void tearDown() { } //----------------------------------------------- DevInf tests /** * Test that DevInf are sent only one time if server receive them */ public void testSendDevInfOnlyDuringFirstSync() throws Exception { Log.debug(TAG_LOG, "testSendDevInfOnlyDuringFirstSync"); syncManager.setTransportAgent(testTransportAgentNormalSync); testSyncSource.endSending(); //no item to send to server String outgoingStream; Log.debug(TAG_LOG, "Starting first sync..."); testTransportAgentNormalSync.flushOutgoingStream(); syncManager.sync(testSyncSource); outgoingStream = testTransportAgentNormalSync.getOutgoingStream(); assertTrue("DevInf not sent to server", containsDevInf(outgoingStream)); Log.debug(TAG_LOG, "Starting second sync..."); testTransportAgentNormalSync.flushOutgoingStream(); syncManager.sync(testSyncSource); outgoingStream = testTransportAgentNormalSync.getOutgoingStream(); assertFalse("DevInf sent to server", containsDevInf(outgoingStream)); Log.debug(TAG_LOG, "Starting third sync..."); testTransportAgentNormalSync.flushOutgoingStream(); syncManager.sync(testSyncSource); outgoingStream = testTransportAgentNormalSync.getOutgoingStream(); assertFalse("DevInf sent to server", containsDevInf(outgoingStream)); } /** * Tests that DevInf are sent every time when using a {@link SourceConfig} * and not a {@link SyncMLSourceConfig} */ public void testSendDevInfEveryTimeWithANormalSyncSource() { Log.debug(TAG_LOG, "testSendDevInfEveryTimeWithANormalSyncSource"); //replaces the config syncSourceConfig = new SourceConfig("briefcase", SourceConfig.BRIEFCASE_TYPE, "briefcase"); SyncMLAnchor anchor = new SyncMLAnchor(); syncSourceConfig.setSyncAnchor(anchor); testSyncSource.setConfig(syncSourceConfig); syncManager.setTransportAgent(testTransportAgentNormalSync); testSyncSource.endSending(); //no item to send to server String outgoingStream; Log.debug(TAG_LOG, "Starting first sync..."); testTransportAgentNormalSync.flushOutgoingStream(); syncManager.sync(testSyncSource); outgoingStream = testTransportAgentNormalSync.getOutgoingStream(); assertTrue("DevInf not sent to server", containsDevInf(outgoingStream)); Log.debug(TAG_LOG, "Starting second sync..."); testTransportAgentNormalSync.flushOutgoingStream(); syncManager.sync(testSyncSource); outgoingStream = testTransportAgentNormalSync.getOutgoingStream(); assertTrue("DevInf sent to server", containsDevInf(outgoingStream)); } /** * Test that DevInf are sent when the flag to force them is set */ public void testSendDevInfWhenForced() throws Exception { Log.debug(TAG_LOG, "testSendDevInfWhenForced"); syncManager.setTransportAgent(testTransportAgentNormalSync); testSyncSource.endSending(); //no item to send to server String outgoingStream; Log.debug(TAG_LOG, "Starting first sync..."); testTransportAgentNormalSync.flushOutgoingStream(); syncManager.sync(testSyncSource); outgoingStream = testTransportAgentNormalSync.getOutgoingStream(); assertTrue("DevInf not sent to server", containsDevInf(outgoingStream)); Log.debug(TAG_LOG, "Starting second sync..."); testTransportAgentNormalSync.flushOutgoingStream(); syncManager.setFlagSendDevInf(); syncManager.sync(testSyncSource); outgoingStream = testTransportAgentNormalSync.getOutgoingStream(); assertTrue("DevInf sent to server", containsDevInf(outgoingStream)); } /** * Tests that DevInf are resent if the server doesn't accept them */ public void testSendDevInfWhenServerDoesNotAcceptThem() { Log.debug(TAG_LOG, "testSendDevInfWhenServerDoesNotAcceptThem"); TestTransportAgent testTransportAgentDenyDevInf = new TestTransportAgent(new TestMessageHandler() { public byte[] handleMessage(byte message[]) throws Exception { String response = null; sentMessagesCount++; switch (sentMessagesCount) { case 1: response = getServerResponse1(false); break; case 2: response = getServerResponse2(); break; case 3: response = getServerResponse3(); break; case 4: response = getServerResponse4(); sentMessagesCount = 0; //restart the count break; } return response.getBytes("UTF-8"); } public String handleMessage(String message) throws Exception { return null; } }, true); syncManager.setTransportAgent(testTransportAgentDenyDevInf); testSyncSource.endSending(); //no item to send to server String outgoingStream; //DevInf are not accepted Log.debug(TAG_LOG, "Starting first sync..."); testTransportAgentDenyDevInf.flushOutgoingStream(); syncManager.sync(testSyncSource); outgoingStream = testTransportAgentDenyDevInf.getOutgoingStream(); assertTrue("DevInf not sent to server", containsDevInf(outgoingStream)); //DevInf are resent, but still not accepted Log.debug(TAG_LOG, "Starting second sync..."); testTransportAgentDenyDevInf.flushOutgoingStream(); syncManager.sync(testSyncSource); outgoingStream = testTransportAgentDenyDevInf.getOutgoingStream(); assertTrue("DevInf not sent to server", containsDevInf(outgoingStream)); //now DevInf are accepted testTransportAgentDenyDevInf = testTransportAgentNormalSync; syncManager.setTransportAgent(testTransportAgentNormalSync); Log.debug(TAG_LOG, "Starting third sync..."); testTransportAgentDenyDevInf.flushOutgoingStream(); syncManager.sync(testSyncSource); outgoingStream = testTransportAgentDenyDevInf.getOutgoingStream(); assertTrue("DevInf not sent to server", containsDevInf(outgoingStream)); //so there are not send in this sync Log.debug(TAG_LOG, "Starting fourth sync..."); testTransportAgentDenyDevInf.flushOutgoingStream(); syncManager.sync(testSyncSource); outgoingStream = testTransportAgentDenyDevInf.getOutgoingStream(); assertFalse("DevInf sent to server", containsDevInf(outgoingStream)); } private String getServerResponse1(boolean devInfAcceptedFromServer) { StringBuffer res = new StringBuffer(); createServerHeader(res, 1); res.append(getStatus_AUTH_BASIC_OK()); int cmdId = 2; //1 already used by previous block res.append("<Status>\n") .append("<CmdID>").append(cmdId++).append("</CmdID>\n") .append("<MsgRef>1</MsgRef>\n") .append("<CmdRef>1</CmdRef>\n") .append("<Cmd>Alert</Cmd>\n") .append("<TargetRef>" + syncSourceConfig.getName() + "</TargetRef>\n") .append("<SourceRef>" + syncSourceConfig.getRemoteUri() + "</SourceRef>\n") .append("<Data>200</Data>\n") .append("</Status>\n") .append("<Status>\n") .append("<CmdID>").append(cmdId++).append("</CmdID>\n") .append("<MsgRef>1</MsgRef>\n") .append("<CmdRef>2</CmdRef>\n") .append("<Cmd>Put</Cmd>\n") .append("<SourceRef>./devinf12</SourceRef>\n"); if (devInfAcceptedFromServer) { //DevInf accepted res.append("<Data>200</Data>\n"); } else { //DevInf not accepted res.append("<Data>500</Data>\n"); } res.append("</Status>\n") .append(getAlertFromServer()) .append("<Final/>\n") .append("</SyncBody>\n") .append("</SyncML>"); return res.toString(); } private String getServerResponse2() { StringBuffer res = new StringBuffer(); int cmdId = 1; createServerHeader(res, 2); res.append("<Status>\n") .append("<CmdID>").append(cmdId++).append("</CmdID>\n") .append("<MsgRef>2</MsgRef>\n") .append("<CmdRef>0</CmdRef>\n") .append("<Cmd>SyncHdr</Cmd>\n") .append("<TargetRef>").append(syncConfig.syncUrl).append("</TargetRef>\n") .append("<SourceRef>").append(deviceConfig.getDevID()).append("</SourceRef>\n") .append("<Data>200</Data>\n") .append("</Status>"); res.append("<Status>\n") .append("<CmdID>").append(cmdId++).append("</CmdID>\n") .append("<MsgRef>2</MsgRef>\n") .append("<CmdRef>3</CmdRef>\n") .append("<Cmd>Sync</Cmd>\n") .append("<TargetRef>").append(syncSourceConfig.getName()).append("</TargetRef>\n") .append("<SourceRef>").append(syncSourceConfig.getRemoteUri()).append("</SourceRef>\n") .append("<Data>200</Data>\n") .append("</Status>"); createServerFooter(res); return res.toString(); } private String getServerResponse3() { StringBuffer res = new StringBuffer(); int cmdId = 1; createServerHeader(res, 3); res.append("<Status>\n") .append("<CmdID>").append(cmdId++).append("</CmdID>\n") .append("<MsgRef>3</MsgRef>\n") .append("<CmdRef>0</CmdRef>\n") .append("<Cmd>SyncHdr</Cmd>\n") .append("<TargetRef>").append(syncConfig.syncUrl).append("</TargetRef>\n") .append("<SourceRef>").append(deviceConfig.getDevID()).append("</SourceRef>\n") .append("<Data>200</Data>\n") .append("</Status>"); res.append("<Status>\n") .append("<CmdID>").append(cmdId++).append("</CmdID>\n") .append("<MsgRef>3</MsgRef>\n") .append("<CmdRef>2</CmdRef>\n") .append("<Cmd>Alert</Cmd>\n") .append("<TargetRef>").append(syncSourceConfig.getName()).append("</TargetRef>\n") .append("<SourceRef>").append(syncSourceConfig.getRemoteUri()).append("</SourceRef>\n") .append("<Data>200</Data>\n") .append("<Item>\n") .append("<Source>\n") .append("<LocURI>").append(syncSourceConfig.getRemoteUri()).append("</LocURI>\n") .append("</Source>\n") .append("<Target>\n") .append("<LocURI>").append(syncSourceConfig.getName()).append("</LocURI>\n") .append("</Target>\n") .append("</Item>\n") .append("</Status>\n"); res.append("<Sync>\n") .append("<CmdID>").append(cmdId++).append("</CmdID>\n") .append("<Target>\n") .append("<LocURI>").append(syncSourceConfig.getRemoteUri()).append("</LocURI>\n") .append("</Target>\n") .append("<Source>\n") .append("<LocURI>").append(syncSourceConfig.getName()).append("</LocURI>\n") .append("</Source>\n") .append("<NumberOfChanges>0</NumberOfChanges>\n") .append("</Sync>\n") .append("<Final></Final>\n"); createServerFooter(res); return res.toString(); } private String getServerResponse4() { StringBuffer res = new StringBuffer(); int cmdId = 1; createServerHeader(res, 4); res.append("<Status>\n") .append("<CmdID>").append(cmdId++).append("</CmdID>\n") .append("<MsgRef>4</MsgRef>\n") .append("<CmdRef>0</CmdRef>\n") .append("<Cmd>SyncHdr</Cmd>\n") .append("<TargetRef>").append(syncConfig.syncUrl).append("</TargetRef>\n") .append("<SourceRef>").append(deviceConfig.getDevID()).append("</SourceRef>\n") .append("<Data>200</Data>\n") .append("</Status>"); res.append("<Final></Final>\n"); createServerFooter(res); return res.toString(); } private void createServerHeader(StringBuffer res, int messageCount) { res.append("<SyncML>\n") .append("<SyncHdr>\n") .append("<VerDTD>1.2</VerDTD>\n") .append("<VerProto>SyncML/1.2</VerProto>\n") .append("<SessionID>1266917419910</SessionID>\n") .append("<MsgID>").append(messageCount).append("</MsgID>\n") .append("<Target>\n") .append("<LocURI>").append(deviceConfig.getDevID()).append("</LocURI>\n") .append("</Target>\n") .append("<Source>\n") .append("<LocURI>" + syncConfig.syncUrl + "</LocURI>\n") .append("</Source>\n") .append("<RespURI>").append(syncConfig.syncUrl).append(JSESSION_ID).append("</RespURI>\n") .append("</SyncHdr>\n") .append("<SyncBody>\n"); } private void createServerFooter(StringBuffer res) { res.append("</SyncBody>\n") .append("</SyncML>"); } private String getStatus_AUTH_BASIC_OK() { return "<Status>\n" + "<CmdID>1</CmdID>\n" + "<MsgRef>1</MsgRef>\n" + "<CmdRef>0</CmdRef>\n" + "<Cmd>SyncHdr</Cmd>\n" + "<TargetRef>" + syncConfig.syncUrl + "</TargetRef>\n" + "<SourceRef>" + deviceConfig.getDevID() + "</SourceRef>\n" + "<Data>212</Data>\n" + "</Status>"; } private String getAlertFromServer() { return "<Alert>\n" + "<CmdID>4</CmdID>\n" + "<Data>200</Data>\n" + "<Item>\n" + "<Target>\n" + "<LocURI>" + syncSourceConfig.getName() + "</LocURI>\n" + "</Target>\n" + "<Source>\n" + "<LocURI>" + syncSourceConfig.getRemoteUri() + "</LocURI>\n" + "</Source>\n" + "<Meta>\n" + "<Anchor xmlns='syncml:metinf'>\n" + "<Last>0</Last>\n" + "<Next>0</Next>\n" + "</Anchor>\n" + "</Meta>\n" + "</Item>\n" + "</Alert>\n"; } private boolean containsDevInf(String message) { if (StringUtil.isNullOrEmpty(message)) return false; return message.contains( "<Type xmlns=\"syncml:metinf\">application/vnd.syncml-devinf+wbxml</Type>") || message.contains( "<Type xmlns=\"syncml:metinf\">application/vnd.syncml-devinf+xml</Type>"); } /** * Transport Agent for a normal sync, where DevInf are recognized and * accepted by the server */ private final TestTransportAgent testTransportAgentNormalSync = new TestTransportAgent(new TestMessageHandler() { public byte[] handleMessage(byte message[]) throws Exception { String response = null; sentMessagesCount++; switch (sentMessagesCount) { case 1: response = getServerResponse1(true); break; case 2: response = getServerResponse2(); break; case 3: response = getServerResponse3(); break; case 4: response = getServerResponse4(); sentMessagesCount = 0; //restart the count break; } return response.getBytes("UTF-8"); } public String handleMessage(String message) throws Exception { return null; } }, true); }