def test_state_machine_illegal_path(self): model_file = self.SIMPLE_MACHINE_DEF_FILE illegal_trigger_name = 'ILLEGAL_TRIGGER' sm, trigger_name, callback_routine = \ self._setup_state_machine_for_execution(filename=model_file) steps = [ PathStep( trigger=trigger_name, trigger_id=f'from_{sm.machine.initial}'), PathStep( trigger=illegal_trigger_name, trigger_id="ILLEGAL STEP") ] # Execute the state machine sm.execute_state_machine(input_data=steps) # Illegal path should cause duplication of last state since # transition was requested but action denied. expected_path = [sm.machine.initial, sm.state, sm.state] logging.info(f"EXPECTED PATH: {expected_path}") logging.info(f"ACTUAL PATH: {sm.path}") assert_true(isinstance(sm.path, list)) assert_equals(expected_path, sm.path)
def test_add_data(self): # Verify data is added to PathStep correctly test_data = str(uuid4()) step = PathStep(trigger=self.TRIGGER_NAME) step.add_data(data=test_data) assert_equals(step.trigger_data, test_data)
def test_add_id(self): # Verify ID is added to PathStep correctly test_id = str(uuid4()) step = PathStep(trigger=self.TRIGGER_NAME) step.add_id(step_id=test_id) assert_equals(step.id, test_id)
def test__str__does_not_crash(self): test_id = str(uuid4()) validation_ids = ['test'] expectations = [False] step = PathStep(trigger=self.TRIGGER_NAME) step.add_id(step_id=test_id) self._add_and_validate_expectations( validation_ids=validation_ids, expectations=expectations) assert_true(isinstance(str(step), str))
def build_test_case(self, test_suite: str, test_name: str) -> typing.List[PathStep]: """ Get the test case definition for the specified test suite & test case Args: test_suite (str): Name of test suite (ConfigParser section) test_name (str): Name of test case (Config Parser section option) Returns: (list[dict]) Paths for state machine with execution and validation parameters """ test_cases = self.get_possible_test_cases(test_suite) # Check if test case is defined... if test_name not in test_cases: logging.error(f"The test case '{test_name}' was not found in " f"specified suite: '{test_suite}'") return [] # Get test suite data, get the test case steps and return list ts_data = [x for x in self.data if test_suite in x][0][test_suite] test_case = [] for tc in ts_data[test_name].get(YamlPathConsts.STEPS, []): step = PathStep(trigger=list(tc.keys())[0]) # Record the trigger's unique id (if present) if YamlPathConsts.ID in tc[step.trigger]: step.add_id(tc[step.trigger][YamlPathConsts.ID]) # Save validation expectations (id corresponds to specific # validation routine associated with step and result is the # expectation) if tc[step.trigger][YamlPathConsts.EXPECTATIONS] is not None: for v_id, exp in \ tc[step.trigger][YamlPathConsts.EXPECTATIONS].items(): step.add_expectation(v_id, exp) # Save the data to passed to the trigger if provided if (tc[step.trigger][YamlPathConsts.DATA] is not None or tc[step.trigger][YamlPathConsts.DATA] != {}): step.add_data(tc[step.trigger][YamlPathConsts.DATA]) test_case.append(step) self.test_case = test_case valid_path = ValidatePaths.validate_steps(steps=self.test_case) if not valid_path: logging.error("Errors found in the path definitions. " "Returning an empty list of steps.") return self.test_case if valid_path else []
def _add_and_validate_expectations( self, validation_ids: List[str], expectations: List[bool]) -> NoReturn: # Add requested expectations step = PathStep(trigger=self.TRIGGER_NAME) for id_, expect in zip(validation_ids, expectations): step.add_expectation( validation_id=id_, expectation=expect) # Verify the expectations were added correctly (format and value) assert_equals(len(step.expectations), len(validation_ids)) for index in range(len(validation_ids)): assert_equals( step.expectations[index][PathStep.ID], validation_ids[index]) assert_equals( step.expectations[index][PathStep.EXPECTATION], expectations[index])
def test_get_expectations(self): # Verify requested expectation value is returned validation_ids = ['test_1', 'test_2'] expectations = [False, True] target_index = choice(range(len(expectations))) logging.info(f"Selecting expectation element: {target_index}") # Add expectations step = PathStep(trigger=self.TRIGGER_NAME) for id_, expect in zip(validation_ids, expectations): step.add_expectation( validation_id=id_, expectation=expect) # Get randomly selected expectation (selected from expectations added) expectation = step.get_expectation(validation_ids[target_index]) # Verify return value matches the expectation assert_equals(expectation, expectations[target_index])
def _setup_state_machine_for_execution(filename): def_file, model_cfg, model_def = setup_state_machine_definitions( filename) obj_model = ImportCheck() sm = StateMachine(data_model=model_def, object_model=obj_model) sm.configure_state_machine() # Get data about transition configuration trans_data = model_def.get_transitions(sm.machine.initial)[0] callback_routine = trans_data[SMConsts.CHANGE_STATE_ROUTINE] # Setup state machine to execute transition trigger_name = trans_data[SMConsts.TRIGGER_NAME] sm.current_step = PathStep( trigger=trigger_name, trigger_id=f'from_{sm.machine.initial}') return sm, trigger_name, callback_routine
def test_state_machine_traversal_path(self): model_file = self.SIMPLE_MACHINE_DEF_FILE sm, trigger_name, callback_routine = \ self._setup_state_machine_for_execution(filename=model_file) steps = [PathStep( trigger=trigger_name, trigger_id=f'from_{sm.machine.initial}')] sm.execute_state_machine(input_data=steps) expected_path = [sm.machine.initial, sm.state] logging.info(f"EXPECTED PATH: {expected_path}") logging.info(f"ACTUAL PATH: {sm.path}") assert_true(isinstance(sm.path, list)) assert_equals(expected_path, sm.path)
def _setup_and_execute_state_machine(self) -> Tuple[StateMachine, str, str]: """ Sets up and executes the model Returns: Tuple: state_machine (StateMachine), trigger_name (str), trigger_id (str) """ model_file = self.SIMPLE_MACHINE_DEF_FILE sm, trigger_name, callback_routine = \ self._setup_state_machine_for_execution(filename=model_file) trigger_id = f'from_{sm.machine.initial}' steps = [PathStep( trigger=trigger_name, trigger_id=trigger_id)] sm.execute_state_machine(input_data=steps) return sm, trigger_name, trigger_id
def _define_path_step(self, trigger_name: str = None, trigger_id: str = None) -> PathStep: """ Builds a simple path step with a name, id, expectations, and data Args: trigger_name (str): Name of trigger/step trigger_id (str): Unique id for trigger/step Returns: Instantiated and populated PathStep object """ trigger_name = trigger_name or self.TRIGGER_NAME trigger_id = trigger_id or self.TRIGGER_ID step = PathStep(trigger=trigger_name, trigger_id=trigger_id) step.add_data(self.STEP_DATA) for validation_id, expectation in self.EXPECTATIONS.items(): step.add_expectation(validation_id, expectation) return step