def setUp(self): thread_patch = mock.patch("threading.Thread", autospec=True) thread_patch.start() self.addCleanup(thread_patch.stop) configurator = Configurator() configurator.add_route("example", "/example", request_method="GET") configurator.add_view(example_application, route_name="example", renderer="json") configurator.add_route("local_test", "/local_test", request_method="GET") configurator.add_view(local_parent_trace_within_context, route_name="local_test", renderer="json") self.client = make_client("test-service") self.observer = TraceBaseplateObserver(self.client) self.baseplate = Baseplate() self.baseplate.register(self.observer) self.baseplate_configurator = BaseplateConfigurator( self.baseplate, trust_trace_headers=True, ) configurator.include(self.baseplate_configurator.includeme) app = configurator.make_wsgi_app() self.local_span_ids = [] self.local_span_observers = [] self.test_app = webtest.TestApp(app)
def test_simple_config(self): baseplate = Baseplate({"db.url": "sqlite://"}) baseplate.configure_context({"db": SQLAlchemySession()}) context = baseplate.make_context_object() with baseplate.make_server_span(context, "test"): context.db.execute("SELECT 1;")
def test_connection_error(client_cls): baseplate = Baseplate({ "myclient.filter.ip_allowlist": "127.0.0.0/8", "myclient.filter.port_denylist": "0" }) baseplate.configure_context({"myclient": client_cls()}) observer = TestBaseplateObserver() baseplate.register(observer) bogus_url = "http://localhost:1/" with pytest.raises(requests.exceptions.ConnectionError): with baseplate.server_context("test") as context: context.myclient.get(bogus_url) server_span_observer = observer.children[0] assert len(server_span_observer.children) == 1 client_span_observer = server_span_observer.children[0] assert client_span_observer.span.name == "myclient.request" assert client_span_observer.on_start_called assert client_span_observer.on_finish_called assert client_span_observer.on_finish_exc_info is not None assert client_span_observer.tags["http.url"] == bogus_url assert client_span_observer.tags["http.method"] == "GET" assert "http.status_code" not in client_span_observer.tags
def test_configure_context_supports_complex_specs(self): from baseplate.clients.thrift import ThriftClient from baseplate.thrift import BaseplateService app_config = { "enable_some_fancy_feature": "true", "thrift.foo.endpoint": "localhost:9090", "thrift.bar.endpoint": "localhost:9091", } baseplate = Baseplate() baseplate.configure_context( app_config, { "enable_some_fancy_feature": config.Boolean, "thrift": { "foo": ThriftClient(BaseplateService.Client), "bar": ThriftClient(BaseplateService.Client), }, }, ) context = baseplate.make_context_object() with baseplate.make_server_span(context, "test"): self.assertTrue(context.enable_some_fancy_feature) self.assertIsNotNone(context.thrift.foo) self.assertIsNotNone(context.thrift.bar)
def http_server(gevent_socket): class HttpServer: def __init__(self, address): self.url = f"http://{address[0]}:{address[1]}/" self.requests = [] def handle_request(self, request): self.requests.append(request) return HTTPNoContent() server_bind_endpoint = config.Endpoint("127.0.0.1:0") listener = make_listener(server_bind_endpoint) server_address = listener.getsockname() http_server = HttpServer(server_address) baseplate = Baseplate() trust_handler = StaticTrustHandler(trust_headers=True) baseplate_configurator = BaseplateConfigurator( baseplate, header_trust_handler=trust_handler) configurator = Configurator() configurator.include(baseplate_configurator.includeme) configurator.add_route("test_view", "/") configurator.add_view(http_server.handle_request, route_name="test_view", renderer="json") wsgi_app = configurator.make_wsgi_app() server = make_server({"stop_timeout": "1 millisecond"}, listener, wsgi_app) server_greenlet = gevent.spawn(server.serve_forever) try: yield http_server finally: server_greenlet.kill()
def setUp(self): self.baseplate_observer = TestBaseplateObserver() profiles = { "foo": ExecutionProfile(consistency_level=ConsistencyLevel.QUORUM) } baseplate = Baseplate() baseplate.register(self.baseplate_observer) baseplate.configure_context( { "cassandra.contact_points": cassandra_endpoint.address.host, "cassandra_no_prof.contact_points": cassandra_endpoint.address.host, }, { "cassandra_no_prof": CassandraClient(keyspace="system"), "cassandra": CassandraClient(keyspace="system", execution_profiles=profiles), }, ) self.context = baseplate.make_context_object() self.server_span = baseplate.make_server_span(self.context, "test")
def make_wsgi_app(app_config): cfg = config.parse_config(app_config) signer = MessageSigner(cfg.ads_tracking.click_secret) metrics_client = make_metrics_client(app_config) baseplate = Baseplate() baseplate.configure_logging() baseplate.configure_metrics(metrics_client) baseplate.add_to_context("events", events.EventQueue("production")) baseplate.add_to_context("events_test", events.EventQueue("test")) configurator = Configurator(settings=app_config) baseplate_configurator = BaseplateConfigurator(baseplate) configurator.include(baseplate_configurator.includeme) controller = TrackingService(signer=signer, ) configurator.add_route("health", "/health", request_method="GET") configurator.add_view(controller.is_healthy, route_name="health", renderer="json") configurator.add_route("click", "/click", request_method="GET") configurator.add_view(controller.track_click, route_name="click", renderer="json") return configurator.make_wsgi_app()
def setUp(self): configurator = Configurator() configurator.add_route("example", "/example", request_method="GET") configurator.add_route("trace_context", "/trace_context", request_method="GET") configurator.add_view(example_application, route_name="example", renderer="json") configurator.add_view(local_tracing_within_context, route_name="trace_context", renderer="json") self.observer = mock.Mock(spec=BaseplateObserver) self.server_observer = mock.Mock(spec=ServerSpanObserver) def _register_mock(context, server_span): server_span.register(self.server_observer) self.observer.on_server_span_created.side_effect = _register_mock self.baseplate = Baseplate() self.baseplate.register(self.observer) self.baseplate_configurator = BaseplateConfigurator( self.baseplate, trust_trace_headers=True, ) configurator.include(self.baseplate_configurator.includeme) app = configurator.make_wsgi_app() self.test_app = webtest.TestApp(app)
def make_processor(app_config): # pragma: nocover cfg = config.parse_config(app_config, { "activity": { "window": config.Timespan, "fuzz_threshold": config.Integer, }, "redis": { "url": config.String, "max_connections": config.Optional(config.Integer, default=100), }, }) metrics_client = make_metrics_client(app_config) redis_pool = redis.BlockingConnectionPool.from_url( cfg.redis.url, max_connections=cfg.redis.max_connections, timeout=0.1, ) baseplate = Baseplate() baseplate.configure_logging() baseplate.configure_metrics(metrics_client) baseplate.add_to_context("redis", RedisContextFactory(redis_pool)) counter = ActivityCounter(cfg.activity.window.total_seconds()) handler = Handler( fuzz_threshold=cfg.activity.fuzz_threshold, counter=counter, ) processor = ActivityService.ContextProcessor(handler) event_handler = BaseplateProcessorEventHandler(logger, baseplate) processor.setEventHandler(event_handler) return processor
def baseplate_thrift_client(endpoint, client_spec, client_span_observer=None): baseplate = Baseplate( app_config={ "baseplate.service_name": "fancy test client", "example_service.endpoint": str(endpoint), } ) if client_span_observer: class TestServerSpanObserver(ServerSpanObserver): def on_child_span_created(self, span): span.register(client_span_observer) observer = TestServerSpanObserver() class TestBaseplateObserver(BaseplateObserver): def on_server_span_created(self, context, span): span.register(observer) baseplate.register(TestBaseplateObserver()) context = baseplate.make_context_object() trace_info = TraceInfo.from_upstream( trace_id="1234", parent_id="2345", span_id="3456", flags=4567, sampled=True ) baseplate.configure_context({"example_service": ThriftClient(client_spec.Client)}) baseplate.make_server_span(context, "example_service.example", trace_info) context.raw_edge_context = FakeEdgeContextFactory.RAW_BYTES yield context
def test_client_makes_client_span(client_cls, method, http_server): baseplate = Baseplate({ "myclient.filter.ip_allowlist": "127.0.0.0/8", "myclient.filter.port_denylist": "0" }) baseplate.configure_context({"myclient": client_cls()}) observer = TestBaseplateObserver() baseplate.register(observer) with baseplate.server_context("test") as context: fn = getattr(context.myclient, method.lower()) response = fn(http_server.url) assert response.status_code == 204 server_span_observer = observer.children[0] assert len(server_span_observer.children) == 1 client_span_observer = server_span_observer.children[0] assert client_span_observer.span.name == "myclient.request" assert client_span_observer.on_start_called assert client_span_observer.on_finish_called assert client_span_observer.on_finish_exc_info is None assert client_span_observer.tags["http.url"] == http_server.url assert client_span_observer.tags["http.method"] == method assert client_span_observer.tags["http.status_code"] == 204
def serve_thrift(handler, server_span_observer=None): # create baseplate root baseplate = Baseplate() if server_span_observer: class TestBaseplateObserver(BaseplateObserver): def on_server_span_created(self, context, server_span): server_span.register(server_span_observer) baseplate.register(TestBaseplateObserver()) # set up the server's processor logger = mock.Mock(spec=logging.Logger) edge_context_factory = make_edge_context_factory() processor = TestService.Processor(handler) processor = baseplateify_processor(processor, logger, baseplate, edge_context_factory) # bind a server socket on an available port server_bind_endpoint = config.Endpoint("127.0.0.1:0") listener = make_listener(server_bind_endpoint) server = make_server( {"max_concurrency": "100", "stop_timeout": "1 millisecond"}, listener, processor ) # figure out what port the server ended up on server_address = listener.getsockname() server.endpoint = config.Endpoint(f"{server_address[0]}:{server_address[1]}") # run the server until our caller is done with it server_greenlet = gevent.spawn(server.serve_forever) try: yield server finally: server_greenlet.kill()
def test_configure_tracing_with_defaults_legacy_style(self): baseplate = Baseplate() self.assertEqual(0, len(baseplate.observers)) baseplate.configure_tracing('test') self.assertEqual(1, len(baseplate.observers)) tracing_observer = baseplate.observers[0] self.assertEqual('test', tracing_observer.service_name)
def setUp(self): configurator = Configurator() configurator.add_route("example", "/example", request_method="GET") configurator.add_route("trace_context", "/trace_context", request_method="GET") configurator.add_view(example_application, route_name="example", renderer="json") configurator.add_view(local_tracing_within_context, route_name="trace_context", renderer="json") configurator.add_view(render_exception_view, context=ControlFlowException, renderer="json") configurator.add_view(render_bad_exception_view, context=ControlFlowException2, renderer="json") mock_filewatcher = mock.Mock(spec=FileWatcher) mock_filewatcher.get_data.return_value = { "secrets": { "secret/authentication/public-key": { "type": "versioned", "current": AUTH_TOKEN_PUBLIC_KEY, } }, "vault": { "token": "test", "url": "http://vault.example.com:8200/" }, } secrets = SecretsStore("/secrets") secrets._filewatcher = mock_filewatcher self.observer = mock.Mock(spec=BaseplateObserver) self.server_observer = mock.Mock(spec=ServerSpanObserver) def _register_mock(context, server_span): server_span.register(self.server_observer) self.observer.on_server_span_created.side_effect = _register_mock self.baseplate = Baseplate() self.baseplate.register(self.observer) self.baseplate_configurator = BaseplateConfigurator( self.baseplate, trust_trace_headers=True, edge_context_factory=EdgeRequestContextFactory(secrets), ) configurator.include(self.baseplate_configurator.includeme) self.context_init_event_subscriber = mock.Mock() configurator.add_subscriber(self.context_init_event_subscriber, ServerSpanInitialized) app = configurator.make_wsgi_app() self.test_app = webtest.TestApp(app)
def make_wsgi_app(app_config): cfg = config.parse_config(app_config, { "activity": { "endpoint": config.Endpoint, }, }) metrics_client = make_metrics_client(app_config) pool = ThriftConnectionPool(cfg.activity.endpoint) baseplate = Baseplate() baseplate.configure_logging() baseplate.configure_metrics(metrics_client) baseplate.add_to_context( "activity", ThriftContextFactory(pool, ActivityService.Client)) configurator = Configurator(settings=app_config) baseplate_configurator = BaseplateConfigurator(baseplate) configurator.include(baseplate_configurator.includeme) controller = ActivityGateway() configurator.add_route("health", "/health", request_method="GET") configurator.add_view(controller.is_healthy, route_name="health", renderer="json") configurator.add_route("pixel", "/{context_id:[A-Za-z0-9_]{,40}}.png", request_method="GET") configurator.add_view(controller.pixel, route_name="pixel") return configurator.make_wsgi_app()
def test_configure_tracing_with_defaults_new_style(self): baseplate = Baseplate() self.assertEqual(0, len(baseplate.observers)) client = make_client("test") baseplate.configure_tracing(client) self.assertEqual(1, len(baseplate.observers)) tracing_observer = baseplate.observers[0] self.assertEqual('test', tracing_observer.service_name)
def test_null_server_observer(self): baseplate = Baseplate() mock_context = baseplate.make_context_object() mock_observer = mock.Mock(spec=BaseplateObserver) mock_observer.on_server_span_created.return_value = None baseplate.register(mock_observer) server_span = baseplate.make_server_span(mock_context, "name", TraceInfo(1, 2, 3, None, 0)) self.assertEqual(server_span.observers, [])
def test_with_server_context(self): baseplate = Baseplate() observer = mock.Mock(spec=BaseplateObserver) baseplate.register(observer) observer.on_server_span_created.assert_not_called() with baseplate.server_context("example") as context: observer.on_server_span_created.assert_called_once() self.assertIsInstance(context, RequestContext)
def setUp(self): self.baseplate_observer = TestBaseplateObserver() baseplate = Baseplate({"redis.url": f"redis://{redis_endpoint}/0"}) baseplate.register(self.baseplate_observer) baseplate.configure_context({"redis": RedisClient()}) self.context = baseplate.make_context_object() self.server_span = baseplate.make_server_span(self.context, "test")
def setUp(self): self.baseplate_observer = TestBaseplateObserver() baseplate = Baseplate({"memcache.endpoint": str(memcached_endpoint)}) baseplate.register(self.baseplate_observer) baseplate.configure_context({"memcache": MemcacheClient()}) self.context = baseplate.make_context_object() self.server_span = baseplate.make_server_span(self.context, "test")
def setUp(self): self.baseplate_observer = TestBaseplateObserver() baseplate = Baseplate({"cassandra.contact_points": cassandra_endpoint.address.host}) baseplate.register(self.baseplate_observer) baseplate.configure_context({"cassandra": CassandraClient(keyspace="system")}) self.context = baseplate.make_context_object() self.server_span = baseplate.make_server_span(self.context, "test")
def make_wsgi_app(app_config): baseplate = Baseplate() baseplate.configure_observers(app_config) configurator = Configurator(settings=app_config) configurator.include(BaseplateConfigurator(baseplate).includeme) configurator.add_route("hello_world", "/", request_method="GET") configurator.scan() return configurator.make_wsgi_app()
def test_context_object_reused(self): baseplate = Baseplate() context = baseplate.make_context_object() with baseplate.make_server_span(context, "foo"): pass with self.assertRaises(ReusedContextObjectError): with baseplate.make_server_span(context, "bar"): pass
def test_add_to_context(self): baseplate = Baseplate() forty_two_factory = mock.Mock(spec=ContextFactory) forty_two_factory.make_object_for_context = mock.Mock(return_value=42) baseplate.add_to_context("forty_two", forty_two_factory) baseplate.add_to_context("true", True) context = baseplate.make_context_object() self.assertEqual(42, context.forty_two) self.assertTrue(context.true)
def test_server_observer_made(self): baseplate = Baseplate() mock_context = baseplate.make_context_object() mock_observer = mock.Mock(spec=BaseplateObserver) baseplate.register(mock_observer) server_span = baseplate.make_server_span(mock_context, "name", TraceInfo(1, 2, 3, None, 0)) self.assertEqual(baseplate.observers, [mock_observer]) self.assertEqual(mock_observer.on_server_span_created.call_count, 1) self.assertEqual(mock_observer.on_server_span_created.call_args, mock.call(mock_context, server_span))
def setUp(self): self.baseplate_observer = TestBaseplateObserver() baseplate = Baseplate({ "rediscluster.url": f"redis://{redis_endpoint}/0", "rediscluster.timeout": "1 second", "rediscluster.max_connections": "4", }) baseplate.register(self.baseplate_observer) baseplate.configure_context({"rediscluster": ClusterRedisClient()}) self.context = baseplate.make_context_object() self.server_span = baseplate.make_server_span(self.context, "test")
def test_configure_tracing_with_args(self): baseplate = Baseplate() self.assertEqual(0, len(baseplate.observers)) baseplate.configure_tracing('test', None, max_span_queue_size=500, num_span_workers=5, span_batch_interval=0.5, num_conns=100, sample_rate=0.1) self.assertEqual(1, len(baseplate.observers)) tracing_observer = baseplate.observers[0] self.assertEqual('test', tracing_observer.service_name)
def setUp(self): engine = engine_from_config({"database.url": "sqlite://"}) # in-memory db Base.metadata.create_all(bind=engine) factory = SQLAlchemySessionContextFactory(engine) self.baseplate_observer = TestBaseplateObserver() baseplate = Baseplate() baseplate.register(self.baseplate_observer) baseplate.add_to_context("db", factory) self.context = baseplate.make_context_object() self.server_span = baseplate.make_server_span(self.context, "test")
def test_default_timeout(): baseplate = Baseplate() observer = TimeoutBaseplateObserver.from_config({"server_timeout.default": "50 milliseconds"}) baseplate.register(observer) context = baseplate.make_context_object() with baseplate.make_server_span(context, "test"): with pytest.raises(ServerTimeout): gevent.sleep(1) context = baseplate.make_context_object() with baseplate.make_server_span(context, "test"): gevent.sleep(0) # shouldn't time out since it's so fast!
def setUp(self): configurator = Configurator() configurator.add_route("example", "/example", request_method="GET") configurator.add_route("trace_context", "/trace_context", request_method="GET") configurator.add_view(example_application, route_name="example", renderer="json") configurator.add_view(local_tracing_within_context, route_name="trace_context", renderer="json") mock_filewatcher = mock.Mock(spec=FileWatcher) mock_filewatcher.get_data.return_value = { "secrets": { "jwt/authentication/secret": { "type": "simple", "value": self.TOKEN_SECRET, }, }, "vault": { "token": "test", "url": "http://vault.example.com:8200/", } } secrets = store.SecretsStore("/secrets") secrets._filewatcher = mock_filewatcher self.observer = mock.Mock(spec=BaseplateObserver) self.server_observer = mock.Mock(spec=ServerSpanObserver) def _register_mock(context, server_span): server_span.register(self.server_observer) self.observer.on_server_span_created.side_effect = _register_mock self.baseplate = Baseplate() self.baseplate.register(self.observer) self.baseplate_configurator = BaseplateConfigurator( self.baseplate, trust_trace_headers=True, auth_factory=AuthenticationContextFactory(secrets), ) configurator.include(self.baseplate_configurator.includeme) app = configurator.make_wsgi_app() self.test_app = webtest.TestApp(app)