Skip to content

CLI unit tests run the real gcloud: an ADC browser login on every run, and they unset the default project #7880

Closed

Description

@adityasingh2400

🔴 Required Information

Describe the Bug:
On a machine with the gcloud CLI installed, running the unit tests under tests/unittests/cli runs real gcloud commands:

  1. test_handle_login_with_google_option_3 opens a browser for gcloud auth application-default login on every run. Signing in doesn't help, and the run blocks until the sign-in finishes or times out.
  2. test_handle_login_with_google_option_2 reads the real default project. If one is set, the test unsets it with gcloud config unset project, because click.confirm is mocked to always answer yes.

Both tests are in tests/unittests/cli/utils/test_cli_create.py, and both reach code they don't mock:

  • The autouse mock_gcp_metadata_off fixture in tests/unittests/conftest.py hides Application Default Credentials, by setting _cloud_sdk.get_application_default_credentials_path to ''. So gcp_utils.check_adc() is always False inside the suite. option_3 is the only handle_login_with_google test that doesn't mock check_adc, so it always calls gcp_utils.login_adc(), which runs gcloud auth application-default login. On CI, where gcloud isn't installed, that raises RuntimeError, which becomes click.Abort. So the test passes there without ever reaching the "3. Abandon" choice it is meant to cover.
  • option_2 doesn't mock _onboarding.get_gcp_project_from_gcloud, unlike test_handle_login_with_google_option_2_unset_project. After the mocked Express sign-up it runs gcloud config get-value project, compares the result with the new project, and then runs gcloud config unset project.

Steps to Reproduce:

  1. Install the gcloud CLI and set a default project (gcloud config set project my-project).
  2. Run pytest tests/unittests/cli/utils/test_cli_create.py.
  3. Check gcloud config get-value project, and gcloud's own logs in ~/.config/gcloud/logs/.

Expected Behavior:
Unit tests don't run the gcloud CLI, open a browser, or change the developer's gcloud configuration.

Observed Behavior:
gcloud's log from one test run (project id redacted):

17.42.27 Running [gcloud.config.get-value] with arguments: [SECTION/PROPERTY: "project"]   -> <my-project>
17.42.27 Running [gcloud.config.unset] with arguments: [SECTION/PROPERTY: "project"]       -> Unset property [core/project].
17.42.37 Running [gcloud.auth.application-default.login] with arguments: []

Every later run opened the sign-in again (17.45.29, 17.52.41 and 17.56.32 in the same log). Each run also spends about 9 seconds in the two tests waiting on gcloud.

Environment Details:

  • ADK Library Version (pip show google-adk): 2.13.0 (also on main at e9e8f61)
  • Desktop OS: macOS
  • Python Version (python -V): 3.11.16

Model Information:

  • Are you using LiteLLM: No
  • Which model is being used: not applicable (unit tests)

🟡 Optional Information

Minimal Reproduction Code:

To see which tests reach gcloud without touching the real one, put a fake gcloud first on PATH that logs $PYTEST_CURRENT_TEST and exits 1:

test=[tests/unittests/cli/utils/test_cli_create.py::test_handle_login_with_google_option_2 (call)] args=[config get-value project]
test=[tests/unittests/cli/utils/test_cli_create.py::test_handle_login_with_google_option_3 (call)] args=[auth application-default login]

How often has this issue occurred?:

  • Always (100%), on any machine with gcloud installed

Activity

  1. added theissue type on Nov 2, 2026
  2. surajksharma07 commented on Nov 2, 2026

    @surajksharma07
    Collaborator

    @adityasingh2400 Reproduced it on 2.13.0 and current main with a subprocess spy: option_3 tries gcloud auth application-default login, and option_2 runs get-value project and then config unset project whenever gcloud returns a project.

    Mocking check_adc and get_gcp_project_from_gcloud like #7881 does stopped every gcloud call for me. The _no_real_gcloud guard flagged both tests before the mocks were added. Could you check whether moving that guard into tests/unittests/conftest.py works on your side? That way it would cover every CLI test file, not just test_cli_create.py.

    Until this is merged, deselecting those two tests or running with gcloud off PATH keeps your default project safe. Please give the full tests/unittests/cli run a good test before #7881 goes for review.

  3. adityasingh2400 commented on Nov 3, 2026

    @adityasingh2400
    ContributorAuthor

    Thanks for checking, @surajksharma07. Moving the guard into tests/unittests/conftest.py works, and it's pushed to #7881 (6d61ce0). It now covers every unit test file, not just test_cli_create.py.

    Two changes came out of that:

    • It also guards asyncio.create_subprocess_exec, which _dev_deploy uses to run gcloud, and it matches gcloud.cmd and full paths.
    • It uses its own MonkeyPatch instead of the monkeypatch fixture. Requested from a conftest autouse fixture, monkeypatch changed the teardown order of other modules' fixtures. In the full run, that broke 3 tests in telemetry/test_agent_engine.py and 6 in cli/utils/test_cli.py.

    With a logging fake gcloud first on PATH, the full tests/unittests/cli run gives 1629 passed, 5 skipped, 1 xfailed, and zero gcloud calls. Across all of tests/unittests, the guard adds no failures. The same 27 tests fail with and without it, all from my environment; the PR description lists them.

  4. added a commit that references this issue on Nov 4, 2026
    af458fa
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

tools[Component] This issue is related to tools

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions