/**
   * 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);

    try {
      // remove the group
      opSetPersPresence1.removeServerStoredContactGroup(
          opSetPersPresence1.getServerStoredContactListRoot().getGroup(testGroupName2));
    } catch (OperationFailedException ex) {
      logger.error("error removing group", ex);
    }

    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.",
        testGroupName2,
        ((ServerStoredGroupEvent) groupChangeCollector.collectedEvents.get(0))
            .getSourceGroup()
            .getGroupName());

    // check whether the group is still on the contact list
    ContactGroup group =
        opSetPersPresence1.getServerStoredContactListRoot().getGroup(testGroupName2);

    assertNull("A freshly removed group was still on the contact list.", group);
  }
  /** {@inheritDoc} */
  @Override
  protected void setUp() throws Exception {
    Logger root = Logger.getRootLogger();

    for (Enumeration appenders = root.getAllAppenders(); appenders.hasMoreElements(); ) {
      if (appenders.nextElement() instanceof GridLog4jRollingFileAppender) return;
    }

    appender = createAppender();

    root.addAppender(appender);
  }
  /**
   * 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());
  }
 protected void checkLeaf(SimulatedArchivalUnit sau) {
   log.debug("checkLeaf()");
   String parent = sau.getUrlRoot() + "/branch1";
   CachedUrlSetSpec spec = new RangeCachedUrlSetSpec(parent);
   CachedUrlSet set = sau.makeCachedUrlSet(spec);
   Iterator setIt = set.contentHashIterator();
   ArrayList childL = new ArrayList(16);
   while (setIt.hasNext()) {
     childL.add(((CachedUrlSetNode) setIt.next()).getUrl());
   }
   String[] expectedA =
       new String[] {
         parent,
         parent + "/001file.html",
         parent + "/001file.txt",
         parent + "/002file.html",
         parent + "/002file.txt",
         parent + "/branch1",
         parent + "/branch1/001file.html",
         parent + "/branch1/001file.txt",
         parent + "/branch1/002file.html",
         parent + "/branch1/002file.txt",
         parent + "/branch1/index.html",
         parent + "/branch2",
         parent + "/branch2/001file.html",
         parent + "/branch2/001file.txt",
         parent + "/branch2/002file.html",
         parent + "/branch2/002file.txt",
         parent + "/branch2/index.html",
         parent + "/index.html",
       };
   assertIsomorphic(expectedA, childL);
 }
  protected void checkRoot(SimulatedArchivalUnit sau) {
    log.debug("checkRoot()");
    CachedUrlSet set = sau.getAuCachedUrlSet();
    Iterator setIt = set.flatSetIterator();
    ArrayList childL = new ArrayList(1);
    CachedUrlSet cus = null;
    while (setIt.hasNext()) {
      cus = (CachedUrlSet) setIt.next();
      childL.add(cus.getUrl());
    }

    String urlRoot = sau.getUrlRoot();

    String[] expectedA = new String[1];
    expectedA[0] = urlRoot;
    assertIsomorphic(expectedA, childL);

    setIt = cus.flatSetIterator();
    childL = new ArrayList(7);
    while (setIt.hasNext()) {
      childL.add(((CachedUrlSetNode) setIt.next()).getUrl());
    }

    expectedA =
        new String[] {
          urlRoot + "/001file.html",
          urlRoot + "/001file.txt",
          urlRoot + "/002file.html",
          urlRoot + "/002file.txt",
          urlRoot + "/branch1",
          urlRoot + "/branch2",
          urlRoot + "/index.html"
        };
    assertIsomorphic(expectedA, childL);
  }
 /**
  * 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.sleep(5000);
   } catch (InterruptedException ex) {
     logger.debug("Pausing between state changes was interrupted", ex);
   }
 }
/** @author Symphorien Wanko */
public class PopupMessageHandlerSLick extends TestSuite implements BundleActivator {
  /** Logger for this class */
  private static Logger logger = Logger.getLogger(PopupMessageHandlerSLick.class);

  /** our bundle context */
  protected static BundleContext bundleContext = null;

