def test_simple(caplog): """Do all copy strategies possible in RAFCON and check if all Objects have different memory location to secure reference free assignments from origin to new state. :param caplog: :return: """ testing_utils.dummy_gui(None) print("start test simple") # create testbed testing_utils.initialize_environment( gui_already_started=False, gui_config={ 'HISTORY_ENABLED': False, 'AUTO_BACKUP_ENABLED': False }, ) [state, sm_model, state_dict] = create_models() run_copy_test(sm_model) run_copy_performance_test_and_check_storage_copy(sm_model) # currently destroy doesn't do anything if auto_backup is disabled sm_model.destroy() import rafcon rafcon.core.singleton.state_machine_manager.delete_all_state_machines() [state, sm_model, state_dict] = create_models_concurrency() run_copy_test(sm_model) run_copy_performance_test_and_check_storage_copy(sm_model) # currently destroy doesn't do anything if auto_backup is disabled sm_model.destroy() rafcon.core.singleton.state_machine_manager.delete_all_state_machines() # wait until state machine model is destroyed testing_utils.wait_for_gui() testing_utils.shutdown_environment(caplog=caplog, unpatch_threading=False) print("test simple finished")
def test_on_clean_storing_with_name_in_path(caplog): testing_utils.dummy_gui(None) testing_utils.initialize_environment(gui_config={ 'HISTORY_ENABLED': False, 'AUTO_BACKUP_ENABLED': False }, gui_already_started=False) path_old_format = testing_utils.get_test_sm_path( os.path.join("unit_test_state_machines", "id_to_name_plus_id_storage_format_test_do_not_update")) path_new_format = os.path.join( testing_utils.get_unique_temp_path(), "id_to_name_plus_id_storage_format_test_do_not_update") # gui imports better after initialization from rafcon.gui.models.state_machine import StateMachineModel shutil.copytree(path_old_format, path_new_format) from rafcon.core.storage import storage sm = storage.load_state_machine_from_path(path_new_format) check_state_recursively_if_state_scripts_are_valid(sm.root_state) sm.base_path = path_new_format sm_m = StateMachineModel(sm) try: on_save_activate(sm_m, logger) check_that_all_files_are_there(sm, with_print=False) check_id_and_name_plus_id_format(path_old_format, path_new_format, sm_m) finally: testing_utils.shutdown_environment(caplog=caplog, unpatch_threading=False)
def _test_initial_default_config_folder_generation(): """ Test core.start.py and gui.start.py script run on console which should initiate the config folder. """ # TODO: this test is broken # when specifying a config path that does not exist, RAFCON does not start # Yet, the tests wants to see the opposite. This hasen't failed, yet, as the implementation was wrong: # The ~/.config/rafcon folder was moved to ~/.config/rafcon/rafcon_backup testing_utils.dummy_gui(None) user_config_folder = testing_utils.RAFCON_TEMP_PATH_CONFIGS backup_user_config_folder = os.path.join(constants.RAFCON_TEMP_PATH_BASE, 'rafcon_backup') try: if os.path.exists(user_config_folder): shutil.move(user_config_folder, backup_user_config_folder) test_start_script_open() assert os.path.exists(user_config_folder) shutil.rmtree(user_config_folder) test_start_script_print_help_with_gui() assert os.path.exists(user_config_folder) finally: if os.path.exists(user_config_folder): shutil.rmtree(user_config_folder) if os.path.exists(backup_user_config_folder): shutil.move(backup_user_config_folder, user_config_folder)
def gui(request, caplog): parameters = {} if not hasattr(request, "param") else request.param with_gui = parameters.get("with_gui", True) config = { parameter_name: parameters.get(parameter_name) for parameter_name in ["core_config", "gui_config", "runtime_config", "libraries"] } utils.dummy_gui(caplog) if with_gui: utils.run_gui(**deepcopy(config)) else: utils.initialize_environment(gui_already_started=False, **deepcopy(config)) gui_tester = GUITester(with_gui, config) yield gui_tester try: if with_gui: utils.close_gui() finally: utils.shutdown_environment( caplog=caplog, unpatch_threading=with_gui, expected_warnings=gui_tester.expected_warnings, expected_errors=gui_tester.expected_errors) gui_tester.post_test and gui_tester.post_test()
def test_outcome_property_modifications_history(caplog): ################## # outcome properties # change name testing_utils.dummy_gui(None) testing_utils.initialize_environment(gui_config={ 'AUTO_BACKUP_ENABLED': False, 'HISTORY_ENABLED': True }, gui_already_started=False) sm_model, state_dict = create_state_machine_m() #################################################### # modify outcome and generate in previous a observer for state_name in ["Nested", "Nested2"]: state_path = state_dict[state_name].get_path() outcome_ids = list(state_dict[state_name].outcomes.keys()) for outcome_id in outcome_ids: state = sm_model.state_machine.get_state_by_path(state_path) if outcome_id >= 0: outcome = state.outcomes[outcome_id] _, _ = perform_history_action(outcome.__setattr__, "name", "new_name_" + str(outcome_id)) testing_utils.shutdown_environment(caplog=caplog, unpatch_threading=False)
def test_start_script_valid_rmpm_env(): """Tests the execution of ``rafcon_core`` in an environment created by RMPM """ testing_utils.dummy_gui(None) import distutils.spawn rmpm_env = os.environ.copy() rmpm_env[ "PATH"] = "/volume/software/common/packages/rmpm/latest/bin/{}:".format( os.getenv("DLRRM_HOST_PLATFORM", "osl42-x86_64")) + rmpm_env["PATH"] if not distutils.spawn.find_executable("rmpm_do"): print("Could not find rmpm_do, skipping test") return start_path = testing_utils.get_test_sm_path( join("unit_test_state_machines", "start_script_test")) config = join(testing_utils.TESTS_PATH, "assets", "configs", "valid_config", "config.yaml") cmd = "eval `rmpm_do env --env-format=embed_sh sw.common.rafcon` && rafcon_core -o {0} -c {1}" \ "".format(start_path, config) print("\ntest_start_script_valid_config: \n", cmd) rafcon_process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, env=rmpm_env) rafcon_process.wait() output = rafcon_process.communicate()[0] print("LOG: \n", output) assert rafcon_process.returncode == 0
def test_value_retrieval(): testing_utils.dummy_gui(None) from rafcon.gui.mygaphas.utils.cache.value_cache import ValueCache cache = ValueCache() cache.store_value("a", 1, {}) assert 1 == cache.get_value("a", {}) assert None is cache.get_value("a", {"par": 2}) cache.store_value("b", 2, {"x": 1, "y": 2}) assert 2 == cache.get_value("b", {"x": 1, "y": 2}) assert None is cache.get_value("b", {}) assert None is cache.get_value("b", {"par": 2}) assert None is cache.get_value("b", {"x": 2, "y": 2}) assert None is cache.get_value("b", {"x": 1, "y": 2, "z": 3}) assert None is cache.get_value("b", {"x": 1}) cache.store_value("b", 3, {"x": 1, "y": 2}) assert 3 == cache.get_value("b", {"x": 1, "y": 2}) cache.store_value("b", 4, {"x": 2, "y": 1}) assert 4 == cache.get_value("b", {"x": 2, "y": 1}) assert 3 is cache.get_value("b", {"x": 1, "y": 2}) cache.empty() assert None is cache.get_value("a", {}) assert None is cache.get_value("b", {"x": 2, "y": 1}) assert None is cache.get_value("b", {"x": 1, "y": 2})
def test_simple_undo_redo(caplog): testing_utils.dummy_gui(None) testing_utils.initialize_environment(gui_config={ 'AUTO_BACKUP_ENABLED': False, 'HISTORY_ENABLED': True }, gui_already_started=False) state_machine_m, state_dict = create_state_machine_m() state1 = ExecutionState('state1', state_id='STATE1') state2 = ExecutionState('state2', state_id='STATE2') state3 = ExecutionState('state2', state_id='STATE2') state4 = ExecutionState('state2', state_id='STATE2') state_machine_m.root_state.state.add_state(state1) state_machine_m.root_state.state.add_state(state2) state_machine_m.root_state.state.add_state(state3) state_machine_m.root_state.state.add_state(state4) assert len(state_machine_m.history.modifications) == 5 perform_multiple_undo(2) perform_multiple_redo(1) perform_multiple_redo(1) assert len(state_machine_m.history.modifications) == 5 testing_utils.shutdown_environment(caplog=caplog, unpatch_threading=False, expected_errors=0)
def test_storage_with_gui(with_gui, caplog): print("test storage with gui", with_gui) testing_utils.dummy_gui(None) if with_gui: testing_utils.run_gui(gui_config={ 'HISTORY_ENABLED': False, 'AUTO_BACKUP_ENABLED': False }) else: testing_utils.initialize_environment(gui_config={ 'HISTORY_ENABLED': False, 'AUTO_BACKUP_ENABLED': False }, gui_already_started=False) e = None try: save_state_machine(with_gui) except Exception as e: pass finally: if with_gui: testing_utils.close_gui() testing_utils.shutdown_environment(caplog=caplog) else: testing_utils.shutdown_environment(caplog=caplog, unpatch_threading=False) if e: raise e print("test storage with gui {0} finished".format(with_gui))
def test_core_create_folder(monkeypatch): """Tests `create_folder_cmd_line` function from `rafcon.core.interface`""" testing_utils.dummy_gui(None) print("execute test_core_create_folder") import rafcon.core.interface as core_interface # replaces raw_input by an expression that returns RAFCON_TEMP_PATH_TEST_BASE monkeypatch.setattr(core_interface, 'input', lambda _: RAFCON_TEMP_PATH_TEST_BASE) # Return user input assert core_interface.create_folder_cmd_line( "query") == RAFCON_TEMP_PATH_TEST_BASE # Return user input despite default path given assert core_interface.create_folder_cmd_line( "query", "/home") == RAFCON_TEMP_PATH_TEST_BASE assert core_interface.create_folder_cmd_line( "query", "new", "/home") == RAFCON_TEMP_PATH_TEST_BASE # replaces raw_input by an expression that returns "" monkeypatch.setattr(core_interface, 'input', lambda _: "") # Return None if no user input and no default path assert core_interface.create_folder_cmd_line("query") is None # Return default path if no user input is given assert core_interface.create_folder_cmd_line( "query", "new_folder", RAFCON_TEMP_PATH_TEST_BASE) == os.path.join(RAFCON_TEMP_PATH_TEST_BASE, "new_folder") # Return None if no user input and default path cannot be created (without root permissions) # in some ci environments the path "/root/not/writable" is writable # assert core_interface.create_folder_cmd_line("query", "new_folder", "/root/not/writable") is None # Return None if no user input and insufficient path information given assert core_interface.create_folder_cmd_line("query", "new_folder") is None
def test_multiple_future_element(): testing_utils.dummy_gui(None) from rafcon.core.states.hierarchy_state import HierarchyState from rafcon.core.states.execution_state import ExecutionState from rafcon.gui.models.state import StateModel from rafcon.gui.models.container_state import ContainerStateModel parent_state = HierarchyState() parent_state_m = ContainerStateModel(parent_state) child_state_a = ExecutionState("A") child_state_a_m = StateModel(child_state_a) child_state_b = ExecutionState("B") child_state_b_m = StateModel(child_state_b) parent_state_m.expected_future_models.add(child_state_a_m) parent_state_m.expected_future_models.add(child_state_b_m) parent_state.add_state(child_state_a) assert len(parent_state_m.states) == 1 new_child_state_a_m = list(parent_state_m.states.values())[0] assert new_child_state_a_m is child_state_a_m assert new_child_state_a_m.core_element is child_state_a assert len(parent_state_m.expected_future_models) == 1 parent_state.add_state(child_state_b) assert len(parent_state_m.states) == 2 new_child_states_m = list(parent_state_m.states.values()) assert new_child_states_m[0] is child_state_b_m or new_child_states_m[ 1] is child_state_b_m assert new_child_states_m[ 0].core_element is child_state_b or new_child_states_m[ 1].core_element is child_state_b assert len(parent_state_m.expected_future_models) == 0
def test_meta_list_modification(): testing_utils.dummy_gui(None) from rafcon.gui.models.meta import MetaModel meta_m = MetaModel() meta_data = meta_m.set_meta_data_editor("list", [1, 2, 3]) assert meta_data["list"] == [1, 2, 3] meta_data = meta_m.set_meta_data_editor("list.0", 4) assert meta_data["list"] == [4, 2, 3]
def test_meta_initialization(): testing_utils.dummy_gui(None) from rafcon.gui.models.meta import MetaModel meta_m = MetaModel(meta={"1": 2, "2": 1}) assert meta_m.meta == {"1": 2, "2": 1} meta_m = MetaModel(meta={'gui': {'editor_gaphas': {"1": 2, "2": 1}}}) meta_data = meta_m.get_meta_data_editor() assert meta_data == {"1": 2, "2": 1}
def test_name(): testing_utils.dummy_gui(None) from rafcon.core.states.state import State from rafcon.gui.models.state import StateModel state = State() state_m = StateModel(state, parent=None) state_m.meta["gui"]["editor_opengl"]["size"] = (96, 150) meta_data = state_m.get_meta_data_editor(for_gaphas=True) assert meta_data["name"]["rel_pos"] == (8, 8) assert meta_data["name"]["size"] == (80, 12)
def test_state_rel_pos(use_gaphas): testing_utils.dummy_gui(None) from rafcon.core.states.state import State from rafcon.gui.models.state import StateModel state = State() state_m = StateModel(state, parent=None) state_m.meta["gui"]["editor_opengl" if use_gaphas else "editor_gaphas"][ "rel_pos"] = (1, 2) meta_data = state_m.get_meta_data_editor(for_gaphas=use_gaphas) assert meta_data["rel_pos"] == (1, -2)
def test_meta_setter_return_value(): testing_utils.dummy_gui(None) from rafcon.gui.models.meta import MetaModel meta_m = MetaModel() meta_data = meta_m.set_meta_data_editor("key", "value") assert meta_data["key"] == "value" meta_data = meta_m.set_meta_data_editor("key2", "value2") assert meta_data["key"] == "value" assert meta_data["key2"] == "value2"
def test_transition_waypoints(use_gaphas): testing_utils.dummy_gui(None) from rafcon.core.state_elements.transition import Transition from rafcon.gui.models.transition import TransitionModel transition = Transition(None, 0, None, 0, None) transition_m = TransitionModel(transition, parent=None) transition_m.meta["gui"][ "editor_opengl" if use_gaphas else "editor_gaphas"]["waypoints"] = [ (1, 2), (-1, 3) ] meta_data = transition_m.get_meta_data_editor(for_gaphas=use_gaphas) assert meta_data["waypoints"] == [(1, -2), (-1, -3)]
def test_editor_setter_getter_conversion(use_gaphas): testing_utils.dummy_gui(None) from rafcon.gui.models.meta import MetaModel meta_m = MetaModel() meta_m.meta["gui"]["editor_opengl" if use_gaphas else "editor_gaphas"][ "test"] = (1, 2) meta_data = meta_m.get_meta_data_editor(for_gaphas=use_gaphas) assert meta_data["test"] == (1, 2) assert_single_editor_meta_data(meta_m, gaphas=use_gaphas) assert meta_m.meta["gui"][ "editor_gaphas" if use_gaphas else "editor_opengl"]["test"] == (1, 2)
def test_slim_observer(caplog): testing_utils.dummy_gui(None) test_observer = ObserverTest() test_observer.test_observable.first_var = 20.0 assert test_observer.test_value == 20 test_observer.test_observable.complex_method(1, 3, "Hello world") assert test_observer.test_observable.observable_test_var == 4 assert test_observer.test_value2 == 4 assert test_observer.test_value3 == 30 testing_utils.assert_logger_warnings_and_errors(caplog)
def test_input_opengl2gaphas(): testing_utils.dummy_gui(None) from rafcon.core.states.state import State from rafcon.gui.models.state import StateModel state = State() state.add_input_data_port("in", int, 0) state_m = StateModel(state, parent=None) state_m.meta["gui"]["editor_opengl"]["size"] = (100, 100) state_m.get_meta_data_editor(for_gaphas=True) input_m = state_m.input_data_ports[0] input_m.meta["gui"]["editor_opengl"]["inner_rel_pos"] = (20, -30) rel_pos = input_m.get_meta_data_editor(for_gaphas=True)["rel_pos"] assert rel_pos == (0, 30)
def test_output_gaphas2opengl(): testing_utils.dummy_gui(None) from rafcon.core.states.state import State from rafcon.gui.models.state import StateModel state = State() state.add_output_data_port("out", int, 0) state_m = StateModel(state, parent=None) state_m.meta["gui"]["editor_gaphas"]["size"] = (100, 100) state_m.get_meta_data_editor(for_gaphas=False) output_m = state_m.output_data_ports[0] output_m.meta["gui"]["editor_gaphas"]["rel_pos"] = (100, 50) rel_pos = output_m.get_meta_data_editor(for_gaphas=False)["inner_rel_pos"] assert rel_pos == (100, -50)
def test_scoped_variable_opengl2gaphas(): testing_utils.dummy_gui(None) from rafcon.core.states.hierarchy_state import HierarchyState from rafcon.gui.models.container_state import ContainerStateModel state = HierarchyState() state.add_scoped_variable("sv", int, 0) state_m = ContainerStateModel(state, parent=None) state_m.meta["gui"]["editor_opengl"]["size"] = (100, 100) state_m.get_meta_data_editor(for_gaphas=True) scoped_var_m = state_m.scoped_variables[0] scoped_var_m.meta["gui"]["editor_opengl"]["inner_rel_pos"] = (70, 30) rel_pos = scoped_var_m.get_meta_data_editor(for_gaphas=True)["rel_pos"] assert rel_pos == (70, 0)
def test_output_port_modify(caplog): ################## # output_data_port properties # change name # change data_type # change default_value # change datatype # create testbed testing_utils.dummy_gui(None) testing_utils.initialize_environment(gui_config={ 'AUTO_BACKUP_ENABLED': False, 'HISTORY_ENABLED': True }, gui_already_started=False) sm_model, state_dict = create_state_machine_m() nested_state = state_dict['Nested2'] new_output_data_port_id, nested_state = perform_history_action( nested_state.add_output_data_port, name='new_output', data_type='str') ################################ # check for modification of name _, nested_state = perform_history_action( nested_state.output_data_ports[new_output_data_port_id].__setattr__, "name", "changed_new_output_name") ##################################### # check for modification of data_type _, nested_state = perform_history_action( nested_state.output_data_ports[new_output_data_port_id].__setattr__, "data_type", "int") ######################################### # check for modification of default_value _, nested_state = perform_history_action( nested_state.output_data_ports[new_output_data_port_id].__setattr__, "default_value", 5) ########################################### # check for modification of change_datatype _, nested_state = perform_history_action( nested_state.output_data_ports[new_output_data_port_id]. change_data_type, data_type='str', default_value='awesome_tool') testing_utils.shutdown_environment(caplog=caplog, unpatch_threading=False)
def test_gui_create_folder(monkeypatch): """Tests `create_folder` function from `rafcon.core.interface`""" testing_utils.dummy_gui(None) print("execute test_gui_create_folder") import rafcon.gui.interface as gui_interface import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk class PatchedFileChooserDialog(Gtk.FileChooserDialog): """Subclass for FileChooserDialog FileChooserDialog cannot be monkey-patched directly. It must first be replaced by a subclass, which is this one. """ pass # prepare FileChooserDialog for monkey-patching monkeypatch.setattr(Gtk, "FileChooserDialog", PatchedFileChooserDialog) # replaces run by an expression that returns Gtk.ResponseType.OK monkeypatch.setattr(Gtk.FileChooserDialog, 'run', lambda _: Gtk.ResponseType.OK) # replaces get_filename by an expression that returns "/tmp" monkeypatch.setattr(Gtk.FileChooserDialog, 'get_filename', lambda _: RAFCON_TEMP_PATH_TEST_BASE) # Return user input assert gui_interface.create_folder("query") == RAFCON_TEMP_PATH_TEST_BASE # Return user input despite default path given assert gui_interface.create_folder("query", "/home") == RAFCON_TEMP_PATH_TEST_BASE assert gui_interface.create_folder("query", "new", "/home") == RAFCON_TEMP_PATH_TEST_BASE # replaces run by an expression that returns Gtk.ResponseType.CANCEL monkeypatch.setattr(Gtk.FileChooserDialog, 'run', lambda _: Gtk.ResponseType.CANCEL) # Return None if no user input and no default path assert gui_interface.create_folder("query") is None # Return default path if no user input is given assert gui_interface.create_folder( "query", "new_folder", RAFCON_TEMP_PATH_TEST_BASE) == os.path.join(RAFCON_TEMP_PATH_TEST_BASE, "new_folder") # Return None if no user input and default path cannot be created (without root permissions) # in some ci environments the path "/root/not/writable" is writable # assert gui_interface.create_folder("query", "new_folder", "/root/not/writable") is None # Return None if no user input and insufficient path information given assert gui_interface.create_folder("query", "new_folder") is None
def test_default(): testing_utils.dummy_gui(None) from rafcon.core.states.hierarchy_state import HierarchyState from rafcon.core.states.execution_state import ExecutionState from rafcon.gui.models.container_state import ContainerStateModel parent_state = HierarchyState() parent_state_m = ContainerStateModel(parent_state) child_state_a = ExecutionState("A") parent_state.add_state(child_state_a) assert len(parent_state_m.states) == 1 child_state_a_m = list(parent_state_m.states.values())[0] assert child_state_a_m.core_element is child_state_a
def test_start_script_valid_config(): """ Test rafcon_core console call which run a rafcon instance with handed config.yaml file, open a state machine, run it and final checks the output file on consistency. """ testing_utils.dummy_gui(None) script = join(testing_utils.RAFCON_BIN_PATH, "rafcon_core") start_path = testing_utils.get_test_sm_path( join("unit_test_state_machines", "start_script_test")) config = join(testing_utils.TESTS_PATH, "assets", "configs", "valid_config", "config.yaml") output = str( subprocess.check_output([script, '-o', start_path, '-c', config])) print("\ntest_start_script_valid_config") assert "enter state_1" in output assert "enter state_2" in output
def test_start_script_print_help_with_gui(): """ Test ``rafcon`` console call which run a RAFCON instance and let it print the helper message and checks if the process terminates correctly. """ testing_utils.dummy_gui(None) script = join(testing_utils.RAFCON_PATH, "gui", "start.py") # start_path = testing_utils.get_test_sm_path(join("unit_test_state_machines", "start_script_test")) # cmd = "%s -o %s" % (script, start_path) cmd = sys.executable + " " + script + " -h" print("\ntest_start_script_open_with_gui: ", cmd) rafcon_gui_process = subprocess.Popen(cmd, shell=True) print("process PID: ", rafcon_gui_process.pid) # rafcon_gui_process.terminate() rafcon_gui_process.wait() assert rafcon_gui_process.returncode == 0
def test_state_property_deletion(): testing_utils.dummy_gui(None) from rafcon.core.states.state import State from rafcon.gui.models.state import StateModel state = State() state_m = StateModel(state, parent=None) state_m.meta["gui"]["editor_gaphas"]["income"]["rel_pos"] = (0, 50) state_m.meta["gui"]["editor_gaphas"]["name"]["rel_pos"] = (10, 10) state_m.meta["gui"]["editor_gaphas"]["name"]["size"] = (200, 100) meta_data = state_m.get_meta_data_editor(for_gaphas=False) assert "income" not in meta_data assert "income" not in state_m.meta["gui"]["editor_gaphas"] assert "income" not in state_m.meta["gui"]["editor_opengl"] assert "name" not in meta_data assert "name" not in state_m.meta["gui"]["editor_gaphas"] assert "name" not in state_m.meta["gui"]["editor_opengl"]
def test_state_machine_baking(caplog): testing_utils.dummy_gui(caplog) testing_utils.run_gui( gui_config={ 'HISTORY_ENABLED': False, 'AUTO_BACKUP_ENABLED': False }, libraries={ 'unit_test_state_machines': testing_utils.get_test_sm_path("unit_test_state_machines") }) try: trigger_baking_commands() finally: testing_utils.close_gui() testing_utils.shutdown_environment(caplog=caplog)
def test_start_script_state(): """ Test core.start.py script run by python call which open a state machine, run from a specific state and final checks the output file on consistency. """ testing_utils.dummy_gui(None) script = join(testing_utils.RAFCON_PATH, "core", "start.py") start_path = testing_utils.get_test_sm_path( join("unit_test_state_machines", "start_script_test")) state_path = "UTUOSC/AHWBOG" print(start_path) output = str( subprocess.check_output([ sys.executable, script, '-o', start_path, '-s', state_path, '-c', testing_utils.RAFCON_TEMP_PATH_CONFIGS ])) print("\ntest_start_script_state") assert "enter state_1" not in output assert "enter state_2" in output