From c3532fb6d1310fc5667b07edbaee344610d57bee Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Mon, 12 Jan 2026 17:06:47 -0800 Subject: [PATCH 1/9] chore(tests): re-enable pipeline system tests on kokoro --- tests/system/test__helpers.py | 2 -- tests/system/test_system.py | 11 ----------- tests/system/test_system_async.py | 11 ----------- 3 files changed, 24 deletions(-) diff --git a/tests/system/test__helpers.py b/tests/system/test__helpers.py index 74b12b7c3..434e1c875 100644 --- a/tests/system/test__helpers.py +++ b/tests/system/test__helpers.py @@ -20,5 +20,3 @@ # run all tests against default database, and a named database TEST_DATABASES = [None, FIRESTORE_OTHER_DB] TEST_DATABASES_W_ENTERPRISE = TEST_DATABASES + [FIRESTORE_ENTERPRISE_DB] -# TODO remove when kokoro fully supports enterprise mode/pipelines -IS_KOKORO_TEST = os.getenv("KOKORO_JOB_NAME") is not None diff --git a/tests/system/test_system.py b/tests/system/test_system.py index 615ff1226..28a36808c 100644 --- a/tests/system/test_system.py +++ b/tests/system/test_system.py @@ -46,7 +46,6 @@ ENTERPRISE_MODE_ERROR, TEST_DATABASES, TEST_DATABASES_W_ENTERPRISE, - IS_KOKORO_TEST, FIRESTORE_ENTERPRISE_DB, ) @@ -69,10 +68,6 @@ def _get_credentials_and_project(): def database(request): from test__helpers import FIRESTORE_ENTERPRISE_DB - # enterprise mode currently does not support RunQuery calls in prod on kokoro test project - # TODO: remove skip when kokoro test project supports full enterprise mode - if request.param == FIRESTORE_ENTERPRISE_DB and IS_KOKORO_TEST: - pytest.skip("enterprise mode does not support RunQuery on kokoro") return request.param @@ -101,11 +96,6 @@ def verify_pipeline(query): """ from google.cloud.firestore_v1.base_aggregation import BaseAggregationQuery - # return early on kokoro. Test project doesn't currently support pipelines - # TODO: enable pipeline verification when kokoro test project is whitelisted - if IS_KOKORO_TEST: - pytest.skip("skipping pipeline verification on kokoro") - def _clean_results(results): if isinstance(results, dict): return {k: _clean_results(v) for k, v in results.items()} @@ -1825,7 +1815,6 @@ def test_query_stream_w_read_time(query_docs, cleanup, database): assert new_values[new_ref.id] == new_data -@pytest.mark.skipif(IS_KOKORO_TEST, reason="skipping pipeline verification on kokoro") @pytest.mark.parametrize("database", [FIRESTORE_ENTERPRISE_DB], indirect=True) def test_pipeline_w_read_time(query_docs, cleanup, database): collection, stored, allowed_vals = query_docs diff --git a/tests/system/test_system_async.py b/tests/system/test_system_async.py index 373c40118..5b046a615 100644 --- a/tests/system/test_system_async.py +++ b/tests/system/test_system_async.py @@ -57,7 +57,6 @@ ENTERPRISE_MODE_ERROR, TEST_DATABASES, TEST_DATABASES_W_ENTERPRISE, - IS_KOKORO_TEST, FIRESTORE_ENTERPRISE_DB, ) @@ -147,10 +146,6 @@ def _verify_explain_metrics_analyze_false(explain_metrics): def database(request): from test__helpers import FIRESTORE_ENTERPRISE_DB - # enterprise mode currently does not support RunQuery calls in prod on kokoro test project - # TODO: remove skip when kokoro test project supports full enterprise mode - if request.param == FIRESTORE_ENTERPRISE_DB and IS_KOKORO_TEST: - pytest.skip("enterprise mode does not support RunQuery on kokoro") return request.param @@ -181,11 +176,6 @@ async def verify_pipeline(query): """ from google.cloud.firestore_v1.base_aggregation import BaseAggregationQuery - # return early on kokoro. Test project doesn't currently support pipelines - # TODO: enable pipeline verification when kokoro test project is whitelisted - if IS_KOKORO_TEST: - pytest.skip("skipping pipeline verification on kokoro") - def _clean_results(results): if isinstance(results, dict): return {k: _clean_results(v) for k, v in results.items()} @@ -1694,7 +1684,6 @@ async def test_pipeline_explain_options_using_additional_options( assert "Execution:" in text_stats -@pytest.mark.skipif(IS_KOKORO_TEST, reason="skipping pipeline verification on kokoro") @pytest.mark.parametrize("database", [FIRESTORE_ENTERPRISE_DB], indirect=True) async def test_pipeline_w_read_time(query_docs, cleanup, database): collection, stored, allowed_vals = query_docs From fcab87d612c4eaba60a97c0d0c7bb00c7ac7b7a9 Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Mon, 12 Jan 2026 17:09:59 -0800 Subject: [PATCH 2/9] re-enable tests in pipeline_acceptance --- tests/system/test_pipeline_acceptance.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/tests/system/test_pipeline_acceptance.py b/tests/system/test_pipeline_acceptance.py index 02a27ca86..4634037ab 100644 --- a/tests/system/test_pipeline_acceptance.py +++ b/tests/system/test_pipeline_acceptance.py @@ -33,16 +33,10 @@ from google.cloud.firestore import Client, AsyncClient -from test__helpers import FIRESTORE_ENTERPRISE_DB, IS_KOKORO_TEST +from test__helpers import FIRESTORE_ENTERPRISE_DB FIRESTORE_PROJECT = os.environ.get("GCLOUD_PROJECT") -# TODO: enable kokoro tests when internal test project is whitelisted -pytestmark = pytest.mark.skipif( - condition=IS_KOKORO_TEST, - reason="Pipeline tests are currently not supported by kokoro", -) - test_dir_name = os.path.dirname(__file__) id_format = ( From 254f555b7d78cb6ff889773bfb39154715d6033f Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Mon, 12 Jan 2026 17:18:40 -0800 Subject: [PATCH 3/9] updated db name --- tests/system/test__helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/test__helpers.py b/tests/system/test__helpers.py index 434e1c875..8032ae119 100644 --- a/tests/system/test__helpers.py +++ b/tests/system/test__helpers.py @@ -15,7 +15,7 @@ EMULATOR_CREDS = EmulatorCreds() FIRESTORE_EMULATOR = os.environ.get(_FIRESTORE_EMULATOR_HOST) is not None FIRESTORE_OTHER_DB = os.environ.get("SYSTEM_TESTS_DATABASE", "system-tests-named-db") -FIRESTORE_ENTERPRISE_DB = os.environ.get("ENTERPRISE_DATABASE", "enterprise-db") +FIRESTORE_ENTERPRISE_DB = os.environ.get("ENTERPRISE_DATABASE", "enterprise-db-native") # run all tests against default database, and a named database TEST_DATABASES = [None, FIRESTORE_OTHER_DB] From 49e7ee90f01ac4ee0faf2dcb078a8fca56a8fe49 Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Mon, 12 Jan 2026 18:11:05 -0800 Subject: [PATCH 4/9] fixed lint --- tests/system/test_system.py | 2 -- tests/system/test_system_async.py | 2 -- 2 files changed, 4 deletions(-) diff --git a/tests/system/test_system.py b/tests/system/test_system.py index 28a36808c..ebf62b6b5 100644 --- a/tests/system/test_system.py +++ b/tests/system/test_system.py @@ -66,8 +66,6 @@ def _get_credentials_and_project(): @pytest.fixture(scope="session") def database(request): - from test__helpers import FIRESTORE_ENTERPRISE_DB - return request.param diff --git a/tests/system/test_system_async.py b/tests/system/test_system_async.py index 5b046a615..1aaa79591 100644 --- a/tests/system/test_system_async.py +++ b/tests/system/test_system_async.py @@ -144,8 +144,6 @@ def _verify_explain_metrics_analyze_false(explain_metrics): @pytest.fixture(scope="session") def database(request): - from test__helpers import FIRESTORE_ENTERPRISE_DB - return request.param From 15d8595156ccbaeb83bd90c225ce15839de0def7 Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Mon, 12 Jan 2026 18:17:26 -0800 Subject: [PATCH 5/9] re-trigger CI From 29f57ef03c8f2c0ea6a1a294215c4f34425a4281 Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Mon, 12 Jan 2026 18:59:52 -0800 Subject: [PATCH 6/9] removed index_mode --- google/cloud/firestore_v1/async_pipeline.py | 10 ++-------- google/cloud/firestore_v1/pipeline.py | 10 ++-------- tests/system/test_system.py | 16 ---------------- 3 files changed, 4 insertions(+), 32 deletions(-) diff --git a/google/cloud/firestore_v1/async_pipeline.py b/google/cloud/firestore_v1/async_pipeline.py index 6b017d88e..5e3748b0f 100644 --- a/google/cloud/firestore_v1/async_pipeline.py +++ b/google/cloud/firestore_v1/async_pipeline.py @@ -68,7 +68,6 @@ async def execute( transaction: "AsyncTransaction" | None = None, read_time: datetime.datetime | None = None, explain_options: PipelineExplainOptions | None = None, - index_mode: str | None = None, additional_options: dict[str, Value | Constant] = {}, ) -> PipelineSnapshot[PipelineResult]: """ @@ -87,10 +86,8 @@ async def execute( explain_options (Optional[:class:`~google.cloud.firestore_v1.query_profile.PipelineExplainOptions`]): Options to enable query profiling for this query. When set, explain_metrics will be available on the returned list. - index_mode (Optional[str]): Configures the pipeline to require a certain type of indexes to be present. - Firestore will reject the request if there is not appropiate indexes to serve the query. additional_options (Optional[dict[str, Value | Constant]]): Additional options to pass to the query. - These options will take precedence over method argument if there is a conflict (e.g. explain_options, index_mode) + These options will take precedence over method argument if there is a conflict (e.g. explain_options) """ kwargs = {k: v for k, v in locals().items() if k != "self"} stream = AsyncPipelineStream(PipelineResult, self, **kwargs) @@ -103,7 +100,6 @@ def stream( read_time: datetime.datetime | None = None, transaction: "AsyncTransaction" | None = None, explain_options: PipelineExplainOptions | None = None, - index_mode: str | None = None, additional_options: dict[str, Value | Constant] = {}, ) -> AsyncPipelineStream[PipelineResult]: """ @@ -122,10 +118,8 @@ def stream( explain_options (Optional[:class:`~google.cloud.firestore_v1.query_profile.PipelineExplainOptions`]): Options to enable query profiling for this query. When set, explain_metrics will be available on the returned generator. - index_mode (Optional[str]): Configures the pipeline to require a certain type of indexes to be present. - Firestore will reject the request if there is not appropiate indexes to serve the query. additional_options (Optional[dict[str, Value | Constant]]): Additional options to pass to the query. - These options will take precedence over method argument if there is a conflict (e.g. explain_options, index_mode) + These options will take precedence over method argument if there is a conflict (e.g. explain_options) """ kwargs = {k: v for k, v in locals().items() if k != "self"} return AsyncPipelineStream(PipelineResult, self, **kwargs) diff --git a/google/cloud/firestore_v1/pipeline.py b/google/cloud/firestore_v1/pipeline.py index 950eb6ffa..0c922ba78 100644 --- a/google/cloud/firestore_v1/pipeline.py +++ b/google/cloud/firestore_v1/pipeline.py @@ -65,7 +65,6 @@ def execute( transaction: "Transaction" | None = None, read_time: datetime.datetime | None = None, explain_options: PipelineExplainOptions | None = None, - index_mode: str | None = None, additional_options: dict[str, Value | Constant] = {}, ) -> PipelineSnapshot[PipelineResult]: """ @@ -84,10 +83,8 @@ def execute( explain_options (Optional[:class:`~google.cloud.firestore_v1.query_profile.PipelineExplainOptions`]): Options to enable query profiling for this query. When set, explain_metrics will be available on the returned list. - index_mode (Optional[str]): Configures the pipeline to require a certain type of indexes to be present. - Firestore will reject the request if there is not appropiate indexes to serve the query. additional_options (Optional[dict[str, Value | Constant]]): Additional options to pass to the query. - These options will take precedence over method argument if there is a conflict (e.g. explain_options, index_mode) + These options will take precedence over method argument if there is a conflict (e.g. explain_options) """ kwargs = {k: v for k, v in locals().items() if k != "self"} stream = PipelineStream(PipelineResult, self, **kwargs) @@ -100,7 +97,6 @@ def stream( transaction: "Transaction" | None = None, read_time: datetime.datetime | None = None, explain_options: PipelineExplainOptions | None = None, - index_mode: str | None = None, additional_options: dict[str, Value | Constant] = {}, ) -> PipelineStream[PipelineResult]: """ @@ -119,10 +115,8 @@ def stream( explain_options (Optional[:class:`~google.cloud.firestore_v1.query_profile.PipelineExplainOptions`]): Options to enable query profiling for this query. When set, explain_metrics will be available on the returned generator. - index_mode (Optional[str]): Configures the pipeline to require a certain type of indexes to be present. - Firestore will reject the request if there is not appropiate indexes to serve the query. additional_options (Optional[dict[str, Value | Constant]]): Additional options to pass to the query. - These options will take precedence over method argument if there is a conflict (e.g. explain_options, index_mode) + These options will take precedence over method argument if there is a conflict (e.g. explain_options) """ kwargs = {k: v for k, v in locals().items() if k != "self"} return PipelineStream(PipelineResult, self, **kwargs) diff --git a/tests/system/test_system.py b/tests/system/test_system.py index ebf62b6b5..328b29098 100644 --- a/tests/system/test_system.py +++ b/tests/system/test_system.py @@ -1759,22 +1759,6 @@ def test_pipeline_explain_options_using_additional_options( assert "Execution:" in text_stats -@pytest.mark.skipif( - FIRESTORE_EMULATOR, reason="Query profile not supported in emulator." -) -@pytest.mark.parametrize("database", [FIRESTORE_ENTERPRISE_DB], indirect=True) -def test_pipeline_index_mode(database, query_docs): - """test pipeline query with explicit index mode""" - - collection, _, allowed_vals = query_docs - client = collection._client - query = collection.where(filter=FieldFilter("a", "==", 1)) - pipeline = client.pipeline().create_from(query) - with pytest.raises(InvalidArgument) as e: - pipeline.execute(index_mode="fake_index") - assert "Invalid index_mode: fake_index" in str(e) - - @pytest.mark.parametrize("database", TEST_DATABASES, indirect=True) def test_query_stream_w_read_time(query_docs, cleanup, database): collection, stored, allowed_vals = query_docs From a512cf7fde6f563cb729ada7676ff4617b07ddd1 Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Mon, 12 Jan 2026 19:22:47 -0800 Subject: [PATCH 7/9] fixed index mode in results --- google/cloud/firestore_v1/pipeline_result.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google/cloud/firestore_v1/pipeline_result.py b/google/cloud/firestore_v1/pipeline_result.py index 6be08fa57..30267cba6 100644 --- a/google/cloud/firestore_v1/pipeline_result.py +++ b/google/cloud/firestore_v1/pipeline_result.py @@ -178,8 +178,8 @@ def __init__( transaction: Transaction | AsyncTransaction | None, read_time: datetime.datetime | None, explain_options: PipelineExplainOptions | None, - index_mode: str | None, additional_options: dict[str, Constant | Value], + index_mode: str | None = None, ): # public self.transaction = transaction From 4bc4cbb0eabb6a549746e747824b8df6bc6ad9b6 Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Mon, 12 Jan 2026 20:51:46 -0800 Subject: [PATCH 8/9] fixed unit test --- tests/unit/v1/test_pipeline_result.py | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/tests/unit/v1/test_pipeline_result.py b/tests/unit/v1/test_pipeline_result.py index 579992741..decadeb6e 100644 --- a/tests/unit/v1/test_pipeline_result.py +++ b/tests/unit/v1/test_pipeline_result.py @@ -213,7 +213,6 @@ def test_ctor(self): expected_transaction = object() expected_read_time = 123 expected_explain_options = object() - expected_index_mode = "mode" expected_addtl_options = {} source = PipelineStream( expected_type, @@ -221,7 +220,6 @@ def test_ctor(self): expected_transaction, expected_read_time, expected_explain_options, - expected_index_mode, expected_addtl_options, ) instance = self._make_one(in_arr, source) @@ -229,7 +227,7 @@ def test_ctor(self): assert instance.pipeline == expected_pipeline assert instance._client == expected_pipeline._client assert instance._additonal_options == expected_addtl_options - assert instance._index_mode == expected_index_mode + assert instance._index_mode is None assert instance._explain_options == expected_explain_options assert instance._explain_stats is None assert instance._started is True @@ -281,7 +279,6 @@ def _mock_init_args(self): "transaction": None, "read_time": None, "explain_options": None, - "index_mode": None, "additional_options": {}, } @@ -312,7 +309,6 @@ def test_explain_stats(self): @pytest.mark.parametrize( "init_kwargs,expected_options", [ - ({"index_mode": "mode"}, {"index_mode": encode_value("mode")}), ( {"explain_options": PipelineExplainOptions()}, {"explain_options": encode_value({"mode": "analyze"})}, @@ -336,13 +332,6 @@ def test_explain_stats(self): }, {"explain_options": encode_value("override")}, ), - ( - { - "index_mode": "mode", - "additional_options": {"index_mode": Constant("new")}, - }, - {"index_mode": encode_value("new")}, - ), ], ) def test_build_request_options(self, init_kwargs, expected_options): From c03634847184d7e9b3555c97df032786bd2b75d8 Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Mon, 12 Jan 2026 21:41:07 -0800 Subject: [PATCH 9/9] removed index_mode --- google/cloud/firestore_v1/pipeline_result.py | 4 ---- tests/unit/v1/test_pipeline_result.py | 1 - 2 files changed, 5 deletions(-) diff --git a/google/cloud/firestore_v1/pipeline_result.py b/google/cloud/firestore_v1/pipeline_result.py index 30267cba6..923010815 100644 --- a/google/cloud/firestore_v1/pipeline_result.py +++ b/google/cloud/firestore_v1/pipeline_result.py @@ -179,7 +179,6 @@ def __init__( read_time: datetime.datetime | None, explain_options: PipelineExplainOptions | None, additional_options: dict[str, Constant | Value], - index_mode: str | None = None, ): # public self.transaction = transaction @@ -192,7 +191,6 @@ def __init__( self._explain_stats: ExplainStats | None = None self._explain_options: PipelineExplainOptions | None = explain_options self._return_type = return_type - self._index_mode = index_mode self._additonal_options = { k: v if isinstance(v, Value) else v._to_pb() for k, v in additional_options.items() @@ -226,8 +224,6 @@ def _build_request(self) -> ExecutePipelineRequest: options = {} if self._explain_options: options["explain_options"] = self._explain_options._to_value() - if self._index_mode: - options["index_mode"] = Value(string_value=self._index_mode) if self._additonal_options: options.update(self._additonal_options) request = ExecutePipelineRequest( diff --git a/tests/unit/v1/test_pipeline_result.py b/tests/unit/v1/test_pipeline_result.py index decadeb6e..eca622801 100644 --- a/tests/unit/v1/test_pipeline_result.py +++ b/tests/unit/v1/test_pipeline_result.py @@ -227,7 +227,6 @@ def test_ctor(self): assert instance.pipeline == expected_pipeline assert instance._client == expected_pipeline._client assert instance._additonal_options == expected_addtl_options - assert instance._index_mode is None assert instance._explain_options == expected_explain_options assert instance._explain_stats is None assert instance._started is True