diff --git a/src/tests/test_messaging.py b/src/tests/test_messaging.py index 1e83935e00..3be2d38870 100644 --- a/src/tests/test_messaging.py +++ b/src/tests/test_messaging.py @@ -20,7 +20,7 @@ # # Integrated tests # -# Purpose: This script runs a series of test to ensure that the messaging +# Purpose: This script runs a series of test to ensure that the messaging # interface is properly set up for C and Cpp messages # Author: Benjamin Bercovici # Creation Date: June 4th, 2021 @@ -29,6 +29,10 @@ from Basilisk.architecture import bskLogging from Basilisk.architecture import messaging +from Basilisk.moduleTemplates import cppModuleTemplate +from Basilisk.utilities import SimulationBaseClass +from Basilisk.utilities import macros +import numpy as np # uncomment this line is this test is to be skipped in the global unit test run, adjust message as needed @@ -47,6 +51,7 @@ def messaging_unit_tests(): test_c_msg_subscription_check() test_cpp_2_c_msg_subscription_check() test_c_2_cpp_msg_subscription_check() + test_standalone_message_scope() @@ -56,13 +61,13 @@ def test_cpp_msg_subscription_check(): bskLogging.setDefaultLogLevel(bskLogging.BSK_WARNING) testFailCount = 0 # zero unit test result counter testMessages = [] # create empty array to store test log messages - + # Try out all the existing cpp messages - cppMessages = [ el for el in dir(messaging) if el.endswith("Msg")] - + cppMessages = [ el for el in dir(messaging) if el.endswith("Msg")] + for el in cppMessages: - + # Create three messages msgA = eval("messaging." + el + "()") msgB = eval("messaging." + el + "()") @@ -86,8 +91,8 @@ def test_cpp_msg_subscription_check(): if msgC_subscriber.isSubscribedTo(msgA) != 0: testFailCount += 1 testMessages.append(el + ": msgC_subscriber.isSubscribedTo(msgA) should be False") - - + + # Change subscription pattern msgB_subscriber.subscribeTo(msgC) # Subscribe B to C msgC_subscriber.subscribeTo(msgA) # Subscribe C to A @@ -103,8 +108,8 @@ def test_cpp_msg_subscription_check(): testFailCount += 1 testMessages.append(el + ": msgC_subscriber.isSubscribedTo(msgB) should be False") - - + + if testFailCount == 0: print("PASSED") else: @@ -122,14 +127,14 @@ def test_c_msg_subscription_check(): bskLogging.setDefaultLogLevel(bskLogging.BSK_WARNING) testFailCount = 0 # zero unit test result counter testMessages = [] # create empty array to store test log messages - + # Try out all the existing c messages - cMessages = [ el for el in dir(messaging) if el.endswith("Msg_C")] + cMessages = [ el for el in dir(messaging) if el.endswith("Msg_C")] + - for el in cMessages: - + # Create three messages msgA = eval("messaging." + el + "()") msgB = eval("messaging." + el + "()") @@ -149,8 +154,8 @@ def test_c_msg_subscription_check(): if msgC.isSubscribedTo(msgA) != 0: testFailCount += 1 testMessages.append(el + ": msgC.isSubscribedTo(msgA) should be False") - - + + # Change subscription pattern msgB.subscribeTo(msgC) # Subscribe B to C msgC.subscribeTo(msgA) # Subscribe C to A @@ -166,8 +171,8 @@ def test_c_msg_subscription_check(): testFailCount += 1 testMessages.append(el + ": msgC.isSubscribedTo(msgB) should be False") - - + + if testFailCount == 0: print("PASSED") else: @@ -176,22 +181,22 @@ def test_c_msg_subscription_check(): def test_c_2_cpp_msg_subscription_check(): - + bskLogging.setDefaultLogLevel(bskLogging.BSK_WARNING) testFailCount = 0 # zero unit test result counter testMessages = [] # create empty array to store test log messages - + # Try out all the existing messages - cppMessages = [ el for el in dir(messaging) if el.endswith("Msg")] - cMessages = [ el for el in dir(messaging) if el.endswith("Msg_C")] - + cppMessages = [ el for el in dir(messaging) if el.endswith("Msg")] + cMessages = [ el for el in dir(messaging) if el.endswith("Msg_C")] + # Find common messages common_messages = [el for el in cppMessages if el + "_C" in cMessages] for el in common_messages: - + # Create c and cpp messages msgA = eval("messaging." + el + "()") msgB = eval("messaging." + el + "()") @@ -199,11 +204,11 @@ def test_c_2_cpp_msg_subscription_check(): msgC = eval("messaging." + el + "_C()") msgD = eval("messaging." + el + "_C()") - + # Subscribe msgC.subscribeTo(msgA) # Subscribe C to A msgD.subscribeTo(msgB) # Subscribe D to B - + # Check if msgC.isSubscribedTo(msgA) != 1: testFailCount += 1 @@ -217,7 +222,7 @@ def test_c_2_cpp_msg_subscription_check(): if msgC.isSubscribedTo(msgB) != 0: testFailCount += 1 testMessages.append(el + ": msgC.isSubscribedTo(msgB) should be False") - + # Change subscription pattern msgC.subscribeTo(msgB) # Subscribe C to B msgD.subscribeTo(msgA) # Subscribe D to A @@ -236,8 +241,8 @@ def test_c_2_cpp_msg_subscription_check(): testFailCount += 1 testMessages.append(el + ": msgD.isSubscribedTo(msgB) should be False") - - + + if testFailCount == 0: print("PASSED") else: @@ -249,18 +254,18 @@ def test_cpp_2_c_msg_subscription_check(): bskLogging.setDefaultLogLevel(bskLogging.BSK_WARNING) testFailCount = 0 # zero unit test result counter testMessages = [] # create empty array to store test log messages - + # Try out all the existing messages - cppMessages = [ el for el in dir(messaging) if el.endswith("Msg")] - cMessages = [ el for el in dir(messaging) if el.endswith("Msg_C")] - + cppMessages = [ el for el in dir(messaging) if el.endswith("Msg")] + cMessages = [ el for el in dir(messaging) if el.endswith("Msg_C")] + # Find common messages common_messages = [el for el in cppMessages if el + "_C" in cMessages] for el in common_messages: - + # Create c and cpp messages msgA = eval("messaging." + el + "_C()") msgB = eval("messaging." + el + "_C()") @@ -271,7 +276,7 @@ def test_cpp_2_c_msg_subscription_check(): # Create subscribers to pair messages msgC_subscriber = msgC.addSubscriber() msgD_subscriber = msgD.addSubscriber() - + # Subscribe msgC_subscriber.subscribeTo(msgA) # Subscribe C to A msgD_subscriber.subscribeTo(msgB) # Subscribe D to B @@ -289,7 +294,7 @@ def test_cpp_2_c_msg_subscription_check(): if msgC_subscriber.isSubscribedTo(msgB) != 0: testFailCount += 1 testMessages.append(el + ": msgC_subscriber.isSubscribedTo(msgB) should be False") - + # Change subscription pattern msgC_subscriber.subscribeTo(msgB) # Subscribe C to B msgD_subscriber.subscribeTo(msgA) # Subscribe D to A @@ -308,8 +313,8 @@ def test_cpp_2_c_msg_subscription_check(): testFailCount += 1 testMessages.append(el + ": msgD_subscriber.isSubscribedTo(msgB) should be False") - - + + if testFailCount == 0: print("PASSED") else: @@ -317,6 +322,69 @@ def test_cpp_2_c_msg_subscription_check(): assert(testFailCount == 0) +def test_standalone_message_scope(): + """ + Test that subscribed messages don't get garbage collected when going out of scope + """ + bskLogging.setDefaultLogLevel(bskLogging.BSK_WARNING) + testFailCount = 0 # zero unit test result counter + testMessages = [] # create empty array to store test log messages + + # Create a sim module as an empty container + scSim = SimulationBaseClass.SimBaseClass() + + # create the simulation process + dynProcess = scSim.CreateNewProcess("dynamicsProcess") + + # create the dynamics task and specify the integration update time + dynProcess.addTask(scSim.CreateNewTask("dynamicsTask", macros.sec2nano(1.))) + + # create modules + mod1 = cppModuleTemplate.CppModuleTemplate() + mod1.ModelTag = "cppModule1" + scSim.AddModelToTask("dynamicsTask", mod1) + + # setup message recording + msgRec = mod1.dataOutMsg.recorder() + scSim.AddModelToTask("dynamicsTask", msgRec) + + # Create a local scope to test message lifetime + def addLocalStandaloneMessage(module): + """Create a stand-alone message in local scope and subscribe to it""" + msgData = messaging.CModuleTemplateMsgPayload() + msgData.dataVector = [10., 20., 30.] + msg = messaging.CModuleTemplateMsg().write(msgData) + module.dataInMsg.subscribeTo(msg) + + # Subscribe to the input message in a local scope + addLocalStandaloneMessage(mod1) + + # initialize Simulation: + scSim.InitializeSimulation() + + # configure a simulation stop time and execute the simulation run + scSim.ConfigureStopTime(macros.sec2nano(3.0)) + scSim.ExecuteSimulation() + + # Verify output matches expected values + expected = np.array([ + [11., 20., 30.], + [12., 20., 30.], + [13., 20., 30.], + [14., 20., 30.] + ]) + + if not (msgRec.dataVector == expected).all(): + testFailCount += 1 + testMessages.append("Output data does not match expected values") + + if testFailCount == 0: + print("PASSED") + else: + [print(msg) for msg in testMessages] + assert testFailCount < 1, testMessages + + if __name__ == "__main__": messaging_unit_tests()