/* * Copyright 2013 Robert von Burg <eitch@eitchnet.ch> * * 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 li.strolch.runtime.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import li.strolch.agent.api.ComponentState; import li.strolch.agent.api.StrolchComponent; import li.strolch.agent.impl.ComponentContainerImpl; import li.strolch.agent.impl.ComponentContainerStateHandler; import li.strolch.agent.impl.ComponentController; import li.strolch.agent.impl.ComponentDependencyAnalyzer; import li.strolch.utils.dbc.DBC.DbcException; @SuppressWarnings("nls") public class ControllerDependencyTest { @Rule public ExpectedException thrown = ExpectedException.none(); // // // 5 // v // 2 <-- 11 ---> 10 // ^ v ^ // | 9 3 // | ^ / // | | v // 7 --> 8 // // // A // ^ ^ // B C // ^ // D // // // A1 // ^ ^ // B1 > C1 // ^ // D1 // // // +-> A2 // | ^ // | B2 > C2 // | ^ // D2 // // // // a -> b : Upstream dependency for a is b // : Downstream dependency for b is a // private ComponentContainerImpl container; private ComponentController con2; private ComponentController con5; private ComponentController con11; private ComponentController con10; private ComponentController con9; private ComponentController con7; private ComponentController con8; private ComponentController con3; private ComponentController conA; private ComponentController conB; private ComponentController conC; private ComponentController conD; private ComponentController conA1; private ComponentController conB1; private ComponentController conC1; private ComponentController conD1; private ComponentController conA2; private ComponentController conB2; private ComponentController conC2; private ComponentController conD2; private StrolchConfiguration strolchConfiguration; private Map<String, ComponentController> controllerMap; @Before public void setupModel() { this.container = new ComponentContainerImpl(null); this.con2 = new ComponentController(new StrolchComponent(this.container, "2")); this.con5 = new ComponentController(new StrolchComponent(this.container, "5")); this.con11 = new ComponentController(new StrolchComponent(this.container, "11")); this.con10 = new ComponentController(new StrolchComponent(this.container, "10")); this.con9 = new ComponentController(new StrolchComponent(this.container, "9")); this.con7 = new ComponentController(new StrolchComponent(this.container, "7")); this.con8 = new ComponentController(new StrolchComponent(this.container, "8")); this.con3 = new ComponentController(new StrolchComponent(this.container, "3")); this.con5.addUpstreamDependency(this.con11); this.con11.addUpstreamDependency(this.con2); this.con11.addUpstreamDependency(this.con10); this.con11.addUpstreamDependency(this.con9); this.con7.addUpstreamDependency(this.con11); this.con7.addUpstreamDependency(this.con8); this.con8.addUpstreamDependency(this.con9); this.con3.addUpstreamDependency(this.con8); this.con3.addUpstreamDependency(this.con10); // this.conA = new ComponentController(new StrolchComponent(this.container, "A")); this.conB = new ComponentController(new StrolchComponent(this.container, "B")); this.conC = new ComponentController(new StrolchComponent(this.container, "C")); this.conD = new ComponentController(new StrolchComponent(this.container, "D")); this.conB.addUpstreamDependency(this.conA); this.conC.addUpstreamDependency(this.conA); this.conD.addUpstreamDependency(this.conB); // this.conA1 = new ComponentController(new StrolchComponent(this.container, "A1")); this.conB1 = new ComponentController(new StrolchComponent(this.container, "B1")); this.conC1 = new ComponentController(new StrolchComponent(this.container, "C1")); this.conD1 = new ComponentController(new StrolchComponent(this.container, "D1")); this.conB1.addUpstreamDependency(this.conA1); this.conB1.addUpstreamDependency(this.conC1); this.conC1.addUpstreamDependency(this.conA1); this.conD1.addUpstreamDependency(this.conB1); // this.conA2 = new ComponentController(new StrolchComponent(this.container, "A2")); this.conB2 = new ComponentController(new StrolchComponent(this.container, "B2")); this.conC2 = new ComponentController(new StrolchComponent(this.container, "C2")); this.conD2 = new ComponentController(new StrolchComponent(this.container, "D2")); this.conB2.addUpstreamDependency(this.conA2); this.conB2.addUpstreamDependency(this.conC2); this.conD2.addUpstreamDependency(this.conB2); this.conD2.addUpstreamDependency(this.conA2); // this.controllerMap = new HashMap<>(); this.controllerMap.put("2", this.con2); this.controllerMap.put("3", this.con3); this.controllerMap.put("5", this.con5); this.controllerMap.put("7", this.con7); this.controllerMap.put("8", this.con8); this.controllerMap.put("9", this.con9); this.controllerMap.put("10", this.con10); this.controllerMap.put("11", this.con11); this.controllerMap.put("A", this.conA); this.controllerMap.put("B", this.conB); this.controllerMap.put("C", this.conC); this.controllerMap.put("D", this.conD); this.controllerMap.put("A1", this.conA1); this.controllerMap.put("B1", this.conB1); this.controllerMap.put("C1", this.conC1); this.controllerMap.put("D1", this.conD1); this.controllerMap.put("A2", this.conA2); this.controllerMap.put("B2", this.conB2); this.controllerMap.put("C2", this.conC2); this.controllerMap.put("D2", this.conD2); // this.strolchConfiguration = ConfigurationParserTest.parseConfiguration(ControllerDependencyTest.class, "dev"); for (ComponentController controller : this.controllerMap.values()) { ComponentConfiguration componentConfiguration = new ComponentConfiguration( this.strolchConfiguration.getRuntimeConfiguration(), controller.getName(), null, null, null, null); this.strolchConfiguration.addConfiguration(controller.getName(), componentConfiguration); } } private void assertModel() { assertTrue(this.con5.hasUpstreamDependencies()); assertFalse(this.con5.hasDownstreamDependencies()); assertEquals(1, this.con5.getUpstreamDependencies().size()); assertEquals(0, this.con5.getDownstreamDependencies().size()); assertTrue(this.con11.hasUpstreamDependencies()); assertTrue(this.con11.hasDownstreamDependencies()); assertEquals(3, this.con11.getUpstreamDependencies().size()); assertEquals(2, this.con11.getDownstreamDependencies().size()); assertFalse(this.con2.hasUpstreamDependencies()); assertTrue(this.con2.hasDownstreamDependencies()); assertEquals(0, this.con2.getUpstreamDependencies().size()); assertEquals(1, this.con2.getDownstreamDependencies().size()); assertTrue(this.con7.hasUpstreamDependencies()); assertFalse(this.con7.hasDownstreamDependencies()); assertEquals(2, this.con7.getUpstreamDependencies().size()); assertEquals(0, this.con7.getDownstreamDependencies().size()); assertTrue(this.con8.hasUpstreamDependencies()); assertTrue(this.con8.hasDownstreamDependencies()); assertEquals(1, this.con8.getUpstreamDependencies().size()); assertEquals(2, this.con8.getDownstreamDependencies().size()); assertTrue(this.con3.hasUpstreamDependencies()); assertFalse(this.con3.hasDownstreamDependencies()); assertEquals(2, this.con3.getUpstreamDependencies().size()); assertEquals(0, this.con3.getDownstreamDependencies().size()); assertFalse(this.con10.hasUpstreamDependencies()); assertTrue(this.con10.hasDownstreamDependencies()); assertEquals(0, this.con10.getUpstreamDependencies().size()); assertEquals(2, this.con10.getDownstreamDependencies().size()); assertFalse(this.con9.hasUpstreamDependencies()); assertTrue(this.con9.hasDownstreamDependencies()); assertEquals(0, this.con9.getUpstreamDependencies().size()); assertEquals(2, this.con9.getDownstreamDependencies().size()); // transitive upstream assertTrue(this.con7.hasTransitiveUpstreamDependency(this.con11)); assertTrue(this.con5.hasTransitiveUpstreamDependency(this.con11)); assertTrue(this.con11.hasTransitiveUpstreamDependency(this.con2)); assertTrue(this.con11.hasTransitiveUpstreamDependency(this.con10)); assertFalse(this.con11.hasTransitiveUpstreamDependency(this.con3)); assertTrue(this.con8.hasTransitiveUpstreamDependency(this.con9)); assertTrue(this.con5.hasTransitiveUpstreamDependency(this.con10)); assertTrue(this.con5.hasTransitiveUpstreamDependency(this.con2)); assertTrue(this.con5.hasTransitiveUpstreamDependency(this.con9)); assertTrue(this.con7.hasTransitiveUpstreamDependency(this.con2)); assertTrue(this.con7.hasTransitiveUpstreamDependency(this.con10)); assertTrue(this.con7.hasTransitiveUpstreamDependency(this.con9)); assertTrue(this.con3.hasTransitiveUpstreamDependency(this.con9)); assertFalse(this.con9.hasTransitiveUpstreamDependency(this.con10)); assertFalse(this.con9.hasTransitiveUpstreamDependency(this.con11)); assertFalse(this.con9.hasTransitiveUpstreamDependency(this.con8)); assertFalse(this.con9.hasTransitiveUpstreamDependency(this.con7)); // transitive downstream assertFalse(this.con5.hasTransitiveDownstreamDependency(this.con8)); assertFalse(this.con5.hasTransitiveDownstreamDependency(this.con3)); assertFalse(this.con5.hasTransitiveDownstreamDependency(this.con7)); assertFalse(this.con9.hasTransitiveDownstreamDependency(this.con10)); assertTrue(this.con9.hasTransitiveDownstreamDependency(this.con3)); assertTrue(this.con9.hasTransitiveDownstreamDependency(this.con7)); // assertFalse(this.conA.hasUpstreamDependencies()); assertTrue(this.conA.hasDownstreamDependencies()); assertEquals(0, this.conA.getUpstreamDependencies().size()); assertEquals(2, this.conA.getDownstreamDependencies().size()); assertTrue(this.conB.hasUpstreamDependencies()); assertTrue(this.conB.hasDownstreamDependencies()); assertEquals(1, this.conB.getUpstreamDependencies().size()); assertEquals(1, this.conB.getDownstreamDependencies().size()); assertTrue(this.conC.hasUpstreamDependencies()); assertFalse(this.conC.hasDownstreamDependencies()); assertEquals(1, this.conC.getUpstreamDependencies().size()); assertEquals(0, this.conC.getDownstreamDependencies().size()); assertTrue(this.conD.hasUpstreamDependencies()); assertFalse(this.conD.hasDownstreamDependencies()); assertEquals(1, this.conD.getUpstreamDependencies().size()); assertEquals(0, this.conD.getDownstreamDependencies().size()); // assertFalse(this.conA1.hasUpstreamDependencies()); assertTrue(this.conA1.hasDownstreamDependencies()); assertEquals(0, this.conA1.getUpstreamDependencies().size()); assertEquals(2, this.conA1.getDownstreamDependencies().size()); assertTrue(this.conB1.hasUpstreamDependencies()); assertTrue(this.conB1.hasDownstreamDependencies()); assertEquals(2, this.conB1.getUpstreamDependencies().size()); assertEquals(1, this.conB1.getDownstreamDependencies().size()); assertTrue(this.conC1.hasUpstreamDependencies()); assertTrue(this.conC1.hasDownstreamDependencies()); assertEquals(1, this.conC1.getUpstreamDependencies().size()); assertEquals(1, this.conC1.getDownstreamDependencies().size()); assertTrue(this.conD1.hasUpstreamDependencies()); assertFalse(this.conD1.hasDownstreamDependencies()); assertEquals(1, this.conD1.getUpstreamDependencies().size()); assertEquals(0, this.conD1.getDownstreamDependencies().size()); } @Test public void testModel() { assertModel(); } @Test public void shouldBreakModel1() { this.thrown.expect(StrolchConfigurationException.class); assertModel(); this.con2.addUpstreamDependency(this.con7); } @Test public void shouldBreakModel2() { this.thrown.expect(StrolchConfigurationException.class); assertModel(); this.con3.addUpstreamDependency(this.con3); } @Test public void shouldBreakModel3() { this.thrown.expect(StrolchConfigurationException.class); assertModel(); this.con9.addUpstreamDependency(this.con3); } @Test public void shouldNotBreakModel1() { assertModel(); this.con11.addUpstreamDependency(this.con8); } @Test public void shouldNotBreakModel2() { assertModel(); this.con9.addUpstreamDependency(this.con10); } @Test public void shouldNotBreakModel3() { assertModel(); this.con11.addUpstreamDependency(this.con8); } @Test public void shouldNotBreakModel4() { assertModel(); this.con8.addUpstreamDependency(this.con11); } @Test public void shouldNotBreakModel() { assertModel(); this.con11.addUpstreamDependency(this.con3); } @Test public void shouldCollectUpstreamDependencies1() { assertModel(); ComponentDependencyAnalyzer dependencyAnalyzer = new ComponentDependencyAnalyzer(this.strolchConfiguration, this.controllerMap); Set<ComponentController> controllers = new HashSet<>(); controllers.add(this.conB); controllers.add(this.conC); Set<ComponentController> directUpstreamDependencies = dependencyAnalyzer .collectDirectUpstreamDependencies(controllers); assertEquals(1, directUpstreamDependencies.size()); assertTrue(directUpstreamDependencies.contains(this.conA)); } @Test public void shouldCollectUpstreamDependencies2() { assertModel(); ComponentDependencyAnalyzer dependencyAnalyzer = new ComponentDependencyAnalyzer(this.strolchConfiguration, this.controllerMap); Set<ComponentController> controllers = new HashSet<>(); controllers.add(this.conD); controllers.add(this.conC); Set<ComponentController> directUpstreamDependencies = dependencyAnalyzer .collectDirectUpstreamDependencies(controllers); assertEquals(1, directUpstreamDependencies.size()); assertTrue(directUpstreamDependencies.contains(this.conB)); } @Test public void shouldCollectUpstreamDependencies3_() { assertModel(); ComponentDependencyAnalyzer dependencyAnalyzer = new ComponentDependencyAnalyzer(this.strolchConfiguration, this.controllerMap); Set<ComponentController> controllers = new HashSet<>(); controllers.add(this.conB); Set<ComponentController> directUpstreamDependencies = dependencyAnalyzer .collectDirectUpstreamDependencies(controllers); assertEquals(1, directUpstreamDependencies.size()); assertTrue(directUpstreamDependencies.contains(this.conA)); } // // A // ^ ^ // B C // ^ // D // @Test public void shouldCollectUpstreamDependencies3() { assertModel(); ComponentDependencyAnalyzer dependencyAnalyzer = new ComponentDependencyAnalyzer(this.strolchConfiguration, this.controllerMap); Set<ComponentController> controllers = new HashSet<>(); controllers.add(this.conB1); Set<ComponentController> directUpstreamDependencies = dependencyAnalyzer .collectDirectUpstreamDependencies(controllers); assertEquals(1, directUpstreamDependencies.size()); assertTrue(directUpstreamDependencies.contains(this.conC1)); } @Test public void shouldNotCollectUpstreamDependencies4() { thrown.expect(DbcException.class); thrown.expectMessage("Upstream C1 is one of the input controllers!"); assertModel(); ComponentDependencyAnalyzer dependencyAnalyzer = new ComponentDependencyAnalyzer(this.strolchConfiguration, this.controllerMap); Set<ComponentController> controllers = new HashSet<>(); controllers.add(this.conD1); controllers.add(this.conC1); Set<ComponentController> directUpstreamDependencies = dependencyAnalyzer .collectDirectUpstreamDependencies(controllers); assertEquals(1, directUpstreamDependencies.size()); assertTrue(directUpstreamDependencies.contains(this.conA1)); } @Test public void shouldCollectUpstreamDependencies5() { assertModel(); ComponentDependencyAnalyzer dependencyAnalyzer = new ComponentDependencyAnalyzer(this.strolchConfiguration, this.controllerMap); Set<ComponentController> controllers = new HashSet<>(); controllers.add(this.conB1); Set<ComponentController> directUpstreamDependencies = dependencyAnalyzer .collectDirectUpstreamDependencies(controllers); assertEquals(1, directUpstreamDependencies.size()); assertTrue(directUpstreamDependencies.contains(this.conC1)); } // // A1 // ^ ^ // B1 > C1 // ^ // D1 // @Test public void shouldCollectUpstreamDependencies6() { assertModel(); ComponentDependencyAnalyzer dependencyAnalyzer = new ComponentDependencyAnalyzer(this.strolchConfiguration, this.controllerMap); Set<ComponentController> controllers = new HashSet<>(); controllers.add(this.conB2); Set<ComponentController> directUpstreamDependencies = dependencyAnalyzer .collectDirectUpstreamDependencies(controllers); assertEquals(2, directUpstreamDependencies.size()); assertTrue(directUpstreamDependencies.contains(this.conA2)); assertTrue(directUpstreamDependencies.contains(this.conC2)); } @Test public void shouldCollectUpstreamDependencies7() { assertModel(); ComponentDependencyAnalyzer dependencyAnalyzer = new ComponentDependencyAnalyzer(this.strolchConfiguration, this.controllerMap); Set<ComponentController> controllers = new HashSet<>(); controllers.add(this.conD2); Set<ComponentController> directUpstreamDependencies = dependencyAnalyzer .collectDirectUpstreamDependencies(controllers); assertEquals(1, directUpstreamDependencies.size()); assertTrue(directUpstreamDependencies.contains(this.conB2)); } // +-> A2 // | ^ // | B2 > C2 // | ^ // D2 // @Test public void shouldAddDepedencies() { ComponentContainerImpl container = new ComponentContainerImpl(null); StrolchComponent component = new StrolchComponent(container, "1"); //$NON-NLS-1$ ComponentController controller = new ComponentController(component); StrolchComponent upstreamDependencyComp1 = new StrolchComponent(container, "1"); //$NON-NLS-1$ ComponentController upstreamDependency1 = new ComponentController(upstreamDependencyComp1); StrolchComponent upstreamDependencyComp2 = new StrolchComponent(container, "1"); //$NON-NLS-1$ ComponentController upstreamDependency2 = new ComponentController(upstreamDependencyComp2); StrolchComponent transitiveUpstreamDependencyComp2 = new StrolchComponent(container, "1"); //$NON-NLS-1$ ComponentController transitiveUpstreamDependency2 = new ComponentController(transitiveUpstreamDependencyComp2); controller.addUpstreamDependency(upstreamDependency1); controller.addUpstreamDependency(upstreamDependency2); upstreamDependency1.addUpstreamDependency(transitiveUpstreamDependency2); assertTrue(controller.hasUpstreamDependencies()); assertFalse(controller.hasDownstreamDependencies()); assertTrue(controller.hasUpstreamDependency(upstreamDependency1)); assertTrue(controller.hasUpstreamDependency(upstreamDependency2)); assertTrue(upstreamDependency1.hasDownstreamDependency(controller)); assertTrue(upstreamDependency2.hasDownstreamDependency(controller)); assertTrue(upstreamDependency1.hasUpstreamDependencies()); assertTrue(upstreamDependency1.hasUpstreamDependency(transitiveUpstreamDependency2)); assertTrue(transitiveUpstreamDependency2.hasDownstreamDependencies()); assertTrue(controller.hasTransitiveUpstreamDependency(transitiveUpstreamDependency2)); assertTrue(transitiveUpstreamDependency2.hasTransitiveDownstreamDependency(controller)); } @Test public void shouldRunThroughModelStates() { ComponentDependencyAnalyzer dependencyAnalyzer = new ComponentDependencyAnalyzer(this.strolchConfiguration, this.controllerMap); ComponentContainerStateHandler stateHandler = new ComponentContainerStateHandler(dependencyAnalyzer, strolchConfiguration); for (ComponentController controller : this.controllerMap.values()) { assertEquals(ComponentState.UNDEFINED, controller.getState()); ComponentConfiguration componentConfiguration = this.strolchConfiguration .getComponentConfiguration(controller.getName()); controller.getComponent().setup(componentConfiguration); } Set<ComponentController> rootUpstreamComponents = dependencyAnalyzer.findRootUpstreamComponents(); assertState(ComponentState.SETUP, this.controllerMap.values()); stateHandler.initialize(rootUpstreamComponents); assertState(ComponentState.INITIALIZED, this.controllerMap.values()); stateHandler.start(rootUpstreamComponents); assertState(ComponentState.STARTED, this.controllerMap.values()); Set<ComponentController> rootDownstreamComponents = dependencyAnalyzer.findRootDownstreamComponents(); stateHandler.stop(rootDownstreamComponents); assertState(ComponentState.STOPPED, this.controllerMap.values()); stateHandler.destroy(rootDownstreamComponents); assertState(ComponentState.DESTROYED, this.controllerMap.values()); } private void assertState(ComponentState expectedState, Collection<ComponentController> collection) { for (ComponentController controller : collection) { assertEquals(expectedState, controller.getState()); } } }