diff --git a/packages/google-cloud-spanner/google/cloud/spanner_v1/_async/snapshot.py b/packages/google-cloud-spanner/google/cloud/spanner_v1/_async/snapshot.py index 116a8a667352..2c52430b26cf 100644 --- a/packages/google-cloud-spanner/google/cloud/spanner_v1/_async/snapshot.py +++ b/packages/google-cloud-spanner/google/cloud/spanner_v1/_async/snapshot.py @@ -471,20 +471,20 @@ async def read( ) request_options = _merge_request_options(request_options, client_context) - if request_options is None: - request_options = RequestOptions() - elif type(request_options) is dict: - request_options = RequestOptions(request_options) - - if self._read_only: - request_options.transaction_tag = None - if ( - directed_read_options is None - and database._directed_read_options is not None - ): - directed_read_options = database._directed_read_options - elif self.transaction_tag is not None: - request_options.transaction_tag = self.transaction_tag + if request_options is not None: + if self._read_only: + request_options.transaction_tag = None + elif self.transaction_tag is not None: + request_options.transaction_tag = self.transaction_tag + elif not self._read_only and self.transaction_tag is not None: + request_options = RequestOptions(transaction_tag=self.transaction_tag) + + if ( + self._read_only + and directed_read_options is None + and database._directed_read_options is not None + ): + directed_read_options = database._directed_read_options read_request = ReadRequest( session=session.name, @@ -665,20 +665,20 @@ async def execute_sql( ) request_options = _merge_request_options(request_options, client_context) - if request_options is None: - request_options = RequestOptions() - elif type(request_options) is dict: - request_options = RequestOptions(request_options) - - if self._read_only: - request_options.transaction_tag = None - if ( - directed_read_options is None - and database._directed_read_options is not None - ): - directed_read_options = database._directed_read_options - elif self.transaction_tag is not None: - request_options.transaction_tag = self.transaction_tag + if request_options is not None: + if self._read_only: + request_options.transaction_tag = None + elif self.transaction_tag is not None: + request_options.transaction_tag = self.transaction_tag + elif not self._read_only and self.transaction_tag is not None: + request_options = RequestOptions(transaction_tag=self.transaction_tag) + + if ( + self._read_only + and directed_read_options is None + and database._directed_read_options is not None + ): + directed_read_options = database._directed_read_options execute_sql_request = _make_execute_sql_request( session_name=session.name, diff --git a/packages/google-cloud-spanner/google/cloud/spanner_v1/_async/transaction.py b/packages/google-cloud-spanner/google/cloud/spanner_v1/_async/transaction.py index f72988d5c8c7..2c2f629805f9 100644 --- a/packages/google-cloud-spanner/google/cloud/spanner_v1/_async/transaction.py +++ b/packages/google-cloud-spanner/google/cloud/spanner_v1/_async/transaction.py @@ -305,16 +305,13 @@ async def commit( ) request_options = _merge_request_options(request_options, client_context) - if request_options is None: - request_options = RequestOptions() - elif type(request_options) is dict: - request_options = RequestOptions(request_options) - - if self.transaction_tag is not None: - request_options.transaction_tag = self.transaction_tag - - # Request tags are not supported for commit requests. - request_options.request_tag = None + if request_options is not None: + if self.transaction_tag is not None: + request_options.transaction_tag = self.transaction_tag + # Request tags are not supported for commit requests. + request_options.request_tag = None + elif self.transaction_tag is not None: + request_options = RequestOptions(transaction_tag=self.transaction_tag) common_commit_request_args = { "session": session.name, @@ -526,11 +523,10 @@ async def execute_update( ) request_options = _merge_request_options(request_options, client_context) - if request_options is None: - request_options = RequestOptions() - elif type(request_options) is dict: - request_options = RequestOptions(request_options) - request_options.transaction_tag = self.transaction_tag + if request_options is not None: + request_options.transaction_tag = self.transaction_tag + elif self.transaction_tag is not None: + request_options = RequestOptions(transaction_tag=self.transaction_tag) trace_attributes = { "db.statement": dml, @@ -686,11 +682,10 @@ async def batch_update( ) request_options = _merge_request_options(request_options, client_context) - if request_options is None: - request_options = RequestOptions() - elif type(request_options) is dict: - request_options = RequestOptions(request_options) - request_options.transaction_tag = self.transaction_tag + if request_options is not None: + request_options.transaction_tag = self.transaction_tag + elif self.transaction_tag is not None: + request_options = RequestOptions(transaction_tag=self.transaction_tag) trace_attributes = { # Get just the queries from the DML statement batch diff --git a/packages/google-cloud-spanner/google/cloud/spanner_v1/snapshot.py b/packages/google-cloud-spanner/google/cloud/spanner_v1/snapshot.py index 838e7589bbc4..6fb43d78c3c9 100644 --- a/packages/google-cloud-spanner/google/cloud/spanner_v1/snapshot.py +++ b/packages/google-cloud-spanner/google/cloud/spanner_v1/snapshot.py @@ -422,19 +422,19 @@ def read( database._instance._client._client_context, self._client_context ) request_options = _merge_request_options(request_options, client_context) - if request_options is None: - request_options = RequestOptions() - elif type(request_options) is dict: - request_options = RequestOptions(request_options) - if self._read_only: - request_options.transaction_tag = None - if ( - directed_read_options is None - and database._directed_read_options is not None - ): - directed_read_options = database._directed_read_options - elif self.transaction_tag is not None: - request_options.transaction_tag = self.transaction_tag + if request_options is not None: + if self._read_only: + request_options.transaction_tag = None + elif self.transaction_tag is not None: + request_options.transaction_tag = self.transaction_tag + elif not self._read_only and self.transaction_tag is not None: + request_options = RequestOptions(transaction_tag=self.transaction_tag) + if ( + self._read_only + and directed_read_options is None + and (database._directed_read_options is not None) + ): + directed_read_options = database._directed_read_options read_request = ReadRequest( session=session.name, table=table, @@ -603,19 +603,19 @@ def execute_sql( database._instance._client._client_context, self._client_context ) request_options = _merge_request_options(request_options, client_context) - if request_options is None: - request_options = RequestOptions() - elif type(request_options) is dict: - request_options = RequestOptions(request_options) - if self._read_only: - request_options.transaction_tag = None - if ( - directed_read_options is None - and database._directed_read_options is not None - ): - directed_read_options = database._directed_read_options - elif self.transaction_tag is not None: - request_options.transaction_tag = self.transaction_tag + if request_options is not None: + if self._read_only: + request_options.transaction_tag = None + elif self.transaction_tag is not None: + request_options.transaction_tag = self.transaction_tag + elif not self._read_only and self.transaction_tag is not None: + request_options = RequestOptions(transaction_tag=self.transaction_tag) + if ( + self._read_only + and directed_read_options is None + and (database._directed_read_options is not None) + ): + directed_read_options = database._directed_read_options execute_sql_request = _make_execute_sql_request( session_name=session.name, sql=sql, diff --git a/packages/google-cloud-spanner/google/cloud/spanner_v1/transaction.py b/packages/google-cloud-spanner/google/cloud/spanner_v1/transaction.py index 4d0dd1c9d2c3..f7fa721227ca 100644 --- a/packages/google-cloud-spanner/google/cloud/spanner_v1/transaction.py +++ b/packages/google-cloud-spanner/google/cloud/spanner_v1/transaction.py @@ -253,13 +253,12 @@ def commit( database._instance._client._client_context, self._client_context ) request_options = _merge_request_options(request_options, client_context) - if request_options is None: - request_options = RequestOptions() - elif type(request_options) is dict: - request_options = RequestOptions(request_options) - if self.transaction_tag is not None: - request_options.transaction_tag = self.transaction_tag - request_options.request_tag = None + if request_options is not None: + if self.transaction_tag is not None: + request_options.transaction_tag = self.transaction_tag + request_options.request_tag = None + elif self.transaction_tag is not None: + request_options = RequestOptions(transaction_tag=self.transaction_tag) common_commit_request_args = { "session": session.name, "transaction_id": self._transaction_id, @@ -438,11 +437,10 @@ def execute_update( database._instance._client._client_context, self._client_context ) request_options = _merge_request_options(request_options, client_context) - if request_options is None: - request_options = RequestOptions() - elif type(request_options) is dict: - request_options = RequestOptions(request_options) - request_options.transaction_tag = self.transaction_tag + if request_options is not None: + request_options.transaction_tag = self.transaction_tag + elif self.transaction_tag is not None: + request_options = RequestOptions(transaction_tag=self.transaction_tag) trace_attributes = {"db.statement": dml, "request_options": request_options} is_inline_begin = False if self._transaction_id is None: @@ -577,11 +575,10 @@ def batch_update( database._instance._client._client_context, self._client_context ) request_options = _merge_request_options(request_options, client_context) - if request_options is None: - request_options = RequestOptions() - elif type(request_options) is dict: - request_options = RequestOptions(request_options) - request_options.transaction_tag = self.transaction_tag + if request_options is not None: + request_options.transaction_tag = self.transaction_tag + elif self.transaction_tag is not None: + request_options = RequestOptions(transaction_tag=self.transaction_tag) trace_attributes = { "db.statement": ";".join([statement.sql for statement in parsed]), "request_options": request_options, diff --git a/packages/google-cloud-spanner/tests/unit/_async/test_session.py b/packages/google-cloud-spanner/tests/unit/_async/test_session.py index 8cebc5a7807b..0d5a530be7a4 100644 --- a/packages/google-cloud-spanner/tests/unit/_async/test_session.py +++ b/packages/google-cloud-spanner/tests/unit/_async/test_session.py @@ -1437,7 +1437,6 @@ async def unit_of_work(txn, *args, **kw): session=self.SESSION_NAME, mutations=txn._mutations, transaction_id=TRANSACTION_ID, - request_options=RequestOptions(), ) gax_api.commit.assert_called_once_with( request=request, @@ -1507,7 +1506,6 @@ async def unit_of_work(txn, *args, **kw): session=session.name, mutations=txn._mutations, transaction_id=begin_transaction.return_value.id, - request_options=RequestOptions(), ), metadata=[ ("google-cloud-resource-prefix", database.name), @@ -1593,7 +1591,6 @@ async def unit_of_work(txn, *args, **kw): session=self.SESSION_NAME, mutations=txn._mutations, transaction_id=TRANSACTION_ID, - request_options=RequestOptions(), ) self.assertEqual( gax_api.commit.call_args_list, @@ -1711,7 +1708,6 @@ async def unit_of_work(txn, *args, **kw): session=self.SESSION_NAME, mutations=txn._mutations, transaction_id=TRANSACTION_ID, - request_options=RequestOptions(), ) self.assertEqual( gax_api.commit.call_args_list, @@ -1808,7 +1804,6 @@ async def unit_of_work(txn, *args, **kw): session=self.SESSION_NAME, mutations=txn._mutations, transaction_id=TRANSACTION_ID, - request_options=RequestOptions(), ) gax_api.commit.assert_called_once_with( request=request, @@ -1901,7 +1896,6 @@ def _time(): session=self.SESSION_NAME, mutations=txn._mutations, transaction_id=TRANSACTION_ID, - request_options=RequestOptions(), ) gax_api.commit.assert_called_once_with( request=request, @@ -2043,7 +2037,6 @@ def _time(): session=self.SESSION_NAME, mutations=txn._mutations, transaction_id=TRANSACTION_ID, - request_options=RequestOptions(), ) self.assertEqual( gax_api.commit.call_args_list, @@ -2148,7 +2141,6 @@ async def unit_of_work(txn, *args, **kw): mutations=txn._mutations, transaction_id=TRANSACTION_ID, return_commit_stats=True, - request_options=RequestOptions(), ) gax_api.commit.assert_called_once_with( request=request, @@ -2214,7 +2206,6 @@ async def unit_of_work(txn, *args, **kw): mutations=txn._mutations, transaction_id=TRANSACTION_ID, return_commit_stats=True, - request_options=RequestOptions(), ) gax_api.commit.assert_called_once_with( request=request, @@ -2351,7 +2342,6 @@ async def unit_of_work(txn, *args, **kw): session=self.SESSION_NAME, mutations=txn._mutations, transaction_id=TRANSACTION_ID, - request_options=RequestOptions(), ) gax_api.commit.assert_called_once_with( request=request, @@ -2462,7 +2452,6 @@ async def unit_of_work(txn, *args, **kw): session=self.SESSION_NAME, mutations=txn._mutations, transaction_id=TRANSACTION_ID, - request_options=RequestOptions(), ) self.assertEqual( gax_api.commit.call_args_list, diff --git a/packages/google-cloud-spanner/tests/unit/_async/test_snapshot.py b/packages/google-cloud-spanner/tests/unit/_async/test_snapshot.py index f85a4c49b1b4..1a37508fffb4 100644 --- a/packages/google-cloud-spanner/tests/unit/_async/test_snapshot.py +++ b/packages/google-cloud-spanner/tests/unit/_async/test_snapshot.py @@ -1588,6 +1588,93 @@ async def test_read_w_transaction_tag(self): call_args.kwargs["request"].request_options.transaction_tag, "tag" ) + async def test_read_w_transaction_tag_default_request_options(self): + database = _Database() + api = database.spanner_api + session = _Session(database) + snapshot = self._make_snapshot(session) + snapshot._transaction_id = TXN_ID + snapshot.transaction_tag = "tag" + snapshot._read_only = False + + api.streaming_read.return_value = _MockIterator(PartialResultSet()) + from google.cloud.spanner_v1.keyset import KeySet + + results = await snapshot.read(TABLE_NAME, COLUMNS, KeySet(all_=True)) + async for _ in results: + pass + + call_args = api.streaming_read.call_args + self.assertIsNotNone(call_args, "streaming_read should have been called") + self.assertEqual( + call_args.kwargs["request"].request_options.transaction_tag, "tag" + ) + + async def test_read_w_request_options_dict_with_transaction_tag(self): + database = _Database() + api = database.spanner_api + session = _Session(database) + snapshot = self._make_snapshot(session) + snapshot._transaction_id = TXN_ID + snapshot.transaction_tag = "tag" + snapshot._read_only = False + + api.streaming_read.return_value = _MockIterator(PartialResultSet()) + from google.cloud.spanner_v1.keyset import KeySet + + raw_dict_options = { + "request_tag": "r-tag", + "transaction_tag": "caller-tx-tag", + } + results = await snapshot.read( + TABLE_NAME, COLUMNS, KeySet(all_=True), request_options=raw_dict_options + ) + async for _ in results: + pass + + call_args = api.streaming_read.call_args + self.assertIsNotNone(call_args, "streaming_read should have been called") + self.assertEqual( + call_args.kwargs["request"].request_options.request_tag, "r-tag" + ) + self.assertEqual( + call_args.kwargs["request"].request_options.transaction_tag, "tag" + ) + + async def test_read_w_request_options_caller_tag_preserved_when_snapshot_tag_is_none( + self, + ): + database = _Database() + api = database.spanner_api + session = _Session(database) + snapshot = self._make_snapshot(session) + snapshot._transaction_id = TXN_ID + snapshot.transaction_tag = None + snapshot._read_only = False + + api.streaming_read.return_value = _MockIterator(PartialResultSet()) + from google.cloud.spanner_v1.keyset import KeySet + + raw_dict_options = { + "request_tag": "r-tag", + "transaction_tag": "caller-tx-tag", + } + results = await snapshot.read( + TABLE_NAME, COLUMNS, KeySet(all_=True), request_options=raw_dict_options + ) + async for _ in results: + pass + + call_args = api.streaming_read.call_args + self.assertIsNotNone(call_args, "streaming_read should have been called") + self.assertEqual( + call_args.kwargs["request"].request_options.request_tag, "r-tag" + ) + self.assertEqual( + call_args.kwargs["request"].request_options.transaction_tag, + "caller-tx-tag", + ) + async def test_execute_sql_w_request_options_dict(self): database = _Database() api = database.spanner_api @@ -1714,6 +1801,84 @@ async def test_execute_sql_w_transaction_tag(self): call_args.kwargs["request"].request_options.transaction_tag, "tag" ) + async def test_execute_sql_w_transaction_tag_default_request_options(self): + database = _Database() + api = database.spanner_api + session = _Session(database) + snapshot = self._make_snapshot(session) + snapshot._transaction_id = TXN_ID + snapshot.transaction_tag = "tag" + snapshot._read_only = False + + api.execute_streaming_sql.return_value = _MockIterator(PartialResultSet()) + results = await snapshot.execute_sql(SQL_QUERY) + async for _ in results: + pass + + call_args = api.execute_streaming_sql.call_args + self.assertEqual( + call_args.kwargs["request"].request_options.transaction_tag, "tag" + ) + + async def test_execute_sql_w_request_options_dict_with_transaction_tag(self): + database = _Database() + api = database.spanner_api + session = _Session(database) + snapshot = self._make_snapshot(session) + snapshot._transaction_id = TXN_ID + snapshot.transaction_tag = "tag" + snapshot._read_only = False + + api.execute_streaming_sql.return_value = _MockIterator(PartialResultSet()) + raw_dict_options = { + "request_tag": "r-tag", + "transaction_tag": "caller-tx-tag", + } + results = await snapshot.execute_sql( + SQL_QUERY, request_options=raw_dict_options + ) + async for _ in results: + pass + + call_args = api.execute_streaming_sql.call_args + self.assertEqual( + call_args.kwargs["request"].request_options.request_tag, "r-tag" + ) + self.assertEqual( + call_args.kwargs["request"].request_options.transaction_tag, "tag" + ) + + async def test_execute_sql_w_request_options_caller_tag_preserved_when_snapshot_tag_is_none( + self, + ): + database = _Database() + api = database.spanner_api + session = _Session(database) + snapshot = self._make_snapshot(session) + snapshot._transaction_id = TXN_ID + snapshot.transaction_tag = None + snapshot._read_only = False + + api.execute_streaming_sql.return_value = _MockIterator(PartialResultSet()) + raw_dict_options = { + "request_tag": "r-tag", + "transaction_tag": "caller-tx-tag", + } + results = await snapshot.execute_sql( + SQL_QUERY, request_options=raw_dict_options + ) + async for _ in results: + pass + + call_args = api.execute_streaming_sql.call_args + self.assertEqual( + call_args.kwargs["request"].request_options.request_tag, "r-tag" + ) + self.assertEqual( + call_args.kwargs["request"].request_options.transaction_tag, + "caller-tx-tag", + ) + def test_ctor_incompatible_options(self): import datetime diff --git a/packages/google-cloud-spanner/tests/unit/_async/test_transaction.py b/packages/google-cloud-spanner/tests/unit/_async/test_transaction.py index 7b0edeb4d171..cb124cb0a248 100644 --- a/packages/google-cloud-spanner/tests/unit/_async/test_transaction.py +++ b/packages/google-cloud-spanner/tests/unit/_async/test_transaction.py @@ -416,6 +416,7 @@ async def _commit_helper( retry_for_precommit_token=None, is_multiplexed=False, expected_begin_mutation=None, + transaction_tag=TRANSACTION_TAG, ): from google.cloud.spanner_v1 import CommitRequest @@ -428,7 +429,7 @@ async def _commit_helper( database = session._database api = database.spanner_api - transaction.transaction_tag = TRANSACTION_TAG + transaction.transaction_tag = transaction_tag if mutations is not None: transaction._mutations = mutations @@ -486,11 +487,16 @@ async def _commit_helper( if mutations is not None: self.assertEqual(transaction._transaction_id, TRANSACTION_ID) + expected_begin_request_options = ( + RequestOptions(transaction_tag=transaction_tag) + if transaction_tag is not None + else None + ) expected_begin_transaction_request = BeginTransactionRequest( session=session.name, options=TransactionOptions(read_write=TransactionOptions.ReadWrite()), mutation_key=expected_begin_mutation, - request_options=RequestOptions(transaction_tag=TRANSACTION_TAG), + request_options=expected_begin_request_options, ) expected_begin_metadata = base_metadata.copy() @@ -511,16 +517,14 @@ async def _commit_helper( # Verify commit API call(s). self.assertEqual(commit.call_count, 1 if not retry_for_precommit_token else 2) - if request_options is None: - expected_request_options = RequestOptions(transaction_tag=TRANSACTION_TAG) - elif type(request_options) is dict: + if request_options is not None: expected_request_options = RequestOptions(request_options) - expected_request_options.transaction_tag = TRANSACTION_TAG + expected_request_options.transaction_tag = transaction_tag expected_request_options.request_tag = None + elif transaction_tag is not None: + expected_request_options = RequestOptions(transaction_tag=transaction_tag) else: - expected_request_options = request_options - expected_request_options.transaction_tag = TRANSACTION_TAG - expected_request_options.request_tag = None + expected_request_options = None common_expected_commit_response_args = { "session": session.name, @@ -717,6 +721,14 @@ async def test_commit_w_incorrect_tag_dictionary_error(self): with pytest.raises(ValueError): await self._commit_helper(request_options=request_options) + @mock.patch( + "google.cloud.spanner_v1._opentelemetry_tracing._get_cloud_region", + return_value="global", + ) + @CrossSync.pytest + async def test_commit_wo_request_options_and_transaction_tag(self, mock_region): + await self._commit_helper(transaction_tag=None) + @mock.patch( "google.cloud.spanner_v1._opentelemetry_tracing._get_cloud_region", return_value="global", @@ -799,6 +811,7 @@ async def _execute_update_helper( timeout=gapic_v1.method.DEFAULT, begin=True, use_multiplexed=False, + transaction_tag=TRANSACTION_TAG, ): from google.protobuf.struct_pb2 import Struct @@ -832,17 +845,12 @@ async def _execute_update_helper( session = _Session(database) transaction = self._make_one(session) - transaction.transaction_tag = TRANSACTION_TAG + transaction.transaction_tag = transaction_tag transaction._execute_sql_request_count = count if begin: transaction._transaction_id = TRANSACTION_ID - if request_options is None: - request_options = RequestOptions() - elif type(request_options) is dict: - request_options = RequestOptions(request_options) - row_count = await transaction.execute_update( DML_QUERY_WITH_PARAM, PARAMS, @@ -873,9 +881,13 @@ async def _execute_update_helper( expected_query_options = _merge_query_options( expected_query_options, query_options ) - expected_request_options = RequestOptions(request_options) - if request_options.request_tag: - expected_request_options.request_tag = request_options.request_tag + if request_options is not None: + expected_request_options = RequestOptions(request_options) + expected_request_options.transaction_tag = transaction_tag + elif transaction_tag is not None: + expected_request_options = RequestOptions(transaction_tag=transaction_tag) + else: + expected_request_options = None expected_request = ExecuteSqlRequest( session=self.SESSION_NAME, @@ -905,8 +917,13 @@ async def _execute_update_helper( expected_attributes = self._build_span_attributes( database, **{"db.statement": DML_QUERY_WITH_PARAM} ) - if request_options.request_tag: - expected_attributes["request.tag"] = request_options.request_tag + request_tag = ( + request_options.get("request_tag") + if isinstance(request_options, dict) + else getattr(request_options, "request_tag", None) + ) + if request_tag: + expected_attributes["request.tag"] = request_tag self.assertSpanAttributes( "CloudSpanner.Transaction.execute_update", attributes=expected_attributes ) @@ -1044,6 +1061,16 @@ async def test_execute_update_w_query_options(self, mock_region): async def test_execute_update_wo_begin(self, mock_region): await self._execute_update_helper(begin=False) + @mock.patch( + "google.cloud.spanner_v1._opentelemetry_tracing._get_cloud_region", + return_value="global", + ) + @CrossSync.pytest + async def test_execute_update_wo_request_options_and_transaction_tag( + self, mock_region + ): + await self._execute_update_helper(transaction_tag=None) + @mock.patch( "google.cloud.spanner_v1._opentelemetry_tracing._get_cloud_region", return_value="global", @@ -1108,6 +1135,7 @@ async def _batch_update_helper( timeout=gapic_v1.method.DEFAULT, begin=True, use_multiplexed=False, + transaction_tag=TRANSACTION_TAG, ): from google.protobuf.struct_pb2 import Struct from google.rpc.status_pb2 import Status @@ -1172,17 +1200,12 @@ async def _batch_update_helper( session = _Session(database) transaction = self._make_one(session) - transaction.transaction_tag = TRANSACTION_TAG + transaction.transaction_tag = transaction_tag transaction._execute_sql_request_count = count if begin: transaction._transaction_id = TRANSACTION_ID - if request_options is None: - request_options = RequestOptions() - elif type(request_options) is dict: - request_options = RequestOptions(request_options) - status, row_counts = await transaction.batch_update( dml_statements, request_options=request_options, @@ -1217,8 +1240,13 @@ async def _batch_update_helper( ExecuteBatchDmlRequest.Statement(sql=update_dml), ExecuteBatchDmlRequest.Statement(sql=delete_dml), ] - expected_request_options = request_options - expected_request_options.transaction_tag = TRANSACTION_TAG + if request_options is not None: + expected_request_options = RequestOptions(request_options) + expected_request_options.transaction_tag = transaction_tag + elif transaction_tag is not None: + expected_request_options = RequestOptions(transaction_tag=transaction_tag) + else: + expected_request_options = None expected_request = ExecuteBatchDmlRequest( session=self.SESSION_NAME, @@ -1255,6 +1283,16 @@ async def _batch_update_helper( async def test_batch_update_wo_begin(self, mock_region): await self._batch_update_helper(begin=False) + @mock.patch( + "google.cloud.spanner_v1._opentelemetry_tracing._get_cloud_region", + return_value="global", + ) + @CrossSync.pytest + async def test_batch_update_wo_request_options_and_transaction_tag( + self, mock_region + ): + await self._batch_update_helper(transaction_tag=None) + @mock.patch( "google.cloud.spanner_v1._opentelemetry_tracing._get_cloud_region", return_value="global", @@ -1415,7 +1453,6 @@ async def test_context_mgr_success(self, mock_region): request=CommitRequest( session=session.name, transaction_id=transaction._transaction_id, - request_options=RequestOptions(), mutations=transaction._mutations, ), metadata=[ diff --git a/packages/google-cloud-spanner/tests/unit/test_session.py b/packages/google-cloud-spanner/tests/unit/test_session.py index eb45d1b7369f..40bd2b4f8173 100644 --- a/packages/google-cloud-spanner/tests/unit/test_session.py +++ b/packages/google-cloud-spanner/tests/unit/test_session.py @@ -1355,7 +1355,6 @@ def unit_of_work(txn, *args, **kw): session=self.SESSION_NAME, mutations=txn._mutations, transaction_id=TRANSACTION_ID, - request_options=RequestOptions(), ) gax_api.commit.assert_called_once_with( request=request, @@ -1424,7 +1423,6 @@ def unit_of_work(txn, *args, **kw): session=session.name, mutations=txn._mutations, transaction_id=begin_transaction.return_value.id, - request_options=RequestOptions(), ), metadata=[ ("google-cloud-resource-prefix", database.name), @@ -1509,7 +1507,6 @@ def unit_of_work(txn, *args, **kw): session=self.SESSION_NAME, mutations=txn._mutations, transaction_id=TRANSACTION_ID, - request_options=RequestOptions(), ) self.assertEqual( gax_api.commit.call_args_list, @@ -1623,7 +1620,6 @@ def unit_of_work(txn, *args, **kw): session=self.SESSION_NAME, mutations=txn._mutations, transaction_id=TRANSACTION_ID, - request_options=RequestOptions(), ) self.assertEqual( gax_api.commit.call_args_list, @@ -1716,7 +1712,6 @@ def unit_of_work(txn, *args, **kw): session=self.SESSION_NAME, mutations=txn._mutations, transaction_id=TRANSACTION_ID, - request_options=RequestOptions(), ) gax_api.commit.assert_called_once_with( request=request, @@ -1805,7 +1800,6 @@ def _time(): session=self.SESSION_NAME, mutations=txn._mutations, transaction_id=TRANSACTION_ID, - request_options=RequestOptions(), ) gax_api.commit.assert_called_once_with( request=request, @@ -1929,7 +1923,6 @@ def _time(): session=self.SESSION_NAME, mutations=txn._mutations, transaction_id=TRANSACTION_ID, - request_options=RequestOptions(), ) self.assertEqual( gax_api.commit.call_args_list, @@ -2020,7 +2013,6 @@ def unit_of_work(txn, *args, **kw): mutations=txn._mutations, transaction_id=TRANSACTION_ID, return_commit_stats=True, - request_options=RequestOptions(), ) gax_api.commit.assert_called_once_with( request=request, @@ -2085,7 +2077,6 @@ def unit_of_work(txn, *args, **kw): mutations=txn._mutations, transaction_id=TRANSACTION_ID, return_commit_stats=True, - request_options=RequestOptions(), ) gax_api.commit.assert_called_once_with( request=request, @@ -2220,7 +2211,6 @@ def unit_of_work(txn, *args, **kw): session=self.SESSION_NAME, mutations=txn._mutations, transaction_id=TRANSACTION_ID, - request_options=RequestOptions(), ) gax_api.commit.assert_called_once_with( request=request, @@ -2327,7 +2317,6 @@ def unit_of_work(txn, *args, **kw): session=self.SESSION_NAME, mutations=txn._mutations, transaction_id=TRANSACTION_ID, - request_options=RequestOptions(), ) self.assertEqual( gax_api.commit.call_args_list, diff --git a/packages/google-cloud-spanner/tests/unit/test_snapshot.py b/packages/google-cloud-spanner/tests/unit/test_snapshot.py index a367b293f798..0729a4734d6e 100644 --- a/packages/google-cloud-spanner/tests/unit/test_snapshot.py +++ b/packages/google-cloud-spanner/tests/unit/test_snapshot.py @@ -58,6 +58,7 @@ TABLE_NAME = "citizens" COLUMNS = ["email", "first_name", "last_name", "age"] +_DEFAULT_EXPECTED_REQUEST_OPTIONS = object() SQL_QUERY = """\ SELECT first_name, last_name, age FROM citizens ORDER BY age""" SQL_QUERY_WITH_PARAM = """ @@ -1643,6 +1644,9 @@ def _execute_read( directed_read_options=None, directed_read_options_at_client_level=None, use_multiplexed=False, + read_only=True, + transaction_tag=None, + expected_request_options=_DEFAULT_EXPECTED_REQUEST_OPTIONS, ): """Helper for testing _SnapshotBase.read(). Executes method and verifies transaction state, begin transaction API call, and span attributes and events. @@ -1710,16 +1714,29 @@ def _execute_read( api = database.spanner_api = build_spanner_api() api.streaming_read.return_value = _MockIterator(*result_sets) session = _Session(database) - derived = _build_snapshot_derived(session, multi_use=multi_use) + derived = _build_snapshot_derived( + session, multi_use=multi_use, read_only=read_only + ) + derived.transaction_tag = transaction_tag derived._read_request_count = count if not first: derived._transaction_id = TXN_ID - if request_options is None: - request_options = RequestOptions() - elif type(request_options) is dict: - request_options = RequestOptions(request_options) + if expected_request_options is not _DEFAULT_EXPECTED_REQUEST_OPTIONS: + actual_expected_request_options = expected_request_options + elif request_options is not None: + actual_expected_request_options = RequestOptions(request_options) + if read_only: + actual_expected_request_options.transaction_tag = None + elif transaction_tag is not None: + actual_expected_request_options.transaction_tag = transaction_tag + elif not read_only and transaction_tag is not None: + actual_expected_request_options = RequestOptions( + transaction_tag=transaction_tag + ) + else: + actual_expected_request_options = None transaction_selector_pb = derived._build_transaction_selector_pb() @@ -1759,11 +1776,6 @@ def _execute_read( else: expected_limit = LIMIT - # Transaction tag is ignored for read request. - expected_request_options = RequestOptions(request_options) - if derived.transaction_tag: - expected_request_options.transaction_tag = derived.transaction_tag - expected_directed_read_options = ( directed_read_options if directed_read_options is not None @@ -1779,19 +1791,19 @@ def _execute_read( index=INDEX, limit=expected_limit, partition_token=partition, - request_options=expected_request_options, + request_options=actual_expected_request_options, directed_read_options=expected_directed_read_options, ) req_id = f"1.{REQ_RAND_PROCESS_ID}.{database._nth_client_id}.{database._channel_id}.1.1" + expected_metadata = [ + ("google-cloud-resource-prefix", database.name), + ] + if not read_only: + expected_metadata.append(("x-goog-spanner-route-to-leader", "true")) + expected_metadata.append(("x-goog-spanner-request-id", req_id)) api.streaming_read.assert_called_once_with( request=expected_request, - metadata=[ - ("google-cloud-resource-prefix", database.name), - ( - "x-goog-spanner-request-id", - req_id, - ), - ], + metadata=expected_metadata, retry=retry, timeout=timeout, ) @@ -1801,8 +1813,13 @@ def _execute_read( columns=tuple(COLUMNS), x_goog_spanner_request_id=req_id, ) - if request_options and request_options.request_tag: - expected_attributes["request.tag"] = request_options.request_tag + request_tag = ( + request_options.get("request_tag") + if isinstance(request_options, dict) + else getattr(request_options, "request_tag", None) + ) + if request_tag: + expected_attributes["request.tag"] = request_tag self.assertSpanAttributes( "CloudSpanner._Derived.read", attributes=expected_attributes ) @@ -1826,7 +1843,11 @@ def test_read_wo_multi_use(self, mock_region): ) def test_read_w_request_tag_success(self, mock_region): request_options = {"request_tag": "tag-1"} - self._execute_read(multi_use=False, request_options=request_options) + self._execute_read( + multi_use=False, + request_options=request_options, + expected_request_options=RequestOptions(request_tag="tag-1"), + ) @mock.patch( "google.cloud.spanner_v1._opentelemetry_tracing._get_cloud_region", @@ -1834,7 +1855,11 @@ def test_read_w_request_tag_success(self, mock_region): ) def test_read_w_transaction_tag_success(self, mock_region): request_options = {"transaction_tag": "tag-1-1"} - self._execute_read(multi_use=False, request_options=request_options) + self._execute_read( + multi_use=False, + request_options=request_options, + expected_request_options=RequestOptions(), + ) @mock.patch( "google.cloud.spanner_v1._opentelemetry_tracing._get_cloud_region", @@ -1842,7 +1867,11 @@ def test_read_w_transaction_tag_success(self, mock_region): ) def test_read_w_request_and_transaction_tag_success(self, mock_region): request_options = {"request_tag": "tag-1", "transaction_tag": "tag-1-1"} - self._execute_read(multi_use=False, request_options=request_options) + self._execute_read( + multi_use=False, + request_options=request_options, + expected_request_options=RequestOptions(request_tag="tag-1"), + ) @mock.patch( "google.cloud.spanner_v1._opentelemetry_tracing._get_cloud_region", @@ -1850,7 +1879,41 @@ def test_read_w_request_and_transaction_tag_success(self, mock_region): ) def test_read_w_request_and_transaction_tag_dictionary_success(self, mock_region): request_options = {"request_tag": "tag-1", "transaction_tag": "tag-1-1"} - self._execute_read(multi_use=False, request_options=request_options) + self._execute_read( + multi_use=False, + request_options=request_options, + expected_request_options=RequestOptions(request_tag="tag-1"), + ) + + @mock.patch( + "google.cloud.spanner_v1._opentelemetry_tracing._get_cloud_region", + return_value="global", + ) + def test_read_in_read_write_transaction_with_tag(self, mock_region): + self._execute_read( + multi_use=False, + read_only=False, + transaction_tag="tx-tag", + expected_request_options=RequestOptions(transaction_tag="tx-tag"), + ) + + @mock.patch( + "google.cloud.spanner_v1._opentelemetry_tracing._get_cloud_region", + return_value="global", + ) + def test_read_in_read_write_transaction_caller_tag_preserved(self, mock_region): + self._execute_read( + multi_use=False, + read_only=False, + transaction_tag=None, + request_options={ + "request_tag": "r-tag", + "transaction_tag": "caller-tx-tag", + }, + expected_request_options=RequestOptions( + request_tag="r-tag", transaction_tag="caller-tx-tag" + ), + ) @mock.patch( "google.cloud.spanner_v1._opentelemetry_tracing._get_cloud_region", @@ -2011,6 +2074,9 @@ def _execute_sql_helper( directed_read_options=None, directed_read_options_at_client_level=None, use_multiplexed=False, + read_only=True, + transaction_tag=None, + expected_request_options=_DEFAULT_EXPECTED_REQUEST_OPTIONS, ): """Helper for testing _SnapshotBase.execute_sql(). Executes method and verifies transaction state, begin transaction API call, and span attributes and events. @@ -2079,16 +2145,29 @@ def _execute_sql_helper( api = database.spanner_api = build_spanner_api() api.execute_streaming_sql.return_value = iterator session = _Session(database) - derived = _build_snapshot_derived(session, multi_use=multi_use) + derived = _build_snapshot_derived( + session, multi_use=multi_use, read_only=read_only + ) + derived.transaction_tag = transaction_tag derived._read_request_count = count derived._execute_sql_request_count = sql_count if not first: derived._transaction_id = TXN_ID - if request_options is None: - request_options = RequestOptions() - elif type(request_options) is dict: - request_options = RequestOptions(request_options) + if expected_request_options is not _DEFAULT_EXPECTED_REQUEST_OPTIONS: + actual_expected_request_options = expected_request_options + elif request_options is not None: + actual_expected_request_options = RequestOptions(request_options) + if read_only: + actual_expected_request_options.transaction_tag = None + elif transaction_tag is not None: + actual_expected_request_options.transaction_tag = transaction_tag + elif not read_only and transaction_tag is not None: + actual_expected_request_options = RequestOptions( + transaction_tag=transaction_tag + ) + else: + actual_expected_request_options = None transaction_selector_pb = derived._build_transaction_selector_pb() @@ -2121,12 +2200,6 @@ def _execute_sql_helper( expected_query_options, query_options ) - expected_request_options = RequestOptions(request_options) - if derived.transaction_tag: - expected_request_options.transaction_tag = derived.transaction_tag - if not derived._read_only and request_options.request_tag: - expected_request_options.request_tag = request_options.request_tag - expected_directed_read_options = ( directed_read_options if directed_read_options is not None @@ -2141,21 +2214,21 @@ def _execute_sql_helper( param_types=PARAM_TYPES, query_mode=MODE, query_options=expected_query_options, - request_options=expected_request_options, + request_options=actual_expected_request_options, partition_token=partition, seqno=sql_count, directed_read_options=expected_directed_read_options, ) req_id = f"1.{REQ_RAND_PROCESS_ID}.{database._nth_client_id}.{database._channel_id}.1.1" + expected_metadata = [ + ("google-cloud-resource-prefix", database.name), + ] + if not read_only: + expected_metadata.append(("x-goog-spanner-route-to-leader", "true")) + expected_metadata.append(("x-goog-spanner-request-id", req_id)) api.execute_streaming_sql.assert_called_once_with( request=expected_request, - metadata=[ - ("google-cloud-resource-prefix", database.name), - ( - "x-goog-spanner-request-id", - req_id, - ), - ], + metadata=expected_metadata, timeout=timeout, retry=retry, ) @@ -2169,8 +2242,13 @@ def _execute_sql_helper( "x_goog_spanner_request_id": req_id, }, ) - if request_options and request_options.request_tag: - expected_attributes["request.tag"] = request_options.request_tag + request_tag = ( + request_options.get("request_tag") + if isinstance(request_options, dict) + else getattr(request_options, "request_tag", None) + ) + if request_tag: + expected_attributes["request.tag"] = request_tag self.assertSpanAttributes( "CloudSpanner._Derived.execute_sql", @@ -2271,7 +2349,11 @@ def test_execute_sql_w_request_options(self, mock_region): ) def test_execute_sql_w_request_tag_success(self, mock_region): request_options = {"request_tag": "tag-1"} - self._execute_sql_helper(multi_use=False, request_options=request_options) + self._execute_sql_helper( + multi_use=False, + request_options=request_options, + expected_request_options=RequestOptions(request_tag="tag-1"), + ) @mock.patch( "google.cloud.spanner_v1._opentelemetry_tracing._get_cloud_region", @@ -2279,7 +2361,11 @@ def test_execute_sql_w_request_tag_success(self, mock_region): ) def test_execute_sql_w_transaction_tag_success(self, mock_region): request_options = {"transaction_tag": "tag-1-1"} - self._execute_sql_helper(multi_use=False, request_options=request_options) + self._execute_sql_helper( + multi_use=False, + request_options=request_options, + expected_request_options=RequestOptions(), + ) @mock.patch( "google.cloud.spanner_v1._opentelemetry_tracing._get_cloud_region", @@ -2287,7 +2373,11 @@ def test_execute_sql_w_transaction_tag_success(self, mock_region): ) def test_execute_sql_w_request_and_transaction_tag_success(self, mock_region): request_options = {"request_tag": "tag-1", "transaction_tag": "tag-1-1"} - self._execute_sql_helper(multi_use=False, request_options=request_options) + self._execute_sql_helper( + multi_use=False, + request_options=request_options, + expected_request_options=RequestOptions(request_tag="tag-1"), + ) @mock.patch( "google.cloud.spanner_v1._opentelemetry_tracing._get_cloud_region", @@ -2297,7 +2387,43 @@ def test_execute_sql_w_request_and_transaction_tag_dictionary_success( self, mock_region ): request_options = {"request_tag": "tag-1", "transaction_tag": "tag-1-1"} - self._execute_sql_helper(multi_use=False, request_options=request_options) + self._execute_sql_helper( + multi_use=False, + request_options=request_options, + expected_request_options=RequestOptions(request_tag="tag-1"), + ) + + @mock.patch( + "google.cloud.spanner_v1._opentelemetry_tracing._get_cloud_region", + return_value="global", + ) + def test_execute_sql_in_read_write_transaction_with_tag(self, mock_region): + self._execute_sql_helper( + multi_use=False, + read_only=False, + transaction_tag="tx-tag", + expected_request_options=RequestOptions(transaction_tag="tx-tag"), + ) + + @mock.patch( + "google.cloud.spanner_v1._opentelemetry_tracing._get_cloud_region", + return_value="global", + ) + def test_execute_sql_in_read_write_transaction_caller_tag_preserved( + self, mock_region + ): + self._execute_sql_helper( + multi_use=False, + read_only=False, + transaction_tag=None, + request_options={ + "request_tag": "r-tag", + "transaction_tag": "caller-tx-tag", + }, + expected_request_options=RequestOptions( + request_tag="r-tag", transaction_tag="caller-tx-tag" + ), + ) def test_execute_sql_w_incorrect_tag_dictionary_error(self): request_options = {"incorrect_tag": "tag-1-1"} diff --git a/packages/google-cloud-spanner/tests/unit/test_transaction.py b/packages/google-cloud-spanner/tests/unit/test_transaction.py index a444873c2474..2fc4c8629ec3 100644 --- a/packages/google-cloud-spanner/tests/unit/test_transaction.py +++ b/packages/google-cloud-spanner/tests/unit/test_transaction.py @@ -395,6 +395,7 @@ def _commit_helper( retry_for_precommit_token=None, is_multiplexed=False, expected_begin_mutation=None, + transaction_tag=TRANSACTION_TAG, ): from google.cloud.spanner_v1 import CommitRequest @@ -407,7 +408,7 @@ def _commit_helper( database = session._database api = database.spanner_api - transaction.transaction_tag = TRANSACTION_TAG + transaction.transaction_tag = transaction_tag if mutations is not None: transaction._mutations = mutations @@ -465,11 +466,16 @@ def _commit_helper( if mutations is not None: self.assertEqual(transaction._transaction_id, TRANSACTION_ID) + expected_begin_request_options = ( + RequestOptions(transaction_tag=transaction_tag) + if transaction_tag is not None + else None + ) expected_begin_transaction_request = BeginTransactionRequest( session=session.name, options=TransactionOptions(read_write=TransactionOptions.ReadWrite()), mutation_key=expected_begin_mutation, - request_options=RequestOptions(transaction_tag=TRANSACTION_TAG), + request_options=expected_begin_request_options, ) expected_begin_metadata = base_metadata.copy() @@ -490,16 +496,14 @@ def _commit_helper( # Verify commit API call(s). self.assertEqual(commit.call_count, 1 if not retry_for_precommit_token else 2) - if request_options is None: - expected_request_options = RequestOptions(transaction_tag=TRANSACTION_TAG) - elif type(request_options) is dict: + if request_options is not None: expected_request_options = RequestOptions(request_options) - expected_request_options.transaction_tag = TRANSACTION_TAG + expected_request_options.transaction_tag = transaction_tag expected_request_options.request_tag = None + elif transaction_tag is not None: + expected_request_options = RequestOptions(transaction_tag=transaction_tag) else: - expected_request_options = request_options - expected_request_options.transaction_tag = TRANSACTION_TAG - expected_request_options.request_tag = None + expected_request_options = None common_expected_commit_response_args = { "session": session.name, @@ -679,6 +683,13 @@ def test_commit_w_incorrect_tag_dictionary_error(self): with self.assertRaises(ValueError): self._commit_helper(request_options=request_options) + @mock.patch( + "google.cloud.spanner_v1._opentelemetry_tracing._get_cloud_region", + return_value="global", + ) + def test_commit_wo_request_options_and_transaction_tag(self, mock_region): + self._commit_helper(transaction_tag=None) + @mock.patch( "google.cloud.spanner_v1._opentelemetry_tracing._get_cloud_region", return_value="global", @@ -756,6 +767,7 @@ def _execute_update_helper( timeout=gapic_v1.method.DEFAULT, begin=True, use_multiplexed=False, + transaction_tag=TRANSACTION_TAG, ): from google.protobuf.struct_pb2 import Struct @@ -789,17 +801,12 @@ def _execute_update_helper( session = _Session(database) transaction = self._make_one(session) - transaction.transaction_tag = TRANSACTION_TAG + transaction.transaction_tag = transaction_tag transaction._execute_sql_request_count = count if begin: transaction._transaction_id = TRANSACTION_ID - if request_options is None: - request_options = RequestOptions() - elif type(request_options) is dict: - request_options = RequestOptions(request_options) - row_count = transaction.execute_update( DML_QUERY_WITH_PARAM, PARAMS, @@ -830,9 +837,13 @@ def _execute_update_helper( expected_query_options = _merge_query_options( expected_query_options, query_options ) - expected_request_options = RequestOptions(request_options) - if request_options.request_tag: - expected_request_options.request_tag = request_options.request_tag + if request_options is not None: + expected_request_options = RequestOptions(request_options) + expected_request_options.transaction_tag = transaction_tag + elif transaction_tag is not None: + expected_request_options = RequestOptions(transaction_tag=transaction_tag) + else: + expected_request_options = None expected_request = ExecuteSqlRequest( session=self.SESSION_NAME, @@ -862,8 +873,13 @@ def _execute_update_helper( expected_attributes = self._build_span_attributes( database, **{"db.statement": DML_QUERY_WITH_PARAM} ) - if request_options.request_tag: - expected_attributes["request.tag"] = request_options.request_tag + request_tag = ( + request_options.get("request_tag") + if isinstance(request_options, dict) + else getattr(request_options, "request_tag", None) + ) + if request_tag: + expected_attributes["request.tag"] = request_tag self.assertSpanAttributes( "CloudSpanner.Transaction.execute_update", attributes=expected_attributes ) @@ -986,6 +1002,13 @@ def test_execute_update_w_query_options(self, mock_region): def test_execute_update_wo_begin(self, mock_region): self._execute_update_helper(begin=False) + @mock.patch( + "google.cloud.spanner_v1._opentelemetry_tracing._get_cloud_region", + return_value="global", + ) + def test_execute_update_wo_request_options_and_transaction_tag(self, mock_region): + self._execute_update_helper(transaction_tag=None) + @mock.patch( "google.cloud.spanner_v1._opentelemetry_tracing._get_cloud_region", return_value="global", @@ -1046,6 +1069,7 @@ def _batch_update_helper( timeout=gapic_v1.method.DEFAULT, begin=True, use_multiplexed=False, + transaction_tag=TRANSACTION_TAG, ): from google.protobuf.struct_pb2 import Struct from google.rpc.status_pb2 import Status @@ -1110,17 +1134,12 @@ def _batch_update_helper( session = _Session(database) transaction = self._make_one(session) - transaction.transaction_tag = TRANSACTION_TAG + transaction.transaction_tag = transaction_tag transaction._execute_sql_request_count = count if begin: transaction._transaction_id = TRANSACTION_ID - if request_options is None: - request_options = RequestOptions() - elif type(request_options) is dict: - request_options = RequestOptions(request_options) - status, row_counts = transaction.batch_update( dml_statements, request_options=request_options, @@ -1155,8 +1174,13 @@ def _batch_update_helper( ExecuteBatchDmlRequest.Statement(sql=update_dml), ExecuteBatchDmlRequest.Statement(sql=delete_dml), ] - expected_request_options = request_options - expected_request_options.transaction_tag = TRANSACTION_TAG + if request_options is not None: + expected_request_options = RequestOptions(request_options) + expected_request_options.transaction_tag = transaction_tag + elif transaction_tag is not None: + expected_request_options = RequestOptions(transaction_tag=transaction_tag) + else: + expected_request_options = None expected_request = ExecuteBatchDmlRequest( session=self.SESSION_NAME, @@ -1192,6 +1216,13 @@ def _batch_update_helper( def test_batch_update_wo_begin(self, mock_region): self._batch_update_helper(begin=False) + @mock.patch( + "google.cloud.spanner_v1._opentelemetry_tracing._get_cloud_region", + return_value="global", + ) + def test_batch_update_wo_request_options_and_transaction_tag(self, mock_region): + self._batch_update_helper(transaction_tag=None) + @mock.patch( "google.cloud.spanner_v1._opentelemetry_tracing._get_cloud_region", return_value="global", @@ -1337,7 +1368,6 @@ def test_context_mgr_success(self, mock_region): request=CommitRequest( session=session.name, transaction_id=transaction._transaction_id, - request_options=RequestOptions(), mutations=transaction._mutations, ), metadata=[