@Test
  public void testSimpleRouting() throws Exception {
    final CountDownLatch latch = new CountDownLatch(2);
    final MailImpl mail = new MailImpl();
    mail.setName(MailImpl.getId());
    mail.setSender(new MailAddress("test@localhost"));
    mail.setRecipients(
        Arrays.asList(new MailAddress("test@localhost"), new MailAddress("test2@localhost")));

    AbstractStateMailetProcessor processor =
        createProcessor(createConfig(MockMatcher.class, MockMailet.class, 1));
    processor.addListener(
        new MailetProcessorListener() {

          @Override
          public void afterMatcher(
              Matcher m,
              String mailName,
              Collection<MailAddress> recipients,
              Collection<MailAddress> matches,
              long processTime,
              MessagingException e) {
            if (MockMatcher.class.equals(m.getClass())) {
              assertEquals(mail.getName(), mailName);
              // match one recipient
              assertEquals(1, matches.size());
              assertNull(e);
              latch.countDown();
            }
          }

          @Override
          public void afterMailet(
              Mailet m, String mailName, String state, long processTime, MessagingException e) {
            // check for class name as the terminating  mailet will kick in too

            if (MockMailet.class.equals(m.getClass())) {
              // assertEquals(mail.getName(), mailName);
              assertEquals("test", state);
              assertNull(e);
              latch.countDown();
            }
          }
        });

    assertEquals(Mail.DEFAULT, mail.getState());
    processor.service(mail);

    // the source mail should be ghosted as it reached the end of processor as only one recipient
    // matched
    assertEquals(Mail.GHOST, mail.getState());
    latch.await();
    processor.destroy();
  }
  @Test
  public void testMatcherThrowException() throws Exception {
    final CountDownLatch latch = new CountDownLatch(1);
    final MailImpl mail = new MailImpl();
    mail.setName(MailImpl.getId());
    mail.setSender(new MailAddress("test@localhost"));
    mail.setRecipients(
        Arrays.asList(new MailAddress("test@localhost"), new MailAddress("test2@localhost")));

    AbstractStateMailetProcessor processor =
        createProcessor(createConfig(ExceptionThrowingMatcher.class, MockMailet.class, 0));
    processor.addListener(
        new MailetProcessorListener() {

          @Override
          public void afterMatcher(
              Matcher m,
              String mailName,
              Collection<MailAddress> recipients,
              Collection<MailAddress> matches,
              long processTime,
              MessagingException e) {
            if (ExceptionThrowingMatcher.class.equals(m.getClass())) {
              assertEquals(mail.getName(), mailName);
              // match no recipient because of the error
              assertNull(matches);
              assertNotNull(e);
              latch.countDown();
            }
          }

          @Override
          public void afterMailet(
              Mailet m, String mailName, String state, long processTime, MessagingException e) {
            throw new RuntimeException("Should not call any mailet!");
          }
        });

    assertEquals(Mail.DEFAULT, mail.getState());

    boolean catched = false;
    try {
      processor.service(mail);
    } catch (MessagingException e) {
      catched = true;
    }
    assertTrue(catched);

    // the source mail should have state error as the exception was thrown
    assertEquals(Mail.ERROR, mail.getState());
    latch.await();
    processor.destroy();
  }
  @Test
  public void testMailetThrowException() throws Exception {
    final CountDownLatch latch = new CountDownLatch(2);
    final MailImpl mail = new MailImpl();
    mail.setName(MailImpl.getId());
    mail.setSender(new MailAddress("test@localhost"));
    mail.setRecipients(
        Arrays.asList(new MailAddress("test@localhost"), new MailAddress("test2@localhost")));

    AbstractStateMailetProcessor processor =
        createProcessor(createConfig(MockMatcher.class, ExceptionThrowingMailet.class, 1));
    processor.addListener(
        new MailetProcessorListener() {

          @Override
          public void afterMatcher(
              Matcher m,
              String mailName,
              Collection<MailAddress> recipients,
              Collection<MailAddress> matches,
              long processTime,
              MessagingException e) {
            if (MockMatcher.class.equals(m.getClass())) {
              assertEquals(mail.getName(), mailName);
              // match one recipient
              assertEquals(1, matches.size());
              assertNull(e);
              latch.countDown();
            }
          }

          @Override
          public void afterMailet(
              Mailet m, String mailName, String state, long processTime, MessagingException e) {
            if (ExceptionThrowingMailet.class.equals(m.getClass())) {
              // the name should be not the same as we have a part match
              assertFalse(mail.getName().equals(mailName));
              assertNotNull(e);
              assertEquals(Mail.ERROR, state);
              latch.countDown();
            }
          }
        });

    assertEquals(Mail.DEFAULT, mail.getState());

    boolean catched = false;
    try {
      processor.service(mail);
    } catch (MessagingException e) {
      catched = true;
    }
    assertTrue(catched);

    latch.await();
    processor.destroy();
  }
 /**
  * Reads a mail message from the given mail node.
  *
  * @param node mail node
  * @return mail message
  * @throws MessagingException if a messaging error occurs
  * @throws RepositoryException if a repository error occurs
  * @throws IOException if an IO error occurs
  */
 private Mail getMail(Node node) throws MessagingException, RepositoryException, IOException {
   String name = Text.unescapeIllegalJcrChars(node.getName());
   MailImpl mail = new MailImpl(name, getSender(node), getRecipients(node), getMessage(node));
   mail.setState(getState(node));
   mail.setLastUpdated(getLastUpdated(node));
   mail.setErrorMessage(getError(node));
   mail.setRemoteHost(getRemoteHost(node));
   mail.setRemoteAddr(getRemoteAddr(node));
   getAttributes(node, mail);
   return mail;
 }