/*
* 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.action.execution.notification;
import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eurekastreams.commons.actions.context.ActionContext;
import org.eurekastreams.commons.actions.context.TaskHandlerActionContext;
import org.eurekastreams.commons.server.UserActionRequest;
import org.eurekastreams.commons.test.EasyMatcher;
import org.eurekastreams.server.action.execution.notification.filter.RecipientFilter;
import org.eurekastreams.server.action.execution.notification.notifier.Notifier;
import org.eurekastreams.server.action.execution.notification.translator.NotificationTranslator;
import org.eurekastreams.server.action.request.notification.CreateNotificationsRequest;
import org.eurekastreams.server.action.request.notification.CreateNotificationsRequest.RequestType;
import org.eurekastreams.server.domain.NotificationFilterPreferenceDTO;
import org.eurekastreams.server.domain.NotificationType;
import org.eurekastreams.server.domain.Property;
import org.eurekastreams.server.persistence.mappers.DomainMapper;
import org.eurekastreams.server.persistence.mappers.requests.notification.GetNotificationFilterPreferenceRequest;
import org.eurekastreams.server.search.modelview.PersonModelView;
import org.eurekastreams.server.testing.TestContextCreator;
import org.eurekastreams.server.testing.TestHelper;
import org.jmock.Expectations;
import org.jmock.integration.junit4.JUnit4Mockery;
import org.jmock.lib.legacy.ClassImposteriser;
import org.junit.Before;
import org.junit.Test;
/**
* Tests CreateNotificationsExecution.
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public class CreateNotificationsExecutionTest
{
/** Used for mocking objects. */
private final JUnit4Mockery context = new JUnit4Mockery()
{
{
setImposteriser(ClassImposteriser.INSTANCE);
}
};
/** Fixture: translator. */
private final NotificationTranslator translator = context.mock(NotificationTranslator.class, "translator");
/** Map of valid translators. */
private final Map<RequestType, NotificationTranslator> translators = Collections.singletonMap(RequestType.COMMENT,
translator);
/** Fixture: notifier. */
private final Notifier notifier = context.mock(Notifier.class, "notifier");
/** List of notifiers that should be executed. */
private final Map<String, Notifier> notifiers = Collections.singletonMap("EMAIL", notifier);
/** Mapper to filter out unwanted notifications per recipient. */
private final DomainMapper<GetNotificationFilterPreferenceRequest, List<NotificationFilterPreferenceDTO>> // \n
preferencesMapper = context.mock(DomainMapper.class, "preferencesMapper");
/** Mapper to get people for filtering (determining locked users, etc.). */
private final DomainMapper<List<Long>, List<PersonModelView>> personsMapper = context.mock(DomainMapper.class,
"personsMapper");
/** Provides the category for each notification type. */
private final Map<NotificationType, String> notificationTypeToCategory = Collections.singletonMap(
NotificationType.LIKE_ACTIVITY, "LIKE");
/** Fixture: recipient filter. */
private final RecipientFilter recipientFilter = context.mock(RecipientFilter.class, "recipientFilter");
/** Recipient-based filter strategies per notifier type. */
private final Map<String, Collection<RecipientFilter>> recipientFilters = // \n
new HashMap<String, Collection<RecipientFilter>>();
/** Fixture: bulk filter. */
private final RecipientFilter bulkFilter = context.mock(RecipientFilter.class, "bulkFilter");
/** Recipient-independent filter strategies per notifier type. */
private final Map<String, Collection<RecipientFilter>> bulkFilters = // \n
new HashMap<String, Collection<RecipientFilter>>();
/** Mappers for loading notification properties. */
private final Map<Class, DomainMapper<Serializable, Object>> propertyLoadMappers = context.mock(Map.class,
"propertyLoadMappers");
/** Properties provided to all notifications. */
private final Map<String, Property<Object>> defaultProperties = new HashMap<String, Property<Object>>();
/** Fixture: person. */
private final PersonModelView person1 = context.mock(PersonModelView.class, "person1");
/** Fixture: person. */
private final PersonModelView person2 = context.mock(PersonModelView.class, "person2");
/** Fixture: person. */
private final PersonModelView person3 = context.mock(PersonModelView.class, "person3");
/** Fixture: asyncRequest. */
private final Serializable asyncRequest = context.mock(Serializable.class, "asyncRequest");
/** SUT. */
private CreateNotificationsExecution sut;
/**
* Setup before each test.
*/
@Before
public void setUp()
{
bulkFilters.clear();
recipientFilters.clear();
sut = new CreateNotificationsExecution(translators, notifiers, preferencesMapper, personsMapper,
notificationTypeToCategory, bulkFilters, recipientFilters, defaultProperties, propertyLoadMappers);
context.checking(new Expectations()
{
{
allowing(person1).getId();
will(returnValue(1L));
allowing(person2).getId();
will(returnValue(2L));
allowing(person3).getId();
will(returnValue(3L));
}
});
}
/**
* Tests execute.
*/
@Test
public void testExecuteNoTranslator()
{
TaskHandlerActionContext<ActionContext> ac = TestContextCreator
.createTaskHandlerAsyncContext(new CreateNotificationsRequest(RequestType.LIKE, 0));
sut.execute(ac);
context.assertIsSatisfied();
assertTrue(ac.getUserActionRequests().isEmpty());
}
/**
* Tests execute.
*/
@Test
public void testExecuteNoBatch()
{
final CreateNotificationsRequest request = new CreateNotificationsRequest(RequestType.COMMENT, 0);
context.checking(new Expectations()
{
{
oneOf(translator).translate(request);
will(returnValue(null));
}
});
TaskHandlerActionContext<ActionContext> ac = TestContextCreator.createTaskHandlerAsyncContext(request);
sut.execute(ac);
context.assertIsSatisfied();
assertTrue(ac.getUserActionRequests().isEmpty());
}
/**
* Tests execute.
*/
@Test
public void testExecuteBatchNoRecipients()
{
final CreateNotificationsRequest request = new CreateNotificationsRequest(RequestType.COMMENT, 0);
context.checking(new Expectations()
{
{
oneOf(translator).translate(request);
will(returnValue(new NotificationBatch()));
}
});
TaskHandlerActionContext<ActionContext> ac = TestContextCreator.createTaskHandlerAsyncContext(request);
sut.execute(ac);
context.assertIsSatisfied();
assertTrue(ac.getUserActionRequests().isEmpty());
}
/**
* Tests execute.
*/
@Test
public void testExecuteBulkFilterReject()
{
bulkFilters.put("EMAIL", Collections.singletonList(bulkFilter));
final CreateNotificationsRequest request = new CreateNotificationsRequest(RequestType.COMMENT, 0);
context.checking(new Expectations()
{
{
oneOf(translator).translate(request);
will(returnValue(new NotificationBatch(NotificationType.PASS_THROUGH, 1L)));
allowing(personsMapper).execute(Collections.singletonList(1L));
will(returnValue(Collections.singletonList(person1)));
oneOf(bulkFilter).shouldFilter(with(equal(NotificationType.PASS_THROUGH)),
(PersonModelView) with(equal(null)), with(any(Map.class)), with(equal("EMAIL")));
will(returnValue(true));
}
});
TaskHandlerActionContext<ActionContext> ac = TestContextCreator.createTaskHandlerAsyncContext(request);
sut.execute(ac);
context.assertIsSatisfied();
assertTrue(ac.getUserActionRequests().isEmpty());
}
/**
* Tests execute.
*
* @throws Exception
* Won't.
*/
@Test
public void testExecuteShortCircuit1() throws Exception
{
final List<Long> recips = Collections.singletonList(1L);
final CreateNotificationsRequest request = new CreateNotificationsRequest(RequestType.COMMENT, 0);
context.checking(new Expectations()
{
{
oneOf(translator).translate(request);
will(returnValue(new NotificationBatch(NotificationType.PASS_THROUGH, 1L)));
allowing(personsMapper).execute(recips);
will(returnValue(Collections.singletonList(person1)));
oneOf(notifier).notify(with(equal(NotificationType.PASS_THROUGH)), with(equal(recips)),
with(any(Map.class)), with(any(Map.class)));
will(returnValue(null));
}
});
TaskHandlerActionContext<ActionContext> ac = TestContextCreator.createTaskHandlerAsyncContext(request);
sut.execute(ac);
context.assertIsSatisfied();
assertTrue(ac.getUserActionRequests().isEmpty());
}
/**
* Tests execute.
*
* @throws Exception
* Won't.
*/
@Test
public void testExecuteShortCircuit2() throws Exception
{
recipientFilters.put("EMAIL", Collections.EMPTY_LIST);
final List<Long> recips = Arrays.asList(1L, 2L, 3L);
final CreateNotificationsRequest request = new CreateNotificationsRequest(RequestType.COMMENT, 0);
context.checking(new Expectations()
{
{
oneOf(translator).translate(request);
will(returnValue(new NotificationBatch(NotificationType.LIKE_ACTIVITY, recips)));
allowing(personsMapper).execute(recips);
will(returnValue(Arrays.asList(person1, person2, person3)));
oneOf(notifier).notify(with(equal(NotificationType.LIKE_ACTIVITY)), with(equal(recips)),
with(any(Map.class)), with(any(Map.class)));
will(returnValue(Collections.EMPTY_LIST));
}
});
expectPrefsMapper(recips, "LIKE");
TaskHandlerActionContext<ActionContext> ac = TestContextCreator.createTaskHandlerAsyncContext(request);
sut.execute(ac);
context.assertIsSatisfied();
assertTrue(ac.getUserActionRequests().isEmpty());
}
/**
* Tests execute.
*
* @throws Exception
* Won't.
*/
@Test
public void testExecuteSomeFiltering() throws Exception
{
recipientFilters.put("EMAIL", Collections.singletonList(recipientFilter));
final List<Long> recips = Arrays.asList(1L, 2L, 3L);
final CreateNotificationsRequest request = new CreateNotificationsRequest(RequestType.COMMENT, 0);
context.checking(new Expectations()
{
{
oneOf(translator).translate(request);
will(returnValue(new NotificationBatch(NotificationType.LIKE_ACTIVITY, recips)));
allowing(personsMapper).execute(recips);
will(returnValue(Arrays.asList(person1, person2, person3)));
allowing(recipientFilter).shouldFilter(with(equal(NotificationType.LIKE_ACTIVITY)),
with(same(person2)), with(any(Map.class)), with(equal("EMAIL")));
will(returnValue(true));
allowing(recipientFilter).shouldFilter(with(equal(NotificationType.LIKE_ACTIVITY)),
with(same(person3)), with(any(Map.class)), with(equal("EMAIL")));
will(returnValue(false));
oneOf(notifier).notify(with(equal(NotificationType.LIKE_ACTIVITY)),
with(equal(Collections.singletonList(3L))), with(any(Map.class)), with(any(Map.class)));
will(returnValue(Collections.singletonList(new UserActionRequest("async", null, asyncRequest))));
}
});
expectPrefsMapper(recips, "LIKE", new NotificationFilterPreferenceDTO(1L, "EMAIL", "LIKE"));
TaskHandlerActionContext<ActionContext> ac = TestContextCreator.createTaskHandlerAsyncContext(request);
sut.execute(ac);
context.assertIsSatisfied();
assertEquals(1, ac.getUserActionRequests().size());
assertEquals("async", ac.getUserActionRequests().get(0).getActionKey());
}
/**
* Tests execute.
*
* @throws Exception
* Won't.
*/
@Test
public void testExecutePrefFilterAll() throws Exception
{
recipientFilters.put("EMAIL", Collections.singletonList(recipientFilter));
final List<Long> recips = Arrays.asList(1L, 2L);
final CreateNotificationsRequest request = new CreateNotificationsRequest(RequestType.COMMENT, 0);
context.checking(new Expectations()
{
{
oneOf(translator).translate(request);
will(returnValue(new NotificationBatch(NotificationType.LIKE_ACTIVITY, recips)));
allowing(personsMapper).execute(recips);
will(returnValue(Arrays.asList(person1, person2)));
}
});
expectPrefsMapper(recips, "LIKE", new NotificationFilterPreferenceDTO(1L, "EMAIL", "LIKE"),
new NotificationFilterPreferenceDTO(2L, "EMAIL", "LIKE"));
TaskHandlerActionContext<ActionContext> ac = TestContextCreator.createTaskHandlerAsyncContext(request);
sut.execute(ac);
context.assertIsSatisfied();
assertTrue(ac.getUserActionRequests().isEmpty());
}
/**
* Tests execute.
*
* @throws Exception
* Won't.
*/
@Test
public void testExecuteCoverageNotifierException() throws Exception
{
final List<Long> recips = Collections.singletonList(1L);
final CreateNotificationsRequest request = new CreateNotificationsRequest(RequestType.COMMENT, 0);
context.checking(new Expectations()
{
{
oneOf(translator).translate(request);
will(returnValue(new NotificationBatch(NotificationType.PASS_THROUGH, 1L)));
allowing(personsMapper).execute(recips);
will(returnValue(Collections.singletonList(person1)));
oneOf(notifier).notify(with(equal(NotificationType.PASS_THROUGH)), with(equal(recips)),
with(any(Map.class)), with(any(Map.class)));
will(throwException(new Exception("BAD")));
}
});
TaskHandlerActionContext<ActionContext> ac = TestContextCreator.createTaskHandlerAsyncContext(request);
sut.execute(ac);
context.assertIsSatisfied();
assertTrue(ac.getUserActionRequests().isEmpty());
}
/* ------------ helper functions ------------ */
/**
* Prepares the expectation for invocation of the preferences mapper.
*
* @param recips
* Expected Recipients.
* @param category
* Expected category.
* @param results
* Returned prefs.
*/
private void expectPrefsMapper(final List<Long> recips, final String category,
final NotificationFilterPreferenceDTO... results)
{
context.checking(new Expectations()
{
{
allowing(preferencesMapper).execute(with(new EasyMatcher<GetNotificationFilterPreferenceRequest>()
{
@Override
protected boolean isMatch(final GetNotificationFilterPreferenceRequest inTestObject)
{
return TestHelper.containsExactly(inTestObject.getPersonIds(), recips)
&& inTestObject.getCategories().size() == 1
&& category.equals(inTestObject.getCategories().iterator().next());
}
}));
will(returnValue(Arrays.asList(results)));
}
});
}
}