/*
* Copyright (c) 2011 Lockheed Martin Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.eurekastreams.server.service.email;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import javax.mail.Address;
import javax.mail.Message;
import javax.mail.Message.RecipientType;
import javax.mail.MessagingException;
import javax.mail.internet.InternetAddress;
import org.eurekastreams.commons.actions.context.service.ServiceActionContext;
import org.eurekastreams.commons.actions.service.ServiceAction;
import org.eurekastreams.commons.actions.service.TaskHandlerServiceAction;
import org.eurekastreams.commons.exceptions.ExecutionException;
import org.eurekastreams.commons.server.UserActionRequest;
import org.eurekastreams.commons.server.service.ActionController;
import org.eurekastreams.commons.test.EasyMatcher;
import org.eurekastreams.server.persistence.mappers.DomainMapper;
import org.eurekastreams.server.search.modelview.PersonModelView;
import org.jmock.Expectations;
import org.jmock.States;
import org.jmock.integration.junit4.JUnit4Mockery;
import org.jmock.lib.legacy.ClassImposteriser;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
/**
* Tests MessageProcessor.
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public class MessageProcessorTest
{
/** Test data. */
private static final Long PERSON_ID = 100L;
/** Test data. */
private static final String PERSON_ACCOUNT_ID = "jdoe";
/** Test data. */
private static final String PERSON_OS_ID = "1234567890ABCDEF";
/** Test data. */
private static final String ACTION_NAME = "TheAction";
/** Test data. */
private static final String AT_DOMAIN = "@eurekastreams.org";
/** Test data. */
private static final String SENDER_ADDRESS = "john.doe@eurekastreams.org";
/** Test data. */
private static final String OTHER_ADDRESS = "someone.else@eurekastreams.org";
/** Test data. */
private static final String SYSTEM_ADDRESS = "system@eurekastreams.org";
/** Test data. */
private static final String TOKEN = "ThisIsAToken";
/** Test data. */
private static final String TOKEN_CONTENT = "ThisIsDataInAToken";
/** Test data. */
private static final byte[] KEY = "ThisIsAKey".getBytes();
/** Used for mocking objects. */
private final JUnit4Mockery mockery = new JUnit4Mockery()
{
{
setImposteriser(ClassImposteriser.INSTANCE);
}
};
/** For getting the user's content from the message. */
private final MessageContentExtractor messageContentExtractor = mockery.mock(MessageContentExtractor.class,
"messageContentExtractor");
/** Determines which action to execute. */
private final ActionSelectorFactory actionSelector = mockery.mock(ActionSelectorFactory.class, "actionSelector");
/** Instance of {@link ActionController} used to run actions. */
private final ActionController serviceActionController = mockery.mock(ActionController.class,
"serviceActionController");
/** The context from which this service can load action beans. */
private final BeanFactory beanFactory = mockery.mock(BeanFactory.class, "beanFactory");
/** For decoding the token. */
private final TokenEncoder tokenEncoder = mockery.mock(TokenEncoder.class, "tokenEncoder");
/** Parses the token content. */
private final TokenContentFormatter tokenContentFormatter = mockery.mock(TokenContentFormatter.class,
"tokenContentFormatter");
/** Transaction manager (to allow calling mappers). */
private final PlatformTransactionManager transactionMgr = mockery.mock(PlatformTransactionManager.class,
"transactionMgr");
/** DAO to get a user's person ID given their email address. */
private final DomainMapper<String, Long> personIdByEmailDao = mockery.mock(DomainMapper.class,
"personIdByEmailDao");
/** DAO to get a user's crypto key given their person ID. */
private final DomainMapper<Long, byte[]> userKeyByIdDao = mockery.mock(DomainMapper.class, "userKeyByIdDao");
/** DAO to get a person by ID. */
private final DomainMapper<Long, PersonModelView> personDao = mockery.mock(DomainMapper.class, "personDao");
/** Responds to messages that failed execution with result status. */
private final MessageReplier messageReplier = mockery.mock(MessageReplier.class, "messageReplier");
/** Fixture: message. */
private final Message message = mockery.mock(Message.class);
/** Fixture: taskHandlerServiceAction. */
private final TaskHandlerServiceAction taskHandlerServiceAction = mockery.mock(TaskHandlerServiceAction.class,
"taskHandlerServiceAction");
/** Fixture: serviceAction. */
private final ServiceAction serviceAction = mockery.mock(ServiceAction.class, "serviceAction");
/** Fixture. */
private final PersonModelView person = mockery.mock(PersonModelView.class, "person");
/** Fixture: responseMessages. */
private final List<Message> responseMessages = mockery.mock(List.class, "responseMessages");
/** SUT. */
private MessageProcessor sut;
/**
* Setup before each test.
*/
@Before
public void setUp()
{
sut = new MessageProcessor(messageContentExtractor, actionSelector, serviceActionController, beanFactory,
tokenEncoder, tokenContentFormatter, transactionMgr, personIdByEmailDao, userKeyByIdDao, personDao,
messageReplier, SYSTEM_ADDRESS);
mockery.checking(new Expectations()
{
{
allowing(person).getId();
will(returnValue(PERSON_ID));
allowing(person).getAccountId();
will(returnValue(PERSON_ACCOUNT_ID));
allowing(person).getOpenSocialId();
will(returnValue(PERSON_OS_ID));
}
});
}
/**
* Test.
*
* @throws MessagingException
* Won't.
*/
@Test
public void testGetFromOk() throws MessagingException
{
mockery.checking(new Expectations()
{
{
allowing(message).getFrom();
will(returnValue(new Address[] { new InternetAddress(SENDER_ADDRESS) }));
}
});
assertEquals(SENDER_ADDRESS, sut.getFromAddress(message));
mockery.assertIsSatisfied();
}
/**
* Test.
*
* @throws MessagingException
* Won't.
*/
@Test(expected = Exception.class)
public void testGetFromNone1() throws MessagingException
{
mockery.checking(new Expectations()
{
{
allowing(message).getFrom();
will(returnValue(new Address[0]));
}
});
sut.getFromAddress(message);
mockery.assertIsSatisfied();
}
/**
* Test.
*
* @throws MessagingException
* Won't.
*/
@Test(expected = Exception.class)
public void testGetFromNone2() throws MessagingException
{
mockery.checking(new Expectations()
{
{
allowing(message).getFrom();
will(returnValue(null));
}
});
sut.getFromAddress(message);
mockery.assertIsSatisfied();
}
/**
* Test.
*
* @throws MessagingException
* Won't.
*/
@Test(expected = Exception.class)
public void testGetFromNone3() throws MessagingException
{
mockery.checking(new Expectations()
{
{
allowing(message).getFrom();
will(returnValue(new Address[] { null }));
}
});
sut.getFromAddress(message);
mockery.assertIsSatisfied();
}
/**
* Test.
*
* @throws MessagingException
* Won't.
*/
@Test(expected = Exception.class)
public void testGetFromTooMany() throws MessagingException
{
mockery.checking(new Expectations()
{
{
allowing(message).getFrom();
will(returnValue(new Address[] { new InternetAddress(SENDER_ADDRESS),
new InternetAddress(OTHER_ADDRESS) }));
}
});
sut.getFromAddress(message);
mockery.assertIsSatisfied();
}
/**
* Test.
*
* @throws MessagingException
* Won't.
*/
@Test(expected = Exception.class)
public void testGetTokenNone() throws MessagingException
{
mockery.checking(new Expectations()
{
{
allowing(message).getRecipients(RecipientType.TO);
will(returnValue(null));
}
});
sut.getToken(message);
mockery.assertIsSatisfied();
}
/**
* Test.
*
* @throws MessagingException
* Won't.
*/
@Test
public void testGetTokenNoReply() throws MessagingException
{
mockery.checking(new Expectations()
{
{
allowing(message).getRecipients(RecipientType.TO);
will(returnValue(new Address[] { new InternetAddress(OTHER_ADDRESS),
new InternetAddress(SYSTEM_ADDRESS), new InternetAddress("system+ABC" + AT_DOMAIN) }));
allowing(tokenEncoder).couldBeToken("ABC");
will(returnValue(false));
}
});
String result = sut.getToken(message);
mockery.assertIsSatisfied();
assertNull(result);
}
/**
* Test.
*
* @throws MessagingException
* Won't.
*/
@Test(expected = Exception.class)
public void testGetTokenNotFound() throws MessagingException
{
mockery.checking(new Expectations()
{
{
allowing(message).getRecipients(RecipientType.TO);
will(returnValue(new Address[] { new InternetAddress(OTHER_ADDRESS),
new InternetAddress("system+ABC" + AT_DOMAIN) }));
allowing(tokenEncoder).couldBeToken("ABC");
will(returnValue(false));
}
});
sut.getToken(message);
mockery.assertIsSatisfied();
}
/**
* Test.
*
* @throws MessagingException
* Won't.
*/
@Test
public void testGetTokenOk() throws MessagingException
{
mockery.checking(new Expectations()
{
{
allowing(message).getRecipients(RecipientType.TO);
will(returnValue(new Address[] { new InternetAddress(OTHER_ADDRESS),
new InternetAddress(SYSTEM_ADDRESS), new InternetAddress("system+ABC" + AT_DOMAIN),
new InternetAddress("system+XYZ" + AT_DOMAIN), new InternetAddress(SENDER_ADDRESS) }));
allowing(tokenEncoder).couldBeToken("ABC");
will(returnValue(false));
allowing(tokenEncoder).couldBeToken("XYZ");
will(returnValue(true));
}
});
assertEquals("XYZ", sut.getToken(message));
mockery.assertIsSatisfied();
}
/**
* Test.
*/
@Test
public void testExecuteActionSuccessBasic()
{
final UserActionRequest sel = new UserActionRequest(ACTION_NAME, null, "");
mockery.checking(new Expectations()
{
{
allowing(beanFactory).getBean(ACTION_NAME);
will(returnValue(serviceAction));
oneOf(serviceActionController).execute(with(new EasyMatcher<ServiceActionContext>()
{
@Override
protected boolean isMatch(final ServiceActionContext inTestObject)
{
return ACTION_NAME.equals(inTestObject.getActionId()) && "".equals(inTestObject.getParams());
}
}), with(same(serviceAction)));
}
});
sut.executeAction(message, sel, person, responseMessages);
mockery.assertIsSatisfied();
}
/**
* Test.
*/
@Test(expected = ExecutionException.class)
public void testExecuteActionErrorBasic()
{
final UserActionRequest sel = new UserActionRequest(ACTION_NAME, null, "");
final ExecutionException exception = new ExecutionException();
mockery.checking(new Expectations()
{
{
allowing(beanFactory).getBean(ACTION_NAME);
will(returnValue(serviceAction));
oneOf(serviceActionController).execute(with(new EasyMatcher<ServiceActionContext>()
{
@Override
protected boolean isMatch(final ServiceActionContext inTestObject)
{
return ACTION_NAME.equals(inTestObject.getActionId()) && "".equals(inTestObject.getParams());
}
}), with(same(serviceAction)));
will(throwException(exception));
oneOf(messageReplier).reply(message, person, sel, exception, responseMessages);
}
});
sut.executeAction(message, sel, person, responseMessages);
mockery.assertIsSatisfied();
}
/**
* Test.
*/
@Test
public void testExecuteActionSuccessTaskHandler()
{
final UserActionRequest sel = new UserActionRequest(ACTION_NAME, null, "");
mockery.checking(new Expectations()
{
{
allowing(beanFactory).getBean(ACTION_NAME);
will(returnValue(taskHandlerServiceAction));
oneOf(serviceActionController).execute(with(new EasyMatcher<ServiceActionContext>()
{
@Override
protected boolean isMatch(final ServiceActionContext inTestObject)
{
return ACTION_NAME.equals(inTestObject.getActionId()) && "".equals(inTestObject.getParams());
}
}), with(same(taskHandlerServiceAction)));
}
});
sut.executeAction(message, sel, person, responseMessages);
mockery.assertIsSatisfied();
}
/**
* Test.
*/
@Test(expected = ExecutionException.class)
public void testExecuteActionErrorTaskHandler()
{
final UserActionRequest sel = new UserActionRequest(ACTION_NAME, null, "");
final ExecutionException exception = new ExecutionException();
mockery.checking(new Expectations()
{
{
allowing(beanFactory).getBean(ACTION_NAME);
will(returnValue(taskHandlerServiceAction));
oneOf(serviceActionController).execute(with(new EasyMatcher<ServiceActionContext>()
{
@Override
protected boolean isMatch(final ServiceActionContext inTestObject)
{
return ACTION_NAME.equals(inTestObject.getActionId()) && "".equals(inTestObject.getParams());
}
}), with(same(taskHandlerServiceAction)));
will(throwException(exception));
oneOf(messageReplier).reply(message, person, sel, exception, responseMessages);
}
});
sut.executeAction(message, sel, person, responseMessages);
mockery.assertIsSatisfied();
}
/**
* Test.
*/
@Test(expected = ExecutionException.class)
public void testExecuteActionBadBean()
{
final UserActionRequest sel = new UserActionRequest(ACTION_NAME, null, "");
mockery.checking(new Expectations()
{
{
allowing(beanFactory).getBean(ACTION_NAME);
will(returnValue(""));
oneOf(messageReplier).reply(with(equal(message)), with(equal(person)), with(equal(sel)),
with(any(ExecutionException.class)), with(same(responseMessages)));
}
});
sut.executeAction(message, sel, person, responseMessages);
mockery.assertIsSatisfied();
}
/**
* Test.
*/
@Test
public void testGetTokenData()
{
final Map data = mockery.mock(Map.class);
mockery.checking(new Expectations()
{
{
oneOf(tokenEncoder).decode(TOKEN, KEY);
will(returnValue(TOKEN_CONTENT));
oneOf(tokenContentFormatter).parse(TOKEN_CONTENT);
will(returnValue(data));
}
});
assertSame(data, sut.getTokenData(TOKEN, KEY));
mockery.assertIsSatisfied();
}
/**
* Test.
*/
@Test(expected = Exception.class)
public void testGetTokenDataErrorDecrypt()
{
mockery.checking(new Expectations()
{
{
oneOf(tokenEncoder).decode(TOKEN, KEY);
will(returnValue(null));
}
});
sut.getTokenData(TOKEN, KEY);
mockery.assertIsSatisfied();
}
/**
* Test.
*/
@Test(expected = Exception.class)
public void testGetTokenDataErrorParse()
{
mockery.checking(new Expectations()
{
{
oneOf(tokenEncoder).decode(TOKEN, KEY);
will(returnValue(TOKEN_CONTENT));
oneOf(tokenContentFormatter).parse(TOKEN_CONTENT);
will(returnValue(null));
}
});
sut.getTokenData(TOKEN, KEY);
mockery.assertIsSatisfied();
}
/**
* Test.
*
* @throws MessagingException
* Won't.
* @throws IOException
* Won't.
*/
@Test
public void testExecute() throws MessagingException, IOException
{
final Map data = mockery.mock(Map.class);
final TransactionStatus transaction = mockery.mock(TransactionStatus.class);
final States state = mockery.states("trans").startsAs("none");
final String content = "This is the content";
final Serializable params = mockery.mock(Serializable.class, "params");
final UserActionRequest selection = new UserActionRequest(ACTION_NAME, null, params);
mockery.checking(new Expectations()
{
{
allowing(message).getFrom();
will(returnValue(new Address[] { new InternetAddress(SENDER_ADDRESS) }));
allowing(message).getRecipients(RecipientType.TO);
will(returnValue(new Address[] { new InternetAddress("system+" + TOKEN + AT_DOMAIN) }));
allowing(tokenEncoder).couldBeToken(TOKEN);
will(returnValue(true));
oneOf(transactionMgr).getTransaction(with(any(TransactionDefinition.class)));
when(state.is("none"));
will(returnValue(transaction));
then(state.is("in"));
allowing(personIdByEmailDao).execute(SENDER_ADDRESS);
when(state.is("in"));
will(returnValue(PERSON_ID));
allowing(userKeyByIdDao).execute(PERSON_ID);
when(state.is("in"));
will(returnValue(KEY));
allowing(personDao).execute(PERSON_ID);
when(state.is("in"));
will(returnValue(person));
oneOf(transactionMgr).commit(transaction);
when(state.is("in"));
then(state.is("none"));
oneOf(tokenEncoder).decode(TOKEN, KEY);
will(returnValue(TOKEN_CONTENT));
oneOf(tokenContentFormatter).parse(TOKEN_CONTENT);
will(returnValue(data));
allowing(messageContentExtractor).extract(message);
will(returnValue(content));
oneOf(actionSelector).select(data, content, person);
will(returnValue(selection));
allowing(beanFactory).getBean(ACTION_NAME);
will(returnValue(serviceAction));
oneOf(serviceActionController).execute(with(new EasyMatcher<ServiceActionContext>()
{
@Override
protected boolean isMatch(final ServiceActionContext inTestObject)
{
return ACTION_NAME.equals(inTestObject.getActionId()) && params == inTestObject.getParams();
}
}), with(same(serviceAction)));
}
});
boolean result = sut.execute(message, responseMessages);
mockery.assertIsSatisfied();
assertTrue(result);
}
/**
* Test.
*
* @throws MessagingException
* Won't.
* @throws IOException
* Won't.
*/
@Test
public void testExecuteDiscard() throws MessagingException, IOException
{
mockery.checking(new Expectations()
{
{
allowing(message).getFrom();
will(returnValue(new Address[] { new InternetAddress(SENDER_ADDRESS) }));
allowing(message).getRecipients(RecipientType.TO);
will(returnValue(new Address[] { new InternetAddress(SYSTEM_ADDRESS) }));
}
});
assertFalse(sut.execute(message, responseMessages));
mockery.assertIsSatisfied();
}
}