From 6b78e350f171e63bf1f4a58876c4d36e2a87a649 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 24 Jul 2025 16:11:31 +0000 Subject: [PATCH 1/2] chore(deps): update dependency google-cloud-spanner to v3.56.0 --- requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/requirements.txt b/requirements.txt index a4f6d24f..a5e7e410 100644 --- a/requirements.txt +++ b/requirements.txt @@ -144,9 +144,9 @@ google-cloud-core==2.4.3 \ --hash=sha256:1fab62d7102844b278fe6dead3af32408b1df3eb06f5c7e8634cbd40edc4da53 \ --hash=sha256:5130f9f4c14b4fafdff75c79448f9495cfade0d8775facf1b09c3bf67e027f6e # via google-cloud-spanner -google-cloud-spanner==3.55.0 \ - --hash=sha256:bec170c6619f667cc657e977f87391d76975559be70b155d90a2902613662b3c \ - --hash=sha256:fc9f717b612924f5e9bfae9514aa0d5cd30e6b40e8d472d030f84b16de2c18fe +google-cloud-spanner==3.56.0 \ + --hash=sha256:64f732a44f6a2892b5cc3be88e6e2cc92b5e52db883d1e946e1e3ff93c9745f0 \ + --hash=sha256:bf7e4359d2f2148eda18a11f909813d07e794347a02f56dfbbd544418d30e5b2 # via -r requirements.in googleapis-common-protos[grpc]==1.70.0 \ --hash=sha256:0e1b44e0ea153e6594f9f394fef15193a68aaaea2d843f83e2742717ca753257 \ From 7a9eb1a769fd389ce01d23d8cbfc444edde5839a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Wed, 13 Aug 2025 11:03:53 +0200 Subject: [PATCH 2/2] chore: update tests for mux session usage --- .github/workflows/test_suite.yml | 6 +-- .gitignore | 4 +- requirements.txt | 46 ++++++++-------- samples/sample_helper.py | 2 +- .../mockserver_tests/mock_server_test_base.py | 16 +++--- test/mockserver_tests/test_auto_increment.py | 31 +++-------- test/mockserver_tests/test_basics.py | 52 ++++++------------- .../test_bit_reversed_sequence.py | 16 ++---- .../mockserver_tests/test_commit_timestamp.py | 11 +--- test/mockserver_tests/test_float32.py | 4 +- test/mockserver_tests/test_isolation_level.py | 28 ++++------ test/mockserver_tests/test_json.py | 22 +++----- test/mockserver_tests/test_pickle_type.py | 16 ++---- test/mockserver_tests/test_quickstart.py | 4 +- .../test_read_only_transaction.py | 13 ++--- test/mockserver_tests/test_stale_reads.py | 21 +++----- test/mockserver_tests/test_tags.py | 19 +++---- test/test_suite_20.py | 11 ++++ 18 files changed, 117 insertions(+), 205 deletions(-) diff --git a/.github/workflows/test_suite.yml b/.github/workflows/test_suite.yml index 23f28e19..6ffc17d2 100644 --- a/.github/workflows/test_suite.yml +++ b/.github/workflows/test_suite.yml @@ -74,7 +74,7 @@ jobs: services: emulator-0: - image: gcr.io/cloud-spanner-emulator/emulator:latest + image: gcr.io/cloud-spanner-emulator/emulator ports: - 9010:9010 @@ -98,7 +98,7 @@ jobs: services: emulator-0: - image: gcr.io/cloud-spanner-emulator/emulator:latest + image: gcr.io/cloud-spanner-emulator/emulator ports: - 9010:9010 @@ -123,7 +123,7 @@ jobs: services: emulator-0: - image: gcr.io/cloud-spanner-emulator/emulator:latest + image: gcr.io/cloud-spanner-emulator/emulator ports: - 9010:9010 diff --git a/.gitignore b/.gitignore index 6cb13eed..e62c3479 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,7 @@ docs/_build docs.metadata # Virtual environment +.venv/ env/ coverage.xml sponge_log.xml @@ -59,4 +60,5 @@ system_tests/local_test_setup pylintrc pylintrc.test -test.cfg \ No newline at end of file +test.cfg +database diff --git a/requirements.txt b/requirements.txt index a5e7e410..0894601a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,9 +14,9 @@ build==1.2.2.post1 \ # via # -r requirements.in # pip-tools -cachetools==6.1.0 \ - --hash=sha256:1c7bb3cf9193deaf3508b7c5f2a79986c13ea38965c5adcff1f84519cf39163e \ - --hash=sha256:b4c4f404392848db3ce7aac34950d17be4d864da4b8b66911008e430bc544587 +cachetools==5.5.2 \ + --hash=sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4 \ + --hash=sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a # via google-auth certifi==2025.6.15 \ --hash=sha256:2e0c7ce7cb5d8f8634ca55d2ba7e6ec2689a2fd6537d8dec1296a477a4910057 \ @@ -144,9 +144,9 @@ google-cloud-core==2.4.3 \ --hash=sha256:1fab62d7102844b278fe6dead3af32408b1df3eb06f5c7e8634cbd40edc4da53 \ --hash=sha256:5130f9f4c14b4fafdff75c79448f9495cfade0d8775facf1b09c3bf67e027f6e # via google-cloud-spanner -google-cloud-spanner==3.56.0 \ - --hash=sha256:64f732a44f6a2892b5cc3be88e6e2cc92b5e52db883d1e946e1e3ff93c9745f0 \ - --hash=sha256:bf7e4359d2f2148eda18a11f909813d07e794347a02f56dfbbd544418d30e5b2 +google-cloud-spanner==3.57.0 \ + --hash=sha256:5b10b40bc646091f1b4cbb2e7e2e82ec66bcce52c7105f86b65070d34d6df86f \ + --hash=sha256:73f52f58617449fcff7073274a7f7a798f4f7b2788eda26de3b7f98ad857ab99 # via -r requirements.in googleapis-common-protos[grpc]==1.70.0 \ --hash=sha256:0e1b44e0ea153e6594f9f394fef15193a68aaaea2d843f83e2742717ca753257 \ @@ -372,9 +372,9 @@ opentelemetry-sdk==1.34.1 \ --hash=sha256:308effad4059562f1d92163c61c8141df649da24ce361827812c40abb2a1e96e \ --hash=sha256:8091db0d763fcd6098d4781bbc80ff0971f94e260739aa6afe6fd379cdf3aa4d # via -r requirements.in -opentelemetry-semantic-conventions==0.54b1 \ - --hash=sha256:29dab644a7e435b58d3a3918b58c333c92686236b30f7891d5e51f02933ca60d \ - --hash=sha256:d1cecedae15d19bdaafca1e56b29a66aa286f50b5d08f036a145c7f3e9ef9cee +opentelemetry-semantic-conventions==0.55b1 \ + --hash=sha256:5da81dfdf7d52e3d37f8fe88d5e771e191de924cfff5f550ab0b8f7b2409baed \ + --hash=sha256:ef95b1f009159c28d7a7849f5cbc71c4c34c845bb514d66adfdf1b3fff3598b3 # via opentelemetry-sdk packaging==25.0 \ --hash=sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484 \ @@ -396,18 +396,16 @@ proto-plus==1.26.1 \ # via # google-api-core # google-cloud-spanner -protobuf==5.29.5 \ - --hash=sha256:3f1c6468a2cfd102ff4703976138844f78ebd1fb45f49011afc5139e9e283079 \ - --hash=sha256:3f76e3a3675b4a4d867b52e4a5f5b78a2ef9565549d4037e06cf7b0942b1d3fc \ - --hash=sha256:470f3af547ef17847a28e1f47200a1cbf0ba3ff57b7de50d22776607cd2ea353 \ - --hash=sha256:63848923da3325e1bf7e9003d680ce6e14b07e55d0473253a690c3a8b8fd6e61 \ - --hash=sha256:6cf42630262c59b2d8de33954443d94b746c952b01434fc58a417fdbd2e84bd5 \ - --hash=sha256:6f642dc9a61782fa72b90878af134c5afe1917c89a568cd3476d758d3c3a0736 \ - --hash=sha256:7318608d56b6402d2ea7704ff1e1e4597bee46d760e7e4dd42a3d45e24b87f2e \ - --hash=sha256:bc1463bafd4b0929216c35f437a8e28731a2b7fe3d98bb77a600efced5a15c84 \ - --hash=sha256:e38c5add5a311f2a6eb0340716ef9b039c1dfa428b28f25a7838ac329204a671 \ - --hash=sha256:ef91363ad4faba7b25d844ef1ada59ff1604184c0bcd8b39b8a6bef15e1af238 \ - --hash=sha256:fa18533a299d7ab6c55a238bf8629311439995f2e7eca5caaff08663606e9015 +protobuf==6.32.0 \ + --hash=sha256:15eba1b86f193a407607112ceb9ea0ba9569aed24f93333fe9a497cf2fda37d3 \ + --hash=sha256:501fe6372fd1c8ea2a30b4d9be8f87955a64d6be9c88a973996cef5ef6f0abf1 \ + --hash=sha256:75a2aab2bd1aeb1f5dc7c5f33bcb11d82ea8c055c9becbb41c26a8c43fd7092c \ + --hash=sha256:7db8ed09024f115ac877a1427557b838705359f047b2ff2f2b2364892d19dacb \ + --hash=sha256:84f9e3c1ff6fb0308dbacb0950d8aa90694b0d0ee68e75719cb044b7078fe741 \ + --hash=sha256:a81439049127067fc49ec1d36e25c6ee1d1a2b7be930675f919258d03c04e7d2 \ + --hash=sha256:a8bdbb2f009cfc22a36d031f22a625a38b615b5e19e558a7b756b3279723e68e \ + --hash=sha256:ba377e5b67b908c8f3072a57b63e2c6a4cbd18aea4ed98d2584350dbf46f2783 \ + --hash=sha256:d52691e5bee6c860fff9a1c86ad26a13afbeb4b168cd4445c922b7e2cf85aaf0 # via # google-api-core # google-cloud-spanner @@ -547,7 +545,9 @@ typing-extensions==4.14.0 \ --hash=sha256:a1514509136dd0b477638fc68d6a91497af5076466ad0fa6c338e44e359944af # via # alembic + # opentelemetry-api # opentelemetry-sdk + # opentelemetry-semantic-conventions # sqlalchemy urllib3==2.5.0 \ --hash=sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760 \ @@ -637,9 +637,7 @@ wrapt==1.17.2 \ --hash=sha256:f917c1180fdb8623c2b75a99192f4025e412597c50b2ac870f156de8fb101119 \ --hash=sha256:fc78a84e2dfbc27afe4b2bd7c80c8db9bca75cc5b85df52bfe634596a1da846b \ --hash=sha256:ff04ef6eec3eee8a5efef2401495967a916feaa353643defcc03fc74fe213b58 - # via - # deprecated - # opentelemetry-instrumentation + # via opentelemetry-instrumentation zipp==3.23.0 \ --hash=sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e \ --hash=sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166 diff --git a/samples/sample_helper.py b/samples/sample_helper.py index 862d535d..b1c068f8 100644 --- a/samples/sample_helper.py +++ b/samples/sample_helper.py @@ -49,7 +49,7 @@ def start_emulator() -> (DockerContainer, str): ).with_exposed_ports(9010) emulator.start() wait_for_logs(emulator, "gRPC server listening at 0.0.0.0:9010") - port = emulator.get_exposed_port(9010) + port = str(emulator.get_exposed_port(9010)) _create_instance_and_database(port) return emulator, port diff --git a/test/mockserver_tests/mock_server_test_base.py b/test/mockserver_tests/mock_server_test_base.py index a8fea819..6cdf9733 100644 --- a/test/mockserver_tests/mock_server_test_base.py +++ b/test/mockserver_tests/mock_server_test_base.py @@ -11,6 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +import logging from google.cloud.spanner_dbapi.parsed_statement import AutocommitDmlMode from sqlalchemy import Engine, create_engine @@ -22,7 +23,6 @@ from google.cloud.spanner_v1 import ( Client, ResultSet, - PingingPool, TypeCode, ) from google.cloud.spanner_v1.database import Database @@ -131,9 +131,12 @@ class MockServerTestBase(fixtures.TestBase): spanner_service: SpannerServicer = None database_admin_service: DatabaseAdminServicer = None port: int = None + logger: logging.Logger = None @classmethod def setup_class(cls): + MockServerTestBase.logger = logging.getLogger("level warning") + MockServerTestBase.logger.setLevel(logging.WARN) ( MockServerTestBase.server, MockServerTestBase.spanner_service, @@ -151,6 +154,7 @@ def setup_method(self): self._client = None self._instance = None self._database = None + _ = self.database def teardown_method(self): MockServerTestBase.spanner_service.clear_requests() @@ -159,7 +163,7 @@ def teardown_method(self): def create_engine(self) -> Engine: return create_engine( "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": PingingPool(size=10)}, + connect_args={"client": self.client, "logger": MockServerTestBase.logger}, ) @property @@ -177,13 +181,13 @@ def client(self) -> Client: @property def instance(self) -> Instance: if self._instance is None: - self._instance = self.client.instance("test-instance") + self._instance = self.client.instance("i") return self._instance @property def database(self) -> Database: + logger = logging.getLogger("level warning") + logger.setLevel(logging.WARN) if self._database is None: - self._database = self.instance.database( - "test-database", pool=PingingPool(size=10) - ) + self._database = self.instance.database("d", logger=logger) return self._database diff --git a/test/mockserver_tests/test_auto_increment.py b/test/mockserver_tests/test_auto_increment.py index 7fa245e8..9e8051db 100644 --- a/test/mockserver_tests/test_auto_increment.py +++ b/test/mockserver_tests/test_auto_increment.py @@ -12,13 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -from sqlalchemy import create_engine from sqlalchemy.orm import Session from sqlalchemy.testing import eq_, is_instance_of from google.cloud.spanner_v1 import ( - FixedSizePool, ResultSet, - BatchCreateSessionsRequest, + CreateSessionRequest, ExecuteSqlRequest, CommitRequest, BeginTransactionRequest, @@ -45,10 +43,7 @@ def test_create_table(self): """, ResultSet(), ) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() Base.metadata.create_all(engine) requests = self.database_admin_service.requests eq_(1, len(requests)) @@ -74,10 +69,7 @@ def test_create_auto_increment_table(self): """, ResultSet(), ) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() engine.dialect.use_auto_increment = True Base.metadata.create_all(engine) requests = self.database_admin_service.requests @@ -103,10 +95,7 @@ def test_create_table_with_specific_sequence_kind(self): """, ResultSet(), ) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() engine.dialect.default_sequence_kind = "non_existing_kind" Base.metadata.create_all(engine) requests = self.database_admin_service.requests @@ -126,10 +115,7 @@ def test_insert_row(self): from test.mockserver_tests.auto_increment_model import Singer self.add_insert_result("INSERT INTO singers (name) VALUES (@a0) THEN RETURN id") - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() with Session(engine) as session: singer = Singer(name="Test") @@ -141,7 +127,7 @@ def test_insert_row(self): # Verify the requests that we got. requests = self.spanner_service.requests eq_(4, len(requests)) - is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[0], CreateSessionRequest) is_instance_of(requests[1], BeginTransactionRequest) is_instance_of(requests[2], ExecuteSqlRequest) is_instance_of(requests[3], CommitRequest) @@ -152,10 +138,7 @@ def test_insert_row_with_pk_value(self): # SQLAlchemy should not use a THEN RETURN clause when a value for the # primary key has been set on the model. add_update_count("INSERT INTO singers (id, name) VALUES (@a0, @a1)", 1) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() with Session(engine) as session: # Manually specify a value for the primary key. diff --git a/test/mockserver_tests/test_basics.py b/test/mockserver_tests/test_basics.py index 7d40e874..3e6c2fe0 100644 --- a/test/mockserver_tests/test_basics.py +++ b/test/mockserver_tests/test_basics.py @@ -13,6 +13,7 @@ # limitations under the License. import datetime + from google.cloud.spanner_admin_database_v1 import UpdateDatabaseDdlRequest from google.cloud.spanner_dbapi.parsed_statement import AutocommitDmlMode from sqlalchemy import ( @@ -32,11 +33,9 @@ from sqlalchemy.orm import Session, DeclarativeBase, Mapped, mapped_column from sqlalchemy.testing import eq_, is_instance_of from google.cloud.spanner_v1 import ( - FixedSizePool, - BatchCreateSessionsRequest, + CreateSessionRequest, ExecuteSqlRequest, ResultSet, - PingingPool, TypeCode, ) from test.mockserver_tests.mock_server_test_base import ( @@ -58,7 +57,7 @@ def verify_select1(self, results): eq_(1, len(result_list)) requests = self.spanner_service.requests eq_(2, len(requests)) - is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[0], CreateSessionRequest) is_instance_of(requests[1], ExecuteSqlRequest) def test_select1(self): @@ -69,10 +68,7 @@ def test_select1(self): def test_sqlalchemy_select1(self): add_select1_result() - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": PingingPool(size=10)}, - ) + engine = self.create_engine() with engine.connect().execution_options( isolation_level="AUTOCOMMIT" ) as connection: @@ -92,10 +88,7 @@ def test_sqlalchemy_select_now(self): TypeCode.TIMESTAMP, [(iso_now,)], ) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": PingingPool(size=10)}, - ) + engine = self.create_engine() with engine.connect().execution_options( isolation_level="AUTOCOMMIT" ) as connection: @@ -111,10 +104,7 @@ def test_create_table(self): """, ResultSet(), ) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() metadata = MetaData() Table( "users", @@ -148,10 +138,7 @@ def test_create_table_in_schema(self): """, ResultSet(), ) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() metadata = MetaData() Table( "users", @@ -190,10 +177,7 @@ def test_create_multiple_tables(self): """, ResultSet(), ) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() metadata = MetaData() for i in range(2): Table( @@ -224,7 +208,7 @@ def test_partitioned_dml(self): "spanner:///projects/p/instances/i/databases/d", connect_args={ "client": self.client, - "pool": PingingPool(size=10), + "logger": MockServerTestBase.logger, "ignore_transaction_warnings": True, }, ) @@ -258,10 +242,7 @@ class Singer(Base): update = "UPDATE singers SET name=@a0 WHERE singers.id = @a1" add_update_count(update, 1) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() with Session(engine) as session: singer = ( @@ -277,7 +258,7 @@ def test_database_role(self): "spanner:///projects/p/instances/i/databases/d", connect_args={ "client": self.client, - "pool": FixedSizePool(size=10), + "logger": MockServerTestBase.logger, "database_role": "my_role", }, ) @@ -285,10 +266,10 @@ def test_database_role(self): session.execute(select(1)) requests = self.spanner_service.requests eq_(2, len(requests)) - is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[0], CreateSessionRequest) is_instance_of(requests[1], ExecuteSqlRequest) - request: BatchCreateSessionsRequest = requests[0] - eq_("my_role", request.session_template.creator_role) + request: CreateSessionRequest = requests[0] + eq_("my_role", request.session.creator_role) def test_select_table_in_named_schema(self): class Base(DeclarativeBase): @@ -309,10 +290,7 @@ class Singer(Base): " LIMIT @a1" ) add_singer_query_result(query) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() insert = "INSERT INTO my_schema.singers (name) VALUES (@a0) THEN RETURN id" add_single_result(insert, "id", TypeCode.INT64, [("1",)]) diff --git a/test/mockserver_tests/test_bit_reversed_sequence.py b/test/mockserver_tests/test_bit_reversed_sequence.py index 9e7a81a8..b54bb367 100644 --- a/test/mockserver_tests/test_bit_reversed_sequence.py +++ b/test/mockserver_tests/test_bit_reversed_sequence.py @@ -12,13 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -from sqlalchemy import create_engine from sqlalchemy.orm import Session from sqlalchemy.testing import eq_, is_instance_of from google.cloud.spanner_v1 import ( - FixedSizePool, ResultSet, - BatchCreateSessionsRequest, + CreateSessionRequest, ExecuteSqlRequest, CommitRequest, BeginTransactionRequest, @@ -52,10 +50,7 @@ def test_create_table(self): LIMIT 1""", ResultSet(), ) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() Base.metadata.create_all(engine) requests = self.database_admin_service.requests eq_(1, len(requests)) @@ -113,10 +108,7 @@ def test_insert_row(self): "THEN RETURN id", result, ) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() with Session(engine) as session: singer = Singer(name="Test") @@ -128,7 +120,7 @@ def test_insert_row(self): # Verify the requests that we got. requests = self.spanner_service.requests eq_(4, len(requests)) - is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[0], CreateSessionRequest) is_instance_of(requests[1], BeginTransactionRequest) is_instance_of(requests[2], ExecuteSqlRequest) is_instance_of(requests[3], CommitRequest) diff --git a/test/mockserver_tests/test_commit_timestamp.py b/test/mockserver_tests/test_commit_timestamp.py index 3872bde1..f70fcec6 100644 --- a/test/mockserver_tests/test_commit_timestamp.py +++ b/test/mockserver_tests/test_commit_timestamp.py @@ -12,12 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -from sqlalchemy import create_engine from sqlalchemy.testing import eq_, is_instance_of -from google.cloud.spanner_v1 import ( - FixedSizePool, - ResultSet, -) +from google.cloud.spanner_v1 import ResultSet from test.mockserver_tests.mock_server_test_base import ( MockServerTestBase, add_result, @@ -45,10 +41,7 @@ def test_create_table(self): LIMIT 1""", ResultSet(), ) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() Base.metadata.create_all(engine) requests = self.database_admin_service.requests eq_(1, len(requests)) diff --git a/test/mockserver_tests/test_float32.py b/test/mockserver_tests/test_float32.py index 801a57c2..50cd6a86 100644 --- a/test/mockserver_tests/test_float32.py +++ b/test/mockserver_tests/test_float32.py @@ -19,7 +19,7 @@ is_false, ) from google.cloud.spanner_v1 import ( - BatchCreateSessionsRequest, + CreateSessionRequest, ExecuteSqlRequest, ResultSet, ResultSetStats, @@ -59,7 +59,7 @@ def test_insert_data(self): requests = self.spanner_service.requests eq_(4, len(requests)) - is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[0], CreateSessionRequest) is_instance_of(requests[1], BeginTransactionRequest) is_instance_of(requests[2], ExecuteSqlRequest) is_instance_of(requests[3], CommitRequest) diff --git a/test/mockserver_tests/test_isolation_level.py b/test/mockserver_tests/test_isolation_level.py index f6545298..21dca305 100644 --- a/test/mockserver_tests/test_isolation_level.py +++ b/test/mockserver_tests/test_isolation_level.py @@ -16,8 +16,7 @@ from sqlalchemy.orm import Session from sqlalchemy.testing import eq_, is_instance_of from google.cloud.spanner_v1 import ( - FixedSizePool, - BatchCreateSessionsRequest, + CreateSessionRequest, ExecuteSqlRequest, CommitRequest, BeginTransactionRequest, @@ -41,10 +40,7 @@ def test_default_isolation_level(self): from test.mockserver_tests.isolation_level_model import Singer self.add_insert_result("INSERT INTO singers (name) VALUES (@a0) THEN RETURN id") - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() with Session(engine) as session: singer = Singer(name="Test") @@ -60,7 +56,7 @@ def test_engine_isolation_level(self): self.add_insert_result("INSERT INTO singers (name) VALUES (@a0) THEN RETURN id") engine = create_engine( "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + connect_args={"client": self.client, "logger": MockServerTestBase.logger}, isolation_level="REPEATABLE READ", ) @@ -74,10 +70,7 @@ def test_execution_options_isolation_level(self): from test.mockserver_tests.isolation_level_model import Singer self.add_insert_result("INSERT INTO singers (name) VALUES (@a0) THEN RETURN id") - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() with Session( engine.execution_options(isolation_level="repeatable read") @@ -93,7 +86,7 @@ def test_override_engine_isolation_level(self): self.add_insert_result("INSERT INTO singers (name) VALUES (@a0) THEN RETURN id") engine = create_engine( "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + connect_args={"client": self.client, "logger": MockServerTestBase.logger}, isolation_level="REPEATABLE READ", ) @@ -113,7 +106,7 @@ def test_auto_commit(self): "spanner:///projects/p/instances/i/databases/d", connect_args={ "client": self.client, - "pool": FixedSizePool(size=10), + "logger": MockServerTestBase.logger, "ignore_transaction_warnings": True, }, ) @@ -130,7 +123,7 @@ def test_auto_commit(self): # Verify the requests that we got. requests = self.spanner_service.requests eq_(3, len(requests)) - is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[0], CreateSessionRequest) is_instance_of(requests[1], ExecuteSqlRequest) is_instance_of(requests[2], CommitRequest) execute_request: ExecuteSqlRequest = requests[1] @@ -147,10 +140,7 @@ def test_auto_commit(self): def test_invalid_isolation_level(self): from test.mockserver_tests.isolation_level_model import Singer - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() with pytest.raises(ValueError): with Session(engine.execution_options(isolation_level="foo")) as session: singer = Singer(name="Test") @@ -161,7 +151,7 @@ def verify_isolation_level(self, level): # Verify the requests that we got. requests = self.spanner_service.requests eq_(4, len(requests)) - is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[0], CreateSessionRequest) is_instance_of(requests[1], BeginTransactionRequest) is_instance_of(requests[2], ExecuteSqlRequest) is_instance_of(requests[3], CommitRequest) diff --git a/test/mockserver_tests/test_json.py b/test/mockserver_tests/test_json.py index 6395fe3a..2d37a335 100644 --- a/test/mockserver_tests/test_json.py +++ b/test/mockserver_tests/test_json.py @@ -12,13 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -from sqlalchemy import create_engine, select +from sqlalchemy import select from sqlalchemy.orm import Session from sqlalchemy.testing import eq_, is_instance_of from google.cloud.spanner_v1 import ( - FixedSizePool, ResultSet, - BatchCreateSessionsRequest, + CreateSessionRequest, ExecuteSqlRequest, CommitRequest, BeginTransactionRequest, @@ -47,10 +46,7 @@ def test_create_table(self): """, ResultSet(), ) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() Base.metadata.create_all(engine) requests = self.database_admin_service.requests eq_(1, len(requests)) @@ -83,10 +79,7 @@ def _test_insert_json(self, description, expected): add_update_count( "INSERT INTO venues (id, name, description) VALUES (@a0, @a1, @a2)", 1 ) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() with Session(engine) as session: venue = Venue(id=1, name="Test", description=description) @@ -96,7 +89,7 @@ def _test_insert_json(self, description, expected): # Verify the requests that we got. requests = self.spanner_service.requests eq_(4, len(requests)) - is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[0], CreateSessionRequest) is_instance_of(requests[1], BeginTransactionRequest) is_instance_of(requests[2], ExecuteSqlRequest) is_instance_of(requests[3], CommitRequest) @@ -126,10 +119,7 @@ def _test_select_json(self, description, expected): sql = "SELECT venues.id, venues.name, venues.description \n" "FROM venues" add_venue_query_result(sql, description) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() with Session(engine.execution_options(read_only=True)) as session: venue = session.execute(select(Venue)).first()[0] diff --git a/test/mockserver_tests/test_pickle_type.py b/test/mockserver_tests/test_pickle_type.py index b4c2e76c..b2f1a2ab 100644 --- a/test/mockserver_tests/test_pickle_type.py +++ b/test/mockserver_tests/test_pickle_type.py @@ -12,13 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -from sqlalchemy import create_engine from sqlalchemy.orm import Session from sqlalchemy.testing import eq_, is_instance_of from google.cloud.spanner_v1 import ( - FixedSizePool, ResultSet, - BatchCreateSessionsRequest, + CreateSessionRequest, ExecuteSqlRequest, CommitRequest, BeginTransactionRequest, @@ -46,10 +44,7 @@ def test_create_table(self): """, ResultSet(), ) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() Base.metadata.create_all(engine) requests = self.database_admin_service.requests eq_(1, len(requests)) @@ -74,10 +69,7 @@ def test_insert_and_query(self): "VALUES (@a0, @a1, @a2, @a3)", 1, ) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() preferences = {"setting": "true"} preferences_base64 = "gAWVFQAAAAAAAAB9lIwHc2V0dGluZ5SMBHRydWWUcy4=" with Session(engine) as session: @@ -94,7 +86,7 @@ def test_insert_and_query(self): # Verify the requests that we got. requests = self.spanner_service.requests eq_(4, len(requests)) - is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[0], CreateSessionRequest) is_instance_of(requests[1], BeginTransactionRequest) is_instance_of(requests[2], ExecuteSqlRequest) is_instance_of(requests[3], CommitRequest) diff --git a/test/mockserver_tests/test_quickstart.py b/test/mockserver_tests/test_quickstart.py index c7db636e..d62f0359 100644 --- a/test/mockserver_tests/test_quickstart.py +++ b/test/mockserver_tests/test_quickstart.py @@ -16,7 +16,7 @@ from google.cloud.spanner_v1 import ( ResultSet, ResultSetStats, - BatchCreateSessionsRequest, + CreateSessionRequest, ExecuteBatchDmlRequest, CommitRequest, BeginTransactionRequest, @@ -116,7 +116,7 @@ def test_insert_data(self): requests = self.spanner_service.requests eq_(5, len(requests)) - is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[0], CreateSessionRequest) is_instance_of(requests[1], BeginTransactionRequest) is_instance_of(requests[2], ExecuteBatchDmlRequest) is_instance_of(requests[3], ExecuteBatchDmlRequest) diff --git a/test/mockserver_tests/test_read_only_transaction.py b/test/mockserver_tests/test_read_only_transaction.py index 013c0401..0dffbb88 100644 --- a/test/mockserver_tests/test_read_only_transaction.py +++ b/test/mockserver_tests/test_read_only_transaction.py @@ -12,12 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -from sqlalchemy import create_engine, select +from sqlalchemy import select from sqlalchemy.orm import Session from sqlalchemy.testing import eq_, is_instance_of from google.cloud.spanner_v1 import ( - FixedSizePool, - BatchCreateSessionsRequest, + CreateSessionRequest, ExecuteSqlRequest, BeginTransactionRequest, TransactionOptions, @@ -33,11 +32,7 @@ def test_read_only_transaction(self): from test.mockserver_tests.read_only_model import Singer add_singer_query_result("SELECT singers.id, singers.name \n" + "FROM singers") - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - echo=True, - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() for i in range(2): with Session(engine.execution_options(read_only=True)) as session: @@ -48,7 +43,7 @@ def test_read_only_transaction(self): # Verify the requests that we got. requests = self.spanner_service.requests eq_(7, len(requests)) - is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[0], CreateSessionRequest) is_instance_of(requests[1], BeginTransactionRequest) is_instance_of(requests[2], ExecuteSqlRequest) is_instance_of(requests[3], ExecuteSqlRequest) diff --git a/test/mockserver_tests/test_stale_reads.py b/test/mockserver_tests/test_stale_reads.py index d3ac91e8..0dcf8b38 100644 --- a/test/mockserver_tests/test_stale_reads.py +++ b/test/mockserver_tests/test_stale_reads.py @@ -13,12 +13,11 @@ # limitations under the License. import datetime -from sqlalchemy import create_engine, select +from sqlalchemy import select from sqlalchemy.orm import Session from sqlalchemy.testing import eq_, is_instance_of from google.cloud.spanner_v1 import ( - FixedSizePool, - BatchCreateSessionsRequest, + CreateSessionRequest, ExecuteSqlRequest, BeginTransactionRequest, TransactionOptions, @@ -34,11 +33,7 @@ def test_stale_read_multi_use(self): from test.mockserver_tests.stale_read_model import Singer add_singer_query_result("SELECT singers.id, singers.name \nFROM singers") - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - echo=True, - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() timestamp = datetime.datetime.fromtimestamp(1733328910) for i in range(2): @@ -55,7 +50,7 @@ def test_stale_read_multi_use(self): # Verify the requests that we got. requests = self.spanner_service.requests eq_(7, len(requests)) - is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[0], CreateSessionRequest) is_instance_of(requests[1], BeginTransactionRequest) is_instance_of(requests[2], ExecuteSqlRequest) is_instance_of(requests[3], ExecuteSqlRequest) @@ -83,11 +78,7 @@ def test_stale_read_single_use(self): from test.mockserver_tests.stale_read_model import Singer add_singer_query_result("SELECT singers.id, singers.name \nFROM singers") - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - echo=True, - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() with Session( engine.execution_options( @@ -102,7 +93,7 @@ def test_stale_read_single_use(self): # Verify the requests that we got. requests = self.spanner_service.requests eq_(3, len(requests)) - is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[0], CreateSessionRequest) is_instance_of(requests[1], ExecuteSqlRequest) is_instance_of(requests[2], ExecuteSqlRequest) # Verify that the requests use a stale read. diff --git a/test/mockserver_tests/test_tags.py b/test/mockserver_tests/test_tags.py index 8c157154..0a4d6337 100644 --- a/test/mockserver_tests/test_tags.py +++ b/test/mockserver_tests/test_tags.py @@ -12,12 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -from sqlalchemy import create_engine, select +from sqlalchemy import select from sqlalchemy.orm import Session from sqlalchemy.testing import eq_, is_instance_of from google.cloud.spanner_v1 import ( - FixedSizePool, - BatchCreateSessionsRequest, + CreateSessionRequest, ExecuteSqlRequest, BeginTransactionRequest, CommitRequest, @@ -36,10 +35,7 @@ def test_request_tag(self): from test.mockserver_tests.tags_model import Singer add_singer_query_result("SELECT singers.id, singers.name \n" + "FROM singers") - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() with Session(engine.execution_options(read_only=True)) as session: # Execute two queries in a read-only transaction. @@ -53,7 +49,7 @@ def test_request_tag(self): # Verify the requests that we got. requests = self.spanner_service.requests eq_(4, len(requests)) - is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[0], CreateSessionRequest) is_instance_of(requests[1], BeginTransactionRequest) is_instance_of(requests[2], ExecuteSqlRequest) is_instance_of(requests[3], ExecuteSqlRequest) @@ -71,10 +67,7 @@ def test_transaction_tag(self): "WHERE singers.id = @a0" ) add_update_count("INSERT INTO singers (id, name) VALUES (@a0, @a1)", 1) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() with Session( engine.execution_options(transaction_tag="my-transaction-tag") @@ -91,7 +84,7 @@ def test_transaction_tag(self): # Verify the requests that we got. requests = self.spanner_service.requests eq_(6, len(requests)) - is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[0], CreateSessionRequest) is_instance_of(requests[1], BeginTransactionRequest) is_instance_of(requests[2], ExecuteSqlRequest) is_instance_of(requests[3], ExecuteSqlRequest) diff --git a/test/test_suite_20.py b/test/test_suite_20.py index 3cb252d2..27143de9 100644 --- a/test/test_suite_20.py +++ b/test/test_suite_20.py @@ -256,6 +256,11 @@ def test_binary_reflection(self, connection, metadata): assert isinstance(typ, LargeBinary) eq_(typ.length, 20) + @testing.requires.table_reflection + def test_string_length_reflection(self, connection, metadata): + typ = self._type_round_trip(connection, metadata, types.String(52))[0] + assert isinstance(typ, types.String) + class ComputedReflectionFixtureTest(_ComputedReflectionFixtureTest): @classmethod @@ -2576,6 +2581,12 @@ class BizarroCharacterFKResolutionTest(fixtures.TestBase): pass +class BizarroCharacterTest(fixtures.TestBase): + @pytest.mark.skip("Bizarre characters in foreign key names are not supported") + def test_fk_ref(self, testing_engine): + pass + + class IsolationLevelTest(fixtures.TestBase): @pytest.mark.skip("Cloud Spanner does not support different isolation levels") def test_dialect_user_setting_is_restored(self, testing_engine):