  /** implements BundleActivator.start() */
  public void start(BundleContext bc) throws Exception {
    logger.info("starting popup message test ");

    bundleContext = bc;

    setName("PopupMessageHandlerSLick");

    Hashtable<String, String> properties = new Hashtable<String, String>();

    properties.put("service.pid", getName());

    // we maybe are running on machine without WM and systray
    // (test server machine), skip tests
    if (ServiceUtils.getService(bc, SystrayService.class) != null) {
      addTest(TestPopupMessageHandler.suite());
    }

    bundleContext.registerService(getClass().getName(), this, properties);
  }

  /** implements BundleActivator.stop() */
  public void stop(BundleContext bc) throws Exception {}
}
 protected void checkContent(SimulatedArchivalUnit sau) throws IOException {
   log.debug("checkContent()");
   checkRoot(sau);
   checkLeaf(sau);
   checkStoredContent(sau);
   checkDepth(sau);
 }
  /**
   * 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.ICQ_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()) {
      fixture.testerAgent.sendMessage(tokenizer.nextToken(), message);
    }
  }
  /** {@inheritDoc} */
  @Override
  public void tearDown() {
    if (appender != null) {
      Logger.getRootLogger().removeAppender(GridLog4jRollingFileAppender.class.getSimpleName());

      GridLog4jLogger.removeAppender(appender);
    }
  }
 public void waitForUnsubscribre(long waitFor) {
   synchronized (this) {
     try {
       wait(waitFor);
     } catch (InterruptedException ex) {
       logger.debug("Interrupted while waiting for a subscription evt", ex);
     }
   }
 }
 protected void checkDepth(SimulatedArchivalUnit sau) {
   log.debug("checkDepth()");
   String URL_ROOT = sau.getUrlRoot();
   assertEquals(0, sau.getLinkDepth(URL_ROOT + "/index.html"));
   assertEquals(0, sau.getLinkDepth(URL_ROOT + "/"));
   assertEquals(1, sau.getLinkDepth(URL_ROOT + "/001file.html"));
   assertEquals(1, sau.getLinkDepth(URL_ROOT + "/branch1/index.html"));
   assertEquals(1, sau.getLinkDepth(URL_ROOT + "/branch1/"));
   assertEquals(2, sau.getLinkDepth(URL_ROOT + "/branch1/001file.html"));
 }
    public AuthorizationRequest createAuthorizationRequest(Contact contact) {
      logger.trace("createAuthorizationRequest " + contact);

      AuthorizationRequest authReq = new AuthorizationRequest();
      authReq.setReason(authorizationRequestReason);

      isAuthorizationRequestSent = true;

      return authReq;
    }
 public void waitForAuthRequest(long waitFor) {
   synchronized (this) {
     if (isAuthorizationRequestReceived) return;
     try {
       wait(waitFor);
     } catch (InterruptedException ex) {
       logger.debug("Interrupted while waiting for a subscription evt", ex);
     }
   }
 }
  protected void hashContent(SimulatedArchivalUnit sau) throws Exception {
    log.debug("hashContent()");
    measureHashSpeed(sau);

    // If any changes are made to the contents or shape of the simulated
    // content tree, these hash values will have to be changed
    checkHashSet(sau, true, false, fromHex("6AB258B4E1FFD9F9B45316B4F54111FF5E5948D2"));
    checkHashSet(sau, true, true, fromHex("6AB258B4E1FFD9F9B45316B4F54111FF5E5948D2"));
    checkHashSet(sau, false, false, fromHex("409893F1A603F4C276632694DB1621B639BD5164"));
    checkHashSet(sau, false, true, fromHex("85E6213C3771BEAC5A4602CAF7982C6C222800D5"));
  }
  protected void createContent(SimulatedArchivalUnit sau) {
    log.debug("createContent()");
    scgen = sau.getContentGenerator();
    scgen.setFileTypes(
        SimulatedContentGenerator.FILE_TYPE_HTML + SimulatedContentGenerator.FILE_TYPE_TXT);
    scgen.setAbnormalFile("1,1", 1);
    scgen.setOddBranchesHaveContent(true);

    sau.deleteContentTree();
    sau.generateContentTree();
    assertTrue(scgen.isContentTree());
  }
  /**
   * 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();

    Object o = new Object();
    synchronized (o) {
      o.wait(3000);
    }

    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);

      synchronized (o) {
        o.wait(1500);
      }
    } catch (Exception ex) {
      fail("error adding entry to group : " + group.getGroupName() + " " + ex.getMessage());
    }
  }
    public AuthorizationResponse processAuthorisationRequest(
        AuthorizationRequest req, Contact sourceContact) {
      logger.debug("Processing in " + this);
      synchronized (this) {
        logger.trace("processAuthorisationRequest " + req + " " + sourceContact);

        isAuthorizationRequestReceived = true;
        authorizationRequestReason = req.getReason();

        notifyAll();

        // will wait as a normal user
        Object lock = new Object();
        synchronized (lock) {
          try {
            lock.wait(2000);
          } catch (Exception ex) {
          }
        }

        return responseToRequest;
      }
    }
  /**
   * Starts Grid instance. Note that if grid is already started, then it will be looked up and
   * returned from this method.
   *
   * @return Started grid.
   */
  private Grid startGrid() {
    Properties props = System.getProperties();

    gridName = props.getProperty(GRIDGAIN_NAME.name());

    if (!props.containsKey(GRIDGAIN_NAME.name()) || G.state(gridName) != GridFactoryState.STARTED) {
      selfStarted = true;

      // Set class loader for the spring.
      ClassLoader curCl = Thread.currentThread().getContextClassLoader();

      // Add no-op logger to remove no-appender warning.
      Appender app = new NullAppender();

      Logger.getRootLogger().addAppender(app);

      try {
        Thread.currentThread().setContextClassLoader(getClass().getClassLoader());

        Grid grid = G.start(cfgPath);

        gridName = grid.name();

        System.setProperty(GRIDGAIN_NAME.name(), grid.name());

        return grid;
      } catch (GridException e) {
        throw new GridRuntimeException("Failed to start grid: " + cfgPath, e);
      } finally {
        Logger.getRootLogger().removeAppender(app);

        Thread.currentThread().setContextClassLoader(curCl);
      }
    }

    return G.grid(gridName);
  }
    public void processAuthorizationResponse(
        AuthorizationResponse response, Contact sourceContact) {
      synchronized (this) {
        isAuthorizationResponseReceived = true;
        this.response = response;
        authorizationResponseString = response.getReason();

        logger.trace(
            "processAuthorizationResponse '"
                + authorizationResponseString
                + "' "
                + response.getResponseCode()
                + " "
                + sourceContact);

        notifyAll();
      }
    }
  /** implements BundleActivator.start() */
  public void start(BundleContext bc) throws Exception {
    logger.info("starting popup message test ");

    bundleContext = bc;

    setName("PopupMessageHandlerSLick");

    Hashtable<String, String> properties = new Hashtable<String, String>();

    properties.put("service.pid", getName());

    // we maybe are running on machine without WM and systray
    // (test server machine), skip tests
    if (ServiceUtils.getService(bc, SystrayService.class) != null) {
      addTest(TestPopupMessageHandler.suite());
    }

    bundleContext.registerService(getClass().getName(), this, properties);
  }
  protected void checkFilter(SimulatedArchivalUnit sau) throws Exception {
    log.debug("checkFilter()");
    CachedUrl cu = sau.makeCachedUrl(sau.getUrlRoot() + "/001file.html");

    enableFilter(sau, true);
    InputStream is = cu.openForHashing();
    String expected = "001file.html This is file 1, depth 0, branch 0. foobar ";
    assertEquals(expected, StringUtil.fromInputStream(is));
    is.close();
    enableFilter(sau, false);
    cu = sau.makeCachedUrl(sau.getUrlRoot() + "/001file.html");
    is = cu.openForHashing();
    expected =
        "<HTML><HEAD><TITLE>001file.html</TITLE></HEAD><BODY>\n"
            + "This is file 1, depth 0, branch 0.<br><!-- comment -->    "
            + "Citation String   foobar<br><script>"
            + "(defun fact (n) (cond ((= n 0) 1) (t (fact (sub1 n)))))</script>\n"
            + "</BODY></HTML>";
    assertEquals(expected, StringUtil.fromInputStream(is));
    is.close();
  }
  /**
   * 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();
  }
  /**
   * 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();

    Object o = new Object();
    synchronized (o) {
      o.wait(3000);
    }

    String contactList =
        System.getProperty(GibberishProtocolProviderServiceLick.CONTACT_LIST_PROPERTY_NAME, null);

    logger.debug(
        "The "
            + GibberishProtocolProviderServiceLick.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 "
              + GibberishProtocolProviderServiceLick.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<String, List<String>> contactListToCreate = new Hashtable<String, List<String>>();

    // 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 Gibberish user id.");
      }

      // check if we've already seen this group and if not - add it
      List<String> uinInThisGroup = contactListToCreate.get(groupName);
      if (uinInThisGroup == null) {
        uinInThisGroup = new ArrayList<String>();
        contactListToCreate.put(groupName, uinInThisGroup);
      }

      uinInThisGroup.add(uin);
    }

    // now init the list
    Enumeration<String> newGroupsEnum = contactListToCreate.keys();

    // go over all groups in the contactsToAdd table
    while (newGroupsEnum.hasMoreElements()) {
      String groupName = newGroupsEnum.nextElement();
      logger.debug("Will add group " + groupName);

      opSetPersPresence1.createServerStoredContactGroup(
          opSetPersPresence1.getServerStoredContactListRoot(), groupName);

      ContactGroup newlyCreatedGroup =
          opSetPersPresence1.getServerStoredContactListRoot().getGroup(groupName);

      Iterator<String> contactsToAddToThisGroup = contactListToCreate.get(groupName).iterator();
      while (contactsToAddToThisGroup.hasNext()) {
        String id = contactsToAddToThisGroup.next();

        logger.debug("Will add buddy " + id);
        opSetPersPresence1.subscribe(newlyCreatedGroup, id);
      }
    }

    // store the created contact list for later reference
    GibberishSlickFixture.preInstalledBuddyList = contactListToCreate;
  }
/**
 * Tests in this class verify whether a precreated contact list is still there and whether it
 * creating contact groups works as expected.
 *
 * @author Emil Ivov
 */
