@@ -111,7 +111,7 @@ def test_propagation(enable_extended_tracing):
111111        gotNames  =  [span .name  for  span  in  from_inject_spans ]
112112        wantNames  =  [
113113            "CloudSpanner.CreateSession" ,
114-             "CloudSpanner.Snapshot.execute_streaming_sql " ,
114+             "CloudSpanner.Snapshot.execute_sql " ,
115115        ]
116116        assert  gotNames  ==  wantNames 
117117
@@ -239,8 +239,8 @@ def select_in_txn(txn):
239239        ("CloudSpanner.Database.run_in_transaction" , codes .OK , None ),
240240        ("CloudSpanner.CreateSession" , codes .OK , None ),
241241        ("CloudSpanner.Session.run_in_transaction" , codes .OK , None ),
242-         ("CloudSpanner.Transaction.execute_streaming_sql " , codes .OK , None ),
243-         ("CloudSpanner.Transaction.execute_streaming_sql " , codes .OK , None ),
242+         ("CloudSpanner.Transaction.execute_sql " , codes .OK , None ),
243+         ("CloudSpanner.Transaction.execute_sql " , codes .OK , None ),
244244        ("CloudSpanner.Transaction.commit" , codes .OK , None ),
245245    ]
246246    assert  got_statuses  ==  want_statuses 
@@ -273,6 +273,116 @@ def finished_spans_statuses(trace_exporter):
273273    return  got_statuses , got_events 
274274
275275
276+ @pytest .mark .skipif ( 
277+     not  _helpers .USE_EMULATOR , 
278+     reason = "Emulator needed to run this tests" , 
279+ ) 
280+ @pytest .mark .skipif ( 
281+     not  HAS_OTEL_INSTALLED , 
282+     reason = "Tracing requires OpenTelemetry" , 
283+ ) 
284+ def  test_transaction_update_implicit_begin_nested_inside_commit ():
285+     # Tests to ensure that transaction.commit() without a began transaction 
286+     # has transaction.begin() inlined and nested under the commit span. 
287+     from  google .auth .credentials  import  AnonymousCredentials 
288+     from  opentelemetry .sdk .trace .export  import  SimpleSpanProcessor 
289+     from  opentelemetry .sdk .trace .export .in_memory_span_exporter  import  (
290+         InMemorySpanExporter ,
291+     )
292+     from  opentelemetry .sdk .trace  import  TracerProvider 
293+     from  opentelemetry .sdk .trace .sampling  import  ALWAYS_ON 
294+ 
295+     PROJECT  =  _helpers .EMULATOR_PROJECT 
296+     CONFIGURATION_NAME  =  "config-name" 
297+     INSTANCE_ID  =  _helpers .INSTANCE_ID 
298+     DISPLAY_NAME  =  "display-name" 
299+     DATABASE_ID  =  _helpers .unique_id ("temp_db" )
300+     NODE_COUNT  =  5 
301+     LABELS  =  {"test" : "true" }
302+ 
303+     def  tx_update (txn ):
304+         txn .insert (
305+             "Singers" ,
306+             columns = ["SingerId" , "FirstName" ],
307+             values = [["1" , "Bryan" ], ["2" , "Slash" ]],
308+         )
309+ 
310+     tracer_provider  =  TracerProvider (sampler = ALWAYS_ON )
311+     trace_exporter  =  InMemorySpanExporter ()
312+     tracer_provider .add_span_processor (SimpleSpanProcessor (trace_exporter ))
313+     observability_options  =  dict (
314+         tracer_provider = tracer_provider ,
315+         enable_extended_tracing = True ,
316+     )
317+ 
318+     client  =  Client (
319+         project = PROJECT ,
320+         observability_options = observability_options ,
321+         credentials = AnonymousCredentials (),
322+     )
323+ 
324+     instance  =  client .instance (
325+         INSTANCE_ID ,
326+         CONFIGURATION_NAME ,
327+         display_name = DISPLAY_NAME ,
328+         node_count = NODE_COUNT ,
329+         labels = LABELS ,
330+     )
331+ 
332+     try :
333+         instance .create ()
334+     except  Exception :
335+         pass 
336+ 
337+     db  =  instance .database (DATABASE_ID )
338+     try :
339+         db ._ddl_statements  =  [
340+             """CREATE TABLE Singers ( 
341+             SingerId     INT64 NOT NULL, 
342+             FirstName    STRING(1024), 
343+             LastName     STRING(1024), 
344+             SingerInfo   BYTES(MAX), 
345+             FullName   STRING(2048) AS ( 
346+                 ARRAY_TO_STRING([FirstName, LastName], " ") 
347+             ) STORED 
348+             ) PRIMARY KEY (SingerId)""" ,
349+             """CREATE TABLE Albums ( 
350+                 SingerId     INT64 NOT NULL, 
351+                 AlbumId      INT64 NOT NULL, 
352+                 AlbumTitle   STRING(MAX), 
353+                 MarketingBudget INT64, 
354+             ) PRIMARY KEY (SingerId, AlbumId), 
355+             INTERLEAVE IN PARENT Singers ON DELETE CASCADE""" ,
356+         ]
357+         db .create ()
358+     except  Exception :
359+         pass 
360+ 
361+     try :
362+         db .run_in_transaction (tx_update )
363+     except  Exception :
364+         pass 
365+ 
366+     span_list  =  trace_exporter .get_finished_spans ()
367+     # Sort the spans by their start time in the hierarchy. 
368+     span_list  =  sorted (span_list , key = lambda  span : span .start_time )
369+     got_span_names  =  [span .name  for  span  in  span_list ]
370+     want_span_names  =  [
371+         "CloudSpanner.Database.run_in_transaction" ,
372+         "CloudSpanner.CreateSession" ,
373+         "CloudSpanner.Session.run_in_transaction" ,
374+         "CloudSpanner.Transaction.commit" ,
375+         "CloudSpanner.Transaction.begin" ,
376+     ]
377+ 
378+     assert  got_span_names  ==  want_span_names 
379+ 
380+     # Our object is to ensure that .begin() is a child of .commit() 
381+     span_tx_begin  =  span_list [- 1 ]
382+     span_tx_commit  =  span_list [- 2 ]
383+     assert  span_tx_begin .parent .span_id  ==  span_tx_commit .context .span_id 
384+ 
385+ 
276386@pytest .mark .skipif ( 
277387    not  _helpers .USE_EMULATOR , 
278388    reason = "Emulator needed to run this test" , 
0 commit comments