diff options
author | Damian Minkov <damencho@jitsi.org> | 2007-01-12 17:56:58 +0000 |
---|---|---|
committer | Damian Minkov <damencho@jitsi.org> | 2007-01-12 17:56:58 +0000 |
commit | 7c6ccbd03b54d59913b45202f06bf053fe730f61 (patch) | |
tree | 5c1fd10f7382d1b43f2c67029ec0cdbafd260172 /test/net/java | |
parent | 44d48d13eebcb30fbfedd84424c04820aabebba7 (diff) | |
download | jitsi-7c6ccbd03b54d59913b45202f06bf053fe730f61.zip jitsi-7c6ccbd03b54d59913b45202f06bf053fe730f61.tar.gz jitsi-7c6ccbd03b54d59913b45202f06bf053fe730f61.tar.bz2 |
Yahoo Protocol Provider Implementation
Diffstat (limited to 'test/net/java')
11 files changed, 3639 insertions, 0 deletions
diff --git a/test/net/java/sip/communicator/slick/protocol/yahoo/TestAccountInstallation.java b/test/net/java/sip/communicator/slick/protocol/yahoo/TestAccountInstallation.java new file mode 100644 index 0000000..68f6efd --- /dev/null +++ b/test/net/java/sip/communicator/slick/protocol/yahoo/TestAccountInstallation.java @@ -0,0 +1,217 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.slick.protocol.yahoo; + +import java.util.*; + +import org.osgi.framework.*; +import junit.framework.*; +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.util.*; + +public class TestAccountInstallation + extends TestCase +{ + private static final Logger logger = + Logger.getLogger(TestAccountInstallation.class); + + /** + * Creates the test with the specified method name. + * @param name the name of the method to execute. + */ + public TestAccountInstallation(String name) + { + super(name); + } + + /** + * JUnit setup method. + * @throws Exception in case anything goes wrong. + */ + protected void setUp() throws Exception + { + super.setUp(); + } + + /** + * JUnit teardown method. + * @throws Exception in case anything goes wrong. + */ + protected void tearDown() throws Exception + { + super.tearDown(); + } + + /** + * Installs an account and verifies whether the installation has gone well. + */ + public void testInstallAccount() + { + // first obtain a reference to the provider factory + ServiceReference[] serRefs = null; + String osgiFilter = "(" + ProtocolProviderFactory.PROTOCOL + + "="+ProtocolNames.YAHOO+")"; + try{ + serRefs = YahooSlickFixture.bc.getServiceReferences( + ProtocolProviderFactory.class.getName(), osgiFilter); + } + catch (InvalidSyntaxException ex) + { + //this really shouldhn't occur as the filter expression is static. + fail(osgiFilter + " is not a valid osgi filter"); + } + + assertTrue( + "Failed to find a provider factory service for protocol Yahoo", + serRefs != null && serRefs.length > 0); + + //Keep the reference for later usage. + ProtocolProviderFactory yahooProviderFactory = (ProtocolProviderFactory) + YahooSlickFixture.bc.getService(serRefs[0]); + + //make sure the account is empty + assertTrue("There was an account registered with the account mananger " + +"before we've installed any", + yahooProviderFactory.getRegisteredAccounts().size() == 0); + + + //Prepare the properties of the first yahoo account. + + Hashtable yahooAccount1Properties = getAccountProperties( + YahooProtocolProviderServiceLick.ACCOUNT_1_PREFIX); + Hashtable yahooAccount2Properties = getAccountProperties( + YahooProtocolProviderServiceLick.ACCOUNT_2_PREFIX); + + //try to install an account with a null account id + try{ + yahooProviderFactory.installAccount( + null, yahooAccount1Properties); + fail("installing an account with a null account id must result " + +"in a NullPointerException"); + }catch(NullPointerException exc) + { + //that's what had to happen + } + + //now really install the accounts + yahooProviderFactory.installAccount( + (String)yahooAccount1Properties.get(ProtocolProviderFactory.USER_ID) + , yahooAccount1Properties); + yahooProviderFactory.installAccount( + (String)yahooAccount2Properties.get(ProtocolProviderFactory.USER_ID) + , yahooAccount2Properties); + + + //try to install one of the accounts one more time and verify that an + //excepion is thrown. + try{ + yahooProviderFactory.installAccount( + (String)yahooAccount1Properties.get(ProtocolProviderFactory.USER_ID) + , yahooAccount1Properties); + + fail("An IllegalStateException must be thrown when trying to "+ + "install a duplicate account"); + + }catch(IllegalStateException exc) + { + //that's what supposed to happen. + } + + //Verify that the provider factory is aware of our installation + assertTrue( + "The newly installed account was not in the acc man's " + +"registered accounts!", + yahooProviderFactory.getRegisteredAccounts().size() == 2); + + //Verify protocol providers corresponding to the new account have + //been properly registered with the osgi framework. + + osgiFilter = + "(&("+ProtocolProviderFactory.PROTOCOL +"="+ProtocolNames.YAHOO+")" + +"(" + ProtocolProviderFactory.USER_ID + + "=" + (String)yahooAccount1Properties.get( + ProtocolProviderFactory.USER_ID) + + "))"; + + try + { + serRefs = YahooSlickFixture.bc.getServiceReferences( + ProtocolProviderService.class.getName(), + osgiFilter); + } + catch (InvalidSyntaxException ex) + { + //this really shouldhn't occur as the filter expression is static. + fail(osgiFilter + "is not a valid osgi filter"); + } + + assertTrue("An protocol provider was apparently not installed as " + + "requested." + , serRefs != null && serRefs.length > 0); + + Object yahooProtocolProvider + = YahooSlickFixture.bc.getService(serRefs[0]); + + assertTrue("The installed protocol provider does not implement " + + "the protocol provider service." + ,yahooProtocolProvider instanceof ProtocolProviderService); + } + + /** + * Returns all properties necessary for the intialization of the account + * with <tt>accountPrefix</tt>. + * @param accountPrefix the prefix contained by all property names for the + * the account we'd like to initialized + * @return a Hashtable that can be used when creating the account in a + * protocol provider factory. + */ + private Hashtable getAccountProperties(String accountPrefix) + { + Hashtable table = new Hashtable(); + + String userID = System.getProperty( + accountPrefix + ProtocolProviderFactory.USER_ID, null); + + assertNotNull( + "The system property named " + + accountPrefix + ProtocolProviderFactory.USER_ID + +" has to tontain a valid yahoo address that could be used during " + +"SIP Communicator's tests." + , userID); + + table.put(ProtocolProviderFactory.USER_ID, userID); + + String passwd = System.getProperty( + accountPrefix + ProtocolProviderFactory.PASSWORD, null ); + + assertNotNull( + "The system property named " + + accountPrefix + ProtocolProviderFactory.PASSWORD + +" has to contain the password corresponding to the account " + + "specified in " + + accountPrefix + ProtocolProviderFactory.USER_ID + , passwd); + + table.put(ProtocolProviderFactory.PASSWORD, passwd); + + String serverAddress = System.getProperty( + accountPrefix + ProtocolProviderFactory.SERVER_ADDRESS, null); + + // optional + if(serverAddress != null) + table.put(ProtocolProviderFactory.SERVER_ADDRESS, serverAddress); + + String serverPort = System.getProperty( + accountPrefix + ProtocolProviderFactory.SERVER_PORT, null); + + // optional + if(serverPort != null) + table.put(ProtocolProviderFactory.SERVER_PORT, serverPort); + + return table; + } +} diff --git a/test/net/java/sip/communicator/slick/protocol/yahoo/TestAccountUninstallation.java b/test/net/java/sip/communicator/slick/protocol/yahoo/TestAccountUninstallation.java new file mode 100644 index 0000000..cd2a15b --- /dev/null +++ b/test/net/java/sip/communicator/slick/protocol/yahoo/TestAccountUninstallation.java @@ -0,0 +1,270 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.slick.protocol.yahoo; + +import org.osgi.framework.*; +import junit.framework.*; +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.util.*; + + +/** + * Tests whether accaounts are uninstalled properly. It is important that + * tests from this class be called last since they will install the accounts + * that have been used to test the implementations. Apart from uninstallation + * tests the class also contains tests that remove and reinstall the protocol + * provider bundle in order to verify that accounts are persistent. + * + * @author Emil Ivov + */ +public class TestAccountUninstallation + extends TestCase +{ + private static final Logger logger = + Logger.getLogger(TestAccountUninstallation.class); + + private YahooSlickFixture fixture = new YahooSlickFixture(); + + /** + * Constructs a test instance + * @param name The name of the test. + */ + public TestAccountUninstallation(String name) + { + super(name); + } + + /** + * JUnit setup method. + * @throws Exception in case anything goes wrong. + */ + protected void setUp() throws Exception + { + super.setUp(); + fixture.setUp(); + } + + /** + * JUnit teardown method. + * @throws Exception in case anything goes wrong. + */ + protected void tearDown() throws Exception + { + fixture.tearDown(); + super.tearDown(); + } + + /** + * Returns a suite containing tests in this class in the order that we'd + * like them executed. + * @return a Test suite containing tests in this class in the order that + * we'd like them executed. + */ + public static Test suite() + { + TestSuite suite = new TestSuite(); + + suite.addTest( + new TestAccountUninstallation("testInstallationPersistency")); + suite.addTest( + new TestAccountUninstallation("testUninstallAccount")); + + return suite; + } + + /** + * Stops and removes the tested bundle, verifies that it has unregistered + * its provider, then reloads and restarts the bundle and verifies that + * the protocol provider is reRegistered in the bundle context. + * + * @throws java.lang.Exception if an exception occurs during testing. + */ + public void testInstallationPersistency() throws Exception + { + Bundle providerBundle + = fixture.findProtocolProviderBundle(fixture.provider1); + + //set the global providerBundle reference that we will be using + //in the last series of tests (Account uninstallation persistency) + YahooSlickFixture.providerBundle = providerBundle; + + assertNotNull("Couldn't find a bundle for the tested provider" + , providerBundle); + + providerBundle.stop(); + + assertTrue("Couldn't stop the protocol provider bundle. State was " + + providerBundle.getState() + , Bundle.ACTIVE != providerBundle.getState() + && Bundle.STOPPING != providerBundle.getState()); + + providerBundle.uninstall(); + + assertEquals("Couldn't stop the protocol provider bundle." + , Bundle.UNINSTALLED, providerBundle.getState()); + + //verify that the provider is no longer available + ServiceReference[] yahooProviderRefs = null; + try + { + yahooProviderRefs = fixture.bc.getServiceReferences( + ProtocolProviderService.class.getName(), + "(&" + + "(" + ProtocolProviderFactory.PROTOCOL + + "=" +ProtocolNames.YAHOO + ")" + + "(" + ProtocolProviderFactory.USER_ID + + "="+ fixture.userID1 + ")" + + ")"); + } + catch (InvalidSyntaxException ex) + { + fail("We apparently got our filter wrong: " + ex.getMessage()); + } + + //make sure we didn't see a service + assertTrue("A Protocol Provider Service was still regged as an osgi service " + +"for yahoo URI:" + fixture.userID1 + + "After it was explicitly uninstalled" + ,yahooProviderRefs == null || yahooProviderRefs.length == 0); + + //verify that the provider factory knows that we have uninstalled the + //provider. + assertTrue( + "The yahoo provider factory kept a reference to the provider we just " + +"uninstalled (uri="+fixture.userID1+")", + fixture.providerFactory.getRegisteredAccounts().isEmpty() + && fixture.providerFactory.getProviderForAccount( + fixture.provider1.getAccountID()) + == null); + + //Now reinstall the bundle + providerBundle = fixture.bc.installBundle(providerBundle.getLocation()); + + //set the global providerBundle reference that we will be using + //in the last series of tests (Account uninstallation persistency) + YahooSlickFixture.providerBundle = providerBundle; + + assertEquals("Couldn't re-install protocol provider bundle." + , Bundle.INSTALLED, providerBundle.getState()); + + providerBundle.start(); + assertEquals("Couldn't re-start protocol provider bundle." + , Bundle.ACTIVE, providerBundle.getState()); + + //Make sure that the provider is there again. + //verify that the provider is no longer available + try + { + yahooProviderRefs = fixture.bc.getServiceReferences( + ProtocolProviderService.class.getName(), + "(&" + + "(" + ProtocolProviderFactory.PROTOCOL + + "=" +ProtocolNames.YAHOO + ")" + + "(" + ProtocolProviderFactory.USER_ID + + "="+ fixture.userID1 + ")" + + ")"); + } + catch (InvalidSyntaxException ex) + { + fail("We apparently got our filter wrong " + ex.getMessage()); + } + + //make sure we didn't see a service + assertTrue("A Protocol Provider Service was not restored after being" + +"reinstalled. yahoo URI:" + fixture.userID1 + ,yahooProviderRefs != null && yahooProviderRefs.length > 0); + + ServiceReference[] yahooFactoryRefs = null; + try + { + yahooFactoryRefs = fixture.bc.getServiceReferences( + ProtocolProviderFactory.class.getName(), + "(" + ProtocolProviderFactory.PROTOCOL + + "=" +ProtocolNames.YAHOO + ")"); + } + catch (InvalidSyntaxException ex) + { + fail("We apparently got our filter wrong " + ex.getMessage()); + } + + //we're the ones who've reinstalled the factory so it's our + //responsibility to update the fixture. + fixture.providerFactory + = (ProtocolProviderFactory)fixture.bc.getService(yahooFactoryRefs[0]); + fixture.provider1 + = (ProtocolProviderService)fixture.bc.getService(yahooProviderRefs[0]); + + + //verify that the provider is also restored in the provider factory + //itself + assertTrue( + "The yahoo provider did not restore its own reference to the provider " + +"that we just reinstalled (URI="+fixture.userID1+")", + !fixture.providerFactory.getRegisteredAccounts().isEmpty() + && fixture.providerFactory.getProviderForAccount( + fixture.provider1.getAccountID()) + != null); + + } + + /** + * Uinstalls our test account and makes sure it really has been removed. + * + */ + public void testUninstallAccount() + { + assertFalse("No installed accounts found", + fixture.providerFactory.getRegisteredAccounts().isEmpty()); + + assertNotNull( + "Found no provider corresponding to URI " + fixture.userID1 + ,fixture.providerFactory.getProviderForAccount( + fixture.provider1.getAccountID())); + + assertTrue( + "Failed to remove a provider corresponding to URI " + + fixture.userID1 + ,fixture.providerFactory.uninstallAccount( + fixture.provider1.getAccountID())); + assertTrue( + "Failed to remove a provider corresponding to URI " + + fixture.userID1 + ,fixture.providerFactory.uninstallAccount( + fixture.provider2.getAccountID())); + + //make sure no providers have remained installed. + ServiceReference[] yahooProviderRefs = null; + try + { + yahooProviderRefs = fixture.bc.getServiceReferences( + ProtocolProviderService.class.getName(), + "(" + ProtocolProviderFactory.PROTOCOL + + "=" +ProtocolNames.YAHOO + ")"); + } + catch (InvalidSyntaxException ex) + { + fail("We apparently got our filter wrong " + ex.getMessage()); + } + + //make sure we didn't see a service + assertTrue("A Protocol Provider Service was still regged as an osgi " + + "service for yahoo URI:" + fixture.userID1 + + "After it was explicitly uninstalled" + ,yahooProviderRefs == null || yahooProviderRefs.length == 0); + + //verify that the provider factory knows that we have uninstalled the + //provider. + assertTrue( + "The yahoo provider factory kept a reference to the provider we just " + +"uninstalled (uri="+fixture.userID1+")", + fixture.providerFactory.getRegisteredAccounts().isEmpty() + && fixture.providerFactory.getProviderForAccount( + fixture.provider1.getAccountID()) + == null); + + } +} diff --git a/test/net/java/sip/communicator/slick/protocol/yahoo/TestAccountUninstallationPersistence.java b/test/net/java/sip/communicator/slick/protocol/yahoo/TestAccountUninstallationPersistence.java new file mode 100644 index 0000000..f621abc --- /dev/null +++ b/test/net/java/sip/communicator/slick/protocol/yahoo/TestAccountUninstallationPersistence.java @@ -0,0 +1,100 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.slick.protocol.yahoo; + +import org.osgi.framework.*; +import junit.framework.*; +import net.java.sip.communicator.service.configuration.*; +import net.java.sip.communicator.service.protocol.*; + +/** + * Contains tests verifying persistence of account uninstallation. In other + * words we try to make sure that once uninstalled an account remains + * uninstalled. + * + * @author Emil Ivov + */ +public class TestAccountUninstallationPersistence + extends TestCase +{ + /** + * Creates a new test instance wrapper around the test with the specified + * name. + * @param testName the name of the test that we will be executing. + */ + public TestAccountUninstallationPersistence(String testName) + { + super(testName); + } + + /** + * Retrieves a reference to the yahoo bundle, stops it and uninstalls it and + * then reinstalls it in order to make sure that accounts are not reloaded + * once removed. + * + * @throws java.lang.Exception if something goes wrong while manipulating + * the bundles. + */ + public void testAccountUninstallationPersistence() + throws Exception + { + Bundle providerBundle = YahooSlickFixture.providerBundle; + + providerBundle.stop(); + + assertTrue("Couldn't stop the protocol provider bundle. State was " + + providerBundle.getState() + , Bundle.ACTIVE != providerBundle.getState() + && Bundle.STOPPING != providerBundle.getState()); + + providerBundle.uninstall(); + + assertEquals("Couldn't stop the protocol provider bundle." + , Bundle.UNINSTALLED, providerBundle.getState()); + + //Now reinstall the bundle and restart the provider + providerBundle + = YahooSlickFixture.bc.installBundle(providerBundle.getLocation()); + + assertEquals("Couldn't re-install protocol provider bundle." + , Bundle.INSTALLED, providerBundle.getState()); + + providerBundle.start(); + assertEquals("Couldn't re-start protocol provider bundle." + , Bundle.ACTIVE, providerBundle.getState()); + + + //verify that the provider is not reinstalled + ServiceReference[] yahooProviderRefs = null; + try + { + yahooProviderRefs = YahooSlickFixture.bc.getServiceReferences( + ProtocolProviderService.class.getName(), + "(" + ProtocolProviderFactory.PROTOCOL + + "=" +ProtocolNames.YAHOO + ")"); + } + catch (InvalidSyntaxException ex) + { + fail("We apparently got our filter wrong " + ex.getMessage()); + } + + //make sure we didn't retrieve a service + assertTrue("A yahoo Protocol Provider Service was still regged as an " + +"osgi service after it was explicitly uninstalled" + ,yahooProviderRefs == null || yahooProviderRefs.length == 0); + + //and a nasty hack at the end - delete the configuration file so that + //we get a fresh start on next run. + ServiceReference confReference + = YahooSlickFixture.bc.getServiceReference( + ConfigurationService.class.getName()); + ConfigurationService configurationService + = (ConfigurationService) YahooSlickFixture.bc.getService(confReference); + + configurationService.purgeStoredConfiguration(); + } +} diff --git a/test/net/java/sip/communicator/slick/protocol/yahoo/TestOperationSetBasicInstantMessaging.java b/test/net/java/sip/communicator/slick/protocol/yahoo/TestOperationSetBasicInstantMessaging.java new file mode 100644 index 0000000..917ac4b --- /dev/null +++ b/test/net/java/sip/communicator/slick/protocol/yahoo/TestOperationSetBasicInstantMessaging.java @@ -0,0 +1,510 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.slick.protocol.yahoo; + +import java.net.*; +import java.util.*; + +import junit.framework.*; +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.service.protocol.Message; +import net.java.sip.communicator.service.protocol.event.*; +import net.java.sip.communicator.util.*; + +/** + * Performs testing of the basic instant messaging operation set. Tests include + * going over basic functionality such as sending a message from the tested + * implementation and asserting reception by the tester agent and vice versa. + * @author Emil Ivov + */ +public class TestOperationSetBasicInstantMessaging + extends TestCase +{ + private static final Logger logger = + Logger.getLogger(TestOperationSetBasicInstantMessaging.class); + + private YahooSlickFixture fixture = new YahooSlickFixture(); + + private OperationSetBasicInstantMessaging opSetBasicIM1 = null; + private OperationSetBasicInstantMessaging opSetBasicIM2 = null; + + private OperationSetPresence opSetPresence1 = null; + private OperationSetPresence opSetPresence2 = null; + + public TestOperationSetBasicInstantMessaging(String name) + { + super(name); + } + + /** + * Get a reference to the basic IM operation set. + * @throws Exception if this is not a good day. + */ + protected void setUp() throws Exception + { + super.setUp(); + fixture.setUp(); + + Map supportedOperationSets1 = + fixture.provider1.getSupportedOperationSets(); + + if ( supportedOperationSets1 == null + || supportedOperationSets1.size() < 1) + throw new NullPointerException( + "No OperationSet implementations are supported by " + +"this implementation. "); + + //get the operation set presence here. + opSetBasicIM1 = + (OperationSetBasicInstantMessaging)supportedOperationSets1.get( + OperationSetBasicInstantMessaging.class.getName()); + + if (opSetBasicIM1 == null) + { + throw new NullPointerException( + "No implementation for basic IM was found"); + } + + //we also need the presence op set in order to retrieve contacts. + opSetPresence1 = + (OperationSetPresence)supportedOperationSets1.get( + OperationSetPresence.class.getName()); + + //if the op set is null show that we're not happy. + if (opSetPresence1 == null) + { + throw new NullPointerException( + "An implementation of the service must provide an " + + "implementation of at least one of the PresenceOperationSets"); + } + + Map supportedOperationSets2 = + fixture.provider2.getSupportedOperationSets(); + + if ( supportedOperationSets2 == null + || supportedOperationSets2.size() < 1) + throw new NullPointerException( + "No OperationSet implementations are supported by " + +"this implementation. "); + + //get the operation set presence here. + opSetBasicIM2 = + (OperationSetBasicInstantMessaging)supportedOperationSets2.get( + OperationSetBasicInstantMessaging.class.getName()); + + if (opSetBasicIM2 == null) + { + throw new NullPointerException( + "No implementation for basic IM was found"); + } + + opSetPresence2 = + (OperationSetPresence) supportedOperationSets2.get( + OperationSetPresence.class.getName()); + + //if the op set is null show that we're not happy. + if (opSetPresence2 == null) + { + throw new NullPointerException( + "An implementation of the service must provide an " + + "implementation of at least one of the PresenceOperationSets"); + } + + } + + protected void tearDown() throws Exception + { + super.tearDown(); + + fixture.tearDown(); + } + + /** + * Creates a test suite containing tests of this class in a specific order. + * We'll first execute tests beginning with the "test" prefix and then go to + * ordered tests.We first execture tests for receiving messagese, so that + * a volatile contact is created for the sender. we'll then be able to + * retrieve this volatile contact and send them a message on our turn. + * We need to do things this way as the contact corresponding to the tester + * agent has been removed in the previous test and we no longer have it + * in our contact list. + * + * @return Test a testsuite containing all tests to execute. + */ + public static Test suite() + { + TestSuite suite = new TestSuite(); + + suite.addTest(new TestOperationSetBasicInstantMessaging( + "prepareContactList")); + + suite.addTestSuite(TestOperationSetBasicInstantMessaging.class); + + //the following 2 need to be run in the specified order. + suite.addTest(new TestOperationSetBasicInstantMessaging( + "firstTestReceiveMessage")); + suite.addTest(new TestOperationSetBasicInstantMessaging( + "thenTestSendMessage")); + + return suite; + } + + /** + * Create the list to be sure that contacts exchanging messages + * exists in each other lists + * @throws Exception + */ + public void prepareContactList() + throws Exception + { + fixture.clearProvidersLists(); + + Object o = new Object(); + synchronized(o) + { + o.wait(2000); + } + + try + { + opSetPresence1.subscribe(fixture.userID2); + } + catch (OperationFailedException ex) + { + // the contact already exist its OK + } + + try + { + opSetPresence2.subscribe(fixture.userID1); + } + catch (OperationFailedException ex1) + { + // the contact already exist its OK + } + + synchronized(o) + { + o.wait(2000); + } + } + + /** + * Send an instant message from the tested operation set and assert + * reception by the tester agent. + */ + public void firstTestReceiveMessage() + { + String body = "This is an IM coming from the tester agent" + + " on " + new Date().toString(); + + ImEventCollector evtCollector = new ImEventCollector(); + + //add a msg listener and register to the op set and send an instant + //msg from the tester agent. + opSetBasicIM1.addMessageListener(evtCollector); + + Contact testerAgentContact + = opSetPresence2.findContactByID(fixture.userID1); + + logger.debug("Will send message " + body + " to: " + testerAgentContact); + + opSetBasicIM2.sendInstantMessage(testerAgentContact, + opSetBasicIM2.createMessage(body)); + + evtCollector.waitForEvent(10000); + + opSetBasicIM1.removeMessageListener(evtCollector); + + //assert reception of a message event + assertTrue( "No events delivered upon a received message" + , evtCollector.collectedEvents.size() > 0); + + //assert event instance of Message Received Evt + assertTrue( "Received evt was not an instance of " + + MessageReceivedEvent.class.getName() + , evtCollector.collectedEvents.get(0) + instanceof MessageReceivedEvent); + + //assert source contact == testAgent.uin + MessageReceivedEvent evt + = (MessageReceivedEvent)evtCollector.collectedEvents.get(0); + assertEquals("message sender " + , evt.getSourceContact().getAddress() + , fixture.userID2); + + //assert messageBody == body + assertEquals("message body", body, evt.getSourceMessage().getContent()); + } + + /** + * Send an instant message from the tester agent and assert reception by + * the tested implementation + */ + public void thenTestSendMessage() + { + String body = "This is an IM coming from the tested implementation" + + " on " + new Date().toString(); + + //create the message + net.java.sip.communicator.service.protocol.Message msg + = opSetBasicIM1.createMessage(body); + + //register a listener in the op set + ImEventCollector imEvtCollector1 = new ImEventCollector(); + opSetBasicIM1.addMessageListener(imEvtCollector1); + + //register a listener in the tester agent + ImEventCollector imEvtCollector2 = new ImEventCollector(); + opSetBasicIM2.addMessageListener(imEvtCollector2); + + Contact testerAgentContact + = opSetPresence1.findContactByID(fixture.userID2); + + opSetBasicIM1.sendInstantMessage(testerAgentContact, msg); + + imEvtCollector1.waitForEvent(10000); + imEvtCollector2.waitForEvent(10000); + + opSetBasicIM1.removeMessageListener(imEvtCollector1); + opSetBasicIM2.removeMessageListener(imEvtCollector2); + + //verify that the message delivered event was dispatched + assertTrue( "No events delivered when sending a message" + , imEvtCollector1.collectedEvents.size() > 0); + + assertTrue( "Received evt was not an instance of " + + MessageDeliveredEvent.class.getName() + , imEvtCollector1.collectedEvents.get(0) + instanceof MessageDeliveredEvent); + + MessageDeliveredEvent evt + = (MessageDeliveredEvent)imEvtCollector1.collectedEvents.get(0); + assertEquals("message destination " + , evt.getDestinationContact().getAddress() + , fixture.userID2); + + assertSame("source message", msg, evt.getSourceMessage()); + + + //verify that the message has successfully arived at the destination + assertTrue( "No messages received by the tester agent" + , imEvtCollector2.collectedEvents.size() > 0); + String receivedBody = + ((MessageReceivedEvent)imEvtCollector2.collectedEvents + .get(0)).getSourceMessage().getContent(); + + assertEquals("received message body", msg.getContent(), receivedBody); + } + + /** + * Creates an Message through the simple createMessage() method and inspects + * its parameters. + */ + public void testCreateMessage1() + { + String body = "This is an IM coming from the tested implementation" + + " on " + new Date().toString(); + net.java.sip.communicator.service.protocol.Message msg + = opSetBasicIM1.createMessage(body); + + assertEquals("message body", body, msg.getContent()); + assertTrue("message body bytes" + , Arrays.equals(body.getBytes(), msg.getRawData())); + assertEquals("message length", body.length(), msg.getSize()); + assertEquals("message content type" + , OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE + , msg.getContentType()); + + assertEquals("message encoding" + , OperationSetBasicInstantMessaging.DEFAULT_MIME_ENCODING + , msg.getEncoding()); + + assertNotNull("message uid", msg.getMessageUID()); + + //a further test on message uid. + net.java.sip.communicator.service.protocol.Message msg2 + = opSetBasicIM1.createMessage(body); + assertFalse("message uid", msg.getMessageUID().equals( + msg2.getMessageUID())); + } + + /** + * Creates an Message through the advance createMessage() method and + * inspects its parameters. + */ + public void testCreateMessage2() + { + String body = "This is an IM coming from the tested implementation" + + " on " + new Date().toString(); + String contentType = "text/html"; + String encoding = "UTF-16"; + String subject = "test message"; + net.java.sip.communicator.service.protocol.Message msg + = opSetBasicIM1.createMessage( + body.getBytes(), contentType, encoding, subject); + + assertEquals("message body", body, msg.getContent()); + assertTrue("message body bytes" + , Arrays.equals(body.getBytes(), msg.getRawData())); + assertEquals("message length", body.length(), msg.getSize()); + assertEquals("message content type", contentType, msg.getContentType()); + assertEquals("message encoding", encoding, msg.getEncoding()); + assertNotNull("message uid", msg.getMessageUID()); + + //a further test on message uid. + net.java.sip.communicator.service.protocol.Message msg2 + = opSetBasicIM1.createMessage(body); + assertFalse("message uid", msg.getMessageUID().equals( + msg2.getMessageUID())); + } + + /** + * Collects instant messaging events. + */ + private class ImEventCollector implements MessageListener + { + private List collectedEvents = new LinkedList(); + /** + * Called when a new incoming <tt>Message</tt> has been received. + * @param evt the <tt>MessageReceivedEvent</tt> containing the newly + * received message, its sender and other details. + */ + public void messageReceived(MessageReceivedEvent evt) + { + logger.debug("Received a MessageReceivedEvent: " + evt); + + synchronized(this) + { + collectedEvents.add(evt); + notifyAll(); + } + } + + /** + * Called to indicated that delivery of a message sent earlier has failed. + * Reason code and phrase are contained by the <tt>MessageFailedEvent</tt> + * @param evt the <tt>MessageFailedEvent</tt> containing the ID of the + * message whose delivery has failed. + */ + public void messageDeliveryFailed(MessageDeliveryFailedEvent evt) + { + logger.debug("Received a MessageDeliveryFailedEvent: " + evt); + + synchronized(this) + { + collectedEvents.add(evt); + notifyAll(); + } + } + + + /** + * Called when the underlying implementation has received an indication + * that a message, sent earlier has been successfully received by the + * destination. + * @param evt the MessageDeliveredEvent containing the id of the message + * that has caused the event. + */ + public void messageDelivered(MessageDeliveredEvent evt) + { + logger.debug("Received a MessageDeliveredEvent: " + evt); + + synchronized(this) + { + collectedEvents.add(evt); + notifyAll(); + } + } + + /** + * Blocks until at least one event is received or until waitFor + * miliseconds pass (whichever happens first). + * + * @param waitFor the number of miliseconds that we should be waiting + * for an event before simply bailing out. + */ + public void waitForEvent(long waitFor) + { + synchronized(this) + { + + if(collectedEvents.size() > 0) + return; + + try{ + wait(waitFor); + } + catch (InterruptedException ex) + { + logger.debug( + "Interrupted while waiting for a message evt", ex); + } + } + } + } + + /** + * A method that would simply send messages to a group of people so that + * they would get notified that tests are being run. + */ + public void testSendFunMessages() + { + String hostname = ""; + + try{ + hostname = java.net.InetAddress.getLocalHost().getHostName() + ": "; + }catch (UnknownHostException ex){} + + String message = hostname + + "Hello this is the SIP Communicator (version " + + System.getProperty("sip-communicator.version") + + ") build on: " + + new Date().toString() + + ". Have a very nice day!"; + + String list = System.getProperty("accounts.reporting.YAHOO_REPORT_LIST"); + + logger.debug("Will send message " + message + " to: " + list); + + //if no property is specified - return + if(list == null || list.trim().length() == 0) + return; + + StringTokenizer tokenizer = new StringTokenizer(list, " "); + + while(tokenizer.hasMoreTokens()) + { + String contactID = tokenizer.nextToken(); + Contact contact + = opSetPresence2.findContactByID(contactID); + + if(contact == null) + { + try + { + opSetPresence2.subscribe(contactID); + Object o = new Object(); + synchronized (o) + { + o.wait(2000); + } + } + catch (Exception ex1) + { + continue; + } + } + + contact + = opSetPresence2.findContactByID(contactID); + + opSetBasicIM2.sendInstantMessage(contact, + opSetBasicIM2.createMessage(message)); + } + } +} diff --git a/test/net/java/sip/communicator/slick/protocol/yahoo/TestOperationSetPersistentPresence.java b/test/net/java/sip/communicator/slick/protocol/yahoo/TestOperationSetPersistentPresence.java new file mode 100644 index 0000000..ffdc782 --- /dev/null +++ b/test/net/java/sip/communicator/slick/protocol/yahoo/TestOperationSetPersistentPresence.java @@ -0,0 +1,559 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.slick.protocol.yahoo; + +import java.util.*; + +import junit.framework.*; +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.service.protocol.event.*; +import net.java.sip.communicator.util.*; + +/** + * @author Damian Minkov + */ +public class TestOperationSetPersistentPresence + extends TestCase +{ + private static final Logger logger = + Logger.getLogger(TestOperationSetPersistentPresence.class); + + private YahooSlickFixture fixture = new YahooSlickFixture(); + private OperationSetPersistentPresence opSetPersPresence1 = null; + private OperationSetPersistentPresence opSetPersPresence2 = null; + private static final String testGroupName = "NewGroup"; + private static final String testGroupName2 = "Renamed"; + + public TestOperationSetPersistentPresence(String name) + { + super(name); + } + + /** + * Creates a test suite containing all tests of this class followed by + * test methods that we want executed in a specified order. + * @return the Test suite to run + */ + public static Test suite() + { + TestSuite suite = + new TestSuite(); + + //the following 2 need to be run in the specified order. + //(postTestRemoveGroup() needs the group created from + //postTestCreateGroup() ) + suite.addTest( + new TestOperationSetPersistentPresence("postTestCreateGroup")); + + //rename + //suite.addTest( new TestOperationSetPersistentPresence( + // "postTestRenameGroup")); + + suite.addTest( + new TestOperationSetPersistentPresence("postTestRemoveGroup")); + + // create the contact list + suite.addTest( + new TestOperationSetPersistentPresence("prepareContactList")); + + suite.addTestSuite(TestOperationSetPersistentPresence.class); + + return suite; + } + + protected void setUp() throws Exception + { + super.setUp(); + fixture.setUp(); + + Map supportedOperationSets1 = + fixture.provider1.getSupportedOperationSets(); + + if ( supportedOperationSets1 == null + || supportedOperationSets1.size() < 1) + throw new NullPointerException( + "No OperationSet implementations are supported by " + +"this Yahoo implementation. "); + + //get the operation set presence here. + opSetPersPresence1 = + (OperationSetPersistentPresence)supportedOperationSets1.get( + OperationSetPersistentPresence.class.getName()); + + //if still null then the implementation doesn't offer a presence + //operation set which is unacceptable for yahoo. + if (opSetPersPresence1 == null) + throw new NullPointerException( + "An implementation of the Yahoo service must provide an " + + "implementation of at least the one of the Presence " + + "Operation Sets"); + + // lets do it once again for the second provider + Map supportedOperationSets2 = + fixture.provider2.getSupportedOperationSets(); + + if (supportedOperationSets2 == null + || supportedOperationSets2.size() < 1) + throw new NullPointerException( + "No OperationSet implementations are supported by " + + "this Yahoo implementation. "); + + //get the operation set presence here. + opSetPersPresence2 = + (OperationSetPersistentPresence) supportedOperationSets2.get( + OperationSetPersistentPresence.class.getName()); + + //if still null then the implementation doesn't offer a presence + //operation set which is unacceptable for yahoo. + if (opSetPersPresence2 == null) + throw new NullPointerException( + "An implementation of the yahoo service must provide an " + + "implementation of at least the one of the Presence " + + "Operation Sets"); + } + + protected void tearDown() throws Exception + { + fixture.tearDown(); + super.tearDown(); + } + + /** + * Retrieves a server stored contact list and checks whether it contains + * all contacts that have been added there during the initialization + * phase by the testerAgent. + */ + public void testRetrievingServerStoredContactList() + { + ContactGroup rootGroup + = opSetPersPresence1.getServerStoredContactListRoot(); + + logger.debug("=========== Server Stored Contact List ================="); + + logger.debug("rootGroup="+rootGroup.getGroupName() + +" rootGroup.childContacts="+rootGroup.countContacts() + + "rootGroup.childGroups="+rootGroup.countSubgroups() + + "Printing rootGroupContents=\n"+rootGroup.toString()); + + Hashtable expectedContactList = fixture.preInstalledBuddyList; + + logger.debug("============== Expected Contact List ==================="); + logger.debug(expectedContactList); + + //Go through the contact list retrieved by the persistence presence set + //and remove the name of every contact and group that we find there from + //the expected contct list hashtable. + Iterator groups = rootGroup.subgroups(); + while (groups.hasNext() ) + { + ContactGroup group = (ContactGroup)groups.next(); + + List expectedContactsInGroup + = (List)expectedContactList.get(group.getGroupName()); + + // When sending the offline message + // the sever creates a group NotInContactList, + // beacuse the buddy we are sending message to is not in + // the contactlist. So this group must be ignored + // Also we must ignore the group created by default + // from the yahoo lib + if(!group.getGroupName().equals("NotInContactList") && + !group.getGroupName().equals("Default group")) + { + assertNotNull("Group " + group.getGroupName() + + " was returned by " + + + "the server but was not in the expected contact list." + , expectedContactsInGroup); + + Iterator contactsIter = group.contacts(); + while(contactsIter.hasNext()) + { + String contactID = ((Contact)contactsIter.next()). + getAddress(); + expectedContactsInGroup.remove(contactID); + } + + //If we've removed all the sub contacts, remove the group too. + if(expectedContactsInGroup.size() == 0) + expectedContactList.remove(group.getGroupName()); + } + } + + //whatever we now have in the expected contact list snapshot are groups, + //that have been added by the testerAgent but that were not retrieved + //by the persistent presence operation set. + assertTrue("The following contacts were on the server sidec contact " + +"list, but were not returned by the pers. pres. op. set" + + expectedContactList.toString() + , expectedContactList.isEmpty()); + } + + /** + * Creates a group in the server stored contact list, makes sure that the + * corresponding event has been generated and verifies that the group is + * in the list. + * + * @throws java.lang.Exception + */ + public void postTestCreateGroup() + throws Exception + { + // first clear the list + fixture.clearProvidersLists(); + + waitFor(5000); + + logger.trace("testing creation of server stored groups"); + //first add a listener + GroupChangeCollector groupChangeCollector = new GroupChangeCollector(); + opSetPersPresence1 + .addServerStoredGroupChangeListener(groupChangeCollector); + + //create the group + opSetPersPresence1.createServerStoredContactGroup( + opSetPersPresence1.getServerStoredContactListRoot(), testGroupName); + + groupChangeCollector.waitForEvent(10000); + + opSetPersPresence1 + .removeServerStoredGroupChangeListener(groupChangeCollector); + + // check whether we got group created event + assertEquals("Collected Group Change events: ", + 1, groupChangeCollector.collectedEvents.size()); + + assertEquals("Group name.", testGroupName, + ((ServerStoredGroupEvent)groupChangeCollector.collectedEvents + .get(0)).getSourceGroup().getGroupName()); + + // check whether the group is retrievable + ContactGroup group = opSetPersPresence1.getServerStoredContactListRoot() + .getGroup(testGroupName); + + assertNotNull("A newly created group was not in the contact list.", + group); + + assertEquals("New group name", testGroupName, group.getGroupName()); + + // when opearting with groups . the group must have entries + // so changes to take effect. Otherwise group will be lost after loggingout + try + { + opSetPersPresence1.subscribe(group, fixture.userID2); + + waitFor(1500); + } + catch (Exception ex) + { + fail("error adding entry to group : " + + group.getGroupName() + " " + + ex.getMessage()); + } + } + + + /** + * Removes the group created in the server stored contact list by the create + * group test, makes sure that the corresponding event has been generated + * and verifies that the group is not in the list any more. + */ + public void postTestRemoveGroup() + { + logger.trace("testing removal of server stored groups"); + + //first add a listener + GroupChangeCollector groupChangeCollector = new GroupChangeCollector(); + opSetPersPresence1 + .addServerStoredGroupChangeListener(groupChangeCollector); + + //remove the group + opSetPersPresence1.removeServerStoredContactGroup( + opSetPersPresence1.getServerStoredContactListRoot() + .getGroup(testGroupName)); + + groupChangeCollector.waitForEvent(10000); + + opSetPersPresence1 + .removeServerStoredGroupChangeListener(groupChangeCollector); + + // check whether we got group created event + assertEquals("Collected Group Change event", + 1, groupChangeCollector.collectedEvents.size()); + + assertEquals("Group name.", testGroupName, + ((ServerStoredGroupEvent)groupChangeCollector.collectedEvents + .get(0)).getSourceGroup().getGroupName()); + + // check whether the group is still on the contact list + ContactGroup group = opSetPersPresence1.getServerStoredContactListRoot() + .getGroup(testGroupName); + + assertNull("A freshly removed group was still on the contact list. - " + group, + group); + } + + /** + * Renames our test group and checks whether corresponding events are + * triggered. Verifies whether the group has really changed its name and + * whether it is findable by its new name. Also makes sure that it does + * not exist under its previous name any more. + */ + public void postTestRenameGroup() + { + logger.trace("Testing renaming groups."); + + ContactGroup group = opSetPersPresence1.getServerStoredContactListRoot() + .getGroup(testGroupName); + + //first add a listener + GroupChangeCollector groupChangeCollector = new GroupChangeCollector(); + opSetPersPresence1 + .addServerStoredGroupChangeListener(groupChangeCollector); + + //change the name and wait for a confirmation event + opSetPersPresence1.renameServerStoredContactGroup(group, testGroupName2); + + groupChangeCollector.waitForEvent(10000); + + opSetPersPresence1 + .removeServerStoredGroupChangeListener(groupChangeCollector); + + //examine the event + assertEquals("Collected Group Change event", + 1, groupChangeCollector.collectedEvents.size()); + + assertEquals("Group name.", testGroupName2, + ((ServerStoredGroupEvent)groupChangeCollector.collectedEvents + .get(0)).getSourceGroup().getGroupName()); + + // check whether the group is still on the contact list + ContactGroup oldGroup = opSetPersPresence1.getServerStoredContactListRoot() + .getGroup(testGroupName); + + assertNull("A group was still findable by its old name after renaming.", + oldGroup); + + //make sure that we could find the group by its new name. + ContactGroup newGroup = opSetPersPresence1.getServerStoredContactListRoot() + .getGroup(testGroupName2); + + assertNotNull("Could not find a renamed group by its new name.", + newGroup); + } + + /** + * Create the contact list. Later will be test to be sure that creating is ok + * @throws Exception + */ + public void prepareContactList() + throws Exception + { + fixture.clearProvidersLists(); + + waitFor(3000); + + String contactList = System.getProperty( + YahooProtocolProviderServiceLick.CONTACT_LIST_PROPERTY_NAME, null); + + logger.debug("The " + + YahooProtocolProviderServiceLick.CONTACT_LIST_PROPERTY_NAME + + " property is set to=" + contactList); + + if( contactList == null + || contactList.trim().length() < 6)//at least 4 for a UIN, 1 for the + // dot and 1 for the grp name + throw new IllegalArgumentException( + "The " + + YahooProtocolProviderServiceLick.CONTACT_LIST_PROPERTY_NAME + + " property did not contain a contact list."); + StringTokenizer tokenizer = new StringTokenizer(contactList, " \n\t"); + + logger.debug("tokens contained by the CL tokenized=" + +tokenizer.countTokens()); + + Hashtable contactListToCreate = new Hashtable(); + + //go over all group.uin tokens + while (tokenizer.hasMoreTokens()) + { + String groupUinToken = tokenizer.nextToken(); + int dotIndex = groupUinToken.indexOf("."); + + if ( dotIndex == -1 ) + { + throw new IllegalArgumentException(groupUinToken + + " is not a valid Group.UIN token"); + } + + String groupName = groupUinToken.substring(0, dotIndex); + String uin = groupUinToken.substring(dotIndex + 1); + + if( groupName.trim().length() < 1 + || uin.trim().length() < 4 ) + { + throw new IllegalArgumentException( + groupName + " or " + uin + + " are not a valid group name or yahoo UIN."); + } + + //check if we've already seen this group and if not - add it + List uinInThisGroup = (List)contactListToCreate.get(groupName); + if (uinInThisGroup == null) + { + uinInThisGroup = new ArrayList(); + contactListToCreate.put(groupName, uinInThisGroup); + } + + uinInThisGroup.add(uin); + } + + // now init the list + Enumeration newGroupsEnum = contactListToCreate.keys(); + + GroupChangeCollector groupChangeCollector = new GroupChangeCollector(); + opSetPersPresence1.addServerStoredGroupChangeListener(groupChangeCollector); + + //go over all groups in the contactsToAdd table + while (newGroupsEnum.hasMoreElements()) + { + String groupName = (String) newGroupsEnum.nextElement(); + logger.debug("Will add group " + groupName); + + opSetPersPresence1.createServerStoredContactGroup( + opSetPersPresence1.getServerStoredContactListRoot(), groupName); + + groupChangeCollector.waitForEvent(3000); + + ContactGroup newlyCreatedGroup = + opSetPersPresence1.getServerStoredContactListRoot().getGroup(groupName); + + Iterator contactsToAddToThisGroup + = ( (List) contactListToCreate.get(groupName)).iterator(); + while (contactsToAddToThisGroup.hasNext()) + { + String id = (String) contactsToAddToThisGroup.next(); + + logger.debug("Will add buddy " + id); + opSetPersPresence1.subscribe(newlyCreatedGroup, id); + } + } + + waitFor(2000); + + //store the created contact list for later reference + YahooSlickFixture.preInstalledBuddyList = contactListToCreate; + } + + private void waitFor(long time) + throws Exception + { + Object o = new Object(); + synchronized(o) + { + o.wait(time); + } + } + + /** + * The class would listen for and store received events delivered to + * <tt>ServerStoredGroupListener</tt>s. + */ + private class GroupChangeCollector implements ServerStoredGroupListener + { + public ArrayList collectedEvents = new ArrayList(); + + /** + * Blocks until at least one event is received or until waitFor + * miliseconds pass (whicever happens first). + * + * @param waitFor the number of miliseconds that we should be waiting + * for an event before simply bailing out. + */ + public void waitForEvent(long waitFor) + { + synchronized(this) + { + if(collectedEvents.size() > 0) + return; + + try{ + wait(waitFor); + } + catch (InterruptedException ex) + { + logger.debug( + "Interrupted while waiting for a subscription evt", ex); + } + } + } + + /** + * Called whnever an indication is received that a new server stored + * group is created. + * @param evt a ServerStoredGroupChangeEvent containing a reference to + * the newly created group. + */ + public void groupCreated(ServerStoredGroupEvent evt) + { + synchronized(this) + { + logger.debug("Collected evt("+collectedEvents.size()+")= "+evt); + collectedEvents.add(evt); + notifyAll(); + } + } + + /** + * Called when an indication is received that the name of a server stored + * contact group has changed. + * @param evt a ServerStoredGroupChangeEvent containing the details of the + * name change. + */ + public void groupNameChanged(ServerStoredGroupEvent evt) + { + synchronized(this) + { + logger.debug("Collected evt("+collectedEvents.size()+")= "+evt); + collectedEvents.add(evt); + notifyAll(); + } + } + + /** + * Called whnever an indication is received that an existing server stored + * group has been removed. + * @param evt a ServerStoredGroupChangeEvent containing a reference to the + * newly created group. + */ + public void groupRemoved(ServerStoredGroupEvent evt) + { + synchronized(this) + { + logger.debug("Collected evt("+collectedEvents.size()+")= "+evt); + collectedEvents.add(evt); + notifyAll(); + } + } + + /** + * Called whnever an indication is received that an existing server + * stored group has been resolved. + * @param evt a ServerStoredGroupChangeEvent containing a reference to + * the resolved group. + */ + public void groupResolved(ServerStoredGroupEvent evt) + { + synchronized(this) + { + logger.debug("Collected evt("+collectedEvents.size()+")= "+evt); + collectedEvents.add(evt); + notifyAll(); + } + } + } +} diff --git a/test/net/java/sip/communicator/slick/protocol/yahoo/TestOperationSetPresence.java b/test/net/java/sip/communicator/slick/protocol/yahoo/TestOperationSetPresence.java new file mode 100644 index 0000000..caa2df4 --- /dev/null +++ b/test/net/java/sip/communicator/slick/protocol/yahoo/TestOperationSetPresence.java @@ -0,0 +1,989 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.slick.protocol.yahoo; + +import java.beans.*; +import java.util.*; + +import junit.framework.*; +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.service.protocol.event.*; +import net.java.sip.communicator.service.protocol.yahooconstants.*; +import net.java.sip.communicator.util.*; + +/** + * Tests yahoo implementations of a Presence Operation Set. Tests in this class + * verify functionality such as: Changing local (our own) status and + * corresponding event dispatching; Querying status of contacts, Subscribing + * for presence notifications upong status changes of specific contacts. + * <p> + * Using a custom suite() method, we make sure that apart from standard test + * methods (those with a <tt>test</tt> prefix) we also execute those that + * we want run in a specific order like for example - postTestSubscribe() and + * postTestUnsubscribe(). + * <p> + * @author Damian Minkov + */ +public class TestOperationSetPresence + extends TestCase +{ + private static final Logger logger = + Logger.getLogger(TestOperationSetPresence.class); + + private YahooSlickFixture fixture = new YahooSlickFixture(); + private OperationSetPresence operationSetPresence1 = null; + private OperationSetPresence operationSetPresence2 = null; + private String statusMessageRoot = new String("Our status is now: "); + + private AuthHandler authHandler1 = null; + private AuthHandler authHandler2 = null; + + public TestOperationSetPresence(String name) + { + super(name); + } + + protected void setUp() throws Exception + { + super.setUp(); + fixture.setUp(); + + Map supportedOperationSets1 = + fixture.provider1.getSupportedOperationSets(); + + if ( supportedOperationSets1 == null + || supportedOperationSets1.size() < 1) + throw new NullPointerException( + "No OperationSet implementations are supported by " + +"this implementation. "); + + //get the operation set presence here. + operationSetPresence1 = + (OperationSetPresence)supportedOperationSets1.get( + OperationSetPresence.class.getName()); + + //if the op set is null then the implementation doesn't offer a presence + //operation set which is unacceptable for yahoo. + if (operationSetPresence1 == null) + { + throw new NullPointerException( + "An implementation of the yahoo service must provide an " + + "implementation of at least the one of the Presence " + + "Operation Sets"); + } + + // do it once again for the second provider + Map supportedOperationSets2 = + fixture.provider2.getSupportedOperationSets(); + + if ( supportedOperationSets2 == null + || supportedOperationSets2.size() < 1) + throw new NullPointerException( + "No OperationSet implementations are supported by " + +"this yahoo implementation. "); + + //get the operation set presence here. + operationSetPresence2 = + (OperationSetPresence)supportedOperationSets2.get( + OperationSetPresence.class.getName()); + + //if the op set is null then the implementation doesn't offer a presence + //operation set which is unacceptable for yahoo. + if (operationSetPresence2 == null) + { + throw new NullPointerException( + "An implementation of the yahoo service must provide an " + + "implementation of at least the one of the Presence " + + "Operation Sets"); + } + + if(authHandler1 == null) + { + authHandler1 = new AuthHandler(operationSetPresence1); + operationSetPresence1.setAuthorizationHandler(authHandler1); + } + + if(authHandler2 == null) + { + authHandler2 = new AuthHandler(operationSetPresence2); + operationSetPresence2.setAuthorizationHandler(authHandler2); + } + } + + protected void tearDown() throws Exception + { + super.tearDown(); + + fixture.tearDown(); + } + + /** + * Creates a test suite containing all tests of this class followed by + * test methods that we want executed in a specified order. + * @return Test + */ + public static Test suite() + { + //return an (almost) empty suite if we're running in offline mode. + if(YahooSlickFixture.onlineTestingDisabled) + { + TestSuite suite = new TestSuite(); + //the only test around here that we could run without net + //connectivity + suite.addTest( + new TestOperationSetPresence( + "testSupportedStatusSetForCompleteness")); + return suite; + } + + TestSuite suite = new TestSuite(); + + // clear the lists before subscribing users + suite.addTest(new TestOperationSetPresence("clearLists")); + + // first postTestSubscribe. to be sure that contacts are in the + // list so we can further continue and test presences each other + suite.addTest(new TestOperationSetPresence("postTestSubscribe")); + + // add other tests + suite.addTestSuite(TestOperationSetPresence.class); + + // now test unsubscribe + suite.addTest(new TestOperationSetPresence("postTestUnsubscribe")); + + return suite; + } + + /** + * Verifies that all necessary yahoo test states are supported by the + * implementation. + */ + public void testSupportedStatusSetForCompleteness() + { + //first create a local list containing the presence status instances + //supported by the underlying implementation. + Iterator supportedStatusSetIter = + operationSetPresence1.getSupportedStatusSet(); + + List supportedStatusSet = new LinkedList(); + while (supportedStatusSetIter.hasNext()){ + supportedStatusSet.add(supportedStatusSetIter.next()); + } + + //create a copy of the MUST status set and remove any matching status + //that is also present in the supported set. + List requiredStatusSetCopy = (List)YahooStatusEnum.yahooStatusSet.clone(); + + requiredStatusSetCopy.removeAll(supportedStatusSet); + + //if we have anything left then the implementation is wrong. + int unsupported = requiredStatusSetCopy.size(); + assertTrue( "There are " + unsupported + " statuses as follows:" + + requiredStatusSetCopy, + unsupported == 0); + } + + /** + * Verify that changing state to STEPPED_OUT works as supposed to and that it + * generates the corresponding event. + * @throws Exception in case a failure occurs while the operation set + * is switching to the new state. + */ + public void testChangingStateToSteppedOut() throws Exception + { + subtestStateTransition(YahooStatusEnum.STEPPED_OUT); + } + + /** + * Verify that changing state to NOT_IN_OFFICE works as supposed to and that it + * generates the corresponding event. + * @throws Exception in case a failure occurs while the operation set + * is switching to the new state. + */ + public void testChangingStateToNotInOffice() throws Exception + { + subtestStateTransition(YahooStatusEnum.NOT_IN_OFFICE); + } + + /** + * Verify that changing state to BUSY works as supposed to and that it + * generates the corresponding event. + * @throws Exception in case a failure occurs while the operation set + * is switching to the new state. + */ + public void testChangingStateToBusy() throws Exception + { + subtestStateTransition(YahooStatusEnum.BUSY); + } + + /** + * Verify that changing state to FREE_FOR_CHAT works as supposed to and that it + * generates the corresponding event. + * @throws Exception in case a failure occurs while the operation set + * is switching to the new state. + */ + public void testChangingStateToIdle() throws Exception + { + subtestStateTransition(YahooStatusEnum.IDLE); + } + + /** + * Verify that changing state to ONLINE works as supposed to and that it + * generates the corresponding event. + * @throws Exception in case a failure occurs while the operation set + * is switching to the new state. + */ + public void testChangingStateToOnline() throws Exception + { + subtestStateTransition(YahooStatusEnum.AVAILABLE); + } + + /** + * Verify that changing state to OUT_TO_LUNCH works as supposed to and that it + * generates the corresponding event. + * @throws Exception in case a failure occurs while the operation set + * is switching to the new state. + */ + public void testChangingStateToOutToLunch() throws Exception + { + subtestStateTransition(YahooStatusEnum.OUT_TO_LUNCH); + } + + /** + * Verify that changing state to ON_THE_PHONE works as supposed to and that it + * generates the corresponding event. + * @throws Exception in case a failure occurs while the operation set + * is switching to the new state. + */ + public void testChangingStateToOnThePhone() throws Exception + { + subtestStateTransition(YahooStatusEnum.ON_THE_PHONE); + } + + /** + * Used by methods testing state transiotions + * + * @param newStatus the YahooStatusEnum field corresponding to the status + * that we'd like the opeation set to enter. + * + * @throws Exception in case changing the state causes an exception + */ + public void subtestStateTransition( YahooStatusEnum newStatus) + throws Exception + { + logger.trace(" --=== beginning state transition test ===--"); + + PresenceStatus oldStatus = operationSetPresence1.getPresenceStatus(); + + logger.debug( "old status is=" + oldStatus.getStatusName() + + " new status=" + newStatus.getStatusName()); + + //First register a listener to make sure that all corresponding + //events have been generated. + PresenceStatusEventCollector statusEventCollector + = new PresenceStatusEventCollector(); + operationSetPresence1.addProviderPresenceStatusListener( + statusEventCollector); + + //change the status + operationSetPresence1.publishPresenceStatus(newStatus, null); + pauseAfterStateChanges(); + + //test event notification. + statusEventCollector.waitForPresEvent(10000); + + operationSetPresence1.removeProviderPresenceStatusListener( + statusEventCollector); + + assertEquals("Events dispatched during an event transition.", + 1, statusEventCollector.collectedPresEvents.size()); + assertEquals("A status changed event contained wrong old status.", + oldStatus, + ((ProviderPresenceStatusChangeEvent) + statusEventCollector.collectedPresEvents.get(0)) + .getOldStatus()); + assertEquals("A status changed event contained wrong new status.", + newStatus, + ((ProviderPresenceStatusChangeEvent) + statusEventCollector.collectedPresEvents.get(0)) + .getNewStatus()); + + // verify that the operation set itself is aware of the status change + assertEquals("opSet.getPresenceStatus() did not return properly.", + newStatus, + operationSetPresence1.getPresenceStatus()); + + YahooStatusEnum actualStatus = (YahooStatusEnum) + operationSetPresence2.queryContactStatus(fixture.userID1); + + assertEquals("The underlying implementation did not switch to the " + +"requested presence status.", + newStatus, + actualStatus); + + logger.trace(" --=== finished test ===--"); + } + + /** + * Give time changes to take effect + */ + private void pauseAfterStateChanges() + { + try + { + Thread.currentThread().sleep(1500); + } + catch (InterruptedException ex) + { + logger.debug("Pausing between state changes was interrupted", ex); + } + } + /** + * Verifies that querying status works fine. The tester agent would + * change status and the operation set would have to return the right status + * after every change. + * + * @throws java.lang.Exception if one of the transitions fails + */ + public void testQueryContactStatus() + throws Exception + { + // --- NA --- + logger.debug("Will Query an BRB contact."); + subtestQueryContactStatus(YahooStatusEnum.BE_RIGHT_BACK, + YahooStatusEnum.BE_RIGHT_BACK); + + // --- DND --- + logger.debug("Will Query a Busy contact."); + subtestQueryContactStatus(YahooStatusEnum.BUSY, + YahooStatusEnum.BUSY); + + // --- FFC --- + logger.debug("Will Query a Idle contact."); + subtestQueryContactStatus(YahooStatusEnum.IDLE, + YahooStatusEnum.IDLE); + + // --- INVISIBLE --- + logger.debug("Will Query an Invisible contact."); + subtestQueryContactStatus(YahooStatusEnum.INVISIBLE, + YahooStatusEnum.OFFLINE); + + // --- Online --- + logger.debug("Will Query an Online contact."); + subtestQueryContactStatus(YahooStatusEnum.AVAILABLE, + YahooStatusEnum.AVAILABLE); + } + + /** + * Used by functions testing the queryContactStatus method of the + * presence operation set. + * @param status the status as specified, that + * the tester agent should switch to. + * @param expectedReturn the PresenceStatus that the presence operation + * set should see the tester agent in once it has switched to taStatusLong. + * + * @throws java.lang.Exception if querying the status causes some exception. + */ + public void subtestQueryContactStatus(PresenceStatus status, + PresenceStatus expectedReturn) + throws Exception + { + operationSetPresence2.publishPresenceStatus(status, "status message"); + + pauseAfterStateChanges(); + + PresenceStatus actualReturn + = operationSetPresence1.queryContactStatus(fixture.userID2); + assertEquals("Querying a " + + expectedReturn.getStatusName() + + " state did not return as expected" + , expectedReturn, actualReturn); + } + + /** + * The method would add a subscription for a contact, wait for a + * subscription event confirming the subscription, then change the status + * of the newly added contact (which is actually the testerAgent) and + * make sure that the corresponding notification events have been generated. + * + * @throws java.lang.Exception if an exception occurs during testing. + */ + public void postTestSubscribe() + throws Exception + { + logger.debug("Testing Subscription and Subscription Event Dispatch."); + + SubscriptionEventCollector subEvtCollector + = new SubscriptionEventCollector(); + operationSetPresence1.addSubsciptionListener(subEvtCollector); + + + synchronized (subEvtCollector){ + operationSetPresence1.subscribe(fixture.userID2); + //we may already have the event, but it won't hurt to check. + subEvtCollector.waitForEvent(10000); + operationSetPresence1.removeSubscriptionListener(subEvtCollector); + } + + assertEquals("Subscription event dispatching failed." + , 1, subEvtCollector.collectedEvents.size()); + SubscriptionEvent subEvt = + (SubscriptionEvent)subEvtCollector.collectedEvents.get(0); + + assertEquals("SubscriptionEvent Source:", + fixture.userID2, + ((Contact)subEvt.getSource()).getAddress()); + assertEquals("SubscriptionEvent Source Contact:", + fixture.userID2, + subEvt.getSourceContact().getAddress()); + assertSame("SubscriptionEvent Source Provider:", + fixture.provider1, + subEvt.getSourceProvider()); + + subEvtCollector.collectedEvents.clear(); + + // make the user agent tester change its states and make sure we are + // notified + logger.debug("Testing presence notifications."); + YahooStatusEnum oldStatus + = (YahooStatusEnum)operationSetPresence2.getPresenceStatus(); + + + YahooStatusEnum newStatus = YahooStatusEnum.IDLE; + + //in case we are by any chance already in a FREE_FOR_CHAT status, we'll + //be changing to something else + if(oldStatus.equals(newStatus)){ + newStatus = YahooStatusEnum.BUSY; + } + + //now do the actual status notification testing + ContactPresenceEventCollector contactPresEvtCollector + = new ContactPresenceEventCollector( + fixture.userID2, newStatus); + operationSetPresence1.addContactPresenceStatusListener( + contactPresEvtCollector); + + synchronized (contactPresEvtCollector){ + operationSetPresence2.publishPresenceStatus(newStatus, "new status"); + //we may already have the event, but it won't hurt to check. + contactPresEvtCollector.waitForEvent(10000); + operationSetPresence1 + .removeContactPresenceStatusListener(contactPresEvtCollector); + } + + assertEquals("Presence Notif. event dispatching failed." + , 1, contactPresEvtCollector.collectedEvents.size()); + ContactPresenceStatusChangeEvent presEvt = + (ContactPresenceStatusChangeEvent) + contactPresEvtCollector.collectedEvents.get(0); + + assertEquals("Presence Notif. event Source:", + fixture.userID2, + ((Contact)presEvt.getSource()).getAddress()); + assertEquals("Presence Notif. event Source Contact:", + fixture.userID2, + presEvt.getSourceContact().getAddress()); + assertSame("Presence Notif. event Source Provider:", + fixture.provider1, + presEvt.getSourceProvider()); + + PresenceStatus reportedNewStatus = presEvt.getNewStatus(); + PresenceStatus reportedOldStatus = presEvt.getOldStatus(); + + assertEquals( "Reported new PresenceStatus: ", + newStatus, reportedNewStatus ); + + //don't require equality between the reported old PresenceStatus and + //the actual presence status of the tester agent because a first + //notification is not supposed to have the old status as it really was. + assertNotNull( "Reported old PresenceStatus: ", reportedOldStatus ); + + try + { + // add the the user to the reverse side needed for status tests + subEvtCollector.collectedEvents.clear(); + operationSetPresence2.addSubsciptionListener(subEvtCollector); + + synchronized (subEvtCollector) + { + operationSetPresence2.subscribe(fixture.userID1); + //we may already have the event, but it won't hurt to check. + subEvtCollector.waitForEvent(10000); + operationSetPresence2.removeSubscriptionListener( + subEvtCollector); + } + } + catch (OperationFailedException ex) + { + // happens if the user is already subscribed + } + } + + /** + * We unsubscribe from presence notification deliveries concerning + * testerAgent's presence status and verify that we receive the + * subscription removed event. We then make the tester agent change status + * and make sure that no notifications are delivered. + * + * @throws java.lang.Exception in case unsubscribing fails. + */ + public void postTestUnsubscribe() + throws Exception + { + logger.debug("Testing Unsubscribe and unsubscription event dispatch."); + + // First create a subscription and verify that it really gets created. + SubscriptionEventCollector subEvtCollector + = new SubscriptionEventCollector(); + operationSetPresence1.addSubsciptionListener(subEvtCollector); + + Contact yahooTesterAgentContact = operationSetPresence1 + .findContactByID(fixture.userID2); + + assertNotNull( + "Failed to find an existing subscription for the tester agent" + , yahooTesterAgentContact); + + synchronized(subEvtCollector){ + operationSetPresence1.unsubscribe(yahooTesterAgentContact); + subEvtCollector.waitForEvent(10000); + //don't want any more events + operationSetPresence1.removeSubscriptionListener(subEvtCollector); + } + + assertEquals("Subscription event dispatching failed." + , 1, subEvtCollector.collectedEvents.size()); + SubscriptionEvent subEvt = + (SubscriptionEvent)subEvtCollector.collectedEvents.get(0); + + assertEquals("SubscriptionEvent Source:", + yahooTesterAgentContact, subEvt.getSource()); + + assertEquals("SubscriptionEvent Source Contact:", + yahooTesterAgentContact, subEvt.getSourceContact()); + + assertSame("SubscriptionEvent Source Provider:", + fixture.provider1, + subEvt.getSourceProvider()); + + subEvtCollector.collectedEvents.clear(); + + // make the user agent tester change its states and make sure we don't + // get notifications as we're now unsubscribed. + logger.debug("Testing (lack of) presence notifications."); + YahooStatusEnum oldStatus + = (YahooStatusEnum)operationSetPresence2.getPresenceStatus(); + YahooStatusEnum newStatus = YahooStatusEnum.IDLE; + + //in case we are by any chance already in a FREE_FOR_CHAT status, we'll + //be changing to something else + if(oldStatus.equals(newStatus)){ + newStatus = YahooStatusEnum.BUSY; + } + + //now do the actual status notification testing + ContactPresenceEventCollector contactPresEvtCollector + = new ContactPresenceEventCollector(fixture.userID2, null); + operationSetPresence1.addContactPresenceStatusListener( + contactPresEvtCollector); + + synchronized (contactPresEvtCollector){ + operationSetPresence2.publishPresenceStatus(newStatus, "new status"); + + //we may already have the event, but it won't hurt to check. + contactPresEvtCollector.waitForEvent(10000); + operationSetPresence1 + .removeContactPresenceStatusListener(contactPresEvtCollector); + } + + assertEquals("Presence Notifications were received after unsubscibing." + , 0, contactPresEvtCollector.collectedEvents.size()); + } + + public void clearLists() + throws Exception + { + logger.debug("Clear the two lists before tests"); + + // wait for a moment + // give time the impl to get the lists + logger.debug("start clearing"); + fixture.clearProvidersLists(); + + Object o = new Object(); + synchronized(o) + { + o.wait(3000); + } + } + + /** + * An event collector that would collect all events generated by a + * provider after a status change. The collector would also do a notidyAll + * every time it receives an event. + */ + private class PresenceStatusEventCollector + implements ProviderPresenceStatusListener + { + public ArrayList collectedPresEvents = new ArrayList(); + public ArrayList collectedStatMsgEvents = new ArrayList(); + + public void providerStatusChanged(ProviderPresenceStatusChangeEvent evt) + { + synchronized(this) + { + logger.debug("Collected evt("+collectedPresEvents.size()+")= "+evt); + collectedPresEvents.add(evt); + notifyAll(); + } + } + + public void providerStatusMessageChanged(PropertyChangeEvent evt) + { + synchronized(this) + { + logger.debug("Collected stat.msg. evt(" + +collectedPresEvents.size()+")= "+evt); + collectedStatMsgEvents.add(evt); + notifyAll(); + } + } + + /** + * Blocks until at least one event is received or until waitFor + * miliseconds pass (whicever happens first). + * + * @param waitFor the number of miliseconds that we should be waiting + * for an event before simply bailing out. + */ + public void waitForPresEvent(long waitFor) + { + logger.trace("Waiting for a change in provider status."); + synchronized(this) + { + if(collectedPresEvents.size() > 0){ + logger.trace("Change already received. " + collectedPresEvents); + return; + } + + try{ + wait(waitFor); + if(collectedPresEvents.size() > 0) + logger.trace("Received a change in provider status."); + else + logger.trace("No change received for "+waitFor+"ms."); + } + catch (InterruptedException ex){ + logger.debug("Interrupted while waiting for a provider evt" + , ex); + } + } + } + + /** + * Blocks until at least one staus message event is received or until + * waitFor miliseconds pass (whichever happens first). + * + * @param waitFor the number of miliseconds that we should be waiting + * for a status message event before simply bailing out. + */ + public void waitForStatMsgEvent(long waitFor) + { + logger.trace("Waiting for a provider status message event."); + synchronized(this) + { + if(collectedStatMsgEvents.size() > 0){ + logger.trace("Stat msg. evt already received. " + + collectedStatMsgEvents); + return; + } + + try{ + wait(waitFor); + if(collectedStatMsgEvents.size() > 0) + logger.trace("Received a prov. stat. msg. evt."); + else + logger.trace("No prov. stat msg. received for " + +waitFor+"ms."); + } + catch (InterruptedException ex){ + logger.debug("Interrupted while waiting for a status msg evt" + , ex); + } + } + } + } + + /** + * The class would listen for and store received subscription modification + * events. + */ + private class SubscriptionEventCollector implements SubscriptionListener + { + public ArrayList collectedEvents = new ArrayList(); + + /** + * Blocks until at least one event is received or until waitFor + * miliseconds pass (whicever happens first). + * + * @param waitFor the number of miliseconds that we should be waiting + * for an event before simply bailing out. + */ + public void waitForEvent(long waitFor) + { + synchronized(this) + { + if(collectedEvents.size() > 0) + return; + + try{ + wait(waitFor); + } + catch (InterruptedException ex) + { + logger.debug( + "Interrupted while waiting for a subscription evt", ex); + } + } + } + + /** + * Stores the received subsctiption and notifies all waiting on this + * object + * @param evt the SubscriptionEvent containing the corresponding contact + */ + public void subscriptionCreated(SubscriptionEvent evt) + { + synchronized(this) + { + logger.debug("Collected evt("+collectedEvents.size()+")= "+evt); + collectedEvents.add(evt); + notifyAll(); + } + } + + /** + * Stores the received subsctiption and notifies all waiting on this + * object + * @param evt the SubscriptionEvent containing the corresponding contact + */ + public void subscriptionRemoved(SubscriptionEvent evt) + { + synchronized(this) + { + logger.debug("Collected evt("+collectedEvents.size()+")= "+evt); + collectedEvents.add(evt); + notifyAll(); + } + } + + /** + * Stores the received subsctiption and notifies all waiting on this + * object + * @param evt the SubscriptionEvent containing the corresponding contact + */ + public void contactModified(ContactPropertyChangeEvent evt) + { + synchronized(this) + { + logger.debug("Collected evt("+collectedEvents.size()+")= "+evt); + collectedEvents.add(evt); + notifyAll(); + } + } + + + /** + * Stores the received subsctiption and notifies all waiting on this + * object + * @param evt the SubscriptionEvent containing the corresponding contact + */ + public void subscriptionMoved(SubscriptionMovedEvent evt) + { + synchronized(this) + { + logger.debug("Collected evt("+collectedEvents.size()+")= "+evt); + collectedEvents.add(evt); + notifyAll(); + } + } + + /** + * Stores the received subsctiption and notifies all waiting on this + * object + * @param evt the SubscriptionEvent containing the corresponding contact + */ + public void subscriptionFailed(SubscriptionEvent evt) + { + synchronized(this) + { + logger.debug("Collected evt("+collectedEvents.size()+")= "+evt); + collectedEvents.add(evt); + notifyAll(); + } + } + + /** + * Stores the received subsctiption and notifies all waiting on this + * object + * @param evt the SubscriptionEvent containing the corresponding contact + */ + public void subscriptionResolved(SubscriptionEvent evt) + { + synchronized(this) + { + logger.debug("Collected evt("+collectedEvents.size()+")= "+evt); + collectedEvents.add(evt); + notifyAll(); + } + } + + } + + /** + * The class would listen for and store received events caused by changes + * in contact presence states. + */ + private class ContactPresenceEventCollector + implements ContactPresenceStatusListener + { + public ArrayList collectedEvents = new ArrayList(); + private String trackedScreenName = null; + private YahooStatusEnum status = null; + + ContactPresenceEventCollector(String screenname, + YahooStatusEnum wantedStatus) + { + this.trackedScreenName = screenname; + this.status = wantedStatus; + } + + /** + * Blocks until at least one event is received or until waitFor + * miliseconds pass (whicever happens first). + * + * @param waitFor the number of miliseconds that we should be waiting + * for an event before simply bailing out. + */ + public void waitForEvent(long waitFor) + { + synchronized(this) + { + if(collectedEvents.size() > 0) + return; + + try{ + wait(waitFor); + } + catch (InterruptedException ex) + { + logger.debug( + "Interrupted while waiting for a subscription evt", ex); + } + } + } + + /** + * Stores the received status change event and notifies all waiting on + * this object + * @param evt the SubscriptionEvent containing the corresponding contact + */ + public void contactPresenceStatusChanged( + ContactPresenceStatusChangeEvent evt) + { + synchronized(this) + { + //if the user has specified event details and the received + //event does not match - then ignore it. + if( this.trackedScreenName != null + && !evt.getSourceContact().getAddress() + .equals(trackedScreenName)) + return; + if( status != null + && status != evt.getNewStatus()) + return; + + logger.debug("Collected evt("+collectedEvents.size()+")= "+evt); + collectedEvents.add(evt); + notifyAll(); + } + } + } + + /** + * Used to wait till buddy is removed from our contact list. + * Used in the authorization process tests + */ + private class UnsubscribeWait implements SubscriptionListener + { + public void waitForUnsubscribre(long waitFor) + { + synchronized(this) + { + try{ + wait(waitFor); + } + catch (InterruptedException ex) + { + logger.debug( + "Interrupted while waiting for a subscription evt", ex); + } + } + } + + public void subscriptionRemoved(SubscriptionEvent evt) + { + synchronized(this) + { + logger.debug("Got subscriptionRemoved " + evt); + notifyAll(); + } + } + + public void subscriptionCreated(SubscriptionEvent evt) + {} + public void subscriptionFailed(SubscriptionEvent evt) + {} + public void subscriptionMoved(SubscriptionMovedEvent evt) + {} + public void subscriptionResolved(SubscriptionEvent evt) + {} + public void contactModified(ContactPropertyChangeEvent evt) + {} + } + + /** + * AuthorizationHandler which accepts all requests! + */ + private class AuthHandler + implements AuthorizationHandler + { + private OperationSetPresence opset = null; + AuthHandler(OperationSetPresence opset) + { + this.opset = opset; + } + + public AuthorizationResponse processAuthorisationRequest( + AuthorizationRequest req, Contact sourceContact) + { + try{ + opset.subscribe(sourceContact.getAddress()); + }catch(Exception ex){} + + return + new AuthorizationResponse(AuthorizationResponse.ACCEPT, ""); + } + public AuthorizationRequest createAuthorizationRequest(Contact contact ) + { + return new AuthorizationRequest(); + } + public void processAuthorizationResponse( + AuthorizationResponse response, Contact sourceContact){} + } +}
\ No newline at end of file diff --git a/test/net/java/sip/communicator/slick/protocol/yahoo/TestOperationSetTypingNotifications.java b/test/net/java/sip/communicator/slick/protocol/yahoo/TestOperationSetTypingNotifications.java new file mode 100644 index 0000000..1e05ca9 --- /dev/null +++ b/test/net/java/sip/communicator/slick/protocol/yahoo/TestOperationSetTypingNotifications.java @@ -0,0 +1,293 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.slick.protocol.yahoo; + +import java.util.*; + +import junit.framework.*; +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.service.protocol.event.*; +import net.java.sip.communicator.util.*; + +/** + * Tests functionality of the typing notifications operation set. + * + * @author Damian Minkov + */ +public class TestOperationSetTypingNotifications + extends TestCase +{ + private static final Logger logger = + Logger.getLogger(TestOperationSetTypingNotifications.class); + + private YahooSlickFixture fixture = new YahooSlickFixture(); + private OperationSetTypingNotifications opSetTypingNotifs1 = null; + private OperationSetPresence opSetPresence1 = null; + private OperationSetTypingNotifications opSetTypingNotifs2 = null; + private OperationSetPresence opSetPresence2 = null; + + private OperationSetBasicInstantMessaging opSetBasicIM1 = null; + private OperationSetBasicInstantMessaging opSetBasicIM2 = null; + + + public TestOperationSetTypingNotifications(String name) + { + super(name); + } + + protected void setUp() throws Exception + { + super.setUp(); + fixture.setUp(); + + Map supportedOperationSets1 = + fixture.provider1.getSupportedOperationSets(); + + if ( supportedOperationSets1 == null + || supportedOperationSets1.size() < 1) + throw new NullPointerException( + "No OperationSet implementations are supported by " + +"this implementation. "); + + //get the operation set presence here. + opSetTypingNotifs1 = + (OperationSetTypingNotifications)supportedOperationSets1.get( + OperationSetTypingNotifications.class.getName()); + + //if the op set is null then the implementation doesn't offer a typing.n + //operation set which is unacceptable. + if (opSetTypingNotifs1 == null) + { + throw new NullPointerException( + "No implementation for typing notifications was found"); + } + + opSetBasicIM1 = + (OperationSetBasicInstantMessaging)supportedOperationSets1.get( + OperationSetBasicInstantMessaging.class.getName()); + + if (opSetBasicIM1 == null) + { + throw new NullPointerException( + "No implementation for basic IM was found"); + } + + + //we also need the presence op set in order to retrieve contacts. + opSetPresence1 = + (OperationSetPresence)supportedOperationSets1.get( + OperationSetPresence.class.getName()); + + //if the op set is null show that we're not happy. + if (opSetPresence1 == null) + { + throw new NullPointerException( + "An implementation of the service must provide an " + + "implementation of at least one of the PresenceOperationSets"); + } + + Map supportedOperationSets2 = + fixture.provider2.getSupportedOperationSets(); + + if ( supportedOperationSets2 == null + || supportedOperationSets2.size() < 1) + throw new NullPointerException( + "No OperationSet implementations are supported by " + +"this implementation. "); + + //get the operation set presence here. + opSetTypingNotifs2 = + (OperationSetTypingNotifications)supportedOperationSets2.get( + OperationSetTypingNotifications.class.getName()); + + //if the op set is null then the implementation doesn't offer a typing.n + //operation set which is unacceptable for. + if (opSetTypingNotifs2 == null) + { + throw new NullPointerException( + "No implementation for typing notifications was found"); + } + + opSetBasicIM2 = + (OperationSetBasicInstantMessaging)supportedOperationSets2.get( + OperationSetBasicInstantMessaging.class.getName()); + + if (opSetBasicIM2 == null) + { + throw new NullPointerException( + "No implementation for basic IM was found"); + } + + + //we also need the presence op set in order to retrieve contacts. + opSetPresence2 = + (OperationSetPresence)supportedOperationSets2.get( + OperationSetPresence.class.getName()); + + //if the op set is null show that we're not happy. + if (opSetPresence2 == null) + { + throw new NullPointerException( + "An implementation of the service must provide an " + + "implementation of at least one of the PresenceOperationSets"); + } + } + + /** + * Create the list to be sure that contacts exchanging messages + * exists in each other lists + * @throws Exception + */ + public void prepareContactList() throws Exception + { + // be sure that contacts are in their lists + try{ + opSetPresence1.subscribe(fixture.userID2); + } + catch (OperationFailedException ex){ + // the contact already exist its OK + } + + try{ + opSetPresence2.subscribe(fixture.userID1); + } + catch (OperationFailedException ex1){ + // the contact already exist its OK + } + + Object o = new Object(); + synchronized (o) + { + o.wait(2000); + } + } + + protected void tearDown() throws Exception + { + super.tearDown(); + + fixture.tearDown(); + } + + /** + * Creates a test suite containing tests of this class in a specific order. + * We'll first execute a test where we receive a typing notification, and + * a volatile contact is created for the sender. we'll then be able to + * retrieve this volatile contact and them a notification on our turn. + * We need to do things this way as the contact corresponding to the tester + * agent has been removed in the previous test and we no longer have it + * in our contact list. + * + * @return Test a testsuite containing all tests to execute. + */ + public static Test suite() + { + TestSuite suite = new TestSuite(); + + suite.addTest(new TestOperationSetTypingNotifications( + "prepareContactList")); + + //the following 2 need to be run in the specified order. + suite.addTest(new TestOperationSetTypingNotifications( + "testTypingNotificationsEventDelivery")); + return suite; + } + + /** + * Sends a typing notification and verifies + * whether it is properly received by the tested implementation + */ + public void testTypingNotificationsEventDelivery() + { + TypingEventCollector evtCollector = new TypingEventCollector(); + + // send message so request for receiving notifications also to be set + Contact notifingContact = + opSetPresence1.findContactByID(fixture.userID2); + opSetBasicIM1.sendInstantMessage(notifingContact, + opSetBasicIM1.createMessage("ping")); + + opSetTypingNotifs1.addTypingNotificationsListener(evtCollector); + + Contact contactToNotify = + opSetPresence2.findContactByID(fixture.userID1); + + opSetBasicIM2.sendInstantMessage(contactToNotify, + opSetBasicIM2.createMessage("pong")); + + opSetTypingNotifs2.sendTypingNotification( + contactToNotify, OperationSetTypingNotifications.STATE_TYPING); + + evtCollector.waitForEvent(10000); + + opSetTypingNotifs1.removeTypingNotificationsListener(evtCollector); + + //check event dispatching + assertTrue("Number of typing events received was zero." + , evtCollector.collectedEvents.size() > 0); + + TypingNotificationEvent evt = (TypingNotificationEvent)evtCollector + .collectedEvents.get(0); + + assertEquals("Source of the typing notification event" + , fixture.userID2 + , evt.getSourceContact().getAddress() ); + + assertEquals("Source of the typing notification event" + , OperationSetTypingNotifications.STATE_TYPING + , evt.getTypingState()); + } + + /** + * Simply collects allre received events and provides a mechanisim for + * waiting for the next event. + */ + private class TypingEventCollector implements TypingNotificationsListener + { + private List collectedEvents = new LinkedList(); + /** + * Called to indicate that a remote <tt>Contact</tt> has sent us a typing + * notification. The method adds the <tt>event</tt> to the list of + * captured events. + * @param event a <tt>TypingNotificationEvent</tt> containing the sender + * of the notification and its type. + */ + public void typingNotificationReceifed(TypingNotificationEvent event) + { + logger.debug("Received a typing notification: " + event); + synchronized (this) + { + collectedEvents.add(event); + notifyAll(); + } + } + + /** + * Blocks until at least one event is received or until waitFor + * miliseconds pass (whicever happens first). + * + * @param waitFor the number of miliseconds that we should be waiting + * for an event before simply bailing out. + */ + public void waitForEvent(long waitFor) + { + synchronized(this){ + + if(collectedEvents.size() > 0) + return; + + try{ + wait(waitFor); + } + catch (InterruptedException ex){ + logger.debug( + "Interrupted while waiting for a subscription evt", ex); + } + } + } + } +} diff --git a/test/net/java/sip/communicator/slick/protocol/yahoo/TestProtocolProviderServiceYahooImpl.java b/test/net/java/sip/communicator/slick/protocol/yahoo/TestProtocolProviderServiceYahooImpl.java new file mode 100644 index 0000000..e5be043 --- /dev/null +++ b/test/net/java/sip/communicator/slick/protocol/yahoo/TestProtocolProviderServiceYahooImpl.java @@ -0,0 +1,285 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.slick.protocol.yahoo; + +import java.util.*; + +import junit.framework.*; +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.service.protocol.event.*; +import net.java.sip.communicator.util.*; + +/** + * Performs testing on protocol provider methods. + * @todo add more detailed docs once the tests are written. + * @author Damian Minkov + */ +public class TestProtocolProviderServiceYahooImpl + extends TestCase +{ + private static final Logger logger = + Logger.getLogger(TestProtocolProviderServiceYahooImpl.class); + + private YahooSlickFixture fixture = new YahooSlickFixture(); + + /** + * An event adapter that would collec registation state change events + */ + public RegistrationEventCollector regEvtCollector1 + = new RegistrationEventCollector(); + + /** + * An event adapter that would collec registation state change events + */ + public RegistrationEventCollector regEvtCollector2 + = new RegistrationEventCollector(); + + /** + * Creates a test encapsulator for the method with the specified name. + * @param name the name of the method this test should run. + */ + public TestProtocolProviderServiceYahooImpl(String name) + { + super(name); + } + + /** + * Initializes the fixture. + * @throws Exception if super.setUp() throws one. + */ + protected void setUp() throws Exception + { + super.setUp(); + fixture.setUp(); + } + + /** + * Tears the fixture down. + * @throws Exception if fixture.tearDown() fails. + */ + protected void tearDown() throws Exception + { + fixture.tearDown(); + super.tearDown(); + } + + /** + * Makes sure that the instance of the Yahoo protocol provider that we're + * going to use for testing is properly initialized and registered with + * a Yahoo registrar. This MUST be called before any other online testing + * of the Yahoo provider so that we won't have to reregister for every single + * test. + * <p> + * The method also verifies that a registration event is fired upon + * succesful registration and collected by our event collector. + * + * @throws OperationFailedException if provider.register() fails. + */ + public void testRegister() + throws OperationFailedException + { + //add an event collector that will collect all events during the + //registration and allow us to later inspect them and make sure + //they were properly dispatched. + fixture.provider1.addRegistrationStateChangeListener(regEvtCollector1); + fixture.provider2.addRegistrationStateChangeListener(regEvtCollector2); + + //register both our providers + fixture.provider1.register(new SecurityAuthorityImpl( + System.getProperty(YahooProtocolProviderServiceLick.ACCOUNT_1_PREFIX + + ProtocolProviderFactory.PASSWORD).toCharArray())); + fixture.provider2.register(new SecurityAuthorityImpl( + System.getProperty(YahooProtocolProviderServiceLick.ACCOUNT_2_PREFIX + + ProtocolProviderFactory.PASSWORD).toCharArray())); + + //give it enough time to register. We won't really have to wait all this + //time since the registration event collector would notify us the moment + //we get signed on. + logger.debug("Waiting for registration to complete ..."); + + regEvtCollector1.waitForEvent(15000); + regEvtCollector2.waitForEvent(40000); + + //make sure that the registration process trigerred the corresponding + //events. + assertTrue( + "No events were dispatched during the registration process." + ,regEvtCollector1.collectedNewStates.size() > 0); + + assertTrue( + "No registration event notifying of registration was dispatched. " + +"All events were: " + regEvtCollector1.collectedNewStates + ,regEvtCollector1.collectedNewStates + .contains(RegistrationState.REGISTERED)); + + //now the same for provider 2 + assertTrue( + "No events were dispatched during the registration process " + +"of provider2." + ,regEvtCollector2.collectedNewStates.size() > 0); + + assertTrue( + "No registration event notifying of registration was dispatched. " + +"All events were: " + regEvtCollector2.collectedNewStates + ,regEvtCollector2.collectedNewStates + .contains(RegistrationState.REGISTERED)); + + + fixture.provider1 + .removeRegistrationStateChangeListener(regEvtCollector1); + fixture.provider2 + .removeRegistrationStateChangeListener(regEvtCollector2); + } + + + /** + * Verifies that all operation sets have the type they are declarded to + * have. + * + * @throws java.lang.Exception if a class indicated in one of the keys + * could not be forName()ed. + */ + public void testOperationSetTypes() throws Exception + { + Map supportedOperationSets + = fixture.provider1.getSupportedOperationSets(); + + //make sure that keys (which are supposed to be class names) correspond + //what the class of the values recorded against them. + Iterator setNames = supportedOperationSets.keySet().iterator(); + while (setNames.hasNext()) + { + String setName = (String) setNames.next(); + Object opSet = supportedOperationSets.get(setName); + + assertTrue(opSet + " was not an instance of " + + setName + " as declared" + , Class.forName(setName).isInstance(opSet)); + } + } + + /** + * A class that would plugin as a registration listener to a protocol + * provider and simply record all events that it sees and notifyAll() + * if it sees an event that notifies us of a completed + * registration. + */ + public class RegistrationEventCollector + implements RegistrationStateChangeListener + { + public List collectedNewStates = new LinkedList(); + + /** + * The method would simply register all received events so that they + * could be available for later inspection by the unit tests. In the + * case where a registraiton event notifying us of a completed + * registration is seen, the method would call notifyAll(). + * + * @param evt ProviderStatusChangeEvent the event describing the status + * change. + */ + public void registrationStateChanged(RegistrationStateChangeEvent evt) + { + logger.debug("Received a RegistrationStateChangeEvent: " + evt); + + collectedNewStates.add(evt.getNewState()); + + if (evt.getNewState().equals(RegistrationState.REGISTERED)) + { + logger.debug("We're registered and will notify those who wait"); + synchronized (this) + { + notifyAll(); + } + } + } + + /** + * Blocks until an event notifying us of the awaited state change is + * received or until waitFor miliseconds pass (whichever happens first). + * + * @param waitFor the number of miliseconds that we should be waiting + * for an event before simply bailing out. + */ + public void waitForEvent(long waitFor) + { + logger.trace("Waiting for a RegistrationStateChangeEvent "); + + synchronized (this) + { + if (collectedNewStates.contains(RegistrationState.REGISTERED)) + { + logger.trace("Event already received. " + + collectedNewStates); + return; + } + + try + { + wait(waitFor); + + if (collectedNewStates.size() > 0) + logger.trace( + "Received a RegistrationStateChangeEvent."); + else + logger.trace( + "No RegistrationStateChangeEvent received for " + + waitFor + "ms."); + + } + catch (InterruptedException ex) + { + logger.debug( + "Interrupted while waiting for a " + +"RegistrationStateChangeEvent" + , ex); + } + } + } + } + + /** + * A very simple straight forward implementation of a security authority + * that would always return the same password (the one specified upon + * construction) when asked for credentials. + */ + public class SecurityAuthorityImpl + implements SecurityAuthority + { + /** + * The password to return when asked for credentials + */ + private char[] passwd = null; + + /** + * Creates an instance of this class that would always return "passwd" + * when asked for credentials. + * + * @param passwd the password that this class should return when + * asked for credentials. + */ + public SecurityAuthorityImpl(char[] passwd) + { + this.passwd = passwd; + } + + /** + * Returns a Credentials object associated with the specified realm. + * <p> + * @param realm The realm that the credentials are needed for. + * @param defaultValues the values to propose the user by default + * @return The credentials associated with the specified realm or null + * if none could be obtained. + */ + public UserCredentials obtainCredentials(String realm, + UserCredentials defaultValues) + { + defaultValues.setPassword(passwd); + return defaultValues; + } + } +} diff --git a/test/net/java/sip/communicator/slick/protocol/yahoo/YahooProtocolProviderServiceLick.java b/test/net/java/sip/communicator/slick/protocol/yahoo/YahooProtocolProviderServiceLick.java new file mode 100644 index 0000000..49765b1 --- /dev/null +++ b/test/net/java/sip/communicator/slick/protocol/yahoo/YahooProtocolProviderServiceLick.java @@ -0,0 +1,106 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.slick.protocol.yahoo; + +import java.util.*; + +import org.osgi.framework.*; +import junit.framework.*; + +/** + * Yahoo specific testing for a Yahoo Protocol Provider Service implementation. + * The test suite registers two accounts for + * + * @author Damian Minkov + */ +public class YahooProtocolProviderServiceLick + extends TestSuite + implements BundleActivator +{ + /** + * The prefix used for property names containing settings for our first + * testing account. + */ + public static final String ACCOUNT_1_PREFIX + = "accounts.yahoo.account1."; + + /** + * The prefix used for property names containing settings for our second + * testing account. + */ + public static final String ACCOUNT_2_PREFIX + = "accounts.yahoo.account2."; + + /** + * The name of the property that indicates whether the user would like to + * only run the offline tests. + */ + public static final String DISABLE_ONLINE_TESTS_PROPERTY_NAME + = "accounts.yahoo.DISABLE_ONLINE_TESTING"; + + /** + * The name of the property the value of which is a formatted string that + * contains the contact list that. + */ + public static final String CONTACT_LIST_PROPERTY_NAME + = "accounts.yahoo.CONTACT_LIST"; + + /** + * Initializes and registers all tests that we'll run as a part of this + * slick. + * + * @param context a currently valid bundle context. + */ + public void start(BundleContext context) + { + setName("YahooProtocolProviderSlick"); + + Hashtable properties = new Hashtable(); + properties.put("service.pid", getName()); + + YahooSlickFixture.bc = context; + + // verify whether the user wants to avoid online testing + String offlineMode = System.getProperty( + DISABLE_ONLINE_TESTS_PROPERTY_NAME, null); + + if (offlineMode != null && offlineMode.equalsIgnoreCase("true")) + YahooSlickFixture.onlineTestingDisabled = true; + + + addTestSuite(TestAccountInstallation.class); + addTestSuite(TestProtocolProviderServiceYahooImpl.class); + + addTest(TestOperationSetPresence.suite()); + + //the following should only be run when we want online testing. + if(!YahooSlickFixture.onlineTestingDisabled) + { + addTest(TestOperationSetPersistentPresence.suite()); + + addTest(TestOperationSetBasicInstantMessaging.suite()); + + // Sending typing notifications doesn't work for now + //addTest(TestOperationSetTypingNotifications.suite()); + } + + addTest(TestAccountUninstallation.suite()); + addTestSuite(TestAccountUninstallationPersistence.class); + + context.registerService(getClass().getName(), this, properties); + } + + /** + * Prepares the slick for shutdown. + * + * @param context a currently valid bundle context. + */ + public void stop(BundleContext context) + { + + } +} diff --git a/test/net/java/sip/communicator/slick/protocol/yahoo/YahooSlickFixture.java b/test/net/java/sip/communicator/slick/protocol/yahoo/YahooSlickFixture.java new file mode 100644 index 0000000..1a62418 --- /dev/null +++ b/test/net/java/sip/communicator/slick/protocol/yahoo/YahooSlickFixture.java @@ -0,0 +1,295 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.slick.protocol.yahoo; + +import org.osgi.framework.*; +import junit.framework.*; +import net.java.sip.communicator.service.protocol.*; +import java.util.Map; +import java.util.*; + +/** + * Contains fields and methods used by most or all tests in the yahoo slick. + * + * @author Damian Minkov + */ +public class YahooSlickFixture + extends TestCase +{ + /** + * To be set by the slick itself upon activation. + */ + public static BundleContext bc = null; + + /** + * An osgi service reference for the protocol provider corresponding to our + * first testing account. + */ + public ServiceReference provider1ServiceRef = null; + + /** + * The protocol provider corresponding to our first testing account. + */ + public ProtocolProviderService provider1 = null; + + /** + * The user ID associated with testing account 1. + */ + public String userID1 = null; + + /** + * An osgi service reference for the protocol provider corresponding to our + * second testing account. + */ + public ServiceReference provider2ServiceRef = null; + + /** + * The protocol provider corresponding to our first testing account. + */ + public ProtocolProviderService provider2 = null; + + /** + * The user ID associated with testing account 2. + */ + public String userID2 = null; + + + /** + * The tested protocol provider factory. + */ + public ProtocolProviderFactory providerFactory = null; + + /** + * A reference to the bundle containing the tested pp implementation. This + * reference is set during the accoung uninstallation testing and used during + * the account uninstallation persistence testing. + */ + public static Bundle providerBundle = null; + + /** + * Indicates whether the user has requested for onlline tests not to be run. + * (e.g. due to lack of network connectivity or ... time constraints ;)). + */ + public static boolean onlineTestingDisabled = false; + + /** + * A Hashtable containing group names mapped against array lists of buddy + * screen names. This is a snapshot of the server stored buddy list for + * the account that is going to be used by the tested implementation. + * It is filled in by the tester agent who'd login with that account + * and initialise the ss contact list before the tested implementation has + * actually done so. + */ + public static Hashtable preInstalledBuddyList = null; + + + /** + * Initializes protocol provider references and whatever else there is to + * initialize. + * + * @throws java.lang.Exception in case we meet problems while retriving + * protocol providers through OSGI + */ + public void setUp() + throws Exception + { + // first obtain a reference to the provider factory + ServiceReference[] serRefs = null; + String osgiFilter = "(" + ProtocolProviderFactory.PROTOCOL + + "="+ProtocolNames.YAHOO+")"; + try{ + serRefs = bc.getServiceReferences( + ProtocolProviderFactory.class.getName(), osgiFilter); + } + catch (InvalidSyntaxException ex){ + //this really shouldhn't occur as the filter expression is static. + fail(osgiFilter + " is not a valid osgi filter"); + } + + assertTrue( + "Failed to find a provider factory service for protocol yahoo", + serRefs != null || serRefs.length > 0); + + //Keep the reference for later usage. + providerFactory = (ProtocolProviderFactory)bc.getService(serRefs[0]); + + userID1 = + System.getProperty( + YahooProtocolProviderServiceLick.ACCOUNT_1_PREFIX + + ProtocolProviderFactory.USER_ID); + + userID2 = + System.getProperty( + YahooProtocolProviderServiceLick.ACCOUNT_2_PREFIX + + ProtocolProviderFactory.USER_ID); + + //find the protocol providers exported for the two accounts + ServiceReference[] yahooProvider1Refs + = bc.getServiceReferences( + ProtocolProviderService.class.getName(), + "(&" + +"("+ProtocolProviderFactory.PROTOCOL+"="+ProtocolNames.YAHOO+")" + +"("+ProtocolProviderFactory.USER_ID+"=" + + userID1 +")" + +")"); + + //make sure we found a service + assertNotNull("No Protocol Provider was found for yahoo account1:" + + userID1 + , yahooProvider1Refs); + assertTrue("No Protocol Provider was found for yahoo account1:"+ userID1, + yahooProvider1Refs.length > 0); + + ServiceReference[] yahooProvider2Refs + = bc.getServiceReferences( + ProtocolProviderService.class.getName(), + "(&" + +"("+ProtocolProviderFactory.PROTOCOL+"="+ProtocolNames.YAHOO+")" + +"("+ProtocolProviderFactory.USER_ID+"=" + + userID2 +")" + +")"); + + //again make sure we found a service. + assertNotNull("No Protocol Provider was found for yahoo account2:" + + userID2 + , yahooProvider2Refs); + assertTrue("No Protocol Provider was found for yahoo account2:"+ userID2, + yahooProvider2Refs.length > 0); + + //save the service for other tests to use. + provider1ServiceRef = yahooProvider1Refs[0]; + provider1 = (ProtocolProviderService)bc.getService(provider1ServiceRef); + provider2ServiceRef = yahooProvider2Refs[0]; + provider2 = (ProtocolProviderService)bc.getService(provider2ServiceRef); + } + + /** + * Un get service references used in here. + */ + public void tearDown() + { + bc.ungetService(provider1ServiceRef); + bc.ungetService(provider2ServiceRef); + } + + /** + * Returns the bundle that has registered the protocol provider service + * implementation that we're currently testing. The method would go through + * all bundles currently installed in the framework and return the first + * one that exports the same protocol provider instance as the one we test + * in this slick. + * @param provider the provider whose bundle we're looking for. + * @return the Bundle that has registered the protocol provider service + * we're testing in the slick. + */ + public static Bundle findProtocolProviderBundle( + ProtocolProviderService provider) + { + Bundle[] bundles = bc.getBundles(); + + for (int i = 0; i < bundles.length; i++) + { + ServiceReference[] registeredServices + = bundles[i].getRegisteredServices(); + + if (registeredServices == null) + continue; + + for (int j = 0; j < registeredServices.length; j++) + { + Object service + = bc.getService(registeredServices[j]); + if (service == provider) + return bundles[i]; + } + } + + return null; + } + + public void clearProvidersLists() + throws Exception + { + Map supportedOperationSets1 = provider1.getSupportedOperationSets(); + + if ( supportedOperationSets1 == null + || supportedOperationSets1.size() < 1) + throw new NullPointerException( + "No OperationSet implementations are supported by " + +"this yahoo implementation. "); + + //get the operation set presence here. + OperationSetPersistentPresence opSetPersPresence1 = + (OperationSetPersistentPresence)supportedOperationSets1.get( + OperationSetPersistentPresence.class.getName()); + + //if still null then the implementation doesn't offer a presence + //operation set which is unacceptable for yahoo. + if (opSetPersPresence1 == null) + throw new NullPointerException( + "An implementation of the yahoo service must provide an " + + "implementation of at least the one of the Presence " + + "Operation Sets"); + + // lets do it once again for the second provider + Map supportedOperationSets2 = provider2.getSupportedOperationSets(); + + if (supportedOperationSets2 == null + || supportedOperationSets2.size() < 1) + throw new NullPointerException( + "No OperationSet implementations are supported by " + + "this yahoo implementation. "); + + //get the operation set presence here. + OperationSetPersistentPresence opSetPersPresence2 = + (OperationSetPersistentPresence) supportedOperationSets2.get( + OperationSetPersistentPresence.class.getName()); + + //if still null then the implementation doesn't offer a presence + //operation set which is unacceptable for yahoo. + if (opSetPersPresence2 == null) + throw new NullPointerException( + "An implementation of the yahoo service must provide an " + + "implementation of at least the one of the Presence " + + "Operation Sets"); + + ContactGroup rootGroup1 = opSetPersPresence1.getServerStoredContactListRoot(); + + // first delete the groups + Vector groupsToRemove = new Vector(); + Iterator iter = rootGroup1.subgroups(); + while (iter.hasNext()) + { + groupsToRemove.add(iter.next()); + } + + iter = groupsToRemove.iterator(); + while (iter.hasNext()) + { + ContactGroup item = (ContactGroup) iter.next(); + opSetPersPresence1.removeServerStoredContactGroup(item); + } + + ContactGroup rootGroup2 = opSetPersPresence2.getServerStoredContactListRoot(); + + // delete groups + groupsToRemove = new Vector(); + iter = rootGroup2.subgroups(); + while (iter.hasNext()) + { + groupsToRemove.add(iter.next()); + } + + iter = groupsToRemove.iterator(); + while (iter.hasNext()) + { + ContactGroup item = (ContactGroup) iter.next(); + opSetPersPresence2.removeServerStoredContactGroup(item); + } + + } +} diff --git a/test/net/java/sip/communicator/slick/protocol/yahoo/yahoo.provider.slick.manifest.mf b/test/net/java/sip/communicator/slick/protocol/yahoo/yahoo.provider.slick.manifest.mf new file mode 100644 index 0000000..f8a0a77 --- /dev/null +++ b/test/net/java/sip/communicator/slick/protocol/yahoo/yahoo.provider.slick.manifest.mf @@ -0,0 +1,15 @@ +Bundle-Activator: net.java.sip.communicator.slick.protocol.yahoo.YahooProtocolProviderServiceLick +Bundle-Name: Yahoo Protocol Provider Service Leveraging Implementation Compatibility Kit +Bundle-Description: A Service Leveraging Implementation Compatibility Kit for the Yahoo implementation of the ProtocolProvider Service +Bundle-Vendor: sip-communicator.org +Bundle-Version: 0.0.1 +Import-Package: net.java.sip.communicator.service.configuration, + net.java.sip.communicator.service.configuration.event, + junit.framework, + org.osgi.framework, + javax.net.ssl, + javax.xml.parsers, + net.java.sip.communicator.util, + net.java.sip.communicator.service.protocol, + net.java.sip.communicator.service.protocol.yahooconstants, + net.java.sip.communicator.service.protocol.event |