public class TestOperationSetPersistentPresence extends TestCase {
  private static final Logger logger = Logger.getLogger(TestOperationSetPersistentPresence.class);

  private GibberishSlickFixture fixture = new GibberishSlickFixture();
  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;
  }

  @Override
  protected void setUp() throws Exception {
    super.setUp();
    fixture.setUp();

    Map<String, OperationSet> supportedOperationSets1 =
        fixture.provider1.getSupportedOperationSets();

    if (supportedOperationSets1 == null || supportedOperationSets1.size() < 1)
      throw new NullPointerException(
          "No OperationSet implementations are supported by " + "this Gibberish 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 gibberish.
    if (opSetPersPresence1 == null)
      throw new NullPointerException(
          "An implementation of the gibberish 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<String, OperationSet> supportedOperationSets2 =
        fixture.provider2.getSupportedOperationSets();

    if (supportedOperationSets2 == null || supportedOperationSets2.size() < 1)
      throw new NullPointerException(
          "No OperationSet implementations are supported by " + "this Gibberish 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 Gibberish.
    if (opSetPersPresence2 == null)
      throw new NullPointerException(
          "An implementation of the Gibberish service must provide an "
              + "implementation of at least the one of the Presence "
              + "Operation Sets");
  }

  @Override
  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<String, List<String>> expectedContactList =
        GibberishSlickFixture.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<ContactGroup> groups = rootGroup.subgroups();
    while (groups.hasNext()) {
      ContactGroup group = groups.next();

      List<String> expectedContactsInGroup = expectedContactList.get(group.getGroupName());

      // When sending the offline message
      // the sever creates a group NotInContactList,
      // because the buddy we are sending message to is not in
      // the contactlist. So this group must be ignored
      if (!group.getGroupName().equals("NotInContactList")) {
        assertNotNull(
            "Group "
                + group.getGroupName()
                + " was returned by "
                + "the server but was not in the expected contact list.",
            expectedContactsInGroup);

        Iterator<Contact> contactsIter = group.contacts();
        while (contactsIter.hasNext()) {
          String contactID = 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();

    Object o = new Object();
    synchronized (o) {
      o.wait(3000);
    }

    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);

      synchronized (o) {
        o.wait(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);

    try {
      // remove the group
      opSetPersPresence1.removeServerStoredContactGroup(
          opSetPersPresence1.getServerStoredContactListRoot().getGroup(testGroupName2));
    } catch (OperationFailedException ex) {
      logger.error("error removing group", ex);
    }

    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.",
        testGroupName2,
        ((ServerStoredGroupEvent) groupChangeCollector.collectedEvents.get(0))
            .getSourceGroup()
            .getGroupName());

    // check whether the group is still on the contact list
    ContactGroup group =
        opSetPersPresence1.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 =
        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();

    Object o = new Object();
    synchronized (o) {
      o.wait(3000);
    }

    String contactList =
        System.getProperty(GibberishProtocolProviderServiceLick.CONTACT_LIST_PROPERTY_NAME, null);

    logger.debug(
        "The "
            + GibberishProtocolProviderServiceLick.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 "
              + GibberishProtocolProviderServiceLick.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<String, List<String>> contactListToCreate = new Hashtable<String, List<String>>();

    // 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 Gibberish user id.");
      }

      // check if we've already seen this group and if not - add it
      List<String> uinInThisGroup = contactListToCreate.get(groupName);
      if (uinInThisGroup == null) {
        uinInThisGroup = new ArrayList<String>();
        contactListToCreate.put(groupName, uinInThisGroup);
      }

      uinInThisGroup.add(uin);
    }

    // now init the list
    Enumeration<String> newGroupsEnum = contactListToCreate.keys();

    // go over all groups in the contactsToAdd table
    while (newGroupsEnum.hasMoreElements()) {
      String groupName = newGroupsEnum.nextElement();
      logger.debug("Will add group " + groupName);

      opSetPersPresence1.createServerStoredContactGroup(
          opSetPersPresence1.getServerStoredContactListRoot(), groupName);

      ContactGroup newlyCreatedGroup =
          opSetPersPresence1.getServerStoredContactListRoot().getGroup(groupName);

      Iterator<String> contactsToAddToThisGroup = contactListToCreate.get(groupName).iterator();
      while (contactsToAddToThisGroup.hasNext()) {
        String id = contactsToAddToThisGroup.next();

        logger.debug("Will add buddy " + id);
        opSetPersPresence1.subscribe(newlyCreatedGroup, id);
      }
    }

    // store the created contact list for later reference
    GibberishSlickFixture.preInstalledBuddyList = contactListToCreate;
  }

  /**
   * The class would listen for and store received events delivered to
   * <tt>ServerStoredGroupListener</tt>s.
   */
  private class GroupChangeCollector implements ServerStoredGroupListener {
    public ArrayList<EventObject> collectedEvents = new ArrayList<EventObject>();

    /**
     * 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();
      }
    }
  }

  /** The class would listen for and store received subscription modification events. */
  private class SubscriptionEventCollector implements SubscriptionListener {
    public ArrayList<EventObject> collectedEvents = new ArrayList<EventObject>();

    /**
     * Blocks until at least one event is received or until waitFor milliseconds pass (whichever
     * happens first).
     *
     * @param waitFor the number of milliseconds 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();
      }
    }

    /**
     * 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();
      }
    }

    /**
     * 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 contactModified(ContactPropertyChangeEvent evt) {
      synchronized (this) {
        logger.debug("Collected evt(" + collectedEvents.size() + ")= " + evt);
        collectedEvents.add(evt);
        notifyAll();
      }
    }
  }
}
  /**
   * 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<String, List<String>> expectedContactList =
        GibberishSlickFixture.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<ContactGroup> groups = rootGroup.subgroups();
    while (groups.hasNext()) {
      ContactGroup group = groups.next();

      List<String> expectedContactsInGroup = expectedContactList.get(group.getGroupName());

      // When sending the offline message
      // the sever creates a group NotInContactList,
      // because the buddy we are sending message to is not in
      // the contactlist. So this group must be ignored
      if (!group.getGroupName().equals("NotInContactList")) {
        assertNotNull(
            "Group "
                + group.getGroupName()
                + " was returned by "
                + "the server but was not in the expected contact list.",
            expectedContactsInGroup);

        Iterator<Contact> contactsIter = group.contacts();
        while (contactsIter.hasNext()) {
          String contactID = 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());
  }
  /**
   * Makes sure that the instance of the Jabber protocol provider that we're going to use for
   * testing is properly initialized and registered with a Jabber registrar. This MUST be called
   * before any other online testing of the Jabber 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);
    fixture.provider3.addRegistrationStateChangeListener(regEvtCollector3);

    // register our three providers
    fixture.provider1.register(
        new SecurityAuthorityImpl(
            System.getProperty(
                    JabberProtocolProviderServiceLick.ACCOUNT_1_PREFIX
                        + ProtocolProviderFactory.PASSWORD)
                .toCharArray()));
    fixture.provider2.register(
        new SecurityAuthorityImpl(
            System.getProperty(
                    JabberProtocolProviderServiceLick.ACCOUNT_2_PREFIX
                        + ProtocolProviderFactory.PASSWORD)
                .toCharArray()));
    fixture.provider3.register(
        new SecurityAuthorityImpl(
            System.getProperty(
                    JabberProtocolProviderServiceLick.ACCOUNT_3_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);
    regEvtCollector3.waitForEvent(60000);

    // 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));

    // now the same for provider 3
    assertTrue(
        "No events were dispatched during the registration process " + "of provider3.",
        regEvtCollector3.collectedNewStates.size() > 0);

    assertTrue(
        "No registration event notifying of registration was dispatched. "
            + "All events were: "
            + regEvtCollector3.collectedNewStates,
        regEvtCollector3.collectedNewStates.contains(RegistrationState.REGISTERED));

    fixture.provider1.removeRegistrationStateChangeListener(regEvtCollector1);
    fixture.provider2.removeRegistrationStateChangeListener(regEvtCollector2);
    fixture.provider3.removeRegistrationStateChangeListener(regEvtCollector3);
  }
/**
 * Performs testing on protocol provider methods.
 *
 * @todo add more detailed docs once the tests are written.
 * @author Emil Ivov
 * @author Valentin Martinet
 */
public class TestProtocolProviderServiceJabberImpl extends TestCase {
  private static final Logger logger =
      Logger.getLogger(TestProtocolProviderServiceJabberImpl.class);

  private JabberSlickFixture fixture = new JabberSlickFixture();

  /** 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();

  /** An event adapter that would collec registation state change events */
  public RegistrationEventCollector regEvtCollector3 = 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 TestProtocolProviderServiceJabberImpl(String name) {
    super(name);
  }

  /**
   * Initializes the fixture.
   *
   * @throws Exception if super.setUp() throws one.
   */
  @Override
  protected void setUp() throws Exception {
    super.setUp();
    fixture.setUp();
  }

  /**
   * Tears the fixture down.
   *
   * @throws Exception if fixture.tearDown() fails.
   */
  @Override
  protected void tearDown() throws Exception {
    fixture.tearDown();
    super.tearDown();
  }

  /**
   * Makes sure that the instance of the Jabber protocol provider that we're going to use for
   * testing is properly initialized and registered with a Jabber registrar. This MUST be called
   * before any other online testing of the Jabber 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);
    fixture.provider3.addRegistrationStateChangeListener(regEvtCollector3);

    // register our three providers
    fixture.provider1.register(
        new SecurityAuthorityImpl(
            System.getProperty(
                    JabberProtocolProviderServiceLick.ACCOUNT_1_PREFIX
                        + ProtocolProviderFactory.PASSWORD)
                .toCharArray()));
    fixture.provider2.register(
        new SecurityAuthorityImpl(
            System.getProperty(
                    JabberProtocolProviderServiceLick.ACCOUNT_2_PREFIX
                        + ProtocolProviderFactory.PASSWORD)
                .toCharArray()));
    fixture.provider3.register(
        new SecurityAuthorityImpl(
            System.getProperty(
                    JabberProtocolProviderServiceLick.ACCOUNT_3_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);
    regEvtCollector3.waitForEvent(60000);

    // 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));

    // now the same for provider 3
    assertTrue(
        "No events were dispatched during the registration process " + "of provider3.",
        regEvtCollector3.collectedNewStates.size() > 0);

    assertTrue(
        "No registration event notifying of registration was dispatched. "
            + "All events were: "
            + regEvtCollector3.collectedNewStates,
        regEvtCollector3.collectedNewStates.contains(RegistrationState.REGISTERED));

    fixture.provider1.removeRegistrationStateChangeListener(regEvtCollector1);
    fixture.provider2.removeRegistrationStateChangeListener(regEvtCollector2);
    fixture.provider3.removeRegistrationStateChangeListener(regEvtCollector3);
  }

  /**
   * 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<String, OperationSet> 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.
    for (Map.Entry<String, OperationSet> entry : supportedOperationSets.entrySet()) {
      String setName = entry.getKey();
      Object opSet = entry.getValue();

      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<RegistrationState> collectedNewStates = new LinkedList<RegistrationState>();

    /**
     * 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 registration 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);
        }
      }
    }
  }
}
  public static double testCostAndGradientCurrentParameters(Minimizable.ByGradient minable) {
    Matrix parameters = minable.getParameters(minable.getNewMatrix());
    double cost = minable.getCost();
    // the gradient from the minimizable function
    Matrix analyticGradient = minable.getCostGradient(minable.getNewMatrix());
    // the gradient calculate from the slope of the cost
    Matrix empiricalGradient = (Matrix) analyticGradient.cloneMatrix();
    // This setting of epsilon should make the individual elements of
    // the analytical gradient and the empirical gradient equal.  This
    // simplifies the comparison of the individual dimensions of the
    // gradient and thus makes debugging easier.
    double epsilon = 0.1 / analyticGradient.twoNorm();
    double tolerance = epsilon * 5;
    System.out.println("epsilon = " + epsilon + " tolerance=" + tolerance);

    // Check each direction, perturb it, measure new cost,
    // and make sure it agrees with the gradient from minable.getCostGradient()
    for (int i = 0; i < parameters.singleSize(); i++) {
      double param = parameters.singleValue(i);
      parameters.setSingleValue(i, param + epsilon);
      // logger.fine ("Parameters:"); parameters.print();
      minable.setParameters(parameters);
      double epsCost = minable.getCost();
      double slope = (epsCost - cost) / epsilon;
      System.out.println(
          "cost="
              + cost
              + " epsCost="
              + epsCost
              + " slope["
              + i
              + "] = "
              + slope
              + " gradient[]="
              + analyticGradient.singleValue(i));
      assert (!Double.isNaN(slope));
      logger.fine(
          "TestMinimizable checking singleIndex "
              + i
              + ": gradient slope = "
              + analyticGradient.singleValue(i)
              + ", cost+epsilon slope = "
              + slope
              + ": slope difference = "
              + Math.abs(slope - analyticGradient.singleValue(i)));
      // No negative below because the gradient points in the direction
      // of maximizing the function.
      empiricalGradient.setSingleValue(i, slope);
      parameters.setSingleValue(i, param);
    }
    // Normalize the matrices to have the same L2 length
    System.out.println("empiricalGradient.twoNorm = " + empiricalGradient.twoNorm());
    analyticGradient.timesEquals(1.0 / analyticGradient.twoNorm());
    empiricalGradient.timesEquals(1.0 / empiricalGradient.twoNorm());
    // logger.info ("AnalyticGradient:"); analyticGradient.print();
    // logger.info ("EmpiricalGradient:"); empiricalGradient.print();
    // Return the angle between the two vectors, in radians
    double angle = Math.acos(analyticGradient.dotProduct(empiricalGradient));
    logger.info("TestMinimizable angle = " + angle);
    if (Math.abs(angle) > tolerance)
      throw new IllegalStateException("Gradient/Cost mismatch: angle=" + angle);
    if (Double.isNaN(angle)) throw new IllegalStateException("Gradient/Cost error: angle is NaN!");
    return angle;
  }