def test_sio_list_data_type_input_json(self): cid = rand_string() data_format = DATA_FORMAT.JSON transport = rand_string() sio_config = {'int_parameters': [rand_string()]} # Not really used but needed service_sio = Bunch() service_sio.input_required = ('first_name', 'last_name', List('emails')) expected_first_name = faker.first_name() expected_last_name = faker.last_name() expected_emails = sorted([faker.email(), faker.email()]) r = Request(getLogger(__name__), sio_config) r.payload = { 'first_name': expected_first_name, 'last_name': expected_last_name, 'emails': expected_emails, } r.init(True, cid, service_sio, data_format, transport, {}) eq_(r.input.first_name, expected_first_name) eq_(r.input.last_name, expected_last_name) eq_(r.input.emails, expected_emails)
def test_nested_to_json(self): n = Nested('elem', 'sub1', Bool('my_bool1'), 'sub2', 'sub3', Dict('my_dict1', 'key1', 'key2')) expected_sub1_2 = rand_string() expected_sub2_2 = rand_string() expected_sub3_2 = rand_string() expected_my_bool1_2 = rand_bool() expected_key1_2 = rand_string() expected_key2_2 = rand_string() value2 = {'elem': { 'sub1': expected_sub1_2, 'sub2': expected_sub2_2, 'my_bool1': expected_my_bool1_2, 'sub3': expected_sub3_2, 'my_dict1' : { 'key1': expected_key1_2, 'key2': expected_key2_2, } }} ret_value = n.to_json(value2) eq_(ret_value, {'elem': {'my_bool1': expected_my_bool1_2, 'sub2': expected_sub2_2, 'sub3': expected_sub3_2, 'my_dict1': {'key2': expected_key2_2, 'key1': expected_key1_2}, 'sub1': expected_sub1_2}} )
def test_add(self): jps = JSONPointerStore() name1, expr1 = '1', config_value('/{}/{}'.format(*rand_string(2))) name2, expr2 = '2', config_value('/aaa/{}/{}'.format(*rand_string(2))) name3, expr3 = '3', config_value('/aaa/{}/{}'.format(*rand_string(2))) name4, expr4 = '2', config_value('/aaa/{}/{}'.format(*rand_string(2))) jps.add(name1, expr1) self.assertIn(name1, jps.data) self.assertEquals(expr1.value, jps.data[name1].path) jps.add(name2, expr2) self.assertIn(name2, jps.data) self.assertEquals(expr2.value, jps.data[name2].path) jps.add(name3, expr3) self.assertIn(name3, jps.data) self.assertEquals(expr3.value, jps.data[name3].path) # name4's value is '2' so it overrides 2 jps.add(name4, expr4) self.assertIn(name4, jps.data) self.assertEquals(expr4.value, jps.data[name2].path) self.assertEquals(expr4.value, jps.data[name4].path)
def test_publish_custom_attrs(self): self._check_publish(**{ 'mime_type': rand_string(), 'priority': rand_int(), 'expiration': rand_int(1000, 2000), 'msg_id': rand_string(), })
def test_main_loop_max_repeats_reached(self): runs_ctx = [] def callback(ctx): runs_ctx.append(ctx) cb_kwargs = { rand_string():rand_string(), rand_string():rand_string() } interval_in_seconds = 0.01 max_repeats = choice(range(2, 5)) job = get_job(interval_in_seconds=interval_in_seconds, max_repeats=max_repeats) job.callback = callback job.cb_kwargs = cb_kwargs self.assertTrue(job.main_loop()) sleep(0.2) len_runs_ctx = len(runs_ctx) self.assertEquals(len_runs_ctx, max_repeats) self.assertFalse(job.keep_running) self.assertIs(job.callback, callback) for idx, ctx in enumerate(runs_ctx, 1): self.check_ctx(ctx, job, interval_in_seconds, max_repeats, idx, cb_kwargs, len_runs_ctx)
def test_response(self): request = {'cluster_id':rand_int(), 'name':rand_string()} expected_id = rand_int() expected_name = rand_string() expected_is_active = rand_bool() expected_impl_name = rand_string() expected_is_internal = rand_bool() service = Service() service.id = expected_id service.name = expected_name service.is_active = expected_is_active service.impl_name = expected_impl_name service.is_internal = expected_is_internal expected = Expected() expected.add(service) instance = self.invoke(GetByName, request, expected) response = Bunch(loads(instance.response.payload.getvalue())['response']) eq_(response.id, expected_id) eq_(response.name, expected_name) eq_(response.is_active, expected_is_active) eq_(response.impl_name, expected_impl_name) eq_(response.is_internal, expected_is_internal) eq_(response.usage, 0)
def test_nested_from_json(self): n = Nested('elem', 'sub1', Bool('my_bool1'), 'sub2', 'sub3', Dict('my_dict1', 'key1', 'key2')) expected_sub1_1 = rand_string() expected_sub2_1 = rand_string() expected_sub3_1 = rand_string() expected_my_bool1_1 = rand_bool() expected_key1_1 = rand_string() expected_key2_1 = rand_string() value1 = {'elem': { 'sub1': expected_sub1_1, 'sub2': expected_sub2_1, 'my_bool1': expected_my_bool1_1, 'sub3': expected_sub3_1, 'my_dict1' : { 'key1': expected_key1_1, 'key2': expected_key2_1, } }} ret_value = n.from_json(value1) eq_(ret_value, {'elem': {'my_bool1': expected_my_bool1_1, 'sub2': expected_sub2_1, 'sub3': expected_sub3_1, 'my_dict1': {'key2': expected_key2_1, 'key1': expected_key1_1}, 'sub1': expected_sub1_1}} )
def get_response_data(self): return Bunch({'id':rand_int(), 'name':self.name, 'is_active':rand_bool(), 'is_internal':rand_bool(), 'url_path':rand_string(), 'service_id':rand_int(), 'service_name':rand_string(), 'security_id':rand_int(), 'security_name':rand_int(), 'sec_type':rand_string(), 'method':rand_string(), 'soap_action':rand_string(), 'soap_version':rand_string(), 'data_format':rand_string(), 'host':rand_string(), 'ping_method':rand_string(), 'pool_size':rand_int()} )
def test__set_tls_info(self): expected_cert_dict = rand_string() expected_cert_der = rand_string() expected_cert_sha1 = sha1(expected_cert_der).hexdigest().upper() for wsgi_url_scheme in('https', 'http'): wsgi_environ = { 'wsgi.url_scheme': wsgi_url_scheme, 'gunicorn.socket': FakeGunicornSocket(expected_cert_der, expected_cert_dict), 'zato.http.response.status': rand_string(), 'zato.http.channel_item': Bunch(audit_enabled=False), } ps = ParallelServer() ps.worker_store = FakeWorkerStore() ps.on_wsgi_request(wsgi_environ, StartResponse()) if wsgi_url_scheme == 'https': eq_(wsgi_environ['zato.tls.client_cert.dict'], expected_cert_dict) eq_(wsgi_environ['zato.tls.client_cert.der'], expected_cert_der) eq_(wsgi_environ['zato.tls.client_cert.sha1'], expected_cert_sha1) else: self.assertTrue('zato.tls.client_cert.dict' not in wsgi_environ) self.assertTrue('zato.tls.client_cert.der' not in wsgi_environ) self.assertTrue('zato.tls.client_cert.sha1' not in wsgi_environ)
def test_client_ok(self): cid = new_cid() headers = {'x-zato-cid':cid} ok = True _rand = rand_string() soap_action = rand_string() text = """ <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Body> <abc>{}</abc> </soapenv:Body> </soapenv:Envelope>""".format(_rand).strip() status_code = rand_int() client = self.get_client(FakeInnerResponse(headers, ok, text, status_code)) response = client.invoke(soap_action) expected_response_data = """ <abc xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">{}</abc> """.format(_rand).strip() eq_(response.details, None) eq_(response.ok, ok) eq_(response.inner.text, text) eq_(etree.tostring(response.data), expected_response_data) eq_(response.has_data, True) eq_(response.cid, cid)
def get_response_data(self): return Bunch({'id':rand_int(), 'name':self.name, 'host':rand_string(), 'port':rand_int(), 'queue_manager':rand_int(), 'channel':rand_string(), 'cache_open_send_queues':rand_bool(), 'cache_open_receive_queues':rand_bool(), 'use_shared_connections':rand_bool(), 'ssl':rand_bool(), 'needs_mcd':rand_bool(), 'max_chars_printed':rand_int(), 'ssl_cipher_spec':rand_string(), 'ssl_key_repository':rand_string()})
def test_message_serialization(self): msg_id = rand_string() creation_time_utc = rand_date_utc() expire_at_utc = rand_date_utc() producer = rand_string() topic = rand_string() actual = self._get_object(Message, { 'msg_id': msg_id, 'creation_time_utc': creation_time_utc, 'expire_at_utc': expire_at_utc, 'producer': producer, 'topic':topic, }) expected = { 'mime_type': PUB_SUB.DEFAULT_MIME_TYPE, 'msg_id': msg_id, 'topic': topic, 'expiration': PUB_SUB.DEFAULT_EXPIRATION, 'producer': producer, 'creation_time_utc': creation_time_utc.isoformat(), 'priority': PUB_SUB.DEFAULT_PRIORITY, 'expire_at_utc': expire_at_utc.isoformat() } # Dicts must be equal .. assert_equal(actual.to_dict(), expected) # .. as well as JSON. json = actual.to_json() self.assertIsInstance(json, str) unjsonified = loads(json) assert_equal(unjsonified, expected)
def test__startup_services(self): class FakeBrokerClient(object): def __init__(self): self.messages = {} def invoke_async(self, msg): self.messages[msg['service']] = msg broker_client = FakeBrokerClient() startup_services = Bunch() for x in range(10): name = rand_string() payload = rand_string() startup_services[name] = payload ps = ParallelServer() ps.broker_client = broker_client ps.fs_server_config = Bunch() ps.fs_server_config.startup_services = startup_services ps.invoke_startup_services() for expected_service, expected_payload in startup_services.items(): msg = Bunch(broker_client.messages[expected_service]) eq_(msg.action, SERVICE.PUBLISH) eq_(msg.channel, CHANNEL.STARTUP_SERVICE) eq_(msg.payload, expected_payload) eq_(msg.service, expected_service) ok_(msg.cid.startswith('K')) self.assertEquals(len(msg.cid), 40)
def test_client(self): cid = new_cid() headers = {'x-zato-cid':cid} ok = True env = { 'details': rand_string(), 'result': ZATO_OK, 'cid': cid } sio_payload_key = rand_string() sio_payload = {rand_string(): rand_string()} sio_response = { 'zato_env': env, sio_payload_key: sio_payload } text = dumps(sio_response) status_code = rand_int() client = self.get_client(FakeInnerResponse(headers, ok, text, status_code)) response = client.invoke() eq_(response.ok, ok) eq_(response.inner.text, text) eq_(response.data.items(), sio_response[sio_payload_key].items()) eq_(response.has_data, True) eq_(response.cid, cid) eq_(response.cid, sio_response['zato_env']['cid']) eq_(response.details, sio_response['zato_env']['details'])
def test_get_retry_settings_has_invalid_async_callback(self): ir = InvokeRetry(None) callback = [None, rand_string()] repeats = [None, rand_int()] target = rand_string() for callback_item in callback: for repeats_item in repeats: kwargs = { 'async_fallback': True, 'callback': callback_item, 'repeats': repeats_item, } try: ir._get_retry_settings(target, **kwargs) except ValueError, e: for name in 'callback', 'repeats': if name in e.message: self.assertEquals(e.message, 'Could not invoke `{}`, `{}` was not provided ({})'.format( target, name, None)) else: self.assertTrue(callback_item is not None) self.assertTrue(repeats_item is not None)
def test_sio_list_data_type_input_xml(self): cid = rand_string() data_format = DATA_FORMAT.XML transport = rand_string() sio_config = {'int_parameters': [rand_string()]} # Not really used but needed service_sio = Bunch() service_sio.input_required = ('first_name', 'last_name', List('emails')) expected_first_name = faker.first_name() expected_last_name = faker.last_name() expected_emails = sorted([faker.email(), faker.email()]) r = Request(getLogger(__name__), sio_config) r.payload = etree.fromstring("""<request> <first_name>{}</first_name> <last_name>{}</last_name> <emails> <item>{}</item> <item>{}</item> </emails> </request>""".format( expected_first_name, expected_last_name, expected_emails[0], expected_emails[1])) r.init(True, cid, service_sio, data_format, transport, {}) eq_(r.input.first_name, expected_first_name) eq_(r.input.last_name, expected_last_name) eq_(r.input.emails, expected_emails)
def setUp(self): self.url = rand_string() self.auth = None self.path = rand_string() self.session = FakeSession() self.to_bunch = rand_bool() self.max_response_repr = 10000 self.max_cid_repr = rand_int() self.logger = rand_object()
def test_publish_custom_attrs(self): self._check_publish( **{ "mime_type": rand_string(), "priority": rand_int(), "expiration": rand_int(1000, 2000), "msg_id": rand_string(), } )
def test_retry_limit_reached_msg(self): retry_repeats = rand_int() service_name = rand_string() retry_seconds = rand_int() orig_cid = rand_string() msg = retry_limit_reached_msg(retry_repeats, service_name, retry_seconds, orig_cid) self.assertEquals(msg, '({}/{}) Retry limit reached for:`{}`, retry_seconds:`{}`, orig_cid:`{}`'.format( retry_repeats, retry_repeats, service_name, retry_seconds, orig_cid))
def get_request_data(self): return { "cluster_id": rand_int(), "name": self.name, "is_active": rand_bool(), "address": rand_string(), "socket_type": rand_string(), "service": rand_string(), "sub_key": rand_string(), "data_format": rand_string(), }
def test_retry_failed_msg(self): so_far = rand_int() retry_repeats = rand_int() service_name = rand_string() retry_seconds = rand_int() orig_cid = rand_string() try: raise_exception() except Exception, e: pass
def test_clients(self): for class_ in AnyServiceInvoker, JSONClient, JSONSIOClient, XMLClient, RawDataClient, SOAPClient, SOAPSIOClient: with patch('zato.client._Client.inner_invoke', self.get_inner_invoke()): client = class_(*rand_string(2)) header1, value1 = rand_string(2) header2, value2 = rand_string(2) headers = {header1:value1, header2:value2} response = client.invoke(rand_string(), headers=headers) eq_(sorted(headers.items()), sorted(response.headers.items()))
def test_get_ctx_custom_attrs(self): sub_key = rand_string() max_batch_size = rand_int() is_fifo = rand_bool() get_format = rand_string() ctx = GetCtx(sub_key, max_batch_size, is_fifo, get_format) self.assertEquals(ctx.sub_key, sub_key) self.assertEquals(ctx.max_batch_size, max_batch_size) self.assertEquals(ctx.is_fifo, is_fifo) self.assertEquals(ctx.get_format, get_format)
def handle(self): dn = self.dictnav(self.request.input) response = { 'key1': sorted(dn.get(['nested', 'a']).items()), 'value': dn.get(['nested', 'a', 'b', 'c']), 'has_key_flat_true': dn.has_key('flat', False), 'has_key_flat_false': dn.has_key(rand_string(), True), 'has_key_nested_true': dn.has_key('b'), 'has_key_nested_false': dn.has_key(rand_string()), 'has_path': dn.has_path(['nested', 'a', 'b', 'c']), } self.response.payload = response
def test_reject_ctx_custom_attrs(self): sub_key = rand_string() msg_ids = rand_string(2) ctx = RejectCtx(sub_key, msg_ids) self.assertEquals(ctx.sub_key, sub_key) self.assertEquals(ctx.msg_ids, msg_ids) msg_id = rand_string() ctx.append(msg_id) self.assertEquals(ctx.msg_ids, msg_ids)
def test_subscribe(self): client_id, client_name = rand_int(), rand_string() client = Client(client_id, client_name) topics = rand_string(rand_int()) sub_key = self.api.subscribe(client.id, topics) self.assertEquals(self.api.impl.sub_to_cons[sub_key], client_id) self.assertEquals(self.api.impl.cons_to_sub[client_id], sub_key) self.assertEquals(sorted(self.api.impl.cons_to_topic[client_id]), sorted(topics)) for topic in topics: self.assertIn(client_id, self.api.impl.topic_to_cons[topic])
def test_ping_method(self): """ https://github.com/zatosource/zato/issues/44 (outconn HTTP/SOAP ping method) """ config = self._get_config() expected_ping_method = 'ping-{}'.format(rand_string()) config['ping_method'] = expected_ping_method requests_module = _FakeRequestsModule() wrapper = HTTPSOAPWrapper(config, requests_module) wrapper.ping(rand_string()) ping_method = requests_module.session_obj.request_args[0] eq_(expected_ping_method, ping_method)
def test_pool_size(self): """ https://github.com/zatosource/zato/issues/77 (outconn HTTP/SOAP pool size) """ expected_pool_size = rand_int() requests_module = _FakeRequestsModule() config = {'sec_type':rand_string(), 'address':rand_string(), 'ping_method':rand_string(), 'pool_size':expected_pool_size} wrapper = HTTPSOAPWrapper(config, requests_module) wrapper.ping(rand_string()) eq_(expected_pool_size, requests_module.session_obj.pool_size)
def test_ping_method(self): """ https://github.com/zatosource/zato/issues/44 (outconn HTTP/SOAP ping method) """ expected_ping_method = 'ping-{}'.format(rand_string()) requests_module = _FakeRequestsModule() config = {'sec_type':rand_string(), 'address':rand_string(), 'ping_method':expected_ping_method, 'pool_size':rand_int()} wrapper = HTTPSOAPWrapper(config, requests_module) wrapper.ping(rand_string()) ping_method = requests_module.session_obj.request_args[0] eq_(expected_ping_method, ping_method)
def _publish_move(self, move=True, **kwargs): payload = rand_string() topic = Topic(rand_string()) self.api.add_topic(topic) producer = Client(rand_int(), rand_string()) self.api.add_producer(producer, topic) ctx = self.api.publish(payload, topic.name, client_id=producer.id, **kwargs) if move: self.api.impl.move_to_target_queues() return payload, topic, producer, ctx
def test_dictnav(self): key1, key2, key3 = 'a', 'b', 'c' value = rand_string() d = {'flat': 123, 'nested': {key1: {key2: {key3: value}}}} class MyService(Service): def handle(self): dn = self.dictnav(self.request.input) # 'nopep8' is needed because otherwise flake8 treats .has_key as though # it belonged to a dict which is not the case. # I.e. W601 .has_key() is deprecated, use 'in' response = { 'key1': sorted(dn.get(['nested', 'a']).items()), 'value': dn.get(['nested', 'a', 'b', 'c']), 'has_key_flat_true': dn.has_key('flat', False), # nopep8 'has_key_flat_false': dn.has_key(rand_string(), True), 'has_key_nested_true': dn.has_key('b'), 'has_key_nested_false': dn.has_key(rand_string()), 'has_path': dn.has_path(['nested', 'a', 'b', 'c']), } self.response.payload = response service = MyService() service.request.input = d service.handle() eq_(service.response.payload['key1'], [('b', {'c': value})]) eq_(service.response.payload['value'], value) eq_(service.response.payload['has_key_flat_true'], True) eq_(service.response.payload['has_key_flat_false'], False) eq_(service.response.payload['has_key_nested_true'], True) eq_(service.response.payload['has_key_nested_false'], False) eq_(service.response.payload['has_path'], True)
def test_namespace(self): gen = Generator(get_service_store_services( Namespace1, Namespace2, Namespace3, Namespace11, Namespace22, Namespace33, NoNamespace), simple_io_config) info = gen.get_info(rand_string()) sns1 = get_services_from_info('name', '_test.namespace1', info) sns2 = get_services_from_info('name', '_test.namespace2', info) sns3 = get_services_from_info('name', '_test.namespace3', info) sns11 = get_services_from_info('name', '_test.namespace11', info) sns22 = get_services_from_info('name', '_test.namespace22', info) sns33 = get_services_from_info('name', '_test.namespace33', info) snons = get_services_from_info('name', '_test.no-namespace', info) namespaces = bunchify(info['namespaces']) myns = namespaces['myns'] my_other_ns = namespaces['my-other-ns'] my_other_ns_abc = namespaces['my-other-ns-abc'] self.assertEquals(myns.name, 'myns') self.assertEquals(myns.docs, """This is my namespace.\nAs with regular docstrings it can contain multi-line documentation.\n\n* Documentation will be parsed as Markdown\n* Bullet lists *and* other non-obtrusive markup can be used\n""") self.assertEquals(myns.docs_md, """<p>This is my namespace.\nAs with regular docstrings it can contain multi-line documentation.</p>\n<ul>\n<li>Documentation will be parsed as Markdown</li>\n<li>Bullet lists <em>and</em> other non-obtrusive markup can be used</li>\n</ul>""") self.assertEquals(my_other_ns.name, 'my-other-ns') self.assertEquals(my_other_ns.docs, '') self.assertEquals(my_other_ns.docs_md, '') self.assertEquals(my_other_ns_abc.name, 'my-other-ns-abc') self.assertEquals(my_other_ns_abc.docs, '') self.assertEquals(my_other_ns_abc.docs_md, '') self.assertEquals(sns1.namespace_name, 'myns') self.assertEquals(sns2.namespace_name, 'my-other-ns') self.assertEquals(sns3.namespace_name, 'myns') self.assertEquals(sns11.namespace_name, 'myns') self.assertEquals(sns22.namespace_name, 'myns') self.assertEquals(sns33.namespace_name, 'my-other-ns-abc') self.assertEquals(snons.namespace_name, APISPEC.NAMESPACE_NULL)
def test_lock_ok(self): """ Succesfully grab a service lock. """ my_kvdb = FakeKVDB() my_kvdb.conn.setnx_return_value = True lock_name = rand_string() expires = 500 + rand_int( ) # It's 500 which means DummyService.invoke has that many seconds to complete timeout = rand_int() class DummyService(Service): kvdb = my_kvdb def handle(self): with self.lock(lock_name, expires, timeout): pass instance = DummyService() instance.handle() eq_(my_kvdb.conn.delete_args, KVDB.LOCK_SERVICE_PREFIX + lock_name) eq_(my_kvdb.conn.expire_args, (KVDB.LOCK_SERVICE_PREFIX + lock_name, expires)) # First arg is the lock_name that can ne checked directly but the other # one is the expiration time that we can check only approximately, # anything within 3 seconds range is OK. The value of 3 is the maximum # time allowed for execution of DummyService's invoke method which is # way more than needed but let's use 3 to be on the safe side when the # test is run on a very slow system. eq_(my_kvdb.conn.setnx_args[0], KVDB.LOCK_SERVICE_PREFIX + lock_name) expires_approx = time() + expires self.assertAlmostEquals(my_kvdb.conn.setnx_args[1], expires_approx, delta=3)
def test_convert_check_priority(self): func_to_type = { rand_bool: Boolean, rand_float: Float, rand_int: Integer, rand_string: str, } for func, type_ in func_to_type.items(): for params_priority in PARAMS_PRIORITY: param_name = rand_string() payload_value = func() channel_value = func() args = self.get_args(param=type_(param_name), channel_params={param_name:channel_value}, payload={param_name:payload_value}, params_priority=params_priority) given_param_name, given_value = convert_param(**args) expected_value = channel_value if params_priority == PARAMS_PRIORITY.CHANNEL_PARAMS_OVER_MSG else payload_value self.assertEquals(param_name, given_param_name) self.assertEquals(expected_value, given_value)
def test_publish_exceptions(self): payload = rand_string() producer = Client(rand_int(), rand_string()) def invoke_publish(payload, topic, producer_id): self.api.publish(payload, topic, client_id=producer_id) # KeyError because no such producer is in self.api.impl.producers. self.assertRaises(KeyError, invoke_publish, payload, rand_string(), producer.id) # Adding a producer but still, no such topic. self.api.add_producer(producer, Topic(rand_string())) self.assertRaises(PubSubException, invoke_publish, payload, rand_string(), producer.id) # Adding a topic but still PubSubException is raised because the producer is not allowed to use it. topic = Topic(rand_string()) self.api.add_topic(topic) self.assertRaises(PubSubException, invoke_publish, payload, topic.name, producer.id) # Combining the topic and producer, no exception is raised now. self.api.add_producer(producer, topic) invoke_publish(payload, topic.name, producer.id) # But it's not possible to publish to inactive topics. self.api.impl.topics[topic.name].is_active = False self.assertRaises(PubSubException, invoke_publish, payload, topic.name, producer.id) # Make the topic active and it can be published to again. self.api.impl.topics[topic.name].is_active = True invoke_publish(payload, topic.name, producer.id) # Inactive producers cannot publish to topics either. self.api.impl.producers[producer.id].is_active = False self.assertRaises(PubSubException, invoke_publish, payload, topic.name, producer.id) # Making them active means they can publish again. self.api.impl.producers[producer.id].is_active = True invoke_publish(payload, topic.name, producer.id)
def test_create_headers_user_headers_data_format(self): cid = rand_string() now = datetime.utcnow().isoformat() content_type = rand_string() requests_module = _FakeRequestsModule() config = self._get_config() wrapper = HTTPSOAPWrapper(config, requests_module) user_headers = {rand_string():rand_string(), rand_string():rand_string(), 'Content-Type':content_type} headers = wrapper._create_headers(cid, user_headers, now) eq_(headers.pop('X-Zato-CID'), cid) eq_(headers.pop('X-Zato-Msg-TS'), now) eq_(headers.pop('X-Zato-Component'), get_component_name()) eq_(headers.pop('Content-Type'), content_type) # Anything that is left must be user headers self.assertDictEqual(headers, user_headers)
def get_request_data(self): return { 'cluster_id': rand_int(), 'connection': rand_string(), 'transport': rand_string() }
def test_handle_simple_ok_exception(self): test_instance = self for is_ok in True, False: expected_response = 'expected_response_{}'.format( rand_string()) if is_ok else None class Ping(object): name = 'zato.ping' def __init__(self): self.response = Bunch(payload=expected_response) test_instance.given_response = expected_response def accept(self): return True def update(self, *ignored_args, **ignored_kwargs): if not is_ok: raise Exception() post_handle = validate_output = handle = validate_input = call_hooks = pre_handle = update callback = rand_string() target = 'zato.ping' orig_cid, call_cid = new_cid(), new_cid() source, req_ts_utc = rand_string(), rand_string() ping_impl = 'zato.service.internal.Ping' service_store_name_to_impl_name = { 'zato.ping': ping_impl, callback: ping_impl } service_store_impl_name_to_service = {ping_impl: Ping} payload = { 'source': source, 'req_ts_utc': req_ts_utc, 'orig_cid': orig_cid, 'call_cid': call_cid, 'callback': callback, 'callback_context': { rand_string(): rand_string() }, 'target': target, 'retry_repeats': 4, 'retry_seconds': 0.1, 'args': [1, 2, 3], 'kwargs': { rand_string(): rand_string(), rand_int(): rand_int() }, } instance = self.invoke( InvokeRetry, dumps(payload), None, service_store_name_to_impl_name=service_store_name_to_impl_name, service_store_impl_name_to_service= service_store_impl_name_to_service) gevent.sleep(0.5) self.assertEquals(len(instance.broker_client.invoke_async_args), 1) self.assertEquals(len(instance.broker_client.invoke_async_args[0]), 1) async_msg = Bunch(instance.broker_client.invoke_async_args[0][0]) self.assertEquals(len(async_msg), 11) self.assertEquals(async_msg.action, SERVICE.PUBLISH.value) self.assertEquals(async_msg.channel, CHANNEL.INVOKE_ASYNC) self.assertEquals(async_msg.data_format, DATA_FORMAT.DICT) self.assertEquals(async_msg.transport, None) resp_ts_utc = async_msg.payload.pop('resp_ts_utc') # Is it a date? If not, an exception will be raised while parsing. arrow.get(resp_ts_utc) expected_response_msg = { 'ok': is_ok, 'source': source, 'target': target, 'req_ts_utc': req_ts_utc, 'orig_cid': orig_cid, 'call_cid': call_cid, 'retry_seconds': payload['retry_seconds'], 'context': payload['callback_context'], 'retry_repeats': payload['retry_repeats'], 'response': expected_response, } self.assertDictEqual(expected_response_msg, async_msg.payload) self.assertTrue( len(instance.broker_client.invoke_async_kwargs) == 1) self.assertEquals(instance.broker_client.invoke_async_kwargs[0], {'expiration': BROKER.DEFAULT_EXPIRATION})
def get_request_data(self): return {'cluster_id': rand_int(), 'name':rand_string()}
def get_response_data(self): return Bunch({'id':rand_int(), 'name':rand_string, 'is_active':rand_bool(), 'sec_type':rand_string(), 'username':rand_string(), 'realm':rand_string(), 'password_type':rand_string(), 'reject_empty_nonce_creat':rand_bool(), 'reject_stale_tokens':rand_bool(),'reject_expiry_limit':rand_int(), 'nonce_freshness_time':rand_int()})
def get_request_data(self): return {'pong': rand_string()}
def get_request_data(self): return ({'cluster_id':rand_int(), 'name':rand_string(), 'is_active':rand_bool(), 'job_type':rand_string(), 'service':rand_string(), 'start_date':rand_datetime(), 'id':rand_int(), 'extra':rand_string(), 'weeks':rand_int(), 'days':rand_int(), 'hours':rand_int(), 'minutes':rand_int(), 'seconds':rand_int(), 'repeats':rand_int(), 'cron_definition':rand_string()} )
def get_request_data(self): return ({ 'cluster_id': rand_int(), 'name': rand_string(), 'is_active': rand_bool(), 'connection': rand_string(), 'transport': rand_string(), 'url_path': rand_string(), 'service': rand_string(), 'security': rand_string(), 'security_id': rand_int(), 'method': rand_string(), 'soap_action': rand_string(), 'soap_version': rand_string(), 'data_format': rand_string(), 'host': rand_string() })
def test_pub_ctx_custom_attrs(self): client_id, topic, msg = rand_string(3) ctx = PubCtx(client_id, topic, msg) self.assertEquals(ctx.client_id, client_id) self.assertEquals(ctx.topic, topic) self.assertEquals(ctx.msg, msg)
def test_get_reject_acknowledge(self): payload, topic, producer, ctx = self._publish_move(move=False) client_id, client_name = rand_int(), rand_string() client = Client(client_id, client_name) sub_key = self.api.subscribe(client.id, topic.name) # Moves a message to the consumer's queue self.api.impl.move_to_target_queues() self._check_consumer_queue_before_get(ctx, sub_key) # Consumer gets a message which puts it in the in-flight state. self._check_get(ctx, sub_key, topic, producer, client) # However, there should be nothing in the consumer's queue. consumer_msg_ids = self.kvdb.lrange( self.api.impl.CONSUMER_MSG_IDS_PREFIX.format(sub_key), 0, -1) self.assertEquals(consumer_msg_ids, []) # Consumer rejects the message which puts it back on a queue. self.api.reject(sub_key, ctx.msg.msg_id) # After rejection it's as though the message has just been published. self._check_consumer_queue_before_get(ctx, sub_key) # Get after rejection works as before. self._check_get(ctx, sub_key, topic, producer, client) # Consumer acknowledges a message. self.api.acknowledge(sub_key, ctx.msg.msg_id) # This was the only one subscription so now that the message has been delivered # there should be no trace of it in backend. # The only keys left are LAST_PUB_TIME_KEY, LAST_SEEN_CONSUMER_KEY and LAST_SEEN_PRODUCER_KEY - nothing else. keys = self.kvdb.keys('{}*'.format(self.key_prefix)) self.assertEquals(len(keys), 3) now = datetime.utcnow() last_pub_time = parse( self.kvdb.hgetall(self.api.impl.LAST_PUB_TIME_KEY)[topic.name]) last_seen_consumer = parse( self.kvdb.hgetall(self.api.impl.LAST_SEEN_CONSUMER_KEY)[str( client.id)]) last_seen_producer = parse( self.kvdb.hgetall(self.api.impl.LAST_SEEN_PRODUCER_KEY)[str( producer.id)]) self.assertTrue( last_pub_time < now, 'last_pub_time:`{}` is not less than now:`{}`'.format( last_pub_time, now)) self.assertTrue( last_seen_consumer < now, 'last_seen_consumer:`{}` is not less than now:`{}`'.format( last_seen_consumer, now)) self.assertTrue( last_seen_producer < now, 'last_seen_producer:`{}` is not less than now:`{}`'.format( last_seen_producer, now))
def get_request_data(self): return {'id':rand_int(), 'cluster_id':rand_int(), 'name':rand_string(), 'is_active':rand_bool(), 'def_id':rand_int(), 'delivery_mode':rand_string(),'priority':rand_int(), 'content_type':rand_string(), 'content_encoding':rand_string(), 'expiration':rand_int(), 'user_id':rand_string(), 'app_id':rand_string()}
config = self._get_config() config['address_host'] = address_host config['address_url_path'] = address_url_path requests_module = _FakeRequestsModule() wrapper = HTTPSOAPWrapper(config, requests_module) try: wrapper.format_address(cid, None) except ValueError, e: eq_(e.message, 'CID:[{}] No parameters given for URL path'.format(cid)) else: self.fail('Expected ValueError (params is None)') a = rand_string() b = rand_string() c = rand_string() d = rand_string() e = rand_string() f = rand_string() params = {'a': a, 'b': b, 'c': c, 'd': d, 'e': e, 'f': f} address, non_path_params = wrapper.format_address(cid, params) eq_(address, '{}/a/{}/b{}/c-{}/{}d/'.format(address_host, a, b, c, d)) eq_(non_path_params, {'e': e, 'f': f}) params = {'a': a, 'b': b} try: address, non_path_params = wrapper.format_address(cid, params)
def test_http_methods(self): address_host = rand_string() config = self._get_config() config['is_active'] = True config['soap_version'] = '1.2' config['address_host'] = address_host requests_module = _FakeRequestsModule() wrapper = HTTPSOAPWrapper(config, requests_module) for address_url_path in ('/zzz', '/a/{a}/b/{b}'): for transport in ('soap', rand_string()): for name in ('get', 'delete', 'options', 'post', 'put', 'patch'): config['transport'] = transport _cid = rand_string() _data = rand_string() expected_http_request_value = rand_string() expected_http_request_value = rand_string() expected_params = rand_string() expected_args1 = rand_string() expected_args2 = rand_string() expected_kwargs1 = rand_string() expected_kwargs2 = rand_string() def http_request(method, cid, data='', params=None, *args, **kwargs): eq_(method, name.upper()) eq_(cid, _cid) if name in ('get', 'delete', 'options'): eq_(data, '') else: eq_(data, _data) eq_(params, expected_params) eq_(args, (expected_args1, expected_args2)) eq_(sorted(kwargs.items()), [('bar', expected_kwargs2), ('foo', expected_kwargs1)]) return expected_http_request_value def format_address(cid, params): return expected_http_request_value wrapper.http_request = http_request wrapper.format_address = format_address func = getattr(wrapper, name) if name in ('get', 'delete', 'options'): http_request_value = func(_cid, expected_params, expected_args1, expected_args2, foo=expected_kwargs1, bar=expected_kwargs2) else: http_request_value = func(_cid, _data, expected_params, expected_args1, expected_args2, foo=expected_kwargs1, bar=expected_kwargs2) eq_(http_request_value, expected_http_request_value)
def test_dict_no_keys_specified(self): d = Dict('d') value = {rand_string(): rand_string(), rand_string(): rand_string()} ret_value = d.from_json(value) eq_(value, ret_value)
def request(self, *args, **kwargs): self.request_args = args self.request_kwargs = kwargs return Bunch({'status_code': rand_string()})
def get_response_data(self): return Bunch({'info': rand_string()})
def test_main_loop_sleep_spawn_called(self): wait_time = 0.2 sleep_time = rand_int() now_values = [parse_datetime('2019-12-23 22:19:03'), parse_datetime('2021-05-13 17:35:48')] sleep_history = [] spawn_history = [] sleep_time_history = [] def sleep(value): if value != wait_time: sleep_history.append(value) def spawn(*args, **kwargs): spawn_history.append([args, kwargs]) def get_sleep_time(*args, **kwargs): sleep_time_history.append(args[1]) return sleep_time with patch('gevent.sleep', sleep): with patch('zato.scheduler.backend.Job._spawn', spawn): with patch('zato.scheduler.backend.Job.get_sleep_time', get_sleep_time): for now in now_values: self.now = now with patch('zato.scheduler.backend.datetime', self._datetime): for job_type in SCHEDULER.JOB_TYPE.CRON_STYLE, SCHEDULER.JOB_TYPE.INTERVAL_BASED: max_repeats = choice(range(2, 5)) cb_kwargs = { rand_string():rand_string(), rand_string():rand_string() } interval = Interval(seconds=sleep_time) if job_type == SCHEDULER.JOB_TYPE.INTERVAL_BASED \ else CronTab(DEFAULT_CRON_DEFINITION) job = Job(rand_int(), rand_string(), job_type, interval, max_repeats=max_repeats) if job.type == SCHEDULER.JOB_TYPE.CRON_STYLE: job.cron_definition = DEFAULT_CRON_DEFINITION job.cb_kwargs = cb_kwargs job.start_time = datetime.utcnow() job.callback = dummy_callback self.assertTrue(job.main_loop()) time.sleep(0.5) self.assertEquals(max_repeats, len(sleep_history)) self.assertEquals(max_repeats, len(spawn_history)) for item in sleep_history: self.assertEquals(sleep_time, item) for idx, (callback, ctx_dict) in enumerate(spawn_history, 1): self.assertEquals(2, len(callback)) callback = callback[1] self.check_ctx( ctx_dict['ctx'], job, sleep_time, max_repeats, idx, cb_kwargs, len(spawn_history), job_type) self.assertIs(callback, dummy_callback) del sleep_history[:] del spawn_history[:] for item in sleep_time_history: self.assertEquals(item, now) del sleep_time_history[:]
def dispatch(self, *ignored_args, **ignored_kwargs): return rand_string()
def get_response_data(self): return Bunch({'id':rand_int(), 'name':self.name, 'is_active':rand_bool(), 'job_type':rand_string(), 'start_date':rand_datetime(), 'service_id':rand_int(), 'service_name':rand_string(), 'extra':rand_string(), 'weeks':rand_int(), 'days':rand_int(), 'minutes':rand_int(), 'seconds':rand_int(), 'repeats':rand_int(), 'cron_definition':rand_string(), '':True} )
def get_context(): ctx = {'name': rand_string(), 'type':SCHEDULER.JOB_TYPE.INTERVAL_BASED} data['ctx'].append(ctx) return ctx
def get_request_data(self): return { 'id': rand_int(), 'password1': rand_string(), 'password2': rand_string() }
def test_sub_ctx_custom_attrs(self): client_id, topics = rand_string(2) ctx = SubCtx(client_id, topics) self.assertEquals(ctx.client_id, client_id) self.assertEquals(ctx.topics, topics)
def test_audit(self): for expected_audit_enabled in (True, False): for expected_status_code in (httplib.OK, httplib.FORBIDDEN): for use_x_remote_addr in (True, False): expected_auth_ok = True if expected_status_code == httplib.OK else False expected_invoke_ok = True if expected_auth_ok is True else False expected_cid = new_cid() expected_url_scheme = rand_string() expected_payload = rand_string() expected_audit_repl_patt_type = rand_string() expected_replace_patterns_json_pointer = [] expected_replace_patterns_xpath = [] expected_cluster_id = rand_int() expected_id = rand_int() expected_name = rand_string() expected_password = '******' expected_username = rand_string() expected_transport = rand_string() expected_connection = rand_string() expected_data_format = DATA_FORMAT.JSON expected_is_active = True expected_request = rand_string() expected_audit_max_payload = len( expected_request ) - 7 # Substracting any value would do expected_channel_item_key1 = rand_string() expected_channel_item_value1 = rand_string() expected_match_target = rand_string() channel_item = { 'id': expected_id, 'name': expected_name, 'transport': expected_transport, 'connection': expected_connection, 'audit_enabled': expected_audit_enabled, expected_channel_item_key1: expected_channel_item_value1, 'audit_repl_patt_type': expected_audit_repl_patt_type, 'replace_patterns_json_pointer': expected_replace_patterns_json_pointer, 'replace_patterns_xpath': expected_replace_patterns_xpath, 'audit_max_payload': expected_audit_max_payload, 'is_active': expected_is_active, 'data_format': DATA_FORMAT.JSON, 'match_target': expected_match_target, 'username': expected_username, 'method': '', } wsgi_environ = { 'wsgi.url_scheme': expected_url_scheme, 'gunicorn.socket': FakeGunicornSocket(None, None), 'zato.http.response.status': expected_status_code, 'zato.http.channel_item': channel_item, 'PATH_INFO': rand_string(), 'wsgi.input': StringIO(expected_request), 'REQUEST_METHOD': rand_string(), 'SERVER_PROTOCOL': rand_string(), 'HTTP_USER_AGENT': rand_string(), } expected_remote_addr = rand_string() if use_x_remote_addr: expected_remote_addr_header = 'HTTP_X_FORWARDED_FOR' wsgi_environ[ expected_remote_addr_header] = expected_remote_addr else: expected_remote_addr_header = 'REMOTE_ADDR' wsgi_environ[ expected_remote_addr_header] = expected_remote_addr class FakeSession: def __init__(self, audit=None): self.audit = audit self.commit_called = False def close(self): pass def commit(self): self.commit_called = True def add(self, audit): self.audit = audit fake_session = FakeSession() class FakeBrokerClient(object): def __init__(self): self.msg = None def publish(self, msg): self.msg = msg class FakeODB(ODBManager): def __init__(self): self.msg = None self.cluster = Bunch(id=expected_cluster_id) def session(self): return fake_session class FakeURLData(URLData): def __init__(self): self.url_sec = { expected_match_target: Bunch(sec_def=ZATO_NONE) } def match(self, *ignored_args, **ignored_kwargs): return True, channel_item class FakeRequestHandler(object): def handle(self, *ignored_args, **ignored_kwargs): return Bunch(payload=expected_payload, content_type='text/plain', headers={}, status_code=expected_status_code) bc = FakeBrokerClient() ws = FakeWorkerStore() ws.request_dispatcher = RequestDispatcher() ws.request_dispatcher.request_handler = FakeRequestHandler( ) ws.request_dispatcher.url_data = FakeURLData() ws.request_dispatcher.url_data.broker_client = bc ws.request_dispatcher.url_data.odb = FakeODB() ps = ParallelServer() ps.worker_store = ws ps.on_wsgi_request(wsgi_environ, StartResponse(), cid=expected_cid) if expected_audit_enabled: # # Audit 1/2 - Request # # Parsing will confirm the proper value was used datetime.strptime( fake_session.audit.req_time.isoformat(), '%Y-%m-%dT%H:%M:%S.%f') self.assertEquals(fake_session.audit.name, expected_name) self.assertEquals(fake_session.audit.cid, expected_cid) self.assertEquals(fake_session.audit.transport, expected_transport) self.assertEquals(fake_session.audit.connection, expected_connection) self.assertEquals(fake_session.audit.resp_time, None) self.assertEquals(fake_session.audit.user_token, expected_username) self.assertEquals(fake_session.audit.auth_ok, None) self.assertEquals(fake_session.audit.invoke_ok, None) self.assertEquals(fake_session.audit.remote_addr, expected_remote_addr) self.assertEquals( fake_session.audit.req_payload, expected_request[:expected_audit_max_payload]) self.assertEquals(fake_session.audit.resp_headers, None) self.assertEquals(fake_session.audit.resp_payload, None) req_headers = literal_eval( fake_session.audit.req_headers) self.assertEquals( req_headers[expected_remote_addr_header], repr(expected_remote_addr)) self.assertEquals(req_headers['wsgi.url_scheme'], repr(expected_url_scheme)) self.assertEquals(req_headers['gunicorn.socket'], repr(FakeGunicornSocket(None, None))) channel_item = literal_eval( req_headers['zato.http.channel_item']) self.assertEquals(channel_item['audit_max_payload'], expected_audit_max_payload) self.assertEquals(channel_item['name'], expected_name) self.assertEquals(channel_item['username'], expected_username) self.assertEquals( channel_item[expected_channel_item_key1], expected_channel_item_value1) self.assertEquals(channel_item['audit_repl_patt_type'], expected_audit_repl_patt_type) self.assertEquals( channel_item['replace_patterns_json_pointer'], expected_replace_patterns_json_pointer) self.assertEquals(channel_item['is_active'], expected_is_active) self.assertEquals(channel_item['data_format'], expected_data_format) self.assertEquals(channel_item['audit_enabled'], expected_audit_enabled) self.assertEquals(channel_item['password'], expected_password) self.assertEquals(channel_item['transport'], expected_transport) self.assertEquals(channel_item['match_target'], expected_match_target) # # Audit 2/2 - Response # self.assertEquals( bc.msg['action'], CHANNEL_BROKER_MESSAGE. HTTP_SOAP_AUDIT_RESPONSE.value) self.assertEquals(bc.msg['cid'], expected_cid) self.assertEquals(bc.msg['data_format'], DATA_FORMAT.JSON) self.assertEquals( bc.msg['service'], 'zato.http-soap.set-audit-response-data') payload = loads(bc.msg['payload']) self.assertEquals(payload['auth_ok'], expected_auth_ok) self.assertEquals(payload['invoke_ok'], expected_invoke_ok) self.assertEquals(payload['resp_payload'], expected_payload) # Parsing alone will check its format is valid datetime.strptime(payload['resp_time'], '%Y-%m-%dT%H:%M:%S.%f') wsgi_environ = loads(payload['resp_headers']) self.assertEquals(wsgi_environ['wsgi.url_scheme'], repr(expected_url_scheme)) self.assertEquals(wsgi_environ['gunicorn.socket'], repr(FakeGunicornSocket(None, None))) self.assertEquals( wsgi_environ['zato.http.response.status'], "'{} {}'".format( expected_status_code, httplib.responses[expected_status_code], )) channel_item = literal_eval( wsgi_environ['zato.http.channel_item']) self.assertEquals( channel_item[expected_channel_item_key1], expected_channel_item_value1) self.assertEquals(channel_item['audit_enabled'], expected_audit_enabled) self.assertEquals(channel_item['audit_repl_patt_type'], expected_audit_repl_patt_type) self.assertEquals( channel_item['replace_patterns_json_pointer'], expected_replace_patterns_json_pointer) self.assertEquals( channel_item['replace_patterns_xpath'], expected_replace_patterns_xpath) self.assertEquals(channel_item['name'], expected_name) self.assertEquals(channel_item['id'], expected_id) self.assertEquals(channel_item['password'], expected_password) self.assertEquals(channel_item['data_format'], expected_data_format) self.assertEquals(channel_item['transport'], expected_transport) self.assertEquals(channel_item['connection'], expected_connection) self.assertEquals(channel_item['audit_max_payload'], expected_audit_max_payload) self.assertEquals(channel_item['is_active'], expected_is_active) else: # Audit not enabled so no response audit message was published on the broker self.assertTrue(bc.msg is None)
def get_response_data(self): return Bunch({'id': rand_int(), 'name': rand_string()})
def test_access_log(self): def _utcnow(self): return datetime(year=2014, month=1, day=12, hour=16, minute=22, second=12, tzinfo=UTC) local_tz = get_localzone() _now = _utcnow(None) local_dt = _now.replace(tzinfo=UTC).astimezone(local_tz) local_dt = local_tz.normalize(local_dt) request_timestamp = local_dt.strftime(ACCESS_LOG_DT_FORMAT) with patch('arrow.factory.ArrowFactory.utcnow', _utcnow): response = rand_string() * rand_int() cid = new_cid() cluster_id = 1 channel_name = rand_string() url_path = '/{}'.format(rand_string()) user_agent = rand_string() http_version = rand_string() request_method = rand_string() remote_ip = '10.{}.{}.{}'.format(rand_int(), rand_int(), rand_int()) req_timestamp_utc = utcnow() channel_item = { 'name': channel_name, 'audit_enabled': False, 'is_active': True, 'transport': 'plain_http', 'data_format': None, 'match_target': url_path, 'method': '', } wsgi_environ = { 'gunicorn.socket': FakeGunicornSocket(None, None), 'wsgi.url_scheme': 'http', 'wsgi.input': StringIO(response), 'zato.http.response.status': httplib.OK, 'zato.http.channel_item': channel_item, 'zato.request_timestamp_utc': req_timestamp_utc, 'HTTP_X_FORWARDED_FOR': remote_ip, 'PATH_INFO': url_path, 'REQUEST_METHOD': request_method, 'SERVER_PROTOCOL': http_version, 'HTTP_USER_AGENT': user_agent, } class FakeBrokerClient(object): def __init__(self): self.msg = None def publish(self, msg): self.msg = msg class FakeODB(ODBManager): def __init__(self): self.msg = None self.cluster = Bunch(id=cluster_id) class FakeURLData(URLData): def __init__(self): self.url_sec = {url_path: Bunch(sec_def=ZATO_NONE)} def match(self, *ignored_args, **ignored_kwargs): return True, channel_item class FakeRequestHandler(object): def handle(self, *ignored_args, **ignored_kwargs): return Bunch(payload=response, content_type='text/plain', headers={}, status_code=httplib.OK) class FakeAccessLogger(object): def __init__(self): self.extra = {} def info(self, msg, extra): self.extra = extra def isEnabledFor(self, ignored): return True bc = FakeBrokerClient() ws = FakeWorkerStore() ws.request_dispatcher = RequestDispatcher() ws.request_dispatcher.request_handler = FakeRequestHandler() ws.request_dispatcher.url_data = FakeURLData() ws.request_dispatcher.url_data.broker_client = bc ws.request_dispatcher.url_data.odb = FakeODB() ps = ParallelServer() ps.worker_store = ws ps.access_logger = FakeAccessLogger() ps.on_wsgi_request(wsgi_environ, StartResponse(), cid=cid) extra = Bunch(ps.access_logger.extra) eq_(extra.channel_name, channel_name) eq_(extra.user_agent, user_agent) eq_(extra.status_code, '200') eq_(extra.http_version, http_version) eq_(extra.response_size, len(response)) eq_(extra.path, url_path) eq_(extra.cid_resp_time, '{}/0.0'.format( cid)) # It's 0.0 because we mock utcnow to be a constant value eq_(extra.method, request_method) eq_(extra.remote_ip, remote_ip) eq_(extra.req_timestamp_utc, '12/Jan/2014:16:22:12 +0000') eq_(extra.req_timestamp, request_timestamp)