aboutsummaryrefslogtreecommitdiffstats
path: root/test/net/java
diff options
context:
space:
mode:
authorDamian Minkov <damencho@jitsi.org>2007-01-12 17:56:58 +0000
committerDamian Minkov <damencho@jitsi.org>2007-01-12 17:56:58 +0000
commit7c6ccbd03b54d59913b45202f06bf053fe730f61 (patch)
tree5c1fd10f7382d1b43f2c67029ec0cdbafd260172 /test/net/java
parent44d48d13eebcb30fbfedd84424c04820aabebba7 (diff)
downloadjitsi-7c6ccbd03b54d59913b45202f06bf053fe730f61.zip
jitsi-7c6ccbd03b54d59913b45202f06bf053fe730f61.tar.gz
jitsi-7c6ccbd03b54d59913b45202f06bf053fe730f61.tar.bz2
Yahoo Protocol Provider Implementation
Diffstat (limited to 'test/net/java')
-rw-r--r--test/net/java/sip/communicator/slick/protocol/yahoo/TestAccountInstallation.java217
-rw-r--r--test/net/java/sip/communicator/slick/protocol/yahoo/TestAccountUninstallation.java270
-rw-r--r--test/net/java/sip/communicator/slick/protocol/yahoo/TestAccountUninstallationPersistence.java100
-rw-r--r--test/net/java/sip/communicator/slick/protocol/yahoo/TestOperationSetBasicInstantMessaging.java510
-rw-r--r--test/net/java/sip/communicator/slick/protocol/yahoo/TestOperationSetPersistentPresence.java559
-rw-r--r--test/net/java/sip/communicator/slick/protocol/yahoo/TestOperationSetPresence.java989
-rw-r--r--test/net/java/sip/communicator/slick/protocol/yahoo/TestOperationSetTypingNotifications.java293
-rw-r--r--test/net/java/sip/communicator/slick/protocol/yahoo/TestProtocolProviderServiceYahooImpl.java285
-rw-r--r--test/net/java/sip/communicator/slick/protocol/yahoo/YahooProtocolProviderServiceLick.java106
-rw-r--r--test/net/java/sip/communicator/slick/protocol/yahoo/YahooSlickFixture.java295
-rw-r--r--test/net/java/sip/communicator/slick/protocol/yahoo/yahoo.provider.slick.manifest.mf15
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