def test_cancel_job(self): """ Tests that scheduler is stopped whenever a port is failing. """ port_out = object() port_in = Mock(spec=_port_callback) self.flowmap[port_out] = port_in run_deferred = self.scheduler.run(self.clock) self.scheduler.send('some item', port_out) self.assertEquals(len(list(self.scheduler.pending)), 1) self.scheduler.stop('bye!') self.assertEquals(len(list(self.scheduler.pending)), 1) join_deferred = self.scheduler.join() self.clock.advance(self.epsilon) assert_that(join_deferred, twistedsupport.succeeded(matchers.Always())) assert_that(run_deferred, twistedsupport.succeeded(matchers.Equals('bye!'))) self.assertEquals(len(list(self.scheduler.pending)), 0) self.assertEquals(port_in.call_count, 0)
def test_fail_job(self): """ Tests that scheduler is stopped whenever a port is failing. """ port_out = object() port_in = Mock(spec=_port_callback, side_effect=RuntimeError('failed!')) self.flowmap[port_out] = port_in run_deferred = self.scheduler.run(self.clock) self.scheduler.send('some item', port_out) expected_message = 'Job failed on {:s} while processing {:s}'.format( str(port_in), 'some item') from testtools.twistedsupport._runtest import _NoTwistedLogObservers with _NoTwistedLogObservers(): with twistedsupport.CaptureTwistedLogs() as twisted_logs: # Trigger queue run. self.clock.advance(self.epsilon) assert_that(twisted_logs.getDetails(), matchers.MatchesDict({ 'twisted-log': matchers.AfterPreprocessing( lambda log: log.as_text(), matchers.Contains(expected_message)) })) port_in.assert_called_once_with('some item', self.scheduler.send) matcher = matchers.AfterPreprocessing(lambda f: f.value, matchers.IsInstance(RuntimeError)) assert_that(run_deferred, twistedsupport.failed(matcher))
def test_default_client(self): """ When default_client is passed a client it should return that client. """ client = treq_HTTPClient(Agent(reactor)) assert_that(default_client(client, reactor), Is(client))
def test_run_job(self): """ Tests send() and ensure that the job-event is fired. """ job_handler = Mock() self.dispatcher.add_listener(JobEvent, 0, job_handler) port_out = object() port_in = Mock(spec=_port_callback) self.flowmap[port_out] = port_in self.scheduler.run(self.clock) self.scheduler.send('some item', port_out) expected_job = Job(port_in, 'some item', self.scheduler.send, port_out) self.assertEquals(job_handler.call_count, 1) assert_that(job_handler.call_args, MatchesInvocation( MatchesEvent(JobEvent, scheduler=matchers.Equals(self.scheduler), job=matchers.Equals(expected_job), completed=twistedsupport.has_no_result()) )) self.assertEquals(port_in.call_count, 0) self.assertEquals(len(list(self.scheduler.pending)), 1) # Trigger queue run. self.clock.advance(self.epsilon) port_in.assert_called_once_with('some item', self.scheduler.send) self.assertEquals(len(list(self.scheduler.pending)), 0)
def test_provision_second_vif(self, task_catcher, xs_helper, admin_client): """ We can create a new VM using mostly default values. """ createvm_calls = task_catcher.catch_create_vm() _, xs = xs_helper.new_host("xs01.local") templ = xs_helper.db_template("default") assert list(XenVM.objects.all()) == [] assert list(Addresses.objects.all()) == [] # Make the request. resp = admin_client.post(reverse('provision'), { "hostname": "foo.example.com", "template": templ.pk, "group": xs_helper.db_project("fooproj").pk, "extra_network_bridges": "xenbr1", }, follow=True) assert resp.status_code == 200 # Make sure we did the right things. [addr] = Addresses.objects.all() [vm] = XenVM.objects.all() assert_that(createvm_calls, MatchesListwise([listmatcher([ vm, xs, templ, "foo", "example.com", addr.ip, "255.255.255.0", DEFAULT_GATEWAY, Always(), ["xenbr1"]])]))
def test_parse_no_ip_address(self): """ When a listen address is parsed with no IP address, an endpoint description with the listen address's port but no interface is returned. """ assert_that(parse_listen_addr(':8080'), Equals('tcp:8080'))
def test_single_fail(self): """ A single incoming message with a single file path. """ sut = MetadataExtractor('exiftool', ('-some', '-arg')) error = RuntimeError('boom!') sut.peer = Mock(spec=ExiftoolProtocol) sut.peer.execute.return_value = defer.fail(error) insert = { 'inserts': ['a'], 'deletes': [], 'data': { 'a': { 'path': '/path/to/file.jpg', } } } send = Mock(spec=Scheduler.send) result = sut(insert, send) self.assertEquals(send.call_count, 0) sut.peer.execute.assert_called_once_with( b'-some', b'-arg', b'-j', b'-charset', b'exiftool=UTF-8', b'-charset', b'filename=UTF-8', b'/path/to/file.jpg') failure_matcher = matchers.AfterPreprocessing( lambda f: f.value, matchers.IsInstance(MetadataExtractorError)) assert_that(result, twistedsupport.failed(failure_matcher))
def test_whitespace(self): """ When the domain label contains whitespace, the whitespace should be ignored. """ domains = parse_domain_label(' ') assert_that(domains, Equals([]))
def test_get_apps(self): """ When the list of apps is requested, a list of apps added via add_app() should be returned. """ app = { 'id': '/my-app_1', 'cmd': 'sleep 50', 'tasks': [{ "host": "host1.local", "id": "my-app_1-1396592790353", "ports": [] }, { "host": "host2.local", "id": "my-app_1-1396592784349", "ports": [] }] } self.marathon.add_app(app) response = self.client.get('http://localhost/v2/apps') assert_that( response, succeeded( MatchesAll( IsJsonResponseWithCode(200), After(json_content, succeeded(Equals({'apps': [app]}))))))
def test_calls_matching(self): service = self.make_test_service() with service() as service_mock: requests.get("http://example.com/test-endpoint", json=888) requests.get("http://example.com/no-validation") assert_that(service_mock.get_calls_matching('no-validation$'), HasLength(1))
def test_parse_ipv6(self): """ When a listen address is parsed with an IPv4 address, an appropriate interface is present in the returned endpoint description. """ assert_that(parse_listen_addr('[::]:8080'), Equals('tcp6:8080:interface=\:\:'))
def test_connect_fails_when_invalid(self): v1bad = None username = self.getUniqueString() #garbage password = self.getUniqueString() #garbage self.addDetail('address', text_content(PublicTestServerConnection.address)) self.addDetail('instance', text_content(PublicTestServerConnection.instance)) self.addDetail('bad-username', text_content(username)) self.addDetail('bad-password', text_content(password)) try: v1bad = V1Meta( instance_url=PublicTestServerConnection.instance_url, username=username, password=password, use_password_as_token=False, ) # we have to try to use it to get it to connect and fail items = v1bad.Story.select('Name').page(size=1) items.first() #run the query except HTTPError as e: assert_that( e.code, Equals(401), message="Connection failed for reasons other than authorization" ) else: assert_that(False, Equals(True), message="Connection succeeded with bad credentials")
def test_meta_connect_instance_url_overrides_separate(self): v1 = None address = self.getUniqueString() #garbage instance = self.getUniqueString() #garbage self.addDetail('address', text_content(PublicTestServerConnection.address)) self.addDetail('instance-url', text_content(PublicTestServerConnection.instance_url)) self.addDetail('instance', text_content(address)) self.addDetail('username', text_content(instance)) try: v1 = V1Meta( instance_url=PublicTestServerConnection.instance_url, address=address, instance=instance, username=PublicTestServerConnection.username, password=PublicTestServerConnection.password, ) except Exception as e: assert_that(False, Equals(True), message="Error trying to create connection: " + str(e)) try: items = v1.Story.select('Name').page(size=1) items.first() #run the query except Exception as e: assert_that(False, Equals(True), message="Error running query from connection: " + str(e))
def test_listen_events_attach_initial_sync(self): """ When we listen for events from Marathon, and we receive a subscribe event from ourselves subscribing, an initial sync should be performed and certificates issued for any new domains. """ self.fake_marathon.add_app({ 'id': '/my-app_1', 'labels': { 'HAPROXY_GROUP': 'external', 'MARATHON_ACME_0_DOMAIN': 'example.com' }, 'portDefinitions': [{ 'port': 9000, 'protocol': 'tcp', 'labels': {} }] }) self.marathon_acme.listen_events() # Observe that the certificate was stored and marathon-lb notified assert_that(self.cert_store.as_dict(), succeeded(MatchesDict({'example.com': Not(Is(None))}))) assert_that(self.fake_marathon_lb.check_signalled_usr1(), Equals(True))
def test_separators(self): """ When the domain label contains only the separators (commas or whitespace), the separators should be ignored. """ domains = parse_domain_label(' , , ') assert_that(domains, Equals([]))
def test_single_domain(self): """ When the domain label contains just a single domain, that domain should be parsed into a list containing just the one domain. """ domains = parse_domain_label('example.com') assert_that(domains, Equals(['example.com']))
def test_listen_events_attach_initial_sync(self): """ When we listen for events from Marathon, and we receive a subscribe event from ourselves subscribing, an initial sync should be performed and certificates issued for any new domains. """ self.fake_marathon.add_app({ 'id': '/my-app_1', 'labels': { 'HAPROXY_GROUP': 'external', 'MARATHON_ACME_0_DOMAIN': 'example.com' }, 'portDefinitions': [ {'port': 9000, 'protocol': 'tcp', 'labels': {}} ] }) marathon_acme = self.mk_marathon_acme() marathon_acme.listen_events() # Observe that the certificate was stored and marathon-lb notified assert_that(self.cert_store.as_dict(), succeeded(MatchesDict({ 'example.com': Not(Is(None)) }))) assert_that(self.fake_marathon_lb.check_signalled_usr1(), Equals(True))
def test_multiple_domains_whitespace(self): """ When the domain label contains multiple whitespace-separated domains, the domains should be parsed into a list of domains. """ domains = parse_domain_label('example.com example2.com') assert_that(domains, Equals(['example.com', 'example2.com']))
def test_dispatch_with_return_fails(self): dispatcher = EventDispatcher() test_callback_prio_0_cb_0 = Mock(return_value='hello') test_callback_prio_0_cb_1 = Mock(side_effect=RuntimeError('boom!')) test_callback_prio_1_cb_0 = Mock(return_value='world') dispatcher.add_listener(TestEvent, 0, test_callback_prio_0_cb_0) dispatcher.add_listener(TestEvent, 0, test_callback_prio_0_cb_1) dispatcher.add_listener(TestEvent, 1, test_callback_prio_1_cb_0) event = TestEvent() d = dispatcher.dispatch(event, fail_mode=FailMode.RETURN) matcher = matchers.MatchesListwise([ matchers.MatchesListwise([ matchers.Equals(0), matchers.MatchesListwise([ matchers.Equals((True, 'hello')), matchers.MatchesListwise([ matchers.Equals(False), matchers.AfterPreprocessing(lambda f: f.value, matchers.IsInstance(HandlerError)), ]) ]), ]), matchers.MatchesListwise([ matchers.Equals(1), matchers.MatchesListwise([ matchers.Equals((True, 'world')), ]), ]), ]) assert_that(d, twistedsupport.succeeded(matcher))
def extract_VBDs(self, xenserver, VM_ref, spec): """ Get the VBDs for the given VM and match them to a list of (SR, VBD) ref pairs. """ assert_that(xenserver.list_SR_VBDs_for_VM(VM_ref), MatchesSetOfLists(spec))
def test_meta_connect_instance_and_address(self): v1 = None self.addDetail('address', text_content(PublicTestServerConnection.address)) self.addDetail('instance', text_content(PublicTestServerConnection.instance)) self.addDetail('username', text_content(PublicTestServerConnection.username)) try: v1 = V1Meta( address=PublicTestServerConnection.address, instance=PublicTestServerConnection.instance, username=PublicTestServerConnection.username, password=PublicTestServerConnection.password, ) except Exception as e: assert_that(False, Equals(True), message="Error trying to create connection: " + str(e)) try: items = v1.Story.select('Name').page(size=1) items.first() #run the query except Exception as e: assert_that(False, Equals(True), message="Error running query from connection: " + str(e))
def test_meta_connect_oauth_ignores_username(self): v1 = None username = self.getUniqueString() #garbage self.addDetail('address', text_content(PublicTestServerConnection.address)) self.addDetail('instance', text_content(PublicTestServerConnection.instance)) self.addDetail('username', text_content(username)) try: v1 = V1Meta( instance_url=PublicTestServerConnection.instance_url, username=username, password=PublicTestServerConnection.token, use_password_as_token=True, ) except Exception as e: assert_that(False, Equals(True), message="Error trying to create connection: " + str(e)) try: items = v1.Story.select('Name').page(size=1) items.first() #run the query except Exception as e: assert_that(False, Equals(True), message="Error running query from connection: " + str(e))
def test_default_reactor(self): """ When default_reactor is passed a reactor it should return that reactor. """ clock = Clock() assert_that(default_reactor(clock), Is(clock))
def test_multiple_domains(self): """ When the domain label contains multiple comma-separated domains, the domains should be parsed into a list of domains. """ domains = parse_domain_label('example.com,example2.com') assert_that(domains, Equals(['example.com', 'example2.com']))
def test_single_job(self): """ A single incoming message with a single file path. """ sut = MetadataExtractor('exiftool', ('-some', '-arg')) sut.peer = Mock(spec=ExiftoolProtocol) sut.peer.execute.return_value = defer.succeed(b'[{"hello": "world"}]') insert = { 'inserts': ['a'], 'deletes': [], 'data': { 'a': { 'path': '/path/to/file.jpg', } } } expected = copy.deepcopy(insert) expected['data']['a']['metadata'] = {'hello': 'world'} matches = MatchesSendDeltaItemInvocation(expected, sut) send = Mock(spec=Scheduler.send) sut(insert, send) self.assertEquals(send.call_count, 1) assert_that(send.call_args, matches) sut.peer.execute.assert_called_once_with( b'-some', b'-arg', b'-j', b'-charset', b'exiftool=UTF-8', b'-charset', b'filename=UTF-8', b'/path/to/file.jpg')
def test_provision_second_vif(self, task_catcher, xs_helper, admin_client): """ We can create a new VM using mostly default values. """ createvm_calls = task_catcher.catch_create_vm() _, xs = xs_helper.new_host("xs01.local") templ = xs_helper.db_template("default") assert list(XenVM.objects.all()) == [] assert list(Addresses.objects.all()) == [] # Make the request. resp = admin_client.post(reverse('provision'), { "hostname": "foo.example.com", "template": templ.pk, "group": xs_helper.db_project("fooproj").pk, "extra_network_bridges": "xenbr1", }, follow=True) assert resp.status_code == 200 # Make sure we did the right things. [addr] = Addresses.objects.all() [vm] = XenVM.objects.all() assert_that( createvm_calls, MatchesListwise([ listmatcher([ vm, xs, templ, "foo", "example.com", addr.ip, "255.255.255.0", DEFAULT_GATEWAY, Always(), ["xenbr1"] ]) ]))
async def test_get_apps_empty(self): """ When there are no apps to get, an empty app list is returned. """ async with FakeMarathon() as fake_marathon: resp = await fake_marathon.get_client().get("/v2/apps") assert_that(resp, is_json_response({"apps": []}))
def test_image_and_tag(self): """ When an image and tag are provided, the two should be joined using a ':' character. """ image_tag = join_image_tag('bar', 'foo') assert_that(image_tag, Equals('bar:foo'))
def test_does_generate_zero_if_only_zero(self): """ When the version '0' is passed, that version should be returned in a list. """ versions = generate_semver_versions('0') assert_that(versions, Equals(['0']))
def test_separators(self): """ When the domain label contains only the separators (commas or whitespace), the separators should be ignored. """ domains = parse_domain_label(" , , ") assert_that(domains, Equals([]))
def test_precision_equal_to_version(self): """ When precision is equal to the precision of the version, the generated versions should be just the version itself. """ versions = generate_semver_versions('3.5.3', precision=3) assert_that(versions, Equals(['3.5.3']))
def test_does_not_generate_zero(self): """ When a version is passed with a major version of 0, the version '0' should not be returned in the list of versions. """ versions = generate_semver_versions('0.6.11') assert_that(versions, Equals(['0.6.11', '0.6']))
def test_one_version_part(self): """ When a version with a single part is passed, that version should be returned in a list. """ versions = generate_semver_versions('foo') assert_that(versions, Equals(['foo']))
def test_precision_less_than_version(self): """ When precision is less than the precision of the version, semantic versions should be generated up to the specified precision. """ versions = generate_semver_versions('3.5.3', precision=2) assert_that(versions, Equals(['3.5.3', '3.5']))
def test_standard_version(self): """ When a standard 3-part semantic version is passed, 3 version strings should be returned with decreasing levels of precision. """ versions = generate_semver_versions('5.4.1') assert_that(versions, Equals(['5.4.1', '5.4', '5']))
def test_extended_version(self): """ When a version is passed with extra information separated by '-', version strings should be returned with decreasing levels of precision. """ versions = generate_semver_versions('5.5.0-alpha') assert_that(versions, Equals(['5.5.0-alpha', '5.5.0', '5.5', '5']))
def test_multiple_domains_whitespace(self): """ When the domain label contains multiple whitespace-separated domains, the domains should be parsed into a list of domains. """ domains = parse_domain_label("example.com example2.com") assert_that(domains, Equals(["example.com", "example2.com"]))
def check_deployments(self, database, config, subscriptions, k8s_state, aws): for sid in subscriptions: actual = k8s_state.deployments.item_by_name(deployment_name(sid)) reference = create_deployment( config, database.get_subscription(sid), self.kube_model, ) def drop_transients(deployment): simplified = deployment.transform( [ u"metadata", u"annotations", u"deployment.kubernetes.io/revision" ], discard, [u"metadata", u"resourceVersion"], None, [u"status"], None, ) return simplified.serialize() assert_that( actual, AfterPreprocessing(drop_transients, GoodEquals(reference.serialize())), )
def test_image_without_registry(self): """ When an image without a registry is provided, the registry should be prepended to the image with a '/' character. """ image = RegistryTagger('registry:5000').generate_tag('bar') assert_that(image, Equals('registry:5000/bar'))
def extract_VIFs(self, xenserver, VM_ref, spec): """ Get the VIFs for the given VM and match them to a list of (network, VIF) ref pairs. """ assert_that(xenserver.list_network_VIFs_for_VM(VM_ref), MatchesSetOfLists(spec))
def test_str(self): """ ExtractValue instances stringify sensibly. """ ev = ExtractValue("a") assert str(ev) == "ExtractValue(a)" assert_that(3, ev) assert str(ev) == "ExtractValue(a)=[3]"
def test_multiple_domains_comma_whitespace(self): """ When the domain label contains multiple comma-separated domains with whitespace inbetween, the domains should be parsed into a list of domains without the whitespace. """ domains = parse_domain_label(' example.com, example2.com ') assert_that(domains, Equals(['example.com', 'example2.com']))
def test_responder_resource_empty(self): """ When a GET request is made to the ACME challenge path, but the responder resource is empty, a 404 response code should be returned. """ response = self.client.get( 'http://localhost/.well-known/acme-challenge/foo') assert_that(response, succeeded(MatchesStructure(code=Equals(404))))
def extract_VIFs(self, xenserver, VM_ref, spec): """ Get the VIFs for the given VM and match them to a list of (network, VIF) ref pairs. """ assert_that( xenserver.list_network_VIFs_for_VM(VM_ref), MatchesSetOfLists(spec))
def extract_VBDs(self, xenserver, VM_ref, spec): """ Get the VBDs for the given VM and match them to a list of (SR, VBD) ref pairs. """ assert_that( xenserver.list_SR_VBDs_for_VM(VM_ref), MatchesSetOfLists(spec))
def test_value_missing(self): """ When the requested header key is not present in the set of headers, get_single_header returns None. """ headers = Headers({'Content-Type': ['application/json']}) content_type = get_single_header(headers, 'Accept') assert_that(content_type, Is(None))
def test_transport_connection_lost(self, protocol): """ When the connection is lost, the finished deferred should be called. """ finished = protocol.when_finished() protocol.connectionLost() assert_that(finished, succeeded(Is(None)))
def test_single_value(self): """ When a single value is set for a header key and we use get_single_header to get that value, the correct value is returned. """ headers = Headers({'Content-Type': ['application/json']}) content_type = get_single_header(headers, 'Content-Type') assert_that(content_type, Equals('application/json'))
def test_bridge_networking(self, test_app): """ When the app uses Docker containers with BRIDGE networking, the ports should be counted from the 'portDefinitions' field. """ test_app['container'] = CONTAINER_BRIDGE_NETWORKING test_app['portDefinitions'] = PORT_DEFINITIONS_ONE_PORT num_ports = get_number_of_app_ports(test_app) assert_that(num_ports, Equals(1))
def test_ip_per_task_mesos_containerizer(self, test_app): """ When the app uses ip-per-task networking, with the Mesos containerizer, the ports should be counted from the 'ipAddress' field. """ test_app['container'] = CONTAINER_MESOS test_app['ipAddress'] = IP_ADDRESS_TWO_PORTS num_ports = get_number_of_app_ports(test_app) assert_that(num_ports, Equals(2))
def test_ip_per_task_no_container(self, test_app): """ When the app uses ip-per-task networking, but is not running in a container, then the ports should be counted from the 'ipAddress' field. """ test_app['ipAddress'] = IP_ADDRESS_TWO_PORTS num_ports = get_number_of_app_ports(test_app) assert_that(num_ports, Equals(2))
def test_value_with_params(self): """ When the value set for a header key include parameters and we use get_single_header to get the value, the value without the parameters is returned. """ headers = Headers({'Accept': ['application/json; charset=utf-8']}) accept = get_single_header(headers, 'Accept') assert_that(accept, Equals('application/json'))
def test_user_networking_marathon15(self, test_app): """ For Marathon 1.5+, when the app uses Docker containers with 'container' networking, the ports should be counted from the ``container.portMappings`` field. """ test_app['container'] = CONTAINER_USER_NETWORKING_MARATHON15 test_app['networks'] = NETWORKS_CONTAINER_USER_MARATHON15 num_ports = get_number_of_app_ports(test_app) assert_that(num_ports, Equals(1))
def test_bridge_networking_mesos_marathon15(self, test_app): """ For Marathon 1.5+, when the app uses Mesos containers with 'container/bridge' networking, the ports should be counted from the ``container.portMappings`` field. """ test_app['container'] = CONTAINER_MESOS_BRIDGE_NETWORKING_MARATHON15 test_app['networks'] = NETWORKS_CONTAINER_BRIDGE_MARATHON15 num_ports = get_number_of_app_ports(test_app) assert_that(num_ports, Equals(3))
def test_bridge_networking_no_port_definitions(self, test_app): """ When the app uses Docker containers with BRIDGE networking, but the 'portDefinitions' field is not defined, the ports should be counted from the 'ports' field. """ test_app['container'] = CONTAINER_BRIDGE_NETWORKING test_app['ports'] = [10008, 10009] num_ports = get_number_of_app_ports(test_app) assert_that(num_ports, Equals(2))