package org.ei.drishti.scheduler.router;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.motechproject.scheduler.domain.MotechEvent;
import org.motechproject.scheduletracking.api.domain.MilestoneAlert;
import java.util.HashMap;
import java.util.Map;
import static org.ei.drishti.scheduler.router.Matcher.any;
import static org.ei.drishti.scheduler.router.Matcher.eq;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.*;
import static org.mockito.MockitoAnnotations.initMocks;
import static org.motechproject.scheduletracking.api.events.constants.EventDataKeys.*;
public class AlertRouterTest {
@Mock
private Action firstAction;
@Mock
private Action secondAction;
@Mock
private Action thirdAction;
private AlertRouter router;
@Before
public void setUp() throws Exception {
initMocks(this);
router = new AlertRouter();
}
@Test
public void shouldBeAbleToSetACatchAllRoute() {
router.addRoute(any(), any(), any(), firstAction);
assertRouteMatches("someSchedule", "someMilestone", "someWindow", firstAction, new HashMap<String, String>());
assertRouteMatches("someOtherSchedule", "someOtherMilestone", "someOtherWindow", firstAction, new HashMap<String, String>());
}
@Test
public void shouldBeAbleToSetARouteWhichMatchesBasedOnScheduleNameOnly() {
router.addRoute(eq("Schedule X"), any(), any(), firstAction);
assertNoRoutesMatch("someSchedule", "someMilestone", "someWindow");
assertRouteMatches("Schedule X", "someMilestone", "someWindow", firstAction, new HashMap<String, String>());
}
@Test
public void shouldBeAbleToSetARouteWhichMatchesBasedOnMilestoneNameOnly() {
router.addRoute(any(), eq("Milestone X"), any(), firstAction);
assertNoRoutesMatch("someSchedule", "someMilestone", "someWindow");
assertRouteMatches("someOtherSchedule", "Milestone X", "someWindow", firstAction, new HashMap<String, String>());
}
@Test
public void shouldBeAbleToSetARouteWhichMatchesBasedOnWindowNameOnly() {
router.addRoute(any(), any(), eq("Window X"), firstAction);
assertNoRoutesMatch("someSchedule", "someMilestone", "someWindow");
assertRouteMatches("someOtherSchedule", "someOtherMilestone", "Window X", firstAction, new HashMap<String, String>());
}
@Test
public void shouldBeAbleToSetARouteWhichMatchesBasedOnACombinationOfMatchers() {
router.addRoute(eq("Milestone X"), any(), eq("Window X"), firstAction);
assertNoRoutesMatch("someSchedule", "someMilestone", "someWindow");
assertNoRoutesMatch("Milestone X", "someMilestone", "someWindow");
assertNoRoutesMatch("someSchedule", "someMilestone", "Window X");
assertRouteMatches("Milestone X", "someOtherMilestone", "Window X", firstAction, new HashMap<String, String>());
}
@Test
public void shouldBeAbleToSetARouteWithExtraData() {
router.addRoute(eq("Milestone X"), any(), eq("Window X"), firstAction).addExtraData("Unicorns", "AreFun");
assertNoRoutesMatch("someSchedule", "someMilestone", "someWindow");
assertNoRoutesMatch("Milestone X", "someMilestone", "someWindow");
assertNoRoutesMatch("someSchedule", "someMilestone", "Window X");
HashMap<String, String> extraData = new HashMap<>();
extraData.put("Unicorns", "AreFun");
assertRouteMatches("Milestone X", "someOtherMilestone", "Window X", firstAction, extraData);
}
@Test
public void shouldInvokeTheActionOfOnlyTheFirstRouteWhichMatchesInTheOrderInWhichTheyWereAdded() {
router.addRoute(any(), any(), eq("Window X"), firstAction);
router.addRoute(any(), any(), any(), secondAction);
assertRouteMatches("someSchedule", "someMilestone", "Window X", firstAction, new HashMap<String, String>());
verifyZeroInteractions(secondAction);
assertRouteMatches("someSchedule", "someMilestone", "someOtherWindow", secondAction, new HashMap<String, String>());
verifyZeroInteractions(firstAction);
}
@Test
public void shouldNotTryAndLookAtTheBestMatchButJustTheFirstProperMatch() {
router.addRoute(any(), any(), eq("Window X"), firstAction);
router.addRoute(eq("Milestone X"), any(), eq("Window X"), secondAction);
assertRouteMatches("Milestone X", "someMilestone", "Window X", firstAction, new HashMap<String, String>());
verifyZeroInteractions(secondAction);
}
@Test(expected = NoRoutesMatchException.class)
public void shouldFailIfNoRoutesMatch() {
router.handle(event("scheduleName", "milestoneName", "windowName"));
}
private void assertRouteMatches(String schedule, String milestone, String window, Action action, HashMap<String, String> extraData) {
MotechEvent event = handleEvent(schedule, milestone, window);
verify(action, times(1)).invoke(new MilestoneEvent(event), extraData);
}
private void assertNoRoutesMatch(String schedule, String milestone, String window) {
try {
handleEvent(schedule, milestone, window);
fail("Expected no routes to match! It matched a route.");
} catch (NoRoutesMatchException e) {
}
}
private MotechEvent handleEvent(String schedule, String milestone, String window) {
MotechEvent event = event(schedule, milestone, window);
router.handle(event);
return event;
}
private MotechEvent event(String scheduleName, String milestoneName, String windowName) {
MilestoneAlert alert = mock(MilestoneAlert.class);
when(alert.getMilestoneName()).thenReturn(milestoneName);
Map<String, Object> parameters = new HashMap<String, Object>();
parameters.put(SCHEDULE_NAME, scheduleName);
parameters.put(MILESTONE_NAME, alert);
parameters.put(WINDOW_NAME, windowName);
return new MotechEvent("Subject", parameters);
}
}