diff --git a/simulation/src/main/java/gov/hhs/aspr/ms/gcm/simulation/nucleus/ActorContext.java b/simulation/src/main/java/gov/hhs/aspr/ms/gcm/simulation/nucleus/ActorContext.java index 5a52de5b7..4f0638203 100644 --- a/simulation/src/main/java/gov/hhs/aspr/ms/gcm/simulation/nucleus/ActorContext.java +++ b/simulation/src/main/java/gov/hhs/aspr/ms/gcm/simulation/nucleus/ActorContext.java @@ -115,10 +115,36 @@ public boolean actorExists(final ActorId actorId) { return simulation.actorExists(actorId); } + /** + * Returns the data manager instance matching the class reference. + * + * + * @throws ContractException + * + * + * + */ public T getDataManager(Class dataManagerClass) { return simulation.getDataManagerForActor(dataManagerClass); } + /** + * Returns true if and only if there is exactly one data manager instance + * matching the given class reference. Null tolerant. + */ + public boolean dataManagerExists(Class dataManagerClass) { + return simulation.dataManagerExists(dataManagerClass); + } + public double getTime() { return simulation.time; } diff --git a/simulation/src/main/java/gov/hhs/aspr/ms/gcm/simulation/nucleus/DataManagerContext.java b/simulation/src/main/java/gov/hhs/aspr/ms/gcm/simulation/nucleus/DataManagerContext.java index f36786af8..07af91f0b 100644 --- a/simulation/src/main/java/gov/hhs/aspr/ms/gcm/simulation/nucleus/DataManagerContext.java +++ b/simulation/src/main/java/gov/hhs/aspr/ms/gcm/simulation/nucleus/DataManagerContext.java @@ -110,10 +110,10 @@ public void releaseObservationEvent(final Event event) { } /** - * Broadcasts the given event to a single actor. This is used - * for OBSERVATION events that are generated by the data managers. MUTATION - * events that are generated by the data managers as a proxy for actors and data - * managers should use releaseMutationEvent() instead. + * Broadcasts the given event to a single actor. This is used for OBSERVATION + * events that are generated by the data managers. MUTATION events that are + * generated by the data managers as a proxy for actors and data managers should + * use releaseMutationEvent() instead. * * @throws ContractException *
    @@ -198,10 +198,49 @@ public boolean actorExists(final ActorId actorId) { return simulation.actorExists(actorId); } + /** + * Returns the data manager instance matching the class reference. + * + * + * @throws ContractException + * + *
      + *
    • {@linkplain NucleusError#NULL_DATA_MANAGER_CLASS} + * if the class reference is null
    • + *
    • {@linkplain NucleusError#AMBIGUOUS_DATA_MANAGER_CLASS} + * if there is more than one data manager instance + * matching the class reference
    • + *
    • {@linkplain NucleusError#UNKNOWN_DATA_MANAGER} + * if there are no data manager instances matching the + * class reference
    • + *
    • {@linkplain NucleusError#DATA_MANAGER_ACCESS_VIOLATION} + * if the invoking data manager does not have access + * to the instance associated with the class + * reference. This happens where there is not a plugin + * dependency chain from the requestor to the + * requested if they are contained in different + * plugins. Within a plugin, access is granted for + * data manager types that were added by their plugin + * before the invoking instance. + * + * + * + *
    + * + */ public T getDataManager(Class dataManagerClass) { return simulation.getDataManagerForDataManager(dataManagerId, dataManagerClass); } + /** + * Returns true if and only if there is exactly one data manager instance + * matching the given class reference that is available to the data manager that + * is requesting the instance. Null tolerant. + */ + public boolean dataManagerExists(Class dataManagerClass) { + return simulation.dataManagerExistsForDataManager(dataManagerId, dataManagerClass); + } + public double getTime() { return simulation.time; } diff --git a/simulation/src/main/java/gov/hhs/aspr/ms/gcm/simulation/nucleus/ReportContext.java b/simulation/src/main/java/gov/hhs/aspr/ms/gcm/simulation/nucleus/ReportContext.java index c21c533c4..722285d02 100644 --- a/simulation/src/main/java/gov/hhs/aspr/ms/gcm/simulation/nucleus/ReportContext.java +++ b/simulation/src/main/java/gov/hhs/aspr/ms/gcm/simulation/nucleus/ReportContext.java @@ -33,8 +33,8 @@ protected ReportContext(Simulation simulation) { * * @throws ContractException *
      - *
    • {@link NucleusError#NULL_PLAN_CONSUMER} if the consumer is - * null
    • + *
    • {@link NucleusError#NULL_PLAN_CONSUMER} if the + * consumer is null
    • *
    • {@link NucleusError#PAST_PLANNING_TIME} if the * plan is scheduled for a time in the past *
    • *
    • {@link NucleusError#PLANNING_QUEUE_CLOSED} if @@ -146,6 +146,14 @@ public T getDataManager(Class dataManagerClass) { return simulation.getDataManagerForActor(dataManagerClass); } + /** + * Returns true if and only if there is exactly one data manager instance + * matching the given class reference. Null tolerant. + */ + public boolean dataManagerExists(Class dataManagerClass) { + return simulation.dataManagerExists(dataManagerClass); + } + public double getTime() { return simulation.time; } diff --git a/simulation/src/main/java/gov/hhs/aspr/ms/gcm/simulation/nucleus/Simulation.java b/simulation/src/main/java/gov/hhs/aspr/ms/gcm/simulation/nucleus/Simulation.java index 5095719f3..17ef042c5 100644 --- a/simulation/src/main/java/gov/hhs/aspr/ms/gcm/simulation/nucleus/Simulation.java +++ b/simulation/src/main/java/gov/hhs/aspr/ms/gcm/simulation/nucleus/Simulation.java @@ -1275,6 +1275,40 @@ protected void removeActor(final ActorId actorId) { containsDeletedActors = true; } + protected boolean dataManagerExists(Class dataManagerClass) { + boolean result = false; + if (dataManagerClass != null) { + + DataManager dataManager = workingClassToDataManagerMap.get(dataManagerClass); + /* + * If the working map does not contain the data manager, try to find a single + * match from the base map that was collected from the plugins. + * + * If two or more matches are found, then throw an exception. + * + * If exactly one match is found, update the working map. + * + * If no matches are found, nothing is done, but we are vulnerable to somewhat + * slower performance if the data manager is sought repeatedly. + */ + if (dataManager == null) { + List> candidates = new ArrayList<>(); + for (Class c : baseClassToDataManagerMap.keySet()) { + if (dataManagerClass.isAssignableFrom(c)) { + candidates.add(c); + } + } + + if (candidates.size() == 1) { + dataManager = baseClassToDataManagerMap.get(candidates.get(0)); + workingClassToDataManagerMap.put(dataManagerClass, dataManager); + } + } + result = dataManager != null; + } + return result; + } + @SuppressWarnings("unchecked") protected T getDataManagerForActor(Class dataManagerClass) { @@ -1315,6 +1349,58 @@ protected T getDataManagerForActor(Class dataManagerC } return (T) dataManager; } + + + protected boolean dataManagerExistsForDataManager(DataManagerId dataManagerId, + Class dataManagerClass) { + + if (dataManagerClass == null) { + return false; + } + + DataManager dataManager = workingClassToDataManagerMap.get(dataManagerClass); + /* + * If the working map does not contain the data manager, try to find a single + * match from the base map that was collected from the plugins. + * + * If two or more matches are found, then throw an exception. + * + * If exactly one match is found, update the working map. + * + * If no matches are found, nothing is done, but we are vulnerable to somewhat + * slower performance if the data manager is sought repeatedly. + */ + if (dataManager == null) { + List> candidates = new ArrayList<>(); + for (Class c : baseClassToDataManagerMap.keySet()) { + if (dataManagerClass.isAssignableFrom(c)) { + candidates.add(c); + } + } + if (candidates.size() > 1) { + return false; + } + if (candidates.size() == 1) { + dataManager = baseClassToDataManagerMap.get(candidates.get(0)); + workingClassToDataManagerMap.put(dataManagerClass, dataManager); + } + } + + if (dataManager == null) { + return false; + } + + int requestorId = dataManagerId.getValue(); + DataManagerId dataManagerId2 = dataManagerToDataManagerIdMap.get(dataManager); + int requesteeId = dataManagerId2.getValue(); + + boolean accessGranted = dataManagerAccessPermissions[requestorId][requesteeId]; + + if (!accessGranted) { + return false; + } + return true; + } @SuppressWarnings("unchecked") protected T getDataManagerForDataManager(DataManagerId dataManagerId, @@ -1492,10 +1578,10 @@ protected boolean subscribersExistForEvent(Class eventClass) { } /* - * Recursively processes the event through the filter node to the given actor. Events should be - * processed through the root filter node. Each node's consumers have each such - * consumer scheduled onto the actor queue for delayed execution of the - * consumer. + * Recursively processes the event through the filter node to the given actor. + * Events should be processed through the root filter node. Each node's + * consumers have each such consumer scheduled onto the actor queue for delayed + * execution of the consumer. */ private void broadcastEventToFilterNodeAndActor(final Event event, FilterNode filterNode, ActorId actorId) { // determine the value of the function for the given event diff --git a/simulation/src/test/java/gov/hhs/aspr/ms/gcm/simulation/nucleus/AT_ActorContext.java b/simulation/src/test/java/gov/hhs/aspr/ms/gcm/simulation/nucleus/AT_ActorContext.java index acba88e96..0eda0d89f 100644 --- a/simulation/src/test/java/gov/hhs/aspr/ms/gcm/simulation/nucleus/AT_ActorContext.java +++ b/simulation/src/test/java/gov/hhs/aspr/ms/gcm/simulation/nucleus/AT_ActorContext.java @@ -58,6 +58,10 @@ private static class TestDataManager4A extends TestDataManager4 { } + private static class TestDataManager4B extends TestDataManager4 { + + } + private static class DataChangeEvent implements Event { private final DatumType datumType; private final int value; @@ -219,13 +223,13 @@ public void testAddPlan_Consumer() { // show that the last two passive plans did not execute assertTrue(planExecuted.getValue()); - + // precondition test: if the consumer is null ContractException contractException = assertThrows(ContractException.class, () -> { Simulation.builder()// .addPlugin(TestPlugin.getTestPlugin( TestPluginData.builder().addTestActorPlan("actor", new TestActorPlan(0, (c) -> { - c.addPlan(null,0); + c.addPlan(null, 0); })).build()))// .build()// .execute();// @@ -235,12 +239,13 @@ public void testAddPlan_Consumer() { // precondition test: if the plan is scheduled for a time in the past contractException = assertThrows(ContractException.class, () -> { Simulation.builder()// - .addPlugin(TestPlugin.getTestPlugin( - TestPluginData.builder().addTestActorPlan("actor", new TestActorPlan(0, (c) -> { - c.addPlan((c2)->{},-10); - })).build()))// - .build()// - .execute();// + .addPlugin(TestPlugin.getTestPlugin( + TestPluginData.builder().addTestActorPlan("actor", new TestActorPlan(0, (c) -> { + c.addPlan((c2) -> { + }, -10); + })).build()))// + .build()// + .execute();// }); assertEquals(NucleusError.PAST_PLANNING_TIME, contractException.getErrorType()); @@ -248,19 +253,19 @@ public void testAddPlan_Consumer() { // processing is finished contractException = assertThrows(ContractException.class, () -> { Simulation.builder()// - .addPlugin(TestPlugin.getTestPlugin( - TestPluginData.builder().addTestActorPlan("actor", new TestActorPlan(0, (c) -> { - c.subscribeToSimulationClose((c2)->{ - c2.addPlan((c3)->{},0); - }); - - })).build()))// - .build()// - .execute();// + .addPlugin(TestPlugin.getTestPlugin( + TestPluginData.builder().addTestActorPlan("actor", new TestActorPlan(0, (c) -> { + c.subscribeToSimulationClose((c2) -> { + c2.addPlan((c3) -> { + }, 0); + }); + + })).build()))// + .build()// + .execute();// }); assertEquals(NucleusError.PLANNING_QUEUE_CLOSED, contractException.getErrorType()); - } @Test @@ -313,12 +318,13 @@ public void testAddPlan_Plan() { // precondition test: if the plan is scheduled for a time in the past contractException = assertThrows(ContractException.class, () -> { Simulation.builder()// - .addPlugin(TestPlugin.getTestPlugin( - TestPluginData.builder().addTestActorPlan("actor", new TestActorPlan(0, (c) -> { - c.addPlan(new ConsumerActorPlan(-10, (c3)->{})); - })).build()))// - .build()// - .execute();// + .addPlugin(TestPlugin.getTestPlugin( + TestPluginData.builder().addTestActorPlan("actor", new TestActorPlan(0, (c) -> { + c.addPlan(new ConsumerActorPlan(-10, (c3) -> { + })); + })).build()))// + .build()// + .execute();// }); assertEquals(NucleusError.PAST_PLANNING_TIME, contractException.getErrorType()); @@ -326,19 +332,19 @@ public void testAddPlan_Plan() { // processing is finished contractException = assertThrows(ContractException.class, () -> { Simulation.builder()// - .addPlugin(TestPlugin.getTestPlugin( - TestPluginData.builder().addTestActorPlan("actor", new TestActorPlan(0, (c) -> { - c.subscribeToSimulationClose((c2)->{ - c2.addPlan(new ConsumerActorPlan(0, (c3)->{})); - }); - - })).build()))// - .build()// - .execute();// + .addPlugin(TestPlugin.getTestPlugin( + TestPluginData.builder().addTestActorPlan("actor", new TestActorPlan(0, (c) -> { + c.subscribeToSimulationClose((c2) -> { + c2.addPlan(new ConsumerActorPlan(0, (c3) -> { + })); + }); + + })).build()))// + .build()// + .execute();// }); assertEquals(NucleusError.PLANNING_QUEUE_CLOSED, contractException.getErrorType()); - } @Test @@ -386,11 +392,12 @@ public void testGetActorId() { // show that the number of actor ids matches the number of actor aliases assertEquals(3, observedActorIds.size()); } - - @Test - @UnitTestMethod(target = ActorContext.class, name = "getDataManager", args = { Class.class }) - public void testGetDataManager() { - + + + + + private void executeGetDataManagerTest(Consumer consumer) { + // create the test plugin data builder TestPluginData.Builder pluginDataBuilder = TestPluginData.builder(); @@ -401,48 +408,90 @@ public void testGetDataManager() { pluginDataBuilder.addTestDataManager("dm3B", () -> new TestDataManager3B()); pluginDataBuilder.addTestDataManager("dm4A", () -> new TestDataManager4A()); - pluginDataBuilder.addTestActorPlan("actor", new TestActorPlan(0, (c) -> { - c.getDataManager(TestDataManager1.class); - c.getDataManager(TestDataManager3A.class); - c.getDataManager(TestDataManager3B.class); - c.getDataManager(TestDataManager4A.class); - })); + pluginDataBuilder.addTestActorPlan("actor", new TestActorPlan(0, consumer)); // build the action plugin TestPluginData testPluginData = pluginDataBuilder.build(); Plugin testPlugin = TestPlugin.getTestPlugin(testPluginData); TestSimulation.builder().addPlugin(testPlugin).build().execute(); + } + + @Test + @UnitTestMethod(target = ActorContext.class, name = "getDataManager", args = { Class.class }) + public void testGetDataManager() { + + //postcondition test: + executeGetDataManagerTest((c)->{ + assertNotNull(c.getDataManager(TestDataManager1.class)); + assertNotNull(c.getDataManager(TestDataManager3A.class)); + assertNotNull(c.getDataManager(TestDataManager3B.class)); + assertNotNull(c.getDataManager(TestDataManager4A.class)); + assertNotNull(c.getDataManager(TestDataManager4.class)); + }); + + // precondition test: if the class reference is null + ContractException contractException = assertThrows(ContractException.class, ()->{ + executeGetDataManagerTest((c)->{ + c.getDataManager(null); + }); + }); + assertEquals(NucleusError.NULL_DATA_MANAGER_CLASS, contractException.getErrorType()); + + // precondition test: if the class reference is null + contractException = assertThrows(ContractException.class, ()->{ + executeGetDataManagerTest((c)->{ + c.getDataManager(TestDataManager3.class); + }); + }); + assertEquals(NucleusError.AMBIGUOUS_DATA_MANAGER_CLASS, contractException.getErrorType()); + + // precondition test: if the class reference is unknown + contractException = assertThrows(ContractException.class, ()->{ + executeGetDataManagerTest((c)->{ + c.getDataManager(TestDataManager4B.class); + }); + }); + assertEquals(NucleusError.UNKNOWN_DATA_MANAGER, contractException.getErrorType()); + } - // Precondition test 1 + @Test + @UnitTestMethod(target = ActorContext.class, name = "dataManagerExists", args = { Class.class }) + public void testDataManagerExists() { + + // create the test plugin data builder + TestPluginData.Builder pluginDataBuilder = TestPluginData.builder(); + + // create a data manager for the actor to find + + pluginDataBuilder.addTestDataManager("dm1", () -> new TestDataManager1()); pluginDataBuilder.addTestDataManager("dm3A", () -> new TestDataManager3A()); pluginDataBuilder.addTestDataManager("dm3B", () -> new TestDataManager3B()); + pluginDataBuilder.addTestDataManager("dm4A", () -> new TestDataManager4A()); - // show that ambiguous class matching throws an exception pluginDataBuilder.addTestActorPlan("actor", new TestActorPlan(0, (c) -> { - ContractException contractException = assertThrows(ContractException.class, - () -> c.getDataManager(TestDataManager3.class)); - assertEquals(NucleusError.AMBIGUOUS_DATA_MANAGER_CLASS, contractException.getErrorType()); - })); + // show that the explicit class references return true + assertTrue(c.dataManagerExists(TestDataManager1.class)); + assertTrue(c.dataManagerExists(TestDataManager3A.class)); + assertTrue(c.dataManagerExists(TestDataManager3B.class)); + assertTrue(c.dataManagerExists(TestDataManager4A.class)); - // build the action plugin - testPluginData = pluginDataBuilder.build(); - testPlugin = TestPlugin.getTestPlugin(testPluginData); + // show that zero class matching returns false + assertFalse(c.dataManagerExists(TestDataManager4B.class)); - TestSimulation.builder().addPlugin(testPlugin).build().execute(); + // show that ambiguous class matching returns false + assertFalse(c.dataManagerExists(TestDataManager3.class)); + + // show that a null yields a false + assertFalse(c.dataManagerExists(null)); - // Precondition test 2 - pluginDataBuilder.addTestActorPlan("actor", new TestActorPlan(0, (c) -> { - ContractException contractException = assertThrows(ContractException.class, () -> c.getDataManager(null)); - assertEquals(NucleusError.NULL_DATA_MANAGER_CLASS, contractException.getErrorType()); })); // build the action plugin - testPluginData = pluginDataBuilder.build(); - testPlugin = TestPlugin.getTestPlugin(testPluginData); + TestPluginData testPluginData = pluginDataBuilder.build(); + Plugin testPlugin = TestPlugin.getTestPlugin(testPluginData); TestSimulation.builder().addPlugin(testPlugin).build().execute(); - } @Test diff --git a/simulation/src/test/java/gov/hhs/aspr/ms/gcm/simulation/nucleus/AT_DataManagerContext.java b/simulation/src/test/java/gov/hhs/aspr/ms/gcm/simulation/nucleus/AT_DataManagerContext.java index 1f6c824f4..de788dfb7 100644 --- a/simulation/src/test/java/gov/hhs/aspr/ms/gcm/simulation/nucleus/AT_DataManagerContext.java +++ b/simulation/src/test/java/gov/hhs/aspr/ms/gcm/simulation/nucleus/AT_DataManagerContext.java @@ -151,73 +151,207 @@ public void testSubscribeToSimulationClose() { } - @Test - @UnitTestMethod(target = DataManagerContext.class, name = "getDataManager", args = { Class.class }) - public void testGetDataManager() { - + private void executeGetDataManagerTest(String dmName, Consumer consumer) { + PluginId pluginId0 = new SimplePluginId("local plugin 0"); + PluginId pluginId5 = new SimplePluginId("local plugin 5"); // create the test plugin data builder TestPluginData.Builder pluginDataBuilder = TestPluginData.builder(); // create a data manager for the actor to find pluginDataBuilder.addTestDataManager("dm1", () -> new TestDataManager1()); + pluginDataBuilder.addTestDataManager("dm2", () -> new TestDataManager2()); pluginDataBuilder.addTestDataManager("dm3A", () -> new TestDataManager3A()); pluginDataBuilder.addTestDataManager("dm3B", () -> new TestDataManager3B()); pluginDataBuilder.addTestDataManager("dm4A", () -> new TestDataManager4A()); - pluginDataBuilder.addTestActorPlan("actor", new TestActorPlan(0, (c) -> { - TestDataManager1 testDataManager1 = c.getDataManager(TestDataManager1.class); - assertNotNull(testDataManager1); - - TestDataManager3A testDataManager3A = c.getDataManager(TestDataManager3A.class); - assertNotNull(testDataManager3A); + pluginDataBuilder.addTestDataManagerPlan(dmName, new TestDataManagerPlan(0, consumer)); - TestDataManager3B testDataManager3B = c.getDataManager(TestDataManager3B.class); - assertNotNull(testDataManager3B); - - TestDataManager4A testDataManager4A = c.getDataManager(TestDataManager4A.class); - assertNotNull(testDataManager4A); - - })); + pluginDataBuilder.addPluginDependency(pluginId0); // build the action plugin TestPluginData testPluginData = pluginDataBuilder.build(); Plugin testPlugin = TestPlugin.getTestPlugin(testPluginData); - // execute the engine - TestSimulation.builder().addPlugin(testPlugin).build().execute(); + Plugin localPlugin0 = Plugin.builder()// + .setPluginId(pluginId0)// + .setInitializer((c) -> c.addDataManager(new TestDataManager0()))// + .build(); + Plugin localPlugin5 = Plugin.builder()// + .setPluginId(pluginId5)// + .setInitializer((c) -> c.addDataManager(new TestDataManager5()))// + .build(); + + TestSimulation.builder()// + .addPlugin(localPlugin0)// + .addPlugin(localPlugin5)// + .addPlugin(testPlugin).build()// + .execute();// + } + + @Test + @UnitTestMethod(target = DataManagerContext.class, name = "getDataManager", args = { Class.class }) + public void testGetDataManager() { + /* + * postcondition test: we demonstrate for all of the test data managers in the + * test plugin that they can retrieve the instances that are allowed by the + * access rules. Note that TestDataManager0 and TestDataManager5 are defined by + * local plugins and only TestDataManager0 is accessible by the remaining data + * managers since the test plugin has a plugin dependency on the local plugin + * containing the instance of TestDataManager0, but does not have a plugin + * dependency on the plugin containing the instance of TestDataManager5. + */ + executeGetDataManagerTest("dm4A", (c) -> { + assertNotNull(c.getDataManager(TestDataManager0.class)); + assertNotNull(c.getDataManager(TestDataManager1.class)); + assertNotNull(c.getDataManager(TestDataManager2.class)); + assertNotNull(c.getDataManager(TestDataManager3A.class)); + assertNotNull(c.getDataManager(TestDataManager3B.class)); + }); + + executeGetDataManagerTest("dm3B", (c) -> { + assertNotNull(c.getDataManager(TestDataManager0.class)); + assertNotNull(c.getDataManager(TestDataManager1.class)); + assertNotNull(c.getDataManager(TestDataManager2.class)); + assertNotNull(c.getDataManager(TestDataManager3A.class)); + }); - // Precondition test 1 + executeGetDataManagerTest("dm3A", (c) -> { + assertNotNull(c.getDataManager(TestDataManager0.class)); + assertNotNull(c.getDataManager(TestDataManager1.class)); + assertNotNull(c.getDataManager(TestDataManager2.class)); + }); + + executeGetDataManagerTest("dm2", (c) -> { + assertNotNull(c.getDataManager(TestDataManager0.class)); + assertNotNull(c.getDataManager(TestDataManager1.class)); + }); + + executeGetDataManagerTest("dm1", (c) -> { + assertNotNull(c.getDataManager(TestDataManager0.class)); + }); + + // precondition test: if the class reference is null + ContractException contractException = assertThrows(ContractException.class, () -> { + executeGetDataManagerTest("dm1", (c) -> { + c.getDataManager(null); + }); + }); + assertEquals(NucleusError.NULL_DATA_MANAGER_CLASS, contractException.getErrorType()); + + // precondition test: if the class reference is null + contractException = assertThrows(ContractException.class, () -> { + executeGetDataManagerTest("dm1", (c) -> { + c.getDataManager(TestDataManager3.class); + }); + }); + assertEquals(NucleusError.AMBIGUOUS_DATA_MANAGER_CLASS, contractException.getErrorType()); + + // precondition test: if the class reference is unknown + contractException = assertThrows(ContractException.class, () -> { + executeGetDataManagerTest("dm1", (c) -> { + c.getDataManager(TestDataManager4B.class); + }); + }); + assertEquals(NucleusError.UNKNOWN_DATA_MANAGER, contractException.getErrorType()); + // precondition test: if the requestor does not have access due to order within + // the plugin + contractException = assertThrows(ContractException.class, () -> { + executeGetDataManagerTest("dm1", (c) -> { + c.getDataManager(TestDataManager2.class); + }); + }); + assertEquals(NucleusError.DATA_MANAGER_ACCESS_VIOLATION, contractException.getErrorType()); + + // precondition test: if the requestor does not have access due to having no + // plugin dependency path + contractException = assertThrows(ContractException.class, () -> { + executeGetDataManagerTest("dm1", (c) -> { + c.getDataManager(TestDataManager5.class); + }); + }); + assertEquals(NucleusError.DATA_MANAGER_ACCESS_VIOLATION, contractException.getErrorType()); + + } + + @Test + @UnitTestMethod(target = DataManagerContext.class, name = "dataManagerExists", args = { Class.class }) + public void testDataManagerExists() { + + // create the test plugin data builder + TestPluginData.Builder pluginDataBuilder = TestPluginData.builder(); + + // create a data manager for the actor to find + + pluginDataBuilder.addTestDataManager("dm1", () -> new TestDataManager1()); + pluginDataBuilder.addTestDataManager("dm2", () -> new TestDataManager2()); pluginDataBuilder.addTestDataManager("dm3A", () -> new TestDataManager3A()); pluginDataBuilder.addTestDataManager("dm3B", () -> new TestDataManager3B()); + pluginDataBuilder.addTestDataManager("dm4A", () -> new TestDataManager4A()); - pluginDataBuilder.addTestDataManagerPlan("dm3A", new TestDataManagerPlan(4, (c) -> { - ContractException contractException = assertThrows(ContractException.class, - () -> c.getDataManager(TestDataManager3.class)); - assertEquals(NucleusError.AMBIGUOUS_DATA_MANAGER_CLASS, contractException.getErrorType()); + // show the various ways bad class references return false + pluginDataBuilder.addTestDataManagerPlan("dm1", new TestDataManagerPlan(1, (c) -> { + // show that zero class matching returns false + assertFalse(c.dataManagerExists(TestDataManager4B.class)); + + // show that ambiguous class matching returns false + assertFalse(c.dataManagerExists(TestDataManager3.class)); + + // show that a null yields a false + assertFalse(c.dataManagerExists(null)); })); - // build the action plugin - testPluginData = pluginDataBuilder.build(); - testPlugin = TestPlugin.getTestPlugin(testPluginData); + // show ordering restrictions are enforced + pluginDataBuilder.addTestDataManagerPlan("dm1", new TestDataManagerPlan(1, (c) -> { + assertFalse(c.dataManagerExists(TestDataManager1.class)); + assertFalse(c.dataManagerExists(TestDataManager2.class)); + assertFalse(c.dataManagerExists(TestDataManager3A.class)); + assertFalse(c.dataManagerExists(TestDataManager3B.class)); + assertFalse(c.dataManagerExists(TestDataManager4A.class)); + })); - // execute the engine - TestSimulation.builder().addPlugin(testPlugin).build().execute(); + // show ordering restrictions are enforced + pluginDataBuilder.addTestDataManagerPlan("dm2", new TestDataManagerPlan(1, (c) -> { + assertTrue(c.dataManagerExists(TestDataManager1.class)); + assertFalse(c.dataManagerExists(TestDataManager2.class)); + assertFalse(c.dataManagerExists(TestDataManager3A.class)); + assertFalse(c.dataManagerExists(TestDataManager3B.class)); + assertFalse(c.dataManagerExists(TestDataManager4A.class)); + })); - // Precondition test 2 + // show ordering restrictions are enforced + pluginDataBuilder.addTestDataManagerPlan("dm3A", new TestDataManagerPlan(1, (c) -> { + assertTrue(c.dataManagerExists(TestDataManager1.class)); + assertTrue(c.dataManagerExists(TestDataManager2.class)); + assertFalse(c.dataManagerExists(TestDataManager3A.class)); + assertFalse(c.dataManagerExists(TestDataManager3B.class)); + assertFalse(c.dataManagerExists(TestDataManager4A.class)); + })); - pluginDataBuilder.addTestDataManager("dm3B", () -> new TestDataManager3B()); + // show ordering restrictions are enforced + pluginDataBuilder.addTestDataManagerPlan("dm3B", new TestDataManagerPlan(1, (c) -> { + assertTrue(c.dataManagerExists(TestDataManager1.class)); + assertTrue(c.dataManagerExists(TestDataManager2.class)); + assertTrue(c.dataManagerExists(TestDataManager3A.class)); + assertFalse(c.dataManagerExists(TestDataManager3B.class)); + assertFalse(c.dataManagerExists(TestDataManager4A.class)); + })); - pluginDataBuilder.addTestDataManagerPlan("dm3B", new TestDataManagerPlan(4, (c) -> { - ContractException contractException = assertThrows(ContractException.class, () -> c.getDataManager(null)); - assertEquals(NucleusError.NULL_DATA_MANAGER_CLASS, contractException.getErrorType()); + // show ordering restrictions are enforced + pluginDataBuilder.addTestDataManagerPlan("dm4A", new TestDataManagerPlan(1, (c) -> { + assertTrue(c.dataManagerExists(TestDataManager1.class)); + assertTrue(c.dataManagerExists(TestDataManager2.class)); + assertTrue(c.dataManagerExists(TestDataManager3A.class)); + assertTrue(c.dataManagerExists(TestDataManager3B.class)); + assertFalse(c.dataManagerExists(TestDataManager4A.class)); })); // build the action plugin - testPluginData = pluginDataBuilder.build(); - testPlugin = TestPlugin.getTestPlugin(testPluginData); + TestPluginData testPluginData = pluginDataBuilder.build(); + + Plugin testPlugin = TestPlugin.getTestPlugin(testPluginData); // execute the engine TestSimulation.builder().addPlugin(testPlugin).build().execute(); @@ -233,7 +367,6 @@ public void testAddPlan_Consumer() { // test preconditions pluginDataBuilder.addTestDataManager("dm", () -> new TestDataManager1()); - /* * Have the actor add a plan and show that that plan executes */ @@ -268,7 +401,7 @@ public void testAddPlan_Consumer() { .addPlugin(TestPlugin.getTestPlugin(TestPluginData.builder()// .addTestDataManager("dm", () -> new TestDataManager1()) .addTestDataManagerPlan("dm", new TestDataManagerPlan(0, (c) -> { - c.addPlan(null,0); + c.addPlan(null, 0); })).build()))// .build()// .execute();// @@ -281,7 +414,8 @@ public void testAddPlan_Consumer() { .addPlugin(TestPlugin.getTestPlugin(TestPluginData.builder()// .addTestDataManager("dm", () -> new TestDataManager1()) .addTestDataManagerPlan("dm", new TestDataManagerPlan(0, (c) -> { - c.addPlan((c2) -> {},-10); + c.addPlan((c2) -> { + }, -10); })).build()))// .build()// .execute();// @@ -296,7 +430,8 @@ public void testAddPlan_Consumer() { .addTestDataManager("dm", () -> new TestDataManager1()) .addTestDataManagerPlan("dm", new TestDataManagerPlan(0, (c) -> { c.subscribeToSimulationClose(c2 -> { - c2.addPlan((c3) -> {},0); + c2.addPlan((c3) -> { + }, 0); }); })).build()))// .build()// @@ -304,7 +439,6 @@ public void testAddPlan_Consumer() { }); assertEquals(NucleusError.PLANNING_QUEUE_CLOSED, contractException.getErrorType()); - } @Test @@ -557,6 +691,10 @@ private static class TestEvent1 implements Event { } + private static class TestDataManager0 extends DataManager { + + } + private static class TestDataManager1 extends TestDataManager { } @@ -583,6 +721,14 @@ private static class TestDataManager4A extends TestDataManager4 { } + private static class TestDataManager4B extends TestDataManager4 { + + } + + private static class TestDataManager5 extends DataManager { + + } + @Test @UnitTestMethod(target = DataManagerContext.class, name = "actorExists", args = { ActorId.class }) public void testActorExists() { diff --git a/simulation/src/test/java/gov/hhs/aspr/ms/gcm/simulation/nucleus/AT_ReportContext.java b/simulation/src/test/java/gov/hhs/aspr/ms/gcm/simulation/nucleus/AT_ReportContext.java index 6551a2ae2..ff511fd34 100644 --- a/simulation/src/test/java/gov/hhs/aspr/ms/gcm/simulation/nucleus/AT_ReportContext.java +++ b/simulation/src/test/java/gov/hhs/aspr/ms/gcm/simulation/nucleus/AT_ReportContext.java @@ -1,6 +1,7 @@ package gov.hhs.aspr.ms.gcm.simulation.nucleus; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -56,6 +57,10 @@ private static class TestDataManager4A extends TestDataManager4 { } + private static class TestDataManager4B extends TestDataManager4 { + + } + /* * Executes the simulation by adding TestReport that executes the give consumer * in a task planned at time zero. Also adds a TestActor with a task scheduled @@ -143,18 +148,18 @@ public void testAddPlan_Consumer() { })); assertEquals(NucleusError.PAST_PLANNING_TIME, contractException.getErrorType()); - // precondition test : if the plan is added to the simulation after event processing is finished + // precondition test : if the plan is added to the simulation after event + // processing is finished contractException = assertThrows(ContractException.class, () -> testConsumer((c) -> { c.addPlan(new ConsumerReportPlan(0, (c1) -> { - c1.subscribeToSimulationClose((c2->{ - c2.addPlan(c3->{},0); + c1.subscribeToSimulationClose((c2 -> { + c2.addPlan(c3 -> { + }, 0); })); })); })); assertEquals(NucleusError.PLANNING_QUEUE_CLOSED, contractException.getErrorType()); - - } @Test @@ -215,7 +220,6 @@ public void testAddPlan_Plan() { // show that the last two passive plans did not execute assertEquals(expectedOutput, actualOuput); - ContractException contractException = assertThrows(ContractException.class, () -> testConsumer((c) -> { c.addPlan(null); })); @@ -235,38 +239,33 @@ public void testAddPlan_Plan() { })); assertEquals(NucleusError.INVALID_PLAN_ARRIVAL_ID, contractException.getErrorType()); - // precondition test : if the plan is added to the simulation after event processing is finished + // precondition test : if the plan is added to the simulation after event + // processing is finished contractException = assertThrows(ContractException.class, () -> testConsumer((c) -> { c.addPlan(new ConsumerReportPlan(0, (c1) -> { - c1.subscribeToSimulationClose((c2->{ - c2.addPlan(new ConsumerReportPlan(0,(c3->{}))); + c1.subscribeToSimulationClose((c2 -> { + c2.addPlan(new ConsumerReportPlan(0, (c3 -> { + }))); })); })); })); assertEquals(NucleusError.PLANNING_QUEUE_CLOSED, contractException.getErrorType()); } - @Test - @UnitTestMethod(target = ReportContext.class, name = "getDataManager", args = { Class.class }) - public void testGetDataManager() { + private void executeGetDataManagerTest(Consumer consumer) { + // create the test plugin data builder TestPluginData.Builder pluginDataBuilder = TestPluginData.builder(); - // create a data manager for the report to find + // create a data manager for the actor to find pluginDataBuilder.addTestDataManager("dm1", () -> new TestDataManager1()); pluginDataBuilder.addTestDataManager("dm3A", () -> new TestDataManager3A()); pluginDataBuilder.addTestDataManager("dm3B", () -> new TestDataManager3B()); pluginDataBuilder.addTestDataManager("dm4A", () -> new TestDataManager4A()); - pluginDataBuilder.addTestReportPlan("report", new TestReportPlan(0, (c) -> { - c.getDataManager(TestDataManager1.class); - c.getDataManager(TestDataManager3A.class); - c.getDataManager(TestDataManager3B.class); - c.getDataManager(TestDataManager4A.class); - })); - - pluginDataBuilder.addTestActorPlan("actor", new TestActorPlan(Double.POSITIVE_INFINITY, (c) -> { + pluginDataBuilder.addTestReportPlan("report", new TestReportPlan(0, consumer)); + pluginDataBuilder.addTestActorPlan("actor", new TestActorPlan(1, (c) -> { })); // build the action plugin @@ -274,39 +273,86 @@ public void testGetDataManager() { Plugin testPlugin = TestPlugin.getTestPlugin(testPluginData); TestSimulation.builder().addPlugin(testPlugin).build().execute(); + } + + @Test + @UnitTestMethod(target = ReportContext.class, name = "getDataManager", args = { Class.class }) + public void testGetDataManager() { + // postcondition test: + executeGetDataManagerTest((c) -> { + assertNotNull(c.getDataManager(TestDataManager1.class)); + assertNotNull(c.getDataManager(TestDataManager3A.class)); + assertNotNull(c.getDataManager(TestDataManager3B.class)); + assertNotNull(c.getDataManager(TestDataManager4A.class)); + assertNotNull(c.getDataManager(TestDataManager4.class)); + }); + + // precondition test: if the class reference is null + ContractException contractException = assertThrows(ContractException.class, () -> { + executeGetDataManagerTest((c) -> { + c.getDataManager(null); + }); + }); + assertEquals(NucleusError.NULL_DATA_MANAGER_CLASS, contractException.getErrorType()); + + // precondition test: if the class reference is null + contractException = assertThrows(ContractException.class, () -> { + executeGetDataManagerTest((c) -> { + c.getDataManager(TestDataManager3.class); + }); + }); + assertEquals(NucleusError.AMBIGUOUS_DATA_MANAGER_CLASS, contractException.getErrorType()); + + // precondition test: if the class reference is unknown + contractException = assertThrows(ContractException.class, () -> { + executeGetDataManagerTest((c) -> { + c.getDataManager(TestDataManager4B.class); + }); + }); + assertEquals(NucleusError.UNKNOWN_DATA_MANAGER, contractException.getErrorType()); + + } - // precondition test : if the class reference is ambiguous + @Test + @UnitTestMethod(target = ReportContext.class, name = "dataManagerExists", args = { Class.class }) + public void testDataManagerExists() { + // create the test plugin data builder + TestPluginData.Builder pluginDataBuilder = TestPluginData.builder(); + + // create a data manager for the report to find + + pluginDataBuilder.addTestDataManager("dm1", () -> new TestDataManager1()); pluginDataBuilder.addTestDataManager("dm3A", () -> new TestDataManager3A()); pluginDataBuilder.addTestDataManager("dm3B", () -> new TestDataManager3B()); + pluginDataBuilder.addTestDataManager("dm4A", () -> new TestDataManager4A()); - // show that ambiguous class matching throws an exception pluginDataBuilder.addTestReportPlan("report", new TestReportPlan(0, (c) -> { - ContractException contractException = assertThrows(ContractException.class, - () -> c.getDataManager(TestDataManager3.class)); - assertEquals(NucleusError.AMBIGUOUS_DATA_MANAGER_CLASS, contractException.getErrorType()); - })); + // show that the explicit class references return true + c.getDataManager(TestDataManager1.class); + c.getDataManager(TestDataManager3A.class); + c.getDataManager(TestDataManager3B.class); + c.getDataManager(TestDataManager4A.class); - pluginDataBuilder.addTestActorPlan("actor", new TestActorPlan(Double.POSITIVE_INFINITY, (c) -> { - })); + // show that zero class matching returns false + assertFalse(c.dataManagerExists(TestDataManager4B.class)); - // build the action plugin - testPluginData = pluginDataBuilder.build(); - testPlugin = TestPlugin.getTestPlugin(testPluginData); + // show that ambiguous class matching returns false + assertFalse(c.dataManagerExists(TestDataManager3.class)); - TestSimulation.builder().addPlugin(testPlugin).build().execute(); + // show that a null yields a false + assertFalse(c.dataManagerExists(null)); - // Precondition test 2 - pluginDataBuilder.addTestReportPlan("report", new TestReportPlan(0, (c) -> { - ContractException contractException = assertThrows(ContractException.class, () -> c.getDataManager(null)); - assertEquals(NucleusError.NULL_DATA_MANAGER_CLASS, contractException.getErrorType()); })); + pluginDataBuilder.addTestActorPlan("actor", new TestActorPlan(Double.POSITIVE_INFINITY, (c) -> { })); + // build the action plugin - testPluginData = pluginDataBuilder.build(); - testPlugin = TestPlugin.getTestPlugin(testPluginData); + TestPluginData testPluginData = pluginDataBuilder.build(); + Plugin testPlugin = TestPlugin.getTestPlugin(testPluginData); TestSimulation.builder().addPlugin(testPlugin).build().execute(); + } @Test