Test classes for icq implementations of the protocol provider service

cusax-fix
Emil Ivov 20 years ago
parent 21c68d779c
commit 921e04910e

@ -0,0 +1,203 @@
package net.java.sip.communicator.slick.protocol.icq;
import junit.framework.*;
import org.osgi.framework.*;
import net.java.sip.communicator.util.*;
import java.util.*;
import java.text.*;
/**
* @author Emil Ivov
*/
public class IcqProtocolProviderSlick
extends TestSuite
implements BundleActivator
{
private Logger logger = Logger.getLogger(getClass().getName());
/**
* The name of the system property that contains the id of the account
* that will be used when signing the icq protocol provider on icq.
*/
public static final String TESTED_IMPL_ACCOUNT_ID_PROP_NAME =
"accounts.icq.TESTED_IMPL_ACCOUNT_ID";
/**
* The name of the system property that contains the password for the
* account that will be used when signing the icq protocol provider on icq.
*/
public static final String TESTED_IMPL_PWD_PROP_NAME =
"accounts.icq.TESTED_IMPL_PWD";
/**
* The name of the system property that contains the id of the account
* that will be used by the SLICK itself when signing on icq
*/
public static final String TESTING_IMPL_ACCOUNT_ID_PROP_NAME =
"accounts.icq.TESTING_IMPL_ACCOUNT_ID";
/**
* The name of the system property that contains the password for the
* account that will be used when signing the icq protocol provider on icq.
*/
public static final String TESTING_IMPL_PWD_PROP_NAME =
"accounts.icq.TESTING_IMPL_PWD";
/**
* 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.icq.CONTACT_LIST";
/**
* Start the Configuration Sevice Implementation Compatibility Kit.
*
* @param bundleContext BundleContext
* @throws Exception
*/
public void start(BundleContext bundleContext) throws Exception
{
setName("IcqProtocolProviderSlick");
Hashtable properties = new Hashtable();
properties.put("service.pid", getName());
//store the bundle cache reference for usage by other others
IcqSlickFixture.bc = bundleContext;
//register our testing agent on icq.
IcqSlickFixture.testerAgent =
new IcqTesterAgent(System.getProperty(
TESTING_IMPL_ACCOUNT_ID_PROP_NAME, null));
if (!IcqSlickFixture.testerAgent.register(System.getProperty(
TESTING_IMPL_PWD_PROP_NAME, null)))
throw new Exception(
"Registering the IcqTesterAgent on icq has failed.(Possible "
+"reasons: authetification failed, or Connection rate limit "
+"exceeded.)");
//initialize the tested account's contact list so that it could be ready
//when testing starts.
initializeTestedContactList();
//First test account installation so that the service that has been
//installed by it gets tested by the rest of the tests.
addTestSuite(TestAccountInstallation.class);
//This must remain second as that's where the protocol would be made
//to login/authenticate/signon its service provider.
addTest(TestProtocolProviderServiceIcqImpl.suite());
addTest(TestOperationSetPresence.suite());
addTest(TestOperationSetPersistentPresence.suite());
addTestSuite(TestOperationSetBasicInstantMessaging.class);
//This must remain last since it tests account uninstallation and
//the accounts we use for testing won't be available after that.
addTestSuite(TestAccountUninstallation.class);
bundleContext.registerService(getClass().getName(), this, properties);
logger.debug("Successfully registered " + getClass().getName());
}
/**
* Signs the testerAgent off the icq servers
*
* @param bundleContext a valid OSGI bundle context.
* @throws Exception in case anything goes wrong
*/
public void stop(BundleContext bundleContext) throws Exception
{
IcqSlickFixture.testerAgent.unregister();
uninstallTestIcqAccount();
}
/**
* Uninstalls the test icq account used IcqProtocolProvider tests
*/
private void uninstallTestIcqAccount()
{
//sign the corresponding protocol provider off icq
//uninstall the account
}
/**
* The method would make a tester agent sign on icq, ERASE the contact list
* of the account that is being used, fill it in with dummy data (stored
* in the CONTACT_LIST property) that we will later fetch from the tested
* implementation, and sign out.
*/
private void initializeTestedContactList()
{
String contactList = System.getProperty(CONTACT_LIST_PROPERTY_NAME, null);
logger.debug("The " + 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 " + 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 ICQ 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);
}
//Create a tester agent that would connect with the tested impl account
//and initialize the contact list according to what we just parsed.
IcqTesterAgent cListInitTesterAgent = new IcqTesterAgent(
System.getProperty(TESTED_IMPL_ACCOUNT_ID_PROP_NAME, null)
);
cListInitTesterAgent.register(
System.getProperty(TESTED_IMPL_PWD_PROP_NAME, null)
);
cListInitTesterAgent.initializeBuddyList(contactListToCreate);
cListInitTesterAgent.unregister();
//store the created contact list for later reference
IcqSlickFixture.preInstalledBuddyList = contactListToCreate;
}
}

