def with_context( cls, setup_nodes: Optional[phase_collections.SequenceInitializerT], teardown_nodes: Optional[phase_collections.SequenceInitializerT] ) -> Callable[..., 'PhaseGroup']: """Create PhaseGroup creator function with setup and teardown phases. Args: setup_nodes: phases to run during the setup for the PhaseGroup returned from the created function. teardown_nodes: phases to run during the teardown for the PhaseGroup returned from the created function. Returns: Function that takes *phases and returns a PhaseGroup with the predefined setup and teardown phases, with *phases as the main phases. """ setup = phase_collections.PhaseSequence( setup_nodes) if setup_nodes else None teardown = phase_collections.PhaseSequence( teardown_nodes) if teardown_nodes else None def _context_wrapper( *phases: phase_descriptor.PhaseCallableOrNodeT ) -> 'PhaseGroup': return cls(setup=data.attr_copy(setup) if setup else None, main=phase_collections.PhaseSequence(phases), teardown=data.attr_copy(teardown) if teardown else None) return _context_wrapper
def test_nested(self): seq = phase_collections.PhaseSequence( phase_collections.PhaseSequence(phase, empty_phase)) test_rec = yield htf.Test(seq) self.assertTestPass(test_rec) self.assertPhasesOutcomeByName(test_record.PhaseOutcome.PASS, test_rec, 'phase', 'empty_phase')
def testConstruct(self): setup = _fake_phases('1') main = _fake_phases('2') teardown = _fake_phases('3') name = 'name' pg = htf.PhaseGroup(setup=setup, main=main, teardown=teardown, name=name) self.assertEqual(phase_collections.PhaseSequence(tuple(setup)), pg.setup) self.assertEqual(phase_collections.PhaseSequence(tuple(main)), pg.main) self.assertEqual(phase_collections.PhaseSequence(tuple(teardown)), pg.teardown) self.assertEqual(name, pg.name)
def testExecuteAbortable_AbortedPrior(self): self.test_exec.abort() sequence = phase_collections.PhaseSequence(_fake_phases('not-run')) self.assertEqual( test_executor._ExecutorReturn.TERMINAL, self.test_exec._execute_sequence(sequence, None, False)) self.mock_execute_node.assert_not_called()
def setUp(self): super(TestExecutorExecuteBranchTest, self).setUp() self.diag_store = diagnoses_lib.DiagnosesStore() self.mock_test_record = mock.create_autospec(test_record.TestRecord) self.mock_logger = mock.create_autospec(logging.Logger) self.test_state = mock.MagicMock( spec=test_state.TestState, plug_manager=plugs.PlugManager(), diagnoses_manager=mock.MagicMock( spec=diagnoses_lib.DiagnosesManager, store=self.diag_store), execution_uid='01234567890', test_record=self.mock_test_record, state_logger=self.mock_logger) td = test_descriptor.TestDescriptor( phase_sequence=phase_collections.PhaseSequence( phase_group.PhaseGroup()), code_info=test_record.CodeInfo.uncaptured(), metadata={}) self.test_exec = test_executor.TestExecutor( td, td.uid, None, test_descriptor.TestOptions(), run_with_profiling=False) self.test_exec.test_state = self.test_state patcher = mock.patch.object(self.test_exec, '_execute_sequence') self.mock_execute_sequence = patcher.start()
def __init__(self, *nodes: phase_descriptor.PhaseCallableOrNodeT, **metadata: Any): # Some sanity checks on special metadata keys we automatically fill in. if 'config' in metadata: raise KeyError( 'Invalid metadata key "config", it will be automatically populated.' ) self.created_time_millis = util.time_millis() self.last_run_time_millis = None self._test_options = TestOptions() self._lock = threading.Lock() self._executor = None # TODO(arsharma): Drop _flatten at some point. sequence = phase_collections.PhaseSequence(nodes) self._test_desc = TestDescriptor(sequence, htf_test_record.CodeInfo.uncaptured(), metadata) if CONF.capture_source: # Copy the phases with the real CodeInfo for them. self._test_desc.phase_sequence = ( self._test_desc.phase_sequence.load_code_info()) self._test_desc.code_info = ( htf_test_record.CodeInfo.for_module_from_stack(levels_up=2)) # Make sure configure() gets called at least once before Execute(). The # user might call configure() again to override options, but we don't want # to force them to if they want to use defaults. For default values, see # the class definition of TestOptions. if 'test_name' in metadata: # Allow legacy metadata key for specifying test name. self.configure(name=metadata['test_name']) else: self.configure()
def _initialize_group_sequence( seq: Optional[phase_collections.SequenceInitializerT] ) -> Optional[phase_collections.PhaseSequence]: if not seq: return None if isinstance(seq, phase_collections.PhaseSequence): return seq return phase_collections.PhaseSequence(seq)
def setUp(self): super(TestPhaseDescriptor, self).setUp() self._test_state = test_state.TestState( test_descriptor.TestDescriptor( phase_sequence=phase_collections.PhaseSequence(), code_info=test_record.CodeInfo.uncaptured(), metadata={}), execution_uid='', test_options=test_descriptor.TestOptions())
def testExecuteTeardown_Empty(self): self.assertEqual( test_executor._ExecutorReturn.CONTINUE, self.test_exec._execute_sequence(phase_collections.PhaseSequence( tuple()), None, True, override_message='group')) self.mock_execute_node.assert_not_called()
def testExecuteAbortable_NoPhases(self): self.assertEqual( test_executor._ExecutorReturn.CONTINUE, self.test_exec._execute_sequence(phase_collections.PhaseSequence( tuple()), None, False, override_message='main group')) self.mock_execute_node.assert_not_called()
def setUp(self): super(TestExecutorExecutePhaseGroupTest, self).setUp() self.test_state = mock.MagicMock(spec=test_state.TestState, plug_manager=plugs.PlugManager(), execution_uid='01234567890', state_logger=mock.MagicMock()) td = test_descriptor.TestDescriptor( phase_sequence=phase_collections.PhaseSequence( phase_group.PhaseGroup()), code_info=test_record.CodeInfo.uncaptured(), metadata={}) self.test_exec = test_executor.TestExecutor( td, td.uid, None, test_descriptor.TestOptions(), run_with_profiling=False) self.test_exec.test_state = self.test_state patcher = mock.patch.object(self.test_exec, '_execute_sequence') self.mock_execute_sequence = patcher.start() @phase_descriptor.PhaseOptions() def setup(): pass self._setup = phase_collections.PhaseSequence((setup, )) @phase_descriptor.PhaseOptions() def main(): pass self._main = phase_collections.PhaseSequence((main, )) @openhtf.PhaseOptions(timeout_s=30) def teardown(): pass self._teardown = phase_collections.PhaseSequence((teardown, )) self.group = phase_group.PhaseGroup(setup=self._setup, main=self._main, teardown=self._teardown, name='group')
def test_with_args(self): mock_node = mock.create_autospec(phase_nodes.PhaseNode) seq = phase_collections.PhaseSequence( nodes=(empty_phase, phase_with_args, mock_node), name='seq') updated = seq.with_args(arg1=1, ignored_arg=2) self.assertEqual(seq.name, updated.name) self.assertEqual(empty_phase, updated.nodes[0]) self.assertEqual(phase_with_args.with_args(arg1=1), updated.nodes[1]) self.assertEqual(mock_node.with_args.return_value, updated.nodes[2]) mock_node.with_args.assert_called_once_with(arg1=1, ignored_arg=2)
def testExecuteTeardown_Normal(self): self.mock_execute_node.side_effect = [ test_executor._ExecutorReturn.CONTINUE ] sequence = phase_collections.PhaseSequence(_fake_phases('normal')) all_phases = list(sequence.all_phases()) self.assertEqual( test_executor._ExecutorReturn.CONTINUE, self.test_exec._execute_sequence(sequence, None, True)) self.mock_execute_node.assert_called_once_with(all_phases[0], None, True)
def test_with_plugs(self): mock_node = mock.create_autospec(phase_nodes.PhaseNode) seq = phase_collections.PhaseSequence( nodes=(empty_phase, plug_phase, mock_node), name='seq') updated = seq.with_plugs(my_plug=ChildPlug, ignored_plug=ParentPlug) self.assertEqual(seq.name, updated.name) self.assertEqual(empty_phase, updated.nodes[0]) self.assertEqual(plug_phase.with_plugs(my_plug=ChildPlug), updated.nodes[1]) self.assertEqual(mock_node.with_plugs.return_value, updated.nodes[2]) mock_node.with_plugs.assert_called_once_with( my_plug=ChildPlug, ignored_plug=ParentPlug)
def test_apply_to_all_phases(self): mock_node = mock.create_autospec(phase_nodes.PhaseNode) seq = phase_collections.PhaseSequence( nodes=(empty_phase, plug_phase, mock_node), name='seq') updated = seq.apply_to_all_phases(_prefix_name) self.assertEqual(seq.name, updated.name) self.assertEqual(_prefix_name(empty_phase), updated.nodes[0]) self.assertEqual(_prefix_name(plug_phase), updated.nodes[1]) self.assertEqual(mock_node.apply_to_all_phases.return_value, updated.nodes[2]) mock_node.apply_to_all_phases.assert_called_once_with(_prefix_name)
def test_asdict(self): expected = { 'name': 'sequence_name', 'nodes': [{ 'name': '1' }, { 'name': '2' }], } seq = phase_collections.PhaseSequence( _create_nodes('1', '2'), name='sequence_name') self.assertEqual(expected, seq._asdict())
def _handle_phase(self, phase_desc): """Handle execution of a single test phase.""" phase_descriptor.check_for_duplicate_results(iter([phase_desc]), []) logs.configure_logging() self._initialize_plugs(phase_plug.cls for phase_plug in phase_desc.plugs) # Cobble together a fake TestState to pass to the test phase. test_options = test_descriptor.TestOptions() with mock.patch.object(plugs, 'PlugManager', new=lambda _, __: self.plug_manager): test_state_ = test_state.TestState( test_descriptor.TestDescriptor( phase_collections.PhaseSequence((phase_desc, )), phase_desc.code_info, {}), 'Unittest:StubTest:UID', test_options) test_state_.mark_test_started() test_state_.user_defined_state.update(self.phase_user_defined_state) for diag in self.phase_diagnoses: test_state_.diagnoses_manager._add_diagnosis(diag) # pylint: disable=protected-access test_state_.test_record.add_diagnosis(diag) # Save the test_state to the last_test_case attribute to give it access to # the underlying state. self.test_case.last_test_state = test_state_ # Actually execute the phase, saving the result in our return value. executor = phase_executor.PhaseExecutor(test_state_) profile_filepath = self.test_case.get_profile_filepath() # Log an exception stack when a Phase errors out. with mock.patch.object(phase_executor.PhaseExecutorThread, '_log_exception', side_effect=logging.exception): # Use _execute_phase_once because we want to expose all possible outcomes. phase_result, profile_stats = executor._execute_phase_once( phase_desc, is_last_repeat=False, run_with_profiling=profile_filepath, subtest_rec=None) if profile_filepath is not None: _merge_stats(profile_stats, profile_filepath) if phase_result.raised_exception: failure_message = phase_result.phase_result.get_traceback_string() else: failure_message = None return test_state_.test_record.phases[-1], failure_message
def test_load_code_info(self): mock_node = mock.create_autospec(phase_nodes.PhaseNode) seq = phase_collections.PhaseSequence( nodes=(empty_phase, plug_phase, mock_node), name='seq') updated = seq.load_code_info() self.assertEqual(seq.name, updated.name) phases = list(updated.all_phases()) self.assertEqual( test_record.CodeInfo.for_function(empty_phase.func), phases[0].code_info) self.assertEqual( test_record.CodeInfo.for_function(plug_phase.func), phases[1].code_info) self.assertEqual(mock_node.load_code_info.return_value, updated.nodes[2]) mock_node.load_code_info.assert_called_once_with()
def testExecuteAbortable_Terminal(self): self.mock_execute_node.side_effect = [ test_executor._ExecutorReturn.CONTINUE, test_executor._ExecutorReturn.TERMINAL ] sequence = phase_collections.PhaseSequence( _fake_phases('normal', 'abort', 'not_run')) all_phases = list(sequence.all_phases()) self.assertEqual( test_executor._ExecutorReturn.TERMINAL, self.test_exec._execute_sequence(sequence, None, False)) self.assertEqual([ mock.call(all_phases[0], None, False), mock.call(all_phases[1], None, False) ], self.mock_execute_node.call_args_list)
def setUp(self): super(TestTestApi, self).setUp() patcher = mock.patch.object( test_record.PhaseRecord, 'record_start_time', return_value=11235) self.mock_record_start_time = patcher.start() self.addCleanup(patcher.stop) self.test_descriptor = test_descriptor.TestDescriptor( phase_collections.PhaseSequence((test_phase,)), test_record.CodeInfo.uncaptured(), {'config': {}}) self.test_state = test_state.TestState(self.test_descriptor, 'testing-123', test_descriptor.TestOptions()) self.test_record = self.test_state.test_record self.running_phase_state = test_state.PhaseState.from_descriptor( test_phase, self.test_state, logging.getLogger()) self.test_state.running_phase_state = self.running_phase_state self.test_api = self.test_state.test_api
def testExecuteAbortable_AbortedDuring(self): def execute_node(node, subtest_rec, in_teardown): del node # Unused. del subtest_rec # Unused. del in_teardown # Unused. self.test_exec.abort() return test_executor._ExecutorReturn.TERMINAL self.mock_execute_node.side_effect = execute_node sequence = phase_collections.PhaseSequence( _fake_phases('abort', 'not-run')) all_phases = list(sequence.all_phases()) self.assertEqual( test_executor._ExecutorReturn.TERMINAL, self.test_exec._execute_sequence(sequence, None, False)) self.mock_execute_node.assert_called_once_with(all_phases[0], None, False)
def testExecuteTeardown_Terminal(self): def execute_node(node, subtest_rec, in_teardown): del subtest_rec # Unused. del in_teardown # Unused. if node.name == 'error': return test_executor._ExecutorReturn.TERMINAL return test_executor._ExecutorReturn.CONTINUE self.mock_execute_node.side_effect = execute_node sequence = phase_collections.PhaseSequence( _fake_phases('error', 'still-run')) all_phases = list(sequence.all_phases()) self.assertEqual( test_executor._ExecutorReturn.TERMINAL, self.test_exec._execute_sequence(sequence, None, True)) self.assertEqual([ mock.call(all_phases[0], None, True), mock.call(all_phases[1], None, True) ], self.mock_execute_node.call_args_list)
def setUp(self): super(TestExecutorExecuteSequencesTest, self).setUp() self.test_state = mock.MagicMock(spec=test_state.TestState, plug_manager=plugs.PlugManager(), execution_uid='01234567890', state_logger=mock.MagicMock()) td = test_descriptor.TestDescriptor( phase_sequence=phase_collections.PhaseSequence( phase_group.PhaseGroup()), code_info=test_record.CodeInfo.uncaptured(), metadata={}) self.test_exec = test_executor.TestExecutor( td, td.uid, None, test_descriptor.TestOptions(), run_with_profiling=False) self.test_exec.test_state = self.test_state patcher = mock.patch.object(self.test_exec, '_execute_node') self.mock_execute_node = patcher.start()
def _context_wrapper( *phases: phase_descriptor.PhaseCallableOrNodeT ) -> 'PhaseGroup': return cls(setup=data.attr_copy(setup) if setup else None, main=phase_collections.PhaseSequence(phases), teardown=data.attr_copy(teardown) if teardown else None)
def test_check_duplicates__nested_dupes(self): seq = phase_collections.PhaseSequence( nodes=(phase_collections.Subtest( 'dupe', nodes=(phase_collections.Subtest('dupe'),)),)) with self.assertRaises(phase_collections.DuplicateSubtestNamesError): phase_collections.check_for_duplicate_subtest_names(seq)
def test_all_phases(self): mock_node = mock.create_autospec(phase_nodes.PhaseNode) seq = phase_collections.PhaseSequence( nodes=(empty_phase, plug_phase, mock_node), name='seq') self.assertEqual([empty_phase, plug_phase], list(seq.all_phases()))
def test_init__nodes_and_args(self): with self.assertRaises(ValueError): phase_collections.PhaseSequence(phase, nodes=tuple(_create_nodes('1')))
def test_init__single_callable(self): expected = phase_collections.PhaseSequence( nodes=tuple((phase_descriptor.PhaseDescriptor.wrap_or_copy(phase),))) self.assertEqual(expected, phase_collections.PhaseSequence(phase))
def test_init__extra_kwargs(self): with self.assertRaises(ValueError): phase_collections.PhaseSequence(other=1)