1+ from typing import Optional , Any , List , Union , Callable
2+
13import pytest
2- import six
34import tornado
4- from graphql import parse
5- from opencensus .trace import tracer as tracer_module
5+ from graphql import parse , GraphQLBackend
6+ from opencensus .trace import tracer as tracer_module , execution_context
67from opencensus .trace .base_exporter import Exporter
78from opencensus .trace .propagation .google_cloud_format import GoogleCloudFormatPropagator
89from opencensus .trace .samplers import AlwaysOnSampler
1112from graphene_tornado .ext .apollo_engine_reporting .tests .schema import schema
1213from graphene_tornado .ext .apollo_engine_reporting .tests .test_engine_extension import QUERY
1314from graphene_tornado .ext .opencensus .opencensus_tracing_extension import OpenCensusExtension
15+ from graphene_tornado .graphql_extension import GraphQLExtension
1416from graphene_tornado .tests .http_helper import HttpHelper
1517from graphene_tornado .tests .test_graphql import response_json , url_string , GRAPHQL_HEADER
1618from graphene_tornado .tornado_graphql_handler import TornadoGraphQLHandler
1719
1820
21+ class GQLHandler (TornadoGraphQLHandler ):
22+
23+ def initialize (self , schema = None , executor = None , middleware : Optional [Any ] = None , root_value : Any = None ,
24+ graphiql : bool = False , pretty : bool = False , batch : bool = False , backend : GraphQLBackend = None ,
25+ extensions : List [Union [Callable [[], GraphQLExtension ], GraphQLExtension ]] = None ,
26+ exporter = None ):
27+ super ().initialize (schema , executor , middleware , root_value , graphiql , pretty , batch , backend , extensions )
28+ execution_context .set_opencensus_tracer (tracer_module .Tracer (
29+ sampler = AlwaysOnSampler (),
30+ exporter = exporter ,
31+ propagator = GoogleCloudFormatPropagator ()
32+ )
33+ )
34+
35+ def on_finish (self ) -> None :
36+ tracer = execution_context .get_opencensus_tracer ()
37+ tracer .finish ()
38+
39+
1940class ExampleOpenCensusApplication (tornado .web .Application ):
2041
21- def __init__ (self ):
42+ def __init__ (self , exporter ):
2243 extension = lambda : OpenCensusExtension ()
2344 handlers = [
24- (r'/graphql' , TornadoGraphQLHandler , dict (graphiql = True , schema = schema , extensions = [extension ])),
25- (r'/graphql/batch' , TornadoGraphQLHandler , dict (graphiql = True , schema = schema , batch = True )),
45+ (r'/graphql' , GQLHandler , dict (graphiql = True , schema = schema , extensions = [extension ], exporter = exporter )),
2646 ]
2747 tornado .web .Application .__init__ (self , handlers )
2848
2949
3050@pytest .fixture
31- def app ():
32- return ExampleOpenCensusApplication ()
51+ def app (exporter ):
52+ return ExampleOpenCensusApplication (exporter )
53+
54+
55+ @pytest .fixture
56+ def app (exporter ):
57+ return ExampleOpenCensusApplication (exporter )
3358
3459
3560@pytest .fixture
@@ -39,13 +64,7 @@ def http_helper(http_client, base_url):
3964
4065@pytest .fixture
4166def exporter ():
42- exporter = CapturingExporter ()
43- tracer_module .Tracer (
44- sampler = AlwaysOnSampler (),
45- exporter = exporter ,
46- propagator = GoogleCloudFormatPropagator ()
47- )
48- return exporter
67+ return CapturingExporter ()
4968
5069
5170@pytest .mark .gen_test ()
@@ -54,28 +73,28 @@ def test_traces_match_query(http_helper, exporter):
5473 assert response .code == 200
5574 assert 'data' in response_json (response )
5675
57- # OpenCensus is quite ready for Python3+Tornado yet
58- if six . PY3 :
59- return
60-
61- spans = exporter . spans
62-
63- assert spans [ 0 ][ 0 ]. name == 'author'
64- assert spans [ 0 ][ 0 ]. parent_span_id == spans [ 6 ][ 0 ]. span_id
65- assert spans [ 1 ][ 0 ]. name == 'aBoolean'
66- assert spans [ 1 ][ 0 ]. parent_span_id == spans [ 6 ][ 0 ]. span_id
67- assert spans [ 2 ][ 0 ]. name == 'author.name'
68- assert spans [ 2 ][ 0 ]. parent_span_id == spans [ 6 ][ 0 ]. span_id
69- assert spans [ 3 ][ 0 ]. name == 'author.posts'
70- assert spans [ 3 ][ 0 ]. parent_span_id == spans [ 6 ][ 0 ]. span_id
71- assert spans [ 4 ][ 0 ]. name == 'author.posts.0.id'
72- assert spans [ 4 ][ 0 ]. parent_span_id == spans [ 6 ][ 0 ]. span_id
73- assert spans [ 5 ][ 0 ]. name == 'author.posts.1.id'
74- assert spans [ 5 ][ 0 ]. parent_span_id == spans [ 6 ][ 0 ]. span_id
75-
76- assert spans [ 6 ][ 0 ]. name == 'gql[b5c7307ba564]'
77- assert spans [ 6 ][ 0 ]. parent_span_id is None
78- assert spans [ 6 ][ 0 ]. attributes . get ( 'signature' , None ) == default_engine_reporting_signature ( parse ( QUERY ), '' )
76+ parent = exporter . spans . pop ()[ 0 ]
77+
78+ assert parent . name == 'gql[b5c7307ba564]'
79+ assert parent . parent_span_id is None
80+ assert parent . attributes . get ( 'signature' , None ) == default_engine_reporting_signature ( parse ( QUERY ), '' )
81+
82+ spans = [ span for span_list in exporter . spans for span in span_list ]
83+
84+ expected = [
85+ 'gql_parsing' ,
86+ 'gql_validation' ,
87+ 'author' ,
88+ 'aBoolean' ,
89+ 'author.name' ,
90+ 'author.posts' ,
91+ 'author.posts.0.id' ,
92+ 'author.posts.1.id'
93+ ]
94+
95+ for span , exp in zip ( spans , expected ):
96+ assert span . name == exp
97+ assert span . parent_span_id == parent . span_id
7998
8099
81100class CapturingExporter (Exporter ):
0 commit comments