def setUp(self): self.component_manager = ComponentManager() self.component_manager.clear_component_registry() component(scope='session')(TestTestRunnerComponents.Verifier) self.load_components() self.verifier = TestTestRunnerComponents.Verifier() self.parent_scope = Scope('session', None) self.parent_scope.register_instance( _InstanceId(TestTestRunnerComponents.Verifier, ()), self.verifier) self.run_queue = [] self.messagebus = Mock() def send_request(message_id, endpoint_id=None, entities=None, data=None): futures = Mock() if message_id == SCHEDULE_NEXT_TEST: future = Mock() if self.run_queue: future.result.return_value = self.run_queue.pop(0) else: future.result.return_value = None futures.wait.return_value = [future] return futures self.messagebus.send_request.side_effect = send_request self.tr = TestRunner(self.messagebus, Factory(self.component_manager), 'suite-name', parent_scope=self.parent_scope)
def test_throws_on_unexpected_exit_code(self): with _create_harness(ConfigManager()) as harness: scope = Scope(name='myscope') exec = harness.component_factory.call(DockerContainerExec, scope) harness.node._container.exec.return_value = ('stdout', 'stderr', 1) with self.assertRaises(DockerError): exec.send_line('command', expected_exit_code=0)
def init_component_handling(self, components): self.component_registry = create_registry() self.component_manager = ComponentManager(self.component_registry) self.component_factory = Factory(self.component_manager) self.messagebus = MessageBus(self.component_factory, Scope('session')) components.append( ComponentMock(name='ComponentFactory', mock=self.component_factory)) components.append( ComponentMock(name='MessageBus', mock=self.messagebus)) components.append(ComponentMock(name='Config', mock=self.config)) components.append( ComponentMock(name='ComponentManager', mock=self.component_manager)) components.append( ComponentMock(name='ExtensionManager', mock=MagicMock())) for comp in components: if type(comp) == ComponentMock: component(name=comp.name, scope=comp.scope, can=comp.can, provided_by_extension=comp.provided_by_extension)( comp, self.component_manager) else: self.component_manager.register_component(comp)
def test_with_extended_process_information(self): with _create_harness(ConfigManager()) as harness: scope = Scope(name='myscope') exec = harness.component_factory.call(DockerContainerExec, scope) harness.node._container.exec.return_value = ('stdout', 'stderr', 0) self.assertEqual( exec.send_line('command', extended_process_information=True), ('stdout', 'stderr', 0))
def test_maximum_config(self): config = ConfigManager() config.set(SUT, ['mysut']) config.set(SUT_DOCKER_IMAGE_ID, 'myimage', entity='mysut') config.set(DOCKER_IMAGES_IDS, ['myimage', 'myotherimage']) config.set(DOCKER_IMAGES_REPOSITORY, 'repository', entity='myimage') config.set(DOCKER_IMAGES_TAG, 'v1', entity='myimage') config.set(DOCKER_IMAGES_ENVIRONMENT, ['KEY=value'], entity='myimage') config.set(DOCKER_IMAGES_HOSTNAME, 'myhostname', entity='myimage') config.set(DOCKER_IMAGES_MOUNT_POINTS, [ 'type=tmpfs,target=/foo', 'type=volume,source=myvolume,target=/bar', 'type=bind,source=/foo,target=/bar,readonly' ], entity='myimage') config.set(DOCKER_IMAGES_NETWORK, 'mynetwork', entity='myimage') config.set(DOCKER_IMAGES_REPOSITORY, 'otherrepository', entity='myotherimage') config.set(DOCKER_IMAGES_TAG, 'v2', entity='myotherimage') config.set(DOCKER_IMAGE_PULL, False) config.set(DOCKER_IMAGE_REGISTRY, 'registry/') config.set(DOCKER_IMAGE_STOP_TIMEOUT, 5) config.set(DOCKER_KEEP_RUNNING, True) with patch('virt.docker.Docker'): with _create_harness(config) as harness: harness.sut.entity = 'mysut' scope = Scope(name='myscope') node = harness.component_factory.call(DockerContainerNode, scope) self.assertEqual(node._image_entity, 'myimage') self.assertEqual(node._repository, 'repository') self.assertEqual(node._tag, 'v1') self.assertEqual(node._environment, {'KEY': 'value'}) self.assertEqual(node._hostname, 'myhostname') self.assertEqual(node._mounts[0]['Source'], None) self.assertEqual(node._mounts[0]['Target'], '/foo') self.assertEqual(node._mounts[0]['Type'], 'tmpfs') self.assertEqual(node._mounts[0]['ReadOnly'], False) self.assertEqual(node._mounts[1]['Source'], 'myvolume') self.assertEqual(node._mounts[1]['Target'], '/bar') self.assertEqual(node._mounts[1]['Type'], 'volume') self.assertEqual(node._mounts[1]['ReadOnly'], False) self.assertEqual(node._mounts[2]['Source'], '/foo') self.assertEqual(node._mounts[2]['Target'], '/bar') self.assertEqual(node._mounts[2]['Type'], 'bind') self.assertEqual(node._mounts[2]['ReadOnly'], True) self.assertEqual(node._networkname, 'mynetwork') self.assertEqual(node._image_name, 'repository:v1') self.assertEqual(node._timeout, 5) self.assertFalse(node._pull) self.assertEqual(node._registry, 'registry/') self.assertTrue(node._keep_running)
def test_make_forwards_all_exceptions(self): docker_run = Mock() scope = Scope('scope') with create_harness(docker_run) as harness: application = Mock() application.config = harness.config docker_run.run_in_docker.side_effect = Exception() with self.assertRaises(Exception): harness.component_factory.call(make, scope, application)
def test_filter_out_component_with_shorter_scope_than_parent(self): @component(name='A', scope='long', component_manager=self.component_manager) def a1(): pass @component(name='A', scope='short', component_manager=self.component_manager) def a2(): pass @component(name='B', scope='long', component_manager=self.component_manager) @requires(a='A') def b(): pass @requires(b='B') def test(b): pass long = Scope('long') short = Scope('short', parent=long) dependency_graph = self.builder.create_dependency_graph( test, short, None) dependency_graph.select_scopes(short) dependency_graph.remove_with_shorter_scope_than_parent(short) self.assertEqual(dependency_graph._root.callable, test) self.assertEqual(dependency_graph._root.requirements['b'].argument, 'b') callable_b = dependency_graph._root.requirements['b'].callables[0] self.assertEqual(callable_b.callable.__name__, 'b') self.assertEqual(callable_b.requirements['a'].argument, 'a') self.assertEqual( callable_b.requirements['a'].callables[0].callable.__name__, 'a1') self.assertEqual(len(callable_b.requirements['a'].callables), 1)
def test_make_triggers_pre_make_event_with_make_arguments_as_data(self): docker_run = Mock() scope = Scope('scope') with create_harness(docker_run) as harness: application = Mock() application.config = harness.config application.messagebus = harness.messagebus docker_run.docker_config = DockerConfig(harness.config) with LocalMessageQueue(harness.messagebus, [PRE_MAKE], [MAKE_ENDPOINT]) as queue: harness.component_factory.call(make, scope, application) self.assertEqual(queue.get(timeout=1).data, ('arg1', '--opt2'))
def test_shell_called_with_correct_parameters(self): docker_run = Mock() scope = Scope('scope') with create_harness(docker_run) as harness: application = Mock() application.config = harness.config docker_run.run_in_docker.return_value = 0 exit_code = harness.component_factory.call(shell, scope, application) self.assertEqual(exit_code, 0) docker_run.run_in_docker.assert_called_with(['/bin/bash'], forward_signals=True)
def test_exec_called_with_correct_parameters(self): docker_run = Mock() scope = Scope('scope') with create_harness(docker_run) as harness: application = Mock() application.config = harness.config docker_run.run_in_docker.return_value = 0 exit_code = harness.component_factory.call(exec, scope, application) self.assertEqual(exit_code, 0) docker_run.run_in_docker.assert_called_with( ('exec', 'with', 'args'), forward_signals=False)
def test_make_command_taken_from_image(self): docker_run = Mock() scope = Scope('scope') with create_harness(docker_run, 'abs.u12') as harness: application = Mock() application.config = harness.config docker_run.docker_config = DockerConfig(harness.config) docker_run.run_in_docker.return_value = 0 exit_code = harness.component_factory.call(make, scope, application) self.assertEqual(exit_code, 0) docker_run.run_in_docker.assert_called_with( ['make', 'arg1', '--opt2'], forward_signals=False)
def test_default_containername(self): config = ConfigManager() config.set(SUT, ['mysut']) config.set(SUT_DOCKER_IMAGE_ID, 'myimage', entity='mysut') config.set(DOCKER_IMAGES_IDS, ['myimage']) config.set(DOCKER_IMAGES_REPOSITORY, 'repository', entity='myimage') config.set(DOCKER_IMAGES_TAG, 'v1', entity='myimage') with patch('virt.docker.Docker'): with _create_harness(config) as harness: harness.sut.entity = 'mysut' scope = Scope(name='myscope') node = harness.component_factory.call(DockerContainerNode, scope) self.assertIsNone(node.containername)
def test_docker_config_component_uses_config_values(self): scope = Scope('scope') config = ConfigManager() config.set(IMAGE_OPTION, 'abs.u16') config.set(TAG_OPTION, 'tag') config.set(REGISTRY_OPTION, 'registry') config.set(USE_REGISTRY_OPTION, False) config.set(REGISTRY_CACHE_OPTION, 'registry_cache') config.set(PULL_OPTION, False) config.set(HOSTNAME_OPTION, 'hostname') config.set(ENV_VARIABLES_OPTION, ['envvar']) config.set(MOUNTS_OPTION, ['mount']) config.set(ROOT_OPTION, True) config.set(ROOT_DIR_OPTION, 'root_dir') config.set(CONTAINER_ROOT_DIR_OPTION, 'container_root_dir') config.set(PROJECT_DIR_OPTION, 'project_dir') config.set(PROJECT_DIR_NAME_OPTION, 'project_dir_name') config.set(NETWORK_OPTION, 'network') with create_harness(config) as harness: @requires(docker_config='DockerConfig') def assert_docker_config(docker_config): self.assertEqual(docker_config.image, 'abs.u16') self.assertEqual(docker_config.tag, 'tag') self.assertEqual(docker_config.registry, 'registry') self.assertFalse(docker_config.use_registry) self.assertEqual(docker_config.registry_cache, 'registry_cache') self.assertFalse(docker_config.pull) self.assertEqual(docker_config.hostname, 'hostname') self.assertEqual(docker_config.env_variables, ('envvar', )) self.assertEqual(docker_config.mounts, ('mount', )) self.assertEqual(docker_config.root, True) self.assertEqual(docker_config.root_dir, 'root_dir') self.assertEqual(docker_config.container_root_dir, 'container_root_dir') self.assertEqual(docker_config.project_dir, 'project_dir') self.assertEqual(docker_config.project_dir_name, 'project_dir_name') self.assertEqual(docker_config.network, 'network') harness.component_factory.call(assert_docker_config, scope)
def test_iterable_sut_config_extends_image_config(self): config = ConfigManager() config.set(SUT, ['mysut']) config.set(SUT_DOCKER_IMAGE_ID, 'myimage', entity='mysut') config.set(DOCKER_IMAGES_IDS, ['myimage']) config.set(DOCKER_IMAGES_REPOSITORY, 'repository', entity='myimage') config.set(DOCKER_IMAGES_TAG, 'v1', entity='myimage') config.set(DOCKER_IMAGES_ENVIRONMENT, ['KEY=value', 'A=a'], entity='myimage') config.set(DOCKER_IMAGES_MOUNT_POINTS, ['type=tmpfs,target=/foo'], entity='myimage') config.set(SUT_DOCKER_IMAGE_ENVIRONMENT, ['SUT_KEY=sut_value', 'A=b'], entity='mysut') config.set(SUT_DOCKER_IMAGE_MOUNT_POINTS, ['type=tmpfs,target=/bar'], entity='mysut') with patch('virt.docker.Docker'): with _create_harness(config) as harness: harness.sut.entity = 'mysut' scope = Scope(name='myscope') node = harness.component_factory.call(DockerContainerNode, scope) self.assertEqual(node._image_entity, 'myimage') self.assertEqual(node._repository, 'repository') self.assertEqual(node._tag, 'v1') self.assertEqual( node._environment, OrderedDict([('SUT_KEY', 'sut_value'), ('A', 'b'), ('KEY', 'value')])) self.assertEqual(node._mounts[0]['Source'], None) self.assertEqual(node._mounts[0]['Target'], '/bar') self.assertEqual(node._mounts[0]['Type'], 'tmpfs') self.assertEqual(node._mounts[0]['ReadOnly'], False) self.assertEqual(node._mounts[1]['Source'], None) self.assertEqual(node._mounts[1]['Target'], '/foo') self.assertEqual(node._mounts[1]['Type'], 'tmpfs') self.assertEqual(node._mounts[1]['ReadOnly'], False)
def test_minimum_config(self): config = ConfigManager() config.set(SUT, ['mysut']) config.set(SUT_DOCKER_IMAGE_ID, 'myimage', entity='mysut') config.set(DOCKER_IMAGES_IDS, ['myimage']) config.set(DOCKER_IMAGES_REPOSITORY, 'repository', entity='myimage') config.set(DOCKER_IMAGES_TAG, 'v1', entity='myimage') with patch('virt.docker.Docker'): with _create_harness(config) as harness: harness.sut.entity = 'mysut' scope = Scope(name='myscope') node = harness.component_factory.call(DockerContainerNode, scope) self.assertEqual(node._image_entity, 'myimage') self.assertEqual(node._repository, 'repository') self.assertEqual(node._tag, 'v1') self.assertEqual(node._hostname, None) self.assertEqual(node._image_name, 'repository:v1') self.assertEqual(node._timeout, 10) self.assertTrue(node._pull) self.assertFalse(node._keep_running)
def test_atomic_sut_config_overrides_image_config(self): config = ConfigManager() config.set(SUT, ['mysut']) config.set(SUT_DOCKER_IMAGE_ID, 'myimage', entity='mysut') config.set(DOCKER_IMAGES_IDS, ['myimage']) config.set(DOCKER_IMAGES_REPOSITORY, 'repository', entity='myimage') config.set(DOCKER_IMAGES_TAG, 'v1', entity='myimage') config.set(DOCKER_IMAGES_HOSTNAME, 'myhostname', entity='myimage') config.set(DOCKER_IMAGES_NETWORK, 'mynetwork', entity='myimage') config.set(SUT_DOCKER_IMAGE_HOSTNAME, 'mysuthostname', entity='mysut') config.set(SUT_DOCKER_IMAGE_NETWORK, 'mysutnetwork', entity='mysut') with patch('virt.docker.Docker'): with _create_harness(config) as harness: harness.sut.entity = 'mysut' scope = Scope(name='myscope') node = harness.component_factory.call(DockerContainerNode, scope) self.assertEqual(node._image_entity, 'myimage') self.assertEqual(node._repository, 'repository') self.assertEqual(node._tag, 'v1') self.assertEqual(node._hostname, 'mysuthostname') self.assertEqual(node._networkname, 'mysutnetwork')
def setUp(self): self.component_manager = ComponentManager(create_registry(), create_entity_map()) self.registry = self.component_manager.COMPONENT_REGISTRY self.builder = DependencyGraphBuilder(self.registry) self.scope = Scope('scope')
class TestTestRunnerComponents(unittest.TestCase): class Verifier(object): def __init__(self): self.data = [] def load_components(self): @component() @requires(verifier='Verifier') class MyComponent(object): def __init__(self, verifier): self.verifier = verifier def __enter__(self): self.verifier.data.append('enter') return self def __exit__(self, exc_type, exc_val, exc_tb): self.verifier.data.append('exit') def __call__(self, *args, **kwargs): self.verifier.data.append('call') @component() @requires(verifier='Verifier') class MyEnterFailComponent(object): def __init__(self, verifier): self.verifier = verifier def __enter__(self): self.verifier.data.append('enter') raise (Exception('enter fails')) def __exit__(self, exc_type, exc_val, exc_tb): self.verifier.data.append('exit') def __call__(self, *args, **kwargs): self.verifier.data.append('call') @component() @requires(verifier='Verifier') class MyExitFailComponent(object): def __init__(self, verifier): self.verifier = verifier def __enter__(self): self.verifier.data.append('enter') return self def __exit__(self, exc_type, exc_val, exc_tb): self.verifier.data.append('exit') raise (Exception('exit fails')) def __call__(self, *args, **kwargs): self.verifier.data.append('call') def setUp(self): self.component_manager = ComponentManager() self.component_manager.clear_component_registry() component(scope='session')(TestTestRunnerComponents.Verifier) self.load_components() self.verifier = TestTestRunnerComponents.Verifier() self.parent_scope = Scope('session', None) self.parent_scope.register_instance( _InstanceId(TestTestRunnerComponents.Verifier, ()), self.verifier) self.run_queue = [] self.messagebus = Mock() def send_request(message_id, endpoint_id=None, entities=None, data=None): futures = Mock() if message_id == SCHEDULE_NEXT_TEST: future = Mock() if self.run_queue: future.result.return_value = self.run_queue.pop(0) else: future.result.return_value = None futures.wait.return_value = [future] return futures self.messagebus.send_request.side_effect = send_request self.tr = TestRunner(self.messagebus, Factory(self.component_manager), 'suite-name', parent_scope=self.parent_scope) def test_enters_and_exit_called_on_component_with_test_scope(self): @requires(comp='MyComponent', scope='test') def my_test_case(comp): comp() self.run_queue.append(TestCaseDefinition(my_test_case)) self.tr.run() assert 'enter' in self.verifier.data assert 'call' in self.verifier.data assert 'exit' in self.verifier.data def test_enters_and_exit_called_on_component_with_module_scope(self): @requires(comp='MyComponent', scope='module') def my_test_case(comp): comp() self.run_queue.append(TestCaseDefinition(my_test_case)) self.tr.run() assert 'enter' in self.verifier.data assert 'call' in self.verifier.data assert 'exit' in self.verifier.data def test_enters_and_exit_called_on_component_with_class_scope(self): class TestMyTestCase(object): @requires(comp='MyComponent', scope='class') def my_test_case(self, comp): comp() self.run_queue.append(TestCaseDefinition( TestMyTestCase().my_test_case)) self.tr.run() assert 'enter' in self.verifier.data assert 'call' in self.verifier.data assert 'exit' in self.verifier.data def test_enters_and_exit_called_on_component_with_runner_scope(self): @requires(comp='MyComponent', scope='module') def my_test_case(comp): comp() self.run_queue.append(TestCaseDefinition(my_test_case)) self.tr.run() assert 'enter' in self.verifier.data assert 'call' in self.verifier.data assert 'exit' in self.verifier.data def test_enter_and_exit_called_once_on_class_scope_component_for_test_cases_in_same_class( self): class TestMyTestCase(object): @requires(comp='MyComponent', scope='class') def my_test_case1(self, comp): comp() @requires(comp='MyComponent', scope='class') def my_test_case2(self, comp): comp() test_case_class = TestMyTestCase() self.run_queue.extend([ TestCaseDefinition(test_case_class.my_test_case1), TestCaseDefinition(test_case_class.my_test_case2) ]) self.tr.run() assert self.verifier.data.count('enter') == 1 assert self.verifier.data.count('call') == 2 assert self.verifier.data.count('exit') == 1 def test_enter_and_exit_called_once_on_module_scope_component_for_test_cases_in_same_module( self): @requires(comp='MyComponent', scope='module') def my_test_case1(comp): comp() @requires(comp='MyComponent', scope='module') def my_test_case2(comp): comp() self.run_queue.extend([ TestCaseDefinition(my_test_case1), TestCaseDefinition(my_test_case2) ]) self.tr.run() assert self.verifier.data.count('enter') == 1 assert self.verifier.data.count('call') == 2 assert self.verifier.data.count('exit') == 1 def test_enter_and_exit_called_once_on_runner_scope_component(self): @requires(comp='MyComponent', scope='runner') def my_test_case1(comp): comp() @requires(comp='MyComponent', scope='runner') def my_test_case2(comp): comp() self.run_queue.extend([ TestCaseDefinition(my_test_case1), TestCaseDefinition(my_test_case2) ]) self.tr.run() assert self.verifier.data.count('enter') == 1 assert self.verifier.data.count('call') == 2 assert self.verifier.data.count('exit') == 1 def test_enter_fails_sets_test_case_verdict_to_error_and_exit_is_called( self): @requires(comp='MyEnterFailComponent', scope='runner') def my_test_case1(comp): comp() self.run_queue.extend([TestCaseDefinition(my_test_case1)]) self.tr.run() assert self.tr.run_history[0].verdict == Verdict.ERROR assert 'enter' in self.verifier.data assert 'call' not in self.verifier.data assert 'exit' in self.verifier.data def test_enter_fails_sets_test_case_verdict_to_error_and_continues_to_next_test_case( self): @requires(comp='MyEnterFailComponent', scope='runner') def my_test_case1(comp): comp() @requires(comp='MyComponent', scope='runner') def my_test_case2(comp): comp() self.run_queue.extend([ TestCaseDefinition(my_test_case1), TestCaseDefinition(my_test_case2) ]) self.tr.run() assert self.tr.run_history[0].verdict == Verdict.ERROR assert self.tr.run_history[1].verdict == Verdict.PASSED def test_exit_fails_on_test_scope_aborts_test_run(self): @requires(comp='MyExitFailComponent', scope='test') def my_test_case1(comp): comp() @requires(comp='MyComponent', scope='runner') def my_test_case2(comp): comp() self.run_queue.extend([ TestCaseDefinition(my_test_case1), TestCaseDefinition(my_test_case2) ]) self.tr.run() assert self.tr.run_history[0].verdict == Verdict.PASSED assert self.tr.run_history[1].verdict == Verdict.SKIPPED def test_exit_fails_on_non_test_scope_aborts_test_run(self): class MyTestCase1(object): @requires(comp='MyExitFailComponent', scope='class') def my_test_case1(self, comp): comp() class MyTestCase2(object): @requires(comp='MyComponent', scope='class') def my_test_case2(self, comp): comp() self.run_queue.extend([ TestCaseDefinition(MyTestCase1().my_test_case1), TestCaseDefinition(MyTestCase2().my_test_case2) ]) self.tr.run() assert self.tr.run_history[0].verdict == Verdict.PASSED assert self.tr.run_history[1].verdict == Verdict.SKIPPED
def test_error_message_when_remove_with_shorter_scope(self): @component(name='A', can=['stuff', 'other_stuff'], scope='short', component_manager=self.component_manager) def component_a_scope(): pass @component(name='A', can=['no_stuff'], component_manager=self.component_manager) def component_a_cans(): pass @component(name='A', can=['stuff', 'other_stuff'], component_manager=self.component_manager) @requires(require_not_exists='NotExists') def component_a_depends(require_not_exists): pass @component(name='B', scope='long', component_manager=self.component_manager) @requires(require_a='A', can=['stuff', 'other_stuff']) def component_b(require_a): pass @component(name='C', can=['stuff2', 'stuff3', 'stuff4'], component_manager=self.component_manager) def component_c(): pass @component(name='D', component_manager=self.component_manager) @requires(require_c='C', can=['stuff2', 'stuff3']) def component_d(require_c): pass @requires(require_b='B') @requires(require_d=component_d) def test(require_b, require_d): pass long = Scope('long') short = Scope('short', parent=long) dependency_graph = self.builder.create_dependency_graph( test, short, None) expected_message = dedent("""\ Error fulfilling requirements for test U: Requirement 'require_b' with name 'B': Unfulfilled U: Component 'component_b' with name 'B': Unfullfilled requirements U: Requirement 'require_a' with name 'A' and cans 'stuff, other_stuff': Unfulfilled C: Component 'component_a_cans' with name 'A': Cans not fulfilled 'stuff, other_stuff' U: Component 'component_a_depends' with name 'A': Unfullfilled requirements M: Requirement 'require_not_exists' with name 'NotExists': Missing component 'NotExists' S: Component 'component_a_scope' with name 'A': Scope 'short' is not one of the valid scopes 'long' F: Requirement 'require_d' with name 'component_d': Fulfilled E: Component 'component_d' with name 'component_d': Exists F: Requirement 'require_c' with name 'C': Fulfilled E: Component 'component_c' with name 'C': Exists""") with self.assertRaises(ComponentDependencyError) as exc: dependency_graph.resolve(short) self.assertEqual(str(exc), expected_message)