@ -0,0 +1,102 @@
package net.java.sip.communicator.slick.protocol.icq;
import net.java.sip.communicator.service.protocol.*;
import org.osgi.framework.*;
import junit.framework.*;
import java.util.*;
/**
* Provides utility code, such as locating and obtaining references towards
* base services that anyother service would need.
*
* @author Emil Ivov
*/
public class IcqSlickFixture extends TestCase
{
/**
* To be set by the slick itself upon activation.
*/
public static BundleContext bc = null;
/**
* The tested account id obtained during installation.
*/
public static AccountID icqAccountID = null;
/**
* The agent that we use to verify whether the tested implementation is
* being honest with us. The icq tester agent is instantiated and registered
* by the icq slick activator.
*/
static IcqTesterAgent testerAgent = null;
/**
* 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 icq account that is going to be used by the tested implementation.
* It is filled in by the icq 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;
public ServiceReference icqServiceRef = null;
public ProtocolProviderService provider = null;
public AccountManager accManager = null;
public String ourAccountID = null;
public void setUp() throws Exception
{
// first obtain a reference to the account manager
ServiceReference[] serRefs = null;
String osgiFilter = "(" + AccountManager.PROTOCOL_PROPERTY_NAME
+ "="+ProtocolNames.ICQ+")";
try{
serRefs = IcqSlickFixture.bc.getServiceReferences(
AccountManager.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 an account manager service for protocol ICQ",
serRefs != null || serRefs.length > 0);
//Keep the reference for later usage.
accManager = (AccountManager)
IcqSlickFixture.bc.getService(serRefs[0]);
ourAccountID =
System.getProperty(
IcqProtocolProviderSlick.TESTED_IMPL_ACCOUNT_ID_PROP_NAME);
//find the protocol provider service
ServiceReference[] icqProviderRefs
= bc.getServiceReferences(
ProtocolProviderService.class.getName(),
"(&"
+"("+AccountManager.PROTOCOL_PROPERTY_NAME+"="+ProtocolNames.ICQ+")"
+"("+AccountManager.ACCOUNT_ID_PROPERTY_NAME+"="
+ ourAccountID +")"
+")");
//make sure we found a service
assertNotNull("No Protocol Provider was found for ICQ UIN:"+ ourAccountID,
icqProviderRefs);
assertTrue("No Protocol Provider was found for ICQ UIN:"+ ourAccountID,
icqProviderRefs.length > 0);
//save the service for other tests to use.
icqServiceRef = icqProviderRefs[0];
provider = (ProtocolProviderService)bc.getService(icqServiceRef);
}
public void tearDown()
{
bc.ungetService(icqServiceRef);
}
}

@ -0,0 +1,167 @@
/*
* 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.icq;
import junit.framework.*;
import net.java.sip.communicator.service.protocol.*;
import java.util.*;
import org.osgi.framework.*;
/**
* Tests basic account manager functionalitites
* @author Emil Ivov
*/
public class TestAccountInstallation extends TestCase
{
AccountManager icqAccountManager = null;
public TestAccountInstallation(String name)
{
super(name);
}
protected void setUp() throws Exception
{
super.setUp();
}
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 account manager
ServiceReference[] serRefs = null;
String osgiFilter = "(" + AccountManager.PROTOCOL_PROPERTY_NAME
+ "="+ProtocolNames.ICQ+")";
try{
serRefs = IcqSlickFixture.bc.getServiceReferences(
AccountManager.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 an account manager service for protocol ICQ",
serRefs != null || serRefs.length > 0);
//Keep the reference for later usage.
icqAccountManager = (AccountManager)
IcqSlickFixture.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",
icqAccountManager.getRegisteredAcounts().size() == 0);
//Prepare the properties of the icq account.
String passwd = System.getProperty( IcqProtocolProviderSlick
.TESTED_IMPL_PWD_PROP_NAME, null );
String uin = System.getProperty( IcqProtocolProviderSlick
.TESTED_IMPL_ACCOUNT_ID_PROP_NAME, null);
assertNotNull(
"In the " + IcqProtocolProviderSlick.TESTED_IMPL_ACCOUNT_ID_PROP_NAME
+" system property, you need to provide a valid icq UIN for the "
+" slick to use when signing on icq. It's passwd must be set in "
+ IcqProtocolProviderSlick.TESTED_IMPL_PWD_PROP_NAME,
uin);
assertNotNull(
"In the " + IcqProtocolProviderSlick.TESTED_IMPL_PWD_PROP_NAME
+" system property, you need to provide a password for the "
+ uin +" account.",
passwd);
Hashtable icqAccountProperties = new Hashtable();
icqAccountProperties.put(AccountProperties.PASSWORD, passwd);
//try to install an account with a null bundle context
try{
icqAccountManager.installAccount( null, uin, icqAccountProperties);
fail("installing an account with a null BundleContext must result "
+"in a NullPointerException");
}catch(NullPointerException exc){
//that's what had to happen
}
//try to install an account with a null account id
try{
icqAccountManager.installAccount(
IcqSlickFixture.bc, null, icqAccountProperties);
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 account
IcqSlickFixture.icqAccountID = icqAccountManager.installAccount(
IcqSlickFixture.bc, uin, icqAccountProperties);
//try to install the account one more time and verify that an excepion
//is thrown.
try{
IcqSlickFixture.icqAccountID = icqAccountManager.installAccount(
IcqSlickFixture.bc, uin, icqAccountProperties);
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 account manager is aware of our installation
assertTrue(
"The newly installed account was not in the acc man's "
+"registered accounts!",
icqAccountManager.getRegisteredAcounts().size() == 1);
//Verify that the protocol provider corresponding to the new account has
//been properly registered with the osgi framework.
osgiFilter =
"(&("+AccountManager.PROTOCOL_PROPERTY_NAME +"="+ProtocolNames.ICQ+")"
+"(" + AccountManager.ACCOUNT_ID_PROPERTY_NAME
+ "=" + IcqSlickFixture.icqAccountID.getAccountID() + "))";
try
{
serRefs = IcqSlickFixture.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 ICQ protocol provider was apparently not installed as "
+ "requested."
, serRefs != null && serRefs.length > 0);
Object icqProtocolProvider
= IcqSlickFixture.bc.getService(serRefs[0]);
assertTrue("The installed protocol provider does not implement "
+ "the protocol provider service."
,icqProtocolProvider instanceof ProtocolProviderService);
}
}

@ -0,0 +1,90 @@
/*
* 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.icq;
import junit.framework.*;
import net.java.sip.communicator.service.protocol.*;
import org.osgi.framework.*;
/**
* 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.
*
* @author Emil Ivov
*/
public class TestAccountUninstallation
extends TestCase
{
IcqSlickFixture fixture = new IcqSlickFixture();
public TestAccountUninstallation(String name)
{
super(name);
}
protected void setUp() throws Exception
{
super.setUp();
fixture.setUp();
}
protected void tearDown() throws Exception
{
fixture.tearDown();
super.tearDown();
}
/**
* Uinstalls our test account and makes sure it really has been removed.
*/
public void testUninstallAccount()
{
assertFalse("No installed accaounts found",
fixture.accManager.getRegisteredAcounts().isEmpty());
assertNotNull(
"Found no provider corresponding to account ID "
+ fixture.icqAccountID,
fixture.accManager.getProviderForAccount(fixture.icqAccountID));
assertTrue(
"Failed to remove a provider corresponding to acc id "
+ fixture.icqAccountID,
fixture.accManager.uninstallAccount(fixture.icqAccountID));
ServiceReference[] icqProviderRefs = null;
try
{
icqProviderRefs = fixture.bc.getServiceReferences(
ProtocolProviderService.class.getName(),
"(&"
+ "(" + AccountManager.PROTOCOL_PROPERTY_NAME + "=" +ProtocolNames.ICQ + ")"
+ "(" + AccountManager.ACCOUNT_ID_PROPERTY_NAME + "="+ fixture.icqAccountID + ")"
+ ")");
}
catch (InvalidSyntaxException ex)
{
fail("We apparently got our filter wrhong");
}
//make sure we didn't see a service
assertTrue("A Protocol Provider Service was still regged as an osgi service "
+"for ICQ UIN:" + fixture.icqAccountID
+ "After it was explicitly uninstalled"
,icqProviderRefs == null || icqProviderRefs.length == 0);
//verify that the provider knows that we have uninstalled the service.
assertTrue(
"The ICQ account manager kept a reference to the provider we just "
+"uninstalled (accID="+fixture.icqAccountID+")",
fixture.accManager.getRegisteredAcounts().isEmpty()
&& fixture.accManager.getProviderForAccount(fixture.icqAccountID) == null
);
}
}

@ -0,0 +1,51 @@
/*
* 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.icq;
import junit.framework.*;
/**
* @todo describe
* @author Emil Ivov
*/
public class TestOperationSetBasicInstantMessaging
extends TestCase
{
IcqSlickFixture fixture = new IcqSlickFixture();
public TestOperationSetBasicInstantMessaging(String name)
{
super(name);
}
protected void setUp() throws Exception
{
super.setUp();
fixture.setUp();
/** @todo extract corresponding presence set here */
}
protected void tearDown() throws Exception
{
fixture.tearDown();
super.tearDown();
}
public void testSendMessage()
{
/** @todo implement testSendMessage() */
}
public void testReceiveMessage()
{
/**
* @todo implement testReceiveMessage()
*/
}
}

@ -0,0 +1,564 @@
/*
* 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.icq;
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.*;
/**
* @todo describe
*
* @todo testing here would probably be best done if we could first log in
* with one of the agents retrieve the contact list and then check that we
* have the same thing with the other agent
*
* @author Emil Ivov
*/
public class TestOperationSetPersistentPresence
extends TestCase
{
private static final Logger logger =
Logger.getLogger(TestOperationSetPersistentPresence.class);
private IcqSlickFixture fixture = new IcqSlickFixture();
private OperationSetPersistentPresence opSetPersPresence = 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(TestOperationSetPersistentPresence.class);
//the following 2 need to be run in the specified order.
//(postTestRemoveGroup() needs the group created from
//postTestCreateGroup() )
suite.addTest(
new TestOperationSetPersistentPresence("postTestCreateGroup"));
// suite.addTest( new TestOperationSetPersistentPresence(
// "postTestPersistentSubscribe"));
// suite.addTest( new TestOperationSetPersistentPresence(
// "postTestPersistentUnsubscribe"));
//rename
suite.addTest( new TestOperationSetPersistentPresence(
"postTestRenameGroup"));
suite.addTest(
new TestOperationSetPersistentPresence("postTestRemoveGroup"));
return suite;
}
protected void setUp() throws Exception
{
super.setUp();
fixture.setUp();
Map supportedOperationSets =
fixture.provider.getSupportedOperationSets();
if ( supportedOperationSets == null
|| supportedOperationSets.size() < 1)
throw new NullPointerException(
"No OperationSet implementations are supported by "
+"this ICQ implementation. ");
//get the operation set presence here.
opSetPersPresence =
(OperationSetPersistentPresence)supportedOperationSets.get(
OperationSetPersistentPresence.class.getName());
//if still null then the implementation doesn't offer a presence
//operation set which is unacceptable for icq.
if (opSetPersPresence == null)
throw new NullPointerException(
"An implementation of the ICQ 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 icqTesterAgent.
*/
public void testRetrievingServerStoredContactList()
{
ContactGroup rootGroup
= opSetPersPresence.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());
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 IcqTesterAgent 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());
}
/**
* Adds the a contact to a group in our contact list. Verifies that event
* dispatching goes ok. Makes sure that the contact is where it is supposed
* to be.
* <p>
* Note that the method won't be testing presence event notifications since
* these are being tested in TestOperationSetPresence.
*
* @throws java.lang.Exception in case network operations fail.
*/
public void postTestPersistentSubscribe()
throws Exception
{
logger.trace("Testing persistent subscriptions.");
//find the group where we'll be adding the new contact
ContactGroup group = opSetPersPresence.getServerStoredContactListRoot()
.getGroup(testGroupName);
//register a subscription event listener
SubscriptionEventCollector evtCollector
= new SubscriptionEventCollector();
opSetPersPresence.addSubsciptionListener(evtCollector);
//create the subscription and wait for a confirmation event.
opSetPersPresence.subscribe(group, "38687470");
evtCollector.waitForEvent(10000);
opSetPersPresence.removeSubsciptionListener(evtCollector);
//make sure the event delivery went as expected
assertEquals("Number of dispatched events",
1, evtCollector.collectedEvents.size());
assertEquals(
"The SubscriptionEvent had a wrong event id.",
SubscriptionEvent.SUBSCRIPTION_CREATED,
((SubscriptionEvent)evtCollector.collectedEvents.get(0)).getEventID());
assertEquals(
"The parent group in the subscription event did not match.",
group, ((SubscriptionEvent)evtCollector.collectedEvents.get(0))
.getParentGroup());
Contact contact = group.getContact(fixture.testerAgent.getIcqUIN());
//make sure that the contact appears in the new group.
assertNotNull("Couldn't find contact where we created it", contact);
}
/**
* Removes a contact from a group in our contact list. Verifies that event
* dispatching goes ok. Makes sure that the contact is not in the group
* any more.
* <p>
* Note that the method won't be testing presence event notifications since
* these are being tested in TestOperationSetPresence.
*
* @throws java.lang.Exception in case network operations fail.
*/
public void postTestPersistentUnsubscribe()
throws Exception
{
logger.trace("Testing removal of persistent subscriptions.");
//find the group where we'll be adding the new contact
ContactGroup group = opSetPersPresence.getServerStoredContactListRoot()
.getGroup(testGroupName);
Contact contact = group.getContact(fixture.testerAgent.getIcqUIN());
//register a subscription event listener
SubscriptionEventCollector evtCollector
= new SubscriptionEventCollector();
opSetPersPresence.addSubsciptionListener(evtCollector);
//remove the subscription and wait for a confirmation event.
opSetPersPresence.unsubscribe(contact);
evtCollector.waitForEvent(10000);
opSetPersPresence.removeSubsciptionListener(evtCollector);
//make sure the event delivery went as expected
assertEquals("Number of dispatched events",
1, evtCollector.collectedEvents.size());
assertEquals(
"The SubscriptionEvent had a wrong event id.",
SubscriptionEvent.SUBSCRIPTION_REMOVED,
((SubscriptionEvent)evtCollector.collectedEvents.get(0)).getEventID());
assertEquals(
"The parent group in the subscription event did not match.",
group, ((SubscriptionEvent)evtCollector.collectedEvents.get(0))
.getParentGroup());
contact = group.getContact(fixture.testerAgent.getIcqUIN());
//make sure that the contact is not in the group any more.
assertNull("A contact was still present after removing its "
+"corresponding subscription", contact);
}
/**
* 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.
*/
public void postTestCreateGroup()
{
logger.trace("testing creation of server stored groups");
//first add a listener
GroupChangeCollector groupChangeCollector = new GroupChangeCollector();
opSetPersPresence
.addServerStoredGroupChangeListener(groupChangeCollector);
//create the group
opSetPersPresence.createServerStoredContactGroup(
opSetPersPresence.getServerStoredContactListRoot(), testGroupName);
groupChangeCollector.waitForEvent(10000);
opSetPersPresence
.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)).getSrouceGroup().getGroupName());
// check whether the group is retrievable
ContactGroup group = opSetPersPresence.getServerStoredContactListRoot()
.getGroup(testGroupName);
assertNotNull("A newly created group was not in the contact list.",
group);
assertEquals("New group name", testGroupName, group.getGroupName());
}
/**
* 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();
opSetPersPresence
.addServerStoredGroupChangeListener(groupChangeCollector);
//create the group
opSetPersPresence.removeServerStoredContactGroup(
opSetPersPresence.getServerStoredContactListRoot()
.getGroup(testGroupName2));
groupChangeCollector.waitForEvent(10000);
opSetPersPresence
.removeServerStoredGroupChangeListener(groupChangeCollector);
// check whether we got group created event
assertEquals("Collected Group Change event",
1, groupChangeCollector.collectedEvents.size());
assertEquals("Group name.", testGroupName2,
((ServerStoredGroupEvent)groupChangeCollector.collectedEvents
.get(0)).getSrouceGroup().getGroupName());
// check whether the group is still on the contact list
ContactGroup group = opSetPersPresence.getServerStoredContactListRoot()
.getGroup(testGroupName2);
assertNull("A freshly removed group was still on the contact list.",
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 = opSetPersPresence.getServerStoredContactListRoot()
.getGroup(testGroupName);
//first add a listener
GroupChangeCollector groupChangeCollector = new GroupChangeCollector();
opSetPersPresence
.addServerStoredGroupChangeListener(groupChangeCollector);
//change the name and wait for a confirmation event
opSetPersPresence.renameServerStoredContactGroup(group, testGroupName2);
groupChangeCollector.waitForEvent(10000);
opSetPersPresence
.removeServerStoredGroupChangeListener(groupChangeCollector);
//examine the event
assertEquals("Collected Group Change event",
1, groupChangeCollector.collectedEvents.size());
assertEquals("Group name.", testGroupName2,
((ServerStoredGroupEvent)groupChangeCollector.collectedEvents
.get(0)).getSrouceGroup().getGroupName());
// check whether the group is still on the contact list
ContactGroup oldGroup = opSetPersPresence.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 = opSetPersPresence.getServerStoredContactListRoot()
.getGroup(testGroupName2);
assertNotNull("Could not find a renamed group by its new name.",
newGroup);
}
/**
* The class would listen for and store received events delivered to
* <code>ServerStoredGroupListener</code>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();
}
}
}
/**
* 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)
{
logger.trace("Waiting for a persistent subscription event");
synchronized(this){
if(collectedEvents.size() > 0){
logger.trace("SubEvt already received. " + collectedEvents);
return;
}
try{
wait(waitFor);
if(collectedEvents.size() > 0)
logger.trace("Received a SubEvt in provider status.");
else
logger.trace("No SubEvt received for "+waitFor+"ms.");
}
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 subscriptionFailed(SubscriptionEvent evt)
{
synchronized(this)
{
logger.debug("Collected evt("+collectedEvents.size()+")= "+evt);
collectedEvents.add(evt);
notifyAll();
}
}
}
}

@ -0,0 +1,844 @@
/*
* 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.icq;
import junit.framework.*;
import net.java.sip.communicator.service.protocol.*;
import java.util.*;
import net.java.sip.communicator.service.protocol.icqconstants.*;
import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.util.*;
import net.kano.joscar.snaccmd.*;
import java.beans.PropertyChangeEvent;
/**
* Tests ICQ 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 <code>test</code> prefix) we also execute those that
* we want run in a specific order like for example - postTestSubscribe() and
* postTestUnsubscribe().
* <p>
* @author Emil Ivov
*/
public class TestOperationSetPresence
extends TestCase
{
private static final Logger logger =
Logger.getLogger(TestOperationSetPresence.class);
private IcqSlickFixture fixture = new IcqSlickFixture();
private OperationSetPresence operationSetPresence = null;
private String statusMessageRoot = new String("Our status is now: ");
public TestOperationSetPresence(String name)
{
super(name);
}
protected void setUp() throws Exception
{
super.setUp();
fixture.setUp();
Map supportedOperationSets =
fixture.provider.getSupportedOperationSets();
if ( supportedOperationSets == null
|| supportedOperationSets.size() < 1)
throw new NullPointerException(
"No OperationSet implementations are supported by "
+"this ICQ implementation. ");
//get the operation set presence here.
operationSetPresence =
(OperationSetPresence)supportedOperationSets.get(
OperationSetPresence.class.getName());
if (operationSetPresence == null)
{
//if the operation set is still null, it's maybe because the impl
//only registers a persistence operation set. Let's see if that is
//the case.
operationSetPresence =
(OperationSetPersistentPresence) supportedOperationSets.get(
OperationSetPersistentPresence.class.getName());
//if still null then the implementation doesn't offer a presence
//operation set which is unacceptable for icq.
if (operationSetPresence == null)
throw new NullPointerException(
"An implementation of the ICQ service must provide an "
+ "implementation of at least the one of the Presence "
+ "Operation Sets");
}
}
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()
{
TestSuite suite = new TestSuite(TestOperationSetPresence.class);
//the following 2 need to be run in the specified order.
//(postTestUnsubscribe() needs the subscription created from
//postTestSubscribe() )
suite.addTest(new TestOperationSetPresence("postTestSubscribe"));
suite.addTest(new TestOperationSetPresence("postTestUnsubscribe"));
return suite;
}
/**
* Verifies that all necessary ICQ 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 =
operationSetPresence.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)IcqStatusEnum.icqStatusSet.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 AWAY 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 testChangingStateToAway() throws Exception
{
subtestStateTransition(IcqStatusEnum.AWAY);
}
/**
* Verify that changing state to NOT_AVAILABLE 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 testChangingStateToNotAvailable() throws Exception
{
subtestStateTransition(IcqStatusEnum.NOT_AVAILABLE);
}
/**
* Verify that changing state to DND 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 testChangingStateToDnd() throws Exception
{
subtestStateTransition(IcqStatusEnum.DO_NOT_DISTURB);
}
/**
* Verify that changing state to INVISIBLE 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 testChangingStateToInvisible() throws Exception
{
subtestStateTransition(IcqStatusEnum.INVISIBLE);
}
/**
* Verify that changing state to OCCUPIED 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 testChangingStateToOccupied() throws Exception
{
subtestStateTransition(IcqStatusEnum.OCCUPIED);
}
/**
* 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 testChangingStateToFreeForChat() throws Exception
{
subtestStateTransition(IcqStatusEnum.FREE_FOR_CHAT);
}
/**
* 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
{
java.util.logging.Logger.getLogger("net.kano").setLevel(java.util.logging.Level.FINEST);
subtestStateTransition(IcqStatusEnum.ONLINE);
java.util.logging.Logger.getLogger("net.kano").setLevel(java.util.logging.Level.WARNING);
}
/**
* Used by methods testing state transiotions
*
* @param newStatus the IcqStatusEnum 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( IcqStatusEnum newStatus)
throws Exception
{
logger.trace(" --=== beginning state transition test ===--");
PresenceStatus oldStatus = operationSetPresence.getPresenceStatus();
String oldStatusMessage = operationSetPresence.getCurrentStatusMessage();
String newStatusMessage = statusMessageRoot + newStatus;
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();
operationSetPresence.addProviderPresenceStatusListener(
statusEventCollector);
//change the status
operationSetPresence.publishPresenceStatus(newStatus, newStatusMessage);
//test event notification.
statusEventCollector.waitForPresEvent(10000);
statusEventCollector.waitForStatMsgEvent(10000);
operationSetPresence.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,
operationSetPresence.getPresenceStatus());
IcqStatusEnum actualStatus = fixture.testerAgent.getBuddyStatus(
fixture.icqAccountID.getAccountID());
assertEquals("The underlying implementation did not switch to the "
+"requested presence status.",
newStatus,
actualStatus);
//check whether the server returned the status message that we've set.
assertEquals("No status message events.",
1, statusEventCollector.collectedStatMsgEvents.size());
assertEquals("A status message event contained wrong old value.",
oldStatusMessage,
((PropertyChangeEvent)
statusEventCollector.collectedStatMsgEvents.get(0))
.getOldValue());
assertEquals("A status message event contained wrong new value.",
newStatusMessage,
((PropertyChangeEvent)
statusEventCollector.collectedStatMsgEvents.get(0))
.getNewValue());
// verify that the operation set itself is aware of the new status msg.
assertEquals("opSet.getCurrentStatusMessage() did not return properly.",
newStatusMessage,
operationSetPresence.getCurrentStatusMessage());
logger.trace(" --=== finished test ===--");
//make it sleep a bit cause the aol server gets mad otherwise.
pauseBetweenStateChanges();
}
/**
* The AIM server doesn't like it if we change states too often and we
* use this method to slow things down.
*/
private void pauseBetweenStateChanges()
{
try
{
Thread.currentThread().sleep(2000);
}
catch (InterruptedException ex)
{
logger.debug("Pausing between state changes was interrupted", ex);
}
}
/**
* Verifies that querying status works fine. The ICQ 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
{
// --- AWAY ---
logger.debug("Will Query an AWAY contact.");
subtestQueryContactStatus(FullUserInfo.ICQSTATUS_AWAY,
IcqStatusEnum.AWAY);
pauseBetweenStateChanges();
// --- NA ---
logger.debug("Will Query an NA contact.");
subtestQueryContactStatus(FullUserInfo.ICQSTATUS_NA,
IcqStatusEnum.NOT_AVAILABLE);
pauseBetweenStateChanges();
// --- DND ---
logger.debug("Will Query a DND contact.");
subtestQueryContactStatus(FullUserInfo.ICQSTATUS_DND,
IcqStatusEnum.DO_NOT_DISTURB);
pauseBetweenStateChanges();
// --- FFC ---
logger.debug("Will Query a Free For Chat contact.");
subtestQueryContactStatus(FullUserInfo.ICQSTATUS_FFC,
IcqStatusEnum.FREE_FOR_CHAT);
pauseBetweenStateChanges();
// --- INVISIBLE ---
logger.debug("Will Query an Invisible contact.");
subtestQueryContactStatus(FullUserInfo.ICQSTATUS_INVISIBLE,
IcqStatusEnum.INVISIBLE);
pauseBetweenStateChanges();
// --- Occupied ---
logger.debug("Will Query an Occupied contact.");
subtestQueryContactStatus(FullUserInfo.ICQSTATUS_OCCUPIED,
IcqStatusEnum.OCCUPIED);
pauseBetweenStateChanges();
// --- Online ---
logger.debug("Will Query an Online contact.");
subtestQueryContactStatus(IcqTesterAgent.ICQ_ONLINE_MASK,
IcqStatusEnum.ONLINE);
pauseBetweenStateChanges();
}
/**
* Used by functions testing the queryContactStatus method of the
* presence operation set.
* @param taStatusLong the icq status as specified by FullUserInfo, 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(long taStatusLong,
PresenceStatus expectedReturn)
throws Exception
{
if ( !fixture.testerAgent.enterStatus(taStatusLong) ){
throw new RuntimeException(
"Tester UserAgent Failed to switch to the "
+ expectedReturn.getStatusName() + " state.");
}
PresenceStatus actualReturn
= operationSetPresence.queryContactStatus(
fixture.testerAgent.getIcqUIN());
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 IcqTesterAgent) 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.");
// First create a subscription and verify that it really gets created.
SubscriptionEventCollector subEvtCollector
= new SubscriptionEventCollector();
operationSetPresence.addSubsciptionListener(subEvtCollector);
synchronized(subEvtCollector){
operationSetPresence.subscribe(fixture.testerAgent.getIcqUIN());
subEvtCollector.waitForEvent(10000);
//don't want any more events
operationSetPresence.removeSubsciptionListener(subEvtCollector);
}
assertEquals("Subscription event dispatching failed."
, 1, subEvtCollector.collectedEvents.size());
SubscriptionEvent subEvt =
(SubscriptionEvent)subEvtCollector.collectedEvents.get(0);
assertEquals("SubscriptionEvent Source:",
fixture.testerAgent.getIcqUIN(),
((Contact)subEvt.getSource()).getAddress());
assertEquals("SubscriptionEvent Source Contact:",
fixture.testerAgent.getIcqUIN(),
subEvt.getSourceContact().getAddress());
assertSame("SubscriptionEvent Source Provider:",
fixture.provider,
subEvt.getSourceProvider());
subEvtCollector.collectedEvents.clear();
// make the user agent tester change its states and make sure we are
// notified
logger.debug("Testing presence notifications.");
IcqStatusEnum testerAgentOldStatus
= fixture.testerAgent.getPresneceStatus();
IcqStatusEnum testerAgentNewStatus = IcqStatusEnum.FREE_FOR_CHAT;
long testerAgentNewStatusLong = FullUserInfo.ICQSTATUS_FFC;
//in case we are by any chance already in a FREE_FOR_CHAT status, we'll
//be changing to something else
if(testerAgentOldStatus.equals(testerAgentNewStatus)){
testerAgentNewStatus = IcqStatusEnum.DO_NOT_DISTURB;
testerAgentNewStatusLong = FullUserInfo.ICQSTATUS_DND;
}
//now do the actual status notification testing
ContactPresenceEventCollector contactPresEvtCollector
= new ContactPresenceEventCollector(
fixture.testerAgent.getIcqUIN(), testerAgentNewStatus);
operationSetPresence.addContactPresenceStatusListener(
contactPresEvtCollector);
synchronized (contactPresEvtCollector){
if (!fixture.testerAgent.enterStatus(testerAgentNewStatusLong))
{
throw new RuntimeException(
"Tester UserAgent Failed to switch to the "
+ testerAgentNewStatus.getStatusName() + " state.");
}
//we may already have the event, but it won't hurt to check.
contactPresEvtCollector.waitForEvent(10000);
operationSetPresence
.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.testerAgent.getIcqUIN(),
((Contact)presEvt.getSource()).getAddress());
assertEquals("Presence Notif. event Source Contact:",
fixture.testerAgent.getIcqUIN(),
presEvt.getSourceContact().getAddress());
assertSame("Presence Notif. event Source Provider:",
fixture.provider,
presEvt.getSourceProvider());
PresenceStatus reportedNewStatus = presEvt.getNewStatus();
PresenceStatus reportedOldStatus = presEvt.getOldStatus();
assertEquals( "Reported new PresenceStatus: ",
testerAgentNewStatus, 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 );
/** @todo tester agent changes status message we see the new message */
/** @todo we should see the alias of the tester agent. */
}
/**
* We unsubscribe from presence notification deliveries concerning
* IcqTesterAgent'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();
operationSetPresence.addSubsciptionListener(subEvtCollector);
Contact icqTesterAgentContact = operationSetPresence
.findContactByID(fixture.testerAgent.getIcqUIN());
assertNotNull(
"Failed to find an existing subscription for the tester agent"
, icqTesterAgentContact);
synchronized(subEvtCollector){
operationSetPresence.unsubscribe(icqTesterAgentContact);
subEvtCollector.waitForEvent(10000);
//don't want any more events
operationSetPresence.removeSubsciptionListener(subEvtCollector);
}
assertEquals("Subscription event dispatching failed."
, 1, subEvtCollector.collectedEvents.size());
SubscriptionEvent subEvt =
(SubscriptionEvent)subEvtCollector.collectedEvents.get(0);
assertEquals("SubscriptionEvent Source:",
icqTesterAgentContact, subEvt.getSource());
assertEquals("SubscriptionEvent Source Contact:",
icqTesterAgentContact, subEvt.getSourceContact());
assertSame("SubscriptionEvent Source Provider:",
fixture.provider,
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.");
IcqStatusEnum testerAgentOldStatus
= fixture.testerAgent.getPresneceStatus();
IcqStatusEnum testerAgentNewStatus = IcqStatusEnum.FREE_FOR_CHAT;
long testerAgentNewStatusLong = FullUserInfo.ICQSTATUS_FFC;
//in case we are by any chance already in a FREE_FOR_CHAT status, we'll
//be changing to something else
if(testerAgentOldStatus.equals(testerAgentNewStatus)){
testerAgentNewStatus = IcqStatusEnum.DO_NOT_DISTURB;
testerAgentNewStatusLong = FullUserInfo.ICQSTATUS_DND;
}
//now do the actual status notification testing
ContactPresenceEventCollector contactPresEvtCollector
= new ContactPresenceEventCollector(
fixture.testerAgent.getIcqUIN(), null);
operationSetPresence.addContactPresenceStatusListener(
contactPresEvtCollector);
synchronized (contactPresEvtCollector){
if (!fixture.testerAgent.enterStatus(testerAgentNewStatusLong))
{
throw new RuntimeException(
"Tester UserAgent Failed to switch to the "
+ testerAgentNewStatus.getStatusName() + " state.");
}
//we may already have the event, but it won't hurt to check.
contactPresEvtCollector.waitForEvent(10000);
operationSetPresence
.removeContactPresenceStatusListener(contactPresEvtCollector);
}
assertEquals("Presence Notifications were received after unsubscibing."
, 0, contactPresEvtCollector.collectedEvents.size());
}
/**
* 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 subscriptionFailed(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 IcqStatusEnum status = null;
ContactPresenceEventCollector(String screenname,
IcqStatusEnum 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();
}
}
}
}

@ -0,0 +1,267 @@
/*
* 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.icq;
import junit.framework.*;
import net.java.sip.communicator.service.protocol.*;
import java.util.*;
import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.service.protocol.icqconstants.*;
/**
* Test icq/aim specific behaviour for OSCAR (AIM/ICQ) implementations of the
* protocol provider service. The class would basically test that registration
* succeeds, that the provider registration state is updated accordingly and
* that the corrsponding registration change events are generated and dispatched.
*
* In the case of a registration failure we try to remain consistent and do
* assertions accordingly.
*
* It is important to note that it is critical to execute tests in this class
* in a particular order because of protocol limitations (we cannot login and
* logoff to most of the existing protocol services as often as we'd like to).
* This is why we have overridden the suite() method which kind of solves the
* problem but adds the limitation of making extending developers manually add
* the tests they write to the suite method.
*
* @author Emil Ivov
*/
public class TestProtocolProviderServiceIcqImpl extends TestCase
{
private static final Logger logger =
Logger.getLogger(TestProtocolProviderServiceIcqImpl.class);
private IcqSlickFixture fixture = new IcqSlickFixture();
/**
* The lock that we wait on until registration is finalized.
*/
private Object registrationLock = new Object();
/**
* An event adapter that would collec registation state change events
*/
public RegistrationEventCollector regEvtCollector
= new RegistrationEventCollector();
public TestProtocolProviderServiceIcqImpl(String name)
{
super(name);
}
protected void setUp() throws Exception
{
super.setUp();
fixture.setUp();
}
protected void tearDown() throws Exception
{
fixture.tearDown();
super.tearDown();
}
// -------------------------- IMPORTANT ----------------------
/**
* Since we cannot afford to log on and off to the icq service as many
* times as we want we're obliged to do our testing in a predfined order.
* That's why we explicitely difine a suite with the order that suits us ;).
* @return a TestSuite with the tests of this class ordered for execution
* the way we want them to be.
*/
public static Test suite()
{
TestSuite suite = new TestSuite();
suite.addTest(
new TestProtocolProviderServiceIcqImpl("testRegister"));
suite.addTest(
new TestProtocolProviderServiceIcqImpl("testIsRegistered"));
suite.addTest(
new TestProtocolProviderServiceIcqImpl("testGetRegistrationState"));
suite.addTest(
new TestProtocolProviderServiceIcqImpl("testOperationSetTypes"));
return suite;
}
/**
* Makes sure that the instance of the ICQ protocol provider that we're
* going to use for testing is properly initialized and signed on ICQ. This
* method only makes sense if called before any other icq testing.
*
* The method also verifies that a registration event is fired upond
* succesful registration and collected by our event collector.
*/
public void testRegister()
{
//add an event collector that will collect all events during the
//registration and allows us to later inspect them and make sure
//they were properly dispatched.
fixture.provider.addRegistrationStateChangeListener(regEvtCollector);
fixture.provider.register(null);
//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.
try{
synchronized(registrationLock){
logger.debug("Waiting for registration to complete ...");
registrationLock.wait(40000);
logger.debug("Registration was completed or we lost patience.");
}
}
catch (InterruptedException ex){
logger.debug("Interrupted while waiting for registration", ex);
}
catch(Throwable t)
{
logger.debug("We got thrown out while waiting for registration", t);
}
//give time for the AIM server to notify everyone of our arrival
//simply waitinf is really not a reliable way of doing things but I
//can't think of anything better
Object lock = new Object();
synchronized(lock)
{
try
{
logger.debug("Giving the aim server time to notify for our arrival!");
lock.wait(5000);
}
catch (Exception ex)
{}
}
//make sure the provider is on-line
assertTrue(
"The tested ICQ implementation on-line status was OFFLINE",
!IcqStatusEnum.OFFLINE.equals(
fixture.testerAgent.getBuddyStatus(fixture.ourAccountID))
);
//make sure that the registration process trigerred the corresponding
//events.
assertTrue(
"No events were dispatched during the registration process."
,regEvtCollector.collectedNewStates.size() > 0);
assertTrue(
"No registration event notifying of registration was dispatched. "
+"All events were: " + regEvtCollector.collectedNewStates
,regEvtCollector.collectedNewStates
.contains(RegistrationState.REGISTERED));
fixture.provider.removeRegistrationStateChangeListener(regEvtCollector);
}
/**
* Verifies whether the isRegistered method returns whatever it has to.
*/
public void testIsRegistered()
{
if (!IcqStatusEnum.OFFLINE.equals(
fixture.testerAgent.getBuddyStatus(fixture.ourAccountID)))
assertTrue(
"provider.isRegistered() returned false while registered"
,fixture.provider.isRegistered());
else
//in case registration failed - the provider needs to know that.:
assertFalse(
"provider.isRegistered() returned true while unregistered"
,fixture.provider.isRegistered());
}
/**
* Tests that getRegistrationState returns properly after registration
* has completed (or failed)
*/
public void testGetRegistrationState()
{
if (!IcqStatusEnum.OFFLINE.equals(
fixture.testerAgent.getBuddyStatus(fixture.ourAccountID)))
assertEquals(
"a provider was not in a REGISTERED state while registered."
,RegistrationState.REGISTERED
,fixture.provider.getRegistrationState());
else
assertFalse(
"a provider had a REGISTERED reg state while unregistered."
,fixture
.provider.getRegistrationState()
.equals(RegistrationState.REGISTERED));
}
/**
* 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.provider.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 notify the
* registrationLock if it sees an event that notifies us of a completed
* registration.
* @author Emil Ivov
*/
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() on the
* registrationLock.
*
* @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(registrationLock){
logger.debug(".");
registrationLock.notifyAll();
logger.debug(".");
}
}
}
}
}

@ -0,0 +1,13 @@
Bundle-Activator: net.java.sip.communicator.slick.protocol.icq.IcqProtocolProviderSlick
Bundle-Name: ICQ Protocol Provider Service Leveraging Implementation Compatibility Kit
Bundle-Description: A Service Leveraging Implementation Compatibility Kit for the ICQ 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,
net.java.sip.communicator.util,
net.java.sip.communicator.service.protocol,
net.java.sip.communicator.service.protocol.icqconstants,
net.java.sip.communicator.service.protocol.event
Loading…
Cancel
Save