package rocks.inspectit.server.diagnosis.engine.session;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.mockito.Matchers;
import org.mockito.Mock;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import rocks.inspectit.server.diagnosis.engine.rule.ConditionFailure;
import rocks.inspectit.server.diagnosis.engine.rule.RuleDefinition;
import rocks.inspectit.server.diagnosis.engine.rule.RuleInput;
import rocks.inspectit.server.diagnosis.engine.rule.RuleOutput;
import rocks.inspectit.server.diagnosis.engine.rule.exception.RuleDefinitionException;
import rocks.inspectit.server.diagnosis.engine.rule.factory.Rules;
import rocks.inspectit.server.diagnosis.engine.rule.store.IRuleOutputStorage;
import rocks.inspectit.server.diagnosis.engine.session.Session.State;
import rocks.inspectit.server.diagnosis.engine.session.exception.SessionException;
import rocks.inspectit.server.diagnosis.engine.tag.Tag;
import rocks.inspectit.server.diagnosis.engine.tag.Tags;
import rocks.inspectit.server.diagnosis.engine.testrules.RuleA;
import rocks.inspectit.server.diagnosis.engine.testrules.RuleB;
import rocks.inspectit.server.diagnosis.engine.testrules.RuleC;
import rocks.inspectit.server.diagnosis.engine.testrules.RuleD;
import rocks.inspectit.server.diagnosis.engine.testrules.RuleE;
import rocks.inspectit.server.diagnosis.engine.testrules.RuleF;
import rocks.inspectit.server.diagnosis.engine.testrules.RuleG;
import rocks.inspectit.shared.all.testbase.TestBase;
/**
* Tests the {@link Session} class.
*
* @author Claudio Waldvogel, Alexander Wert
*/
@SuppressWarnings("all")
public class SessionTest extends TestBase {
/**
* In this Test class we inject the mocks manually in the init() method as otherwise Mockito
* uses the wrong constructor for mock injection.
*/
Session<String, DefaultSessionResult<String>> session;
@Mock
DefaultSessionResultCollector<String> resultCollector;
@Mock
SessionContext<String> sessionContext;
/**
* Manual injection of mocks.
*
*/
@BeforeMethod
public void init() throws Exception {
session = new Session<>(sessionContext, resultCollector);
}
/**
* Tests the {@link Session#activate(Object, java.util.Map)} method.
*
* @author Alexander Wert
*
*/
public static class Activate extends SessionTest {
Field stateField;
@BeforeMethod
public void initStateField() throws SecurityException, NoSuchFieldException {
stateField = Session.class.getDeclaredField("state");
stateField.setAccessible(true);
}
@DataProvider(name = "failureStates")
public Object[][] dataProviderMethod() {
return new Object[][] { { State.DESTROYED }, { State.FAILURE }, { State.PROCESSED }, { State.ACTIVATED } };
}
@Test
public void fromNew() throws SessionException {
String input = "Input";
session.activate(input, Session.EMPTY_SESSION_VARIABLES);
assertThat(session.getState(), equalTo(Session.State.ACTIVATED));
verify(sessionContext, times(1)).activate(input, Session.EMPTY_SESSION_VARIABLES);
}
@Test
public void fromPassivate() throws SessionException, IllegalArgumentException, IllegalAccessException {
stateField.set(session, State.PASSIVATED);
String input = "Input";
session.activate(input, Session.EMPTY_SESSION_VARIABLES);
assertThat(session.getState(), equalTo(Session.State.ACTIVATED));
verify(sessionContext, times(1)).activate(input, Session.EMPTY_SESSION_VARIABLES);
}
@Test(expectedExceptions = SessionException.class, dataProvider = "failureStates")
public void testWithFailureStates(State state) throws SessionException, IllegalArgumentException, IllegalAccessException {
stateField.set(session, state);
session.activate("Input", Session.EMPTY_SESSION_VARIABLES);
}
}
/**
* Tests the {@link Session#passivate()} method.
*
* @author Alexander Wert
*
*/
public static class Passivate extends SessionTest {
Field stateField;
@BeforeMethod
public void initStateField() throws SecurityException, NoSuchFieldException {
stateField = Session.class.getDeclaredField("state");
stateField.setAccessible(true);
}
@DataProvider(name = "allStates")
public Object[][] dataProviderMethod() {
return new Object[][] { { State.NEW }, { State.PASSIVATED }, { State.DESTROYED }, { State.FAILURE }, { State.PROCESSED }, { State.ACTIVATED } };
}
@Test(dataProvider = "allStates")
public void testFromDifferentStates(State state) throws IllegalArgumentException, IllegalAccessException {
stateField.set(session, state);
session.passivate();
assertThat(session.getState(), equalTo(Session.State.PASSIVATED));
verify(sessionContext, times(1)).passivate();
}
}
/**
* Tests the {@link Session#destroy()} method.
*
* @author Alexander Wert
*
*/
public static class Destroy extends SessionTest {
Field stateField;
@BeforeMethod
public void initStateField() throws SecurityException, NoSuchFieldException {
stateField = Session.class.getDeclaredField("state");
stateField.setAccessible(true);
}
@DataProvider(name = "destroyableStates")
public Object[][] dataProviderMethod() {
return new Object[][] { { State.NEW }, { State.PASSIVATED }, { State.FAILURE }, { State.ACTIVATED } };
}
@Test()
public void fromProcessed() throws IllegalArgumentException, IllegalAccessException {
stateField.set(session, State.PROCESSED);
session.destroy();
assertThat(session.getState(), equalTo(Session.State.DESTROYED));
verify(sessionContext, times(1)).passivate();
}
@Test()
public void fromDestroyed() throws IllegalArgumentException, IllegalAccessException {
stateField.set(session, State.DESTROYED);
session.destroy();
assertThat(session.getState(), equalTo(Session.State.DESTROYED));
verifyNoMoreInteractions(sessionContext);
}
@Test(dataProvider = "destroyableStates")
public void testFromDestroyableStates(State state) throws IllegalArgumentException, IllegalAccessException {
stateField.set(session, state);
session.destroy();
assertThat(session.getState(), equalTo(Session.State.DESTROYED));
}
}
/**
* Test the {@link Session#findNextRules(Set, Set)} method.
*
* @author Alexander Wert
*
*/
public static class FindNextRules extends SessionTest {
@Test
public void allRulesMatch() throws RuleDefinitionException {
Set<RuleDefinition> ruleDefinitions = Rules.define(RuleA.class, RuleB.class, RuleC.class);
Set<String> availableTagTypes = new HashSet<>(Arrays.asList(Tags.ROOT_TAG, "A", "B"));
Collection<RuleDefinition> nextRules = session.findNextRules(availableTagTypes, ruleDefinitions);
assertThat(nextRules, containsInAnyOrder(ruleDefinitions.toArray(new RuleDefinition[0])));
}
@Test
public void onlyRuleBMatch() throws RuleDefinitionException {
RuleDefinition ruleA = Rules.define(RuleA.class);
RuleDefinition ruleB = Rules.define(RuleB.class);
RuleDefinition ruleC = Rules.define(RuleC.class);
Set<RuleDefinition> ruleDefinitions = new HashSet<>(Arrays.asList(ruleA, ruleB, ruleC));
Set<String> availableTagTypes = new HashSet<>(Arrays.asList(new String[] { "A" }));
Collection<RuleDefinition> nextRules = session.findNextRules(availableTagTypes, ruleDefinitions);
assertThat(nextRules, containsInAnyOrder(ruleB));
}
@Test
public void onlyRuleBAndCMatch() throws RuleDefinitionException {
RuleDefinition ruleA = Rules.define(RuleA.class);
RuleDefinition ruleB = Rules.define(RuleB.class);
RuleDefinition ruleC = Rules.define(RuleC.class);
Set<RuleDefinition> ruleDefinitions = new HashSet<>(Arrays.asList(ruleA, ruleB, ruleC));
Set<String> availableTagTypes = new HashSet<>(Arrays.asList(new String[] { "A", "B" }));
Collection<RuleDefinition> nextRules = session.findNextRules(availableTagTypes, ruleDefinitions);
assertThat(nextRules, containsInAnyOrder(ruleB, ruleC));
}
@Test
public void noneMatch() throws RuleDefinitionException {
RuleDefinition ruleA = Rules.define(RuleA.class);
RuleDefinition ruleB = Rules.define(RuleB.class);
RuleDefinition ruleC = Rules.define(RuleC.class);
Set<RuleDefinition> ruleDefinitions = new HashSet<>(Arrays.asList(ruleA, ruleB, ruleC));
Set<String> availableTagTypes = new HashSet<>(Arrays.asList(new String[] { "B" }));
Collection<RuleDefinition> nextRules = session.findNextRules(availableTagTypes, ruleDefinitions);
assertThat(nextRules, empty());
}
}
/**
* Test the {@link Session#collectInputs(RuleDefinition, IRuleOutputStorage)} method.
*
* @author Alexander Wert
*
*/
public static class CollectInputs extends SessionTest {
@Mock
IRuleOutputStorage outputStorage;
@Test
public void singleTagTypeSingleInput() throws RuleDefinitionException, SessionException {
RuleDefinition ruleB = Rules.define(RuleB.class);
Tag rootTag = Tags.rootTag("input");
Tag tagA = Tags.tag("A", "input", rootTag);
RuleOutput outputA = new RuleOutput("RuleA", "A", Collections.<ConditionFailure> emptyList(), Collections.singletonList(tagA));
when(outputStorage.findLatestResultsByTagType(Matchers.<Set<String>> anyObject())).thenReturn(Collections.singleton(outputA));
List<RuleInput> ruleInputs = new ArrayList<>(session.collectInputs(ruleB, outputStorage));
assertThat(ruleInputs, hasSize(1));
assertThat(ruleInputs.get(0).getRoot(), equalTo(tagA));
}
@Test
public void singleTagTypeMultipleInputs() throws RuleDefinitionException, SessionException {
RuleDefinition ruleB = Rules.define(RuleB.class);
Tag rootTag = Tags.rootTag("input");
Tag tagA1 = Tags.tag("A", "A1", rootTag);
Tag tagA2 = Tags.tag("A", "A2", rootTag);
Tag tagA3 = Tags.tag("A", "A3", rootTag);
RuleOutput outputA = new RuleOutput("RuleA", "A", Collections.<ConditionFailure> emptyList(), Arrays.asList(tagA1, tagA2, tagA3));
when(outputStorage.findLatestResultsByTagType(Matchers.<Set<String>> anyObject())).thenReturn(Collections.singleton(outputA));
Collection<RuleInput> ruleInputs = session.collectInputs(ruleB, outputStorage);
assertThat(ruleInputs, hasSize(3));
assertThat(ruleInputs, containsInAnyOrder(new RuleInput(tagA1, Sets.newHashSet(tagA1)), new RuleInput(tagA2, Sets.newHashSet(tagA2)), new RuleInput(tagA3, Sets.newHashSet(tagA3))));
}
@Test
public void multipleTagTypesSingleInput() throws RuleDefinitionException, SessionException {
RuleDefinition ruleC = Rules.define(RuleC.class);
Tag rootTag = Tags.rootTag("input");
Tag tagA = Tags.tag("A", "A1", rootTag);
Tag tagB = Tags.tag("B", "B1", tagA);
RuleOutput outputB = new RuleOutput("RuleB", "B", Collections.<ConditionFailure> emptyList(), Collections.singletonList(tagB));
when(outputStorage.findLatestResultsByTagType(Matchers.<Set<String>> anyObject())).thenReturn(Collections.singleton(outputB));
List<RuleInput> ruleInputs = new ArrayList<>(session.collectInputs(ruleC, outputStorage));
assertThat(ruleInputs, hasSize(1));
assertThat(ruleInputs.get(0).getRoot(), equalTo(tagB));
assertThat(ruleInputs.get(0).getUnraveled(), containsInAnyOrder(tagB, tagA));
}
@Test
public void multipleTagTypesMultipleInputs1() throws RuleDefinitionException, SessionException {
RuleDefinition ruleC = Rules.define(RuleC.class);
Tag rootTag = Tags.rootTag("input");
Tag tagA = Tags.tag("A", "A1", rootTag);
Tag tagB1 = Tags.tag("B", "B1", tagA);
Tag tagB2 = Tags.tag("B", "B2", tagA);
RuleOutput outputB = new RuleOutput("RuleB", "B", Collections.<ConditionFailure> emptyList(), Arrays.asList(tagB1, tagB2));
when(outputStorage.findLatestResultsByTagType(Matchers.<Set<String>> anyObject())).thenReturn(Collections.singleton(outputB));
Collection<RuleInput> ruleInputs = session.collectInputs(ruleC, outputStorage);
assertThat(ruleInputs, hasSize(2));
assertThat(ruleInputs, containsInAnyOrder(new RuleInput(tagB1, Sets.newHashSet(tagA, tagB1)), new RuleInput(tagB2, Sets.newHashSet(tagA, tagB2))));
}
@Test
public void multipleTagTypesMultipleInputs2() throws RuleDefinitionException, SessionException {
RuleDefinition ruleC = Rules.define(RuleC.class);
Tag rootTag = Tags.rootTag("input");
Tag tagA1 = Tags.tag("A", "A1", rootTag);
Tag tagB1 = Tags.tag("B", "B1", tagA1);
Tag tagA2 = Tags.tag("A", "A2", rootTag);
Tag tagB2 = Tags.tag("B", "B2", tagA2);
RuleOutput outputB1 = new RuleOutput("RuleB", "B", Collections.<ConditionFailure> emptyList(), Arrays.asList(tagB1));
RuleOutput outputB2 = new RuleOutput("RuleB", "B", Collections.<ConditionFailure> emptyList(), Arrays.asList(tagB2));
when(outputStorage.findLatestResultsByTagType(Matchers.<Set<String>> anyObject())).thenReturn(Arrays.asList(outputB1, outputB2));
Collection<RuleInput> ruleInputs = session.collectInputs(ruleC, outputStorage);
assertThat(ruleInputs, hasSize(2));
assertThat(ruleInputs, containsInAnyOrder(new RuleInput(tagB1, Sets.newHashSet(tagA1, tagB1)), new RuleInput(tagB2, Sets.newHashSet(tagA2, tagB2))));
}
@Test
public void noMatch1() throws RuleDefinitionException, SessionException {
RuleDefinition ruleC = Rules.define(RuleC.class);
when(outputStorage.findLatestResultsByTagType(Matchers.<Set<String>> anyObject())).thenReturn(Collections.singleton(Rules.triggerRuleOutput("input")));
Collection<RuleInput> ruleInputs = session.collectInputs(ruleC, outputStorage);
assertThat(ruleInputs, empty());
}
@Test
public void noMatch2() throws RuleDefinitionException, SessionException {
RuleDefinition ruleC = Rules.define(RuleC.class);
Tag rootTag = Tags.rootTag("input");
Tag tagA1 = Tags.tag("A", "A1", rootTag);
Tag tagB1 = Tags.tag("B", "B1", rootTag);
RuleOutput outputB1 = new RuleOutput("RuleA", "A", Collections.<ConditionFailure> emptyList(), Arrays.asList(tagB1));
when(outputStorage.findLatestResultsByTagType(Matchers.<Set<String>> anyObject())).thenReturn(Arrays.asList(outputB1));
Collection<RuleInput> ruleInputs = session.collectInputs(ruleC, outputStorage);
assertThat(ruleInputs, empty());
}
}
/**
* Test the {@link Session#filterProcessedInputs(Multimap, RuleDefinition, Collection)} method.
*
* @author Alexander Wert
*
*/
public static class FilterProcessedInputs extends SessionTest {
@Test
public void filterOne() throws RuleDefinitionException, SessionException {
RuleDefinition ruleB = Rules.define(RuleB.class);
RuleInput inputA1 = new RuleInput(Tags.tag("A", "A1"));
RuleInput inputA2 = new RuleInput(Tags.tag("A", "A2"));
RuleInput inputA3 = new RuleInput(Tags.tag("A", "A3"));
RuleInput inputB = new RuleInput(Tags.tag("B", "XY"));
RuleInput inputC = new RuleInput(Tags.tag("C", "XY"));
Collection<RuleInput> inputs = Arrays.asList(inputA1, inputA2, inputA3, inputB, inputC);
Multimap<RuleDefinition, RuleInput> executions = ArrayListMultimap.create();
executions.put(ruleB, inputA1);
inputs = session.filterProcessedInputs(executions, ruleB, inputs);
assertThat(inputs, containsInAnyOrder(inputA2, inputA3, inputB, inputC));
}
@Test
public void filterTwo() throws RuleDefinitionException, SessionException {
RuleDefinition ruleB = Rules.define(RuleB.class);
RuleDefinition ruleA = Rules.define(RuleA.class);
RuleInput inputA1 = new RuleInput(Tags.tag("A", "A1"));
RuleInput inputA2 = new RuleInput(Tags.tag("A", "A2"));
RuleInput inputA3 = new RuleInput(Tags.tag("A", "A3"));
RuleInput inputB = new RuleInput(Tags.tag("B", "XY"));
RuleInput inputC = new RuleInput(Tags.tag("C", "XY"));
Collection<RuleInput> inputs = Arrays.asList(inputA1, inputA2, inputA3, inputB, inputC);
Multimap<RuleDefinition, RuleInput> executions = ArrayListMultimap.create();
executions.put(ruleA, inputA1);
executions.put(ruleB, inputA2);
executions.put(ruleB, inputA3);
inputs = session.filterProcessedInputs(executions, ruleB, inputs);
assertThat(inputs, containsInAnyOrder(inputA1, inputB, inputC));
}
@Test
public void filterAll() throws RuleDefinitionException, SessionException {
RuleDefinition ruleB = Rules.define(RuleB.class);
RuleDefinition ruleA = Rules.define(RuleA.class);
RuleInput inputA1 = new RuleInput(Tags.tag("A", "A1"));
RuleInput inputA2 = new RuleInput(Tags.tag("A", "A2"));
RuleInput inputA3 = new RuleInput(Tags.tag("A", "A3"));
RuleInput inputB = new RuleInput(Tags.tag("B", "XY"));
RuleInput inputC = new RuleInput(Tags.tag("C", "XY"));
Collection<RuleInput> inputs = Arrays.asList(inputA1, inputA2, inputA3, inputB, inputC);
Multimap<RuleDefinition, RuleInput> executions = ArrayListMultimap.create();
executions.put(ruleB, inputA1);
executions.put(ruleB, inputA2);
executions.put(ruleB, inputA3);
executions.put(ruleB, inputB);
executions.put(ruleB, inputC);
inputs = session.filterProcessedInputs(executions, ruleB, inputs);
assertThat(inputs, empty());
}
}
/**
* Test the {@link Session#call()} method.
*
* @author Alexander Wert
*
*/
public static class Call extends SessionTest {
@Test
public void fromActivated() throws Exception {
session = new Session<>(Rules.define(RuleA.class, RuleB.class, RuleC.class), new DefaultSessionResultCollector<String>());
String input = "input";
session.activate(input, Session.EMPTY_SESSION_VARIABLES);
DefaultSessionResult<String> result = session.call();
assertThat(session.getState(), equalTo(State.PROCESSED));
assertThat(result.getConditionFailures().keys(), empty());
assertThat(result.getEndTags().keySet(), containsInAnyOrder("C"));
assertThat(result.getEndTags().get("C"), hasSize(1));
assertThat(((Integer) result.getEndTags().get("C").iterator().next().getValue()), equalTo((input.length() * 2) + 2));
}
@Test
public void twoOfThreeRulesApply() throws Exception {
session = new Session<>(Rules.define(RuleA.class, RuleE.class, RuleF.class), new DefaultSessionResultCollector<String>());
String input = "input";
session.activate(input, Session.EMPTY_SESSION_VARIABLES);
DefaultSessionResult<String> result = session.call();
assertThat(session.getState(), equalTo(State.PROCESSED));
assertThat(result.getConditionFailures().keys(), empty());
assertThat(result.getEndTags().keySet(), hasSize(2));
assertThat(result.getEndTags().keySet(), containsInAnyOrder("A", "E"));
}
@Test
public void ruleWithConditionFailure() throws Exception {
session = new Session<>(Rules.define(RuleA.class, RuleG.class), new DefaultSessionResultCollector<String>());
String input = "input";
session.activate(input, Session.EMPTY_SESSION_VARIABLES);
DefaultSessionResult<String> result = session.call();
assertThat(session.getState(), equalTo(State.PROCESSED));
assertThat(result.getConditionFailures().keySet(), containsInAnyOrder("RuleG"));
assertThat(result.getEndTags().keySet(), hasSize(1));
assertThat(result.getEndTags().keySet(), containsInAnyOrder("A"));
}
@Test(expectedExceptions = { SessionException.class })
public void fromNonActivatedState() throws Exception {
session = new Session<>(Rules.define(RuleA.class, RuleB.class, RuleC.class), new DefaultSessionResultCollector<String>());
session.call();
}
@Test(expectedExceptions = { SessionException.class })
public void withRuleException() throws Exception {
session = new Session<>(Rules.define(RuleA.class, RuleD.class), new DefaultSessionResultCollector<String>());
String input = "input";
session.activate(input, Session.EMPTY_SESSION_VARIABLES);
session.call();
}
}
}