From d4acf6f376699952a5aea40b835fe7d7ab8aca8a Mon Sep 17 00:00:00 2001 From: Anthonios Partheniou Date: Wed, 22 Apr 2026 10:29:34 -0400 Subject: [PATCH 1/6] tests(spanner): update prerelease_deps nox session to match system tests --- packages/google-cloud-spanner/noxfile.py | 93 +++++++++++++++++++----- 1 file changed, 75 insertions(+), 18 deletions(-) diff --git a/packages/google-cloud-spanner/noxfile.py b/packages/google-cloud-spanner/noxfile.py index e208b01edc45..a7c8a0d7b0d3 100644 --- a/packages/google-cloud-spanner/noxfile.py +++ b/packages/google-cloud-spanner/noxfile.py @@ -655,6 +655,12 @@ def prerelease_deps(session, protobuf_implementation, database_dialect): system_test_path = os.path.join("tests", "system.py") system_test_folder_path = os.path.join("tests", "system") + system_test_exists = os.path.exists(system_test_path) + system_test_folder_exists = os.path.exists(system_test_folder_path) + # Sanity check: only run tests if found. + if not system_test_exists and not system_test_folder_exists: + session.skip("System tests were not found") + if os.environ.get("SPANNER_EMULATOR_HOST"): # Run tests against the emulator run_system = True @@ -675,24 +681,75 @@ def prerelease_deps(session, protobuf_implementation, database_dialect): run_system = False if run_system: - # Run the tests (deduplicated logic) - test_path = ( - system_test_path - if os.path.exists(system_test_path) - else system_test_folder_path - ) - session.run( - "py.test", - "--verbose", - f"--junitxml=system_{session.python}_sponge_log.xml", - test_path, - *session.posargs, - env={ - "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, - "SPANNER_DATABASE_DIALECT": database_dialect, - "SKIP_BACKUP_TESTS": "true", - }, - ) + # Run py.test against the system tests. + if system_test_exists: + args = [ + "py.test", + "--quiet", + "-o", + "asyncio_mode=auto", + f"--junitxml=system_{session.python}_sponge_log.xml", + ] + if not session.posargs: + args.append(system_test_path) + args.extend(session.posargs) + + session.run( + *args, + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + "SPANNER_DATABASE_DIALECT": database_dialect, + "SKIP_BACKUP_TESTS": "true", + }, + ) + elif system_test_folder_exists: + # Run sync tests + sync_args = [ + "py.test", + "--quiet", + "-o", + "asyncio_mode=auto", + f"--junitxml=system_{session.python}_sync_sponge_log.xml", + ] + if not session.posargs: + sync_args.append(os.path.join("tests", "system")) + sync_args.append("--ignore=tests/system/_async") + else: + sync_args.extend(session.posargs) + + session.run( + *sync_args, + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + "SPANNER_DATABASE_DIALECT": database_dialect, + "SKIP_BACKUP_TESTS": "true", + }, + ) + + # Run async tests + async_args = [ + "py.test", + "--quiet", + "-o", + "asyncio_mode=auto", + f"--junitxml=system_{session.python}_async_sponge_log.xml", + ] + if not session.posargs: + async_args.append(os.path.join("tests", "system", "_async")) + else: + # If posargs are provided, only run if they match async tests + # or just skip if they were already run in sync. + # For simplicity, we only run async folder if no posargs. + return + + session.run( + *async_args, + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + "SPANNER_DATABASE_DIALECT": database_dialect, + "SKIP_BACKUP_TESTS": "true", + }, + ) @nox.session(python=ALL_PYTHON) From 766c6d37a8fead261036f381bf5454a4789daf0b Mon Sep 17 00:00:00 2001 From: Anthonios Partheniou Date: Thu, 23 Apr 2026 00:02:41 +0000 Subject: [PATCH 2/6] make test more robust --- .../tests/system/test_instance_api.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/google-cloud-spanner/tests/system/test_instance_api.py b/packages/google-cloud-spanner/tests/system/test_instance_api.py index 72921f62b065..e6b481d1d1a4 100644 --- a/packages/google-cloud-spanner/tests/system/test_instance_api.py +++ b/packages/google-cloud-spanner/tests/system/test_instance_api.py @@ -36,8 +36,14 @@ def test_list_instances( ): instances = list(spanner_client.list_instances()) + existing_names = {single_instance.name for single_instance in existing_instances} + shared_instance_name = shared_instance.name + for instance in instances: - assert instance in existing_instances or instance is shared_instance + # We compare by '.name' (the full resource path) rather than the object itself. + # Protobuf objects may fail equality (==) if one has extra metadata populated + # by the server (like 'edition' or 'backup_schedules') that the other lacks. + assert instance.name in existing_names or instance.name == shared_instance_name def test_reload_instance(spanner_client, shared_instance_id, shared_instance): From bf470339cd08e61d3271f24478672b139cca6a71 Mon Sep 17 00:00:00 2001 From: Anthonios Partheniou Date: Thu, 23 Apr 2026 01:06:30 +0000 Subject: [PATCH 3/6] make test more robust --- .../tests/system/test_instance_api.py | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/packages/google-cloud-spanner/tests/system/test_instance_api.py b/packages/google-cloud-spanner/tests/system/test_instance_api.py index e6b481d1d1a4..c875bce3eb29 100644 --- a/packages/google-cloud-spanner/tests/system/test_instance_api.py +++ b/packages/google-cloud-spanner/tests/system/test_instance_api.py @@ -34,16 +34,21 @@ def test_list_instances( existing_instances, shared_instance, ): + # Retrieve all instances currently visible in the project. instances = list(spanner_client.list_instances()) - existing_names = {single_instance.name for single_instance in existing_instances} - shared_instance_name = shared_instance.name - - for instance in instances: - # We compare by '.name' (the full resource path) rather than the object itself. - # Protobuf objects may fail equality (==) if one has extra metadata populated - # by the server (like 'edition' or 'backup_schedules') that the other lacks. - assert instance.name in existing_names or instance.name == shared_instance_name + # We use the instance name (the full resource path) rather than the object itself. + # Protobuf objects may fail equality (==) if one has extra metadata populated + # by the server (like 'edition' or 'backup_schedules') that the other lacks. + instance_names = {instance.name for instance in instances} + + # In a parallel CI environment, other tests may create instances + # (like 'multi-region-...') simultaneously. + # Only verify `shared_instance.name` is in the list of instances. + assert shared_instance.name in instance_names, ( + f"Expected instance {shared_instance.name} was not found in the " + f"list of project instances: {instance_names}" + ) def test_reload_instance(spanner_client, shared_instance_id, shared_instance): From 7c1cc6483eb3943215e98915dacd7e533511e48e Mon Sep 17 00:00:00 2001 From: Anthonios Partheniou Date: Wed, 22 Apr 2026 21:09:20 -0400 Subject: [PATCH 4/6] Update packages/google-cloud-spanner/noxfile.py Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- packages/google-cloud-spanner/noxfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/google-cloud-spanner/noxfile.py b/packages/google-cloud-spanner/noxfile.py index a7c8a0d7b0d3..3f527b4c995b 100644 --- a/packages/google-cloud-spanner/noxfile.py +++ b/packages/google-cloud-spanner/noxfile.py @@ -735,7 +735,7 @@ def prerelease_deps(session, protobuf_implementation, database_dialect): f"--junitxml=system_{session.python}_async_sponge_log.xml", ] if not session.posargs: - async_args.append(os.path.join("tests", "system", "_async")) + async_args.append(os.path.join(system_test_folder_path, "_async")) else: # If posargs are provided, only run if they match async tests # or just skip if they were already run in sync. From 59671087fbf18e47d32bf66b331a6a5c39180f89 Mon Sep 17 00:00:00 2001 From: Anthonios Partheniou Date: Wed, 22 Apr 2026 21:09:29 -0400 Subject: [PATCH 5/6] Update packages/google-cloud-spanner/noxfile.py Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- packages/google-cloud-spanner/noxfile.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/google-cloud-spanner/noxfile.py b/packages/google-cloud-spanner/noxfile.py index 3f527b4c995b..b1102ec0825d 100644 --- a/packages/google-cloud-spanner/noxfile.py +++ b/packages/google-cloud-spanner/noxfile.py @@ -712,8 +712,8 @@ def prerelease_deps(session, protobuf_implementation, database_dialect): f"--junitxml=system_{session.python}_sync_sponge_log.xml", ] if not session.posargs: - sync_args.append(os.path.join("tests", "system")) - sync_args.append("--ignore=tests/system/_async") + sync_args.append(system_test_folder_path) + sync_args.append(f"--ignore={os.path.join(system_test_folder_path, '_async')}") else: sync_args.extend(session.posargs) From 998136ebb093ac45e7b07c94de273953b164ab9b Mon Sep 17 00:00:00 2001 From: Anthonios Partheniou Date: Thu, 23 Apr 2026 01:11:05 +0000 Subject: [PATCH 6/6] lint --- packages/google-cloud-spanner/noxfile.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/google-cloud-spanner/noxfile.py b/packages/google-cloud-spanner/noxfile.py index b1102ec0825d..39c7c32036b4 100644 --- a/packages/google-cloud-spanner/noxfile.py +++ b/packages/google-cloud-spanner/noxfile.py @@ -713,7 +713,9 @@ def prerelease_deps(session, protobuf_implementation, database_dialect): ] if not session.posargs: sync_args.append(system_test_folder_path) - sync_args.append(f"--ignore={os.path.join(system_test_folder_path, '_async')}") + sync_args.append( + f"--ignore={os.path.join(system_test_folder_path, '_async')}" + ) else: sync_args.extend(session.posargs)