chore: import upstream snapshot with attribution
Continuous Integration / Pre-commit Linter (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.10) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.11) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.12) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.13) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.10) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.11) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.12) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.13) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.14) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.10) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.11) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.12) (push) Has been cancelled
Copybara PR Handler / close-imported-pr (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.13) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.14) (push) Has been cancelled
Continuous Integration / Pre-commit Linter (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.10) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.11) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.12) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.13) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.10) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.11) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.12) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.13) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.14) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.10) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.11) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.12) (push) Has been cancelled
Copybara PR Handler / close-imported-pr (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.13) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.14) (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,312 @@
|
||||
# Copyright 2026 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# 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.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import click
|
||||
from click.testing import CliRunner
|
||||
from google.adk.cli.cli_tools_click import _apply_feature_overrides
|
||||
from google.adk.cli.cli_tools_click import feature_options
|
||||
from google.adk.features._feature_registry import _FEATURE_OVERRIDES
|
||||
from google.adk.features._feature_registry import _WARNED_FEATURES
|
||||
from google.adk.features._feature_registry import FeatureName
|
||||
from google.adk.features._feature_registry import is_feature_enabled
|
||||
from google.adk.features._feature_registry import temporary_feature_override
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def reset_feature_overrides():
|
||||
"""Reset feature overrides and warnings before/after each test."""
|
||||
_FEATURE_OVERRIDES.clear()
|
||||
_WARNED_FEATURES.clear()
|
||||
yield
|
||||
_FEATURE_OVERRIDES.clear()
|
||||
_WARNED_FEATURES.clear()
|
||||
|
||||
|
||||
class TestApplyFeatureOverrides:
|
||||
"""Tests for _apply_feature_overrides helper function."""
|
||||
|
||||
def test_single_feature(self):
|
||||
"""Single feature name is applied correctly."""
|
||||
_apply_feature_overrides(enable_features=("JSON_SCHEMA_FOR_FUNC_DECL",))
|
||||
assert is_feature_enabled(FeatureName.JSON_SCHEMA_FOR_FUNC_DECL)
|
||||
|
||||
def test_comma_separated_features(self):
|
||||
"""Comma-separated feature names are applied correctly."""
|
||||
_apply_feature_overrides(
|
||||
enable_features=("JSON_SCHEMA_FOR_FUNC_DECL,PROGRESSIVE_SSE_STREAMING",)
|
||||
)
|
||||
assert is_feature_enabled(FeatureName.JSON_SCHEMA_FOR_FUNC_DECL)
|
||||
assert is_feature_enabled(FeatureName.PROGRESSIVE_SSE_STREAMING)
|
||||
|
||||
def test_multiple_flag_values(self):
|
||||
"""Multiple --enable_features flags are applied correctly."""
|
||||
_apply_feature_overrides(
|
||||
enable_features=(
|
||||
"JSON_SCHEMA_FOR_FUNC_DECL",
|
||||
"PROGRESSIVE_SSE_STREAMING",
|
||||
)
|
||||
)
|
||||
assert is_feature_enabled(FeatureName.JSON_SCHEMA_FOR_FUNC_DECL)
|
||||
assert is_feature_enabled(FeatureName.PROGRESSIVE_SSE_STREAMING)
|
||||
|
||||
def test_whitespace_handling(self):
|
||||
"""Whitespace around feature names is stripped."""
|
||||
_apply_feature_overrides(
|
||||
enable_features=(" JSON_SCHEMA_FOR_FUNC_DECL , COMPUTER_USE ",)
|
||||
)
|
||||
assert is_feature_enabled(FeatureName.JSON_SCHEMA_FOR_FUNC_DECL)
|
||||
assert is_feature_enabled(FeatureName.COMPUTER_USE)
|
||||
|
||||
def test_empty_string_ignored(self):
|
||||
"""Empty strings in the list are ignored."""
|
||||
_apply_feature_overrides(enable_features=("",))
|
||||
# No error should be raised
|
||||
|
||||
def test_unknown_feature_warns(self, capsys):
|
||||
"""Unknown feature names emit a warning."""
|
||||
_apply_feature_overrides(enable_features=("UNKNOWN_FEATURE_XYZ",))
|
||||
captured = capsys.readouterr()
|
||||
assert "WARNING" in captured.err
|
||||
assert "UNKNOWN_FEATURE_XYZ" in captured.err
|
||||
assert "Valid names are:" in captured.err
|
||||
|
||||
def test_single_disable_feature(self):
|
||||
"""Single feature name is disabled correctly."""
|
||||
# First enable a feature
|
||||
_apply_feature_overrides(enable_features=("JSON_SCHEMA_FOR_FUNC_DECL",))
|
||||
assert is_feature_enabled(FeatureName.JSON_SCHEMA_FOR_FUNC_DECL)
|
||||
|
||||
# Then disable it
|
||||
_apply_feature_overrides(disable_features=("JSON_SCHEMA_FOR_FUNC_DECL",))
|
||||
assert not is_feature_enabled(FeatureName.JSON_SCHEMA_FOR_FUNC_DECL)
|
||||
|
||||
def test_comma_separated_disable_features(self):
|
||||
"""Comma-separated feature names are disabled correctly."""
|
||||
# First enable features
|
||||
_apply_feature_overrides(
|
||||
enable_features=("JSON_SCHEMA_FOR_FUNC_DECL,PROGRESSIVE_SSE_STREAMING",)
|
||||
)
|
||||
|
||||
# Then disable them
|
||||
_apply_feature_overrides(
|
||||
disable_features=(
|
||||
"JSON_SCHEMA_FOR_FUNC_DECL,PROGRESSIVE_SSE_STREAMING",
|
||||
)
|
||||
)
|
||||
assert not is_feature_enabled(FeatureName.JSON_SCHEMA_FOR_FUNC_DECL)
|
||||
assert not is_feature_enabled(FeatureName.PROGRESSIVE_SSE_STREAMING)
|
||||
|
||||
def test_disable_overrides_enable(self):
|
||||
"""Disable is applied after enable, so disable wins for same feature."""
|
||||
_apply_feature_overrides(
|
||||
enable_features=("JSON_SCHEMA_FOR_FUNC_DECL",),
|
||||
disable_features=("JSON_SCHEMA_FOR_FUNC_DECL",),
|
||||
)
|
||||
# disable_features is processed after enable_features
|
||||
assert not is_feature_enabled(FeatureName.JSON_SCHEMA_FOR_FUNC_DECL)
|
||||
|
||||
def test_enable_and_disable_different_features(self):
|
||||
"""Enable and disable can be used together for different features."""
|
||||
# First enable a feature that we'll disable
|
||||
_apply_feature_overrides(enable_features=("PROGRESSIVE_SSE_STREAMING",))
|
||||
|
||||
_apply_feature_overrides(
|
||||
enable_features=("JSON_SCHEMA_FOR_FUNC_DECL",),
|
||||
disable_features=("PROGRESSIVE_SSE_STREAMING",),
|
||||
)
|
||||
assert is_feature_enabled(FeatureName.JSON_SCHEMA_FOR_FUNC_DECL)
|
||||
assert not is_feature_enabled(FeatureName.PROGRESSIVE_SSE_STREAMING)
|
||||
|
||||
|
||||
class TestFeatureOptionsDecorator:
|
||||
"""Tests for feature_options decorator."""
|
||||
|
||||
def test_decorator_adds_enable_features_option(self):
|
||||
"""Decorator adds --enable_features option to command."""
|
||||
|
||||
@click.command()
|
||||
@feature_options()
|
||||
def test_cmd():
|
||||
pass
|
||||
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(test_cmd, ["--help"])
|
||||
assert "--enable_features" in result.output
|
||||
|
||||
def test_enable_features_applied_before_command(self):
|
||||
"""Features are enabled before the command function runs."""
|
||||
feature_was_enabled = []
|
||||
|
||||
@click.command()
|
||||
@feature_options()
|
||||
def test_cmd():
|
||||
feature_was_enabled.append(
|
||||
is_feature_enabled(FeatureName.JSON_SCHEMA_FOR_FUNC_DECL)
|
||||
)
|
||||
|
||||
runner = CliRunner()
|
||||
runner.invoke(
|
||||
test_cmd,
|
||||
["--enable_features=JSON_SCHEMA_FOR_FUNC_DECL"],
|
||||
catch_exceptions=False,
|
||||
)
|
||||
assert feature_was_enabled == [True]
|
||||
|
||||
def test_multiple_enable_features_flags(self):
|
||||
"""Multiple --enable_features flags work correctly."""
|
||||
enabled_features = []
|
||||
|
||||
@click.command()
|
||||
@feature_options()
|
||||
def test_cmd():
|
||||
enabled_features.append(
|
||||
is_feature_enabled(FeatureName.JSON_SCHEMA_FOR_FUNC_DECL)
|
||||
)
|
||||
enabled_features.append(
|
||||
is_feature_enabled(FeatureName.PROGRESSIVE_SSE_STREAMING)
|
||||
)
|
||||
|
||||
runner = CliRunner()
|
||||
runner.invoke(
|
||||
test_cmd,
|
||||
[
|
||||
"--enable_features=JSON_SCHEMA_FOR_FUNC_DECL",
|
||||
"--enable_features=PROGRESSIVE_SSE_STREAMING",
|
||||
],
|
||||
catch_exceptions=False,
|
||||
)
|
||||
assert enabled_features == [True, True]
|
||||
|
||||
def test_comma_separated_enable_features(self):
|
||||
"""Comma-separated feature names work correctly."""
|
||||
enabled_features = []
|
||||
|
||||
@click.command()
|
||||
@feature_options()
|
||||
def test_cmd():
|
||||
enabled_features.append(
|
||||
is_feature_enabled(FeatureName.JSON_SCHEMA_FOR_FUNC_DECL)
|
||||
)
|
||||
enabled_features.append(
|
||||
is_feature_enabled(FeatureName.PROGRESSIVE_SSE_STREAMING)
|
||||
)
|
||||
|
||||
runner = CliRunner()
|
||||
runner.invoke(
|
||||
test_cmd,
|
||||
[
|
||||
"--enable_features=JSON_SCHEMA_FOR_FUNC_DECL,PROGRESSIVE_SSE_STREAMING"
|
||||
],
|
||||
catch_exceptions=False,
|
||||
)
|
||||
assert enabled_features == [True, True]
|
||||
|
||||
def test_no_enable_features_flag(self):
|
||||
"""Command works without --enable_features flag."""
|
||||
enabled_features = []
|
||||
|
||||
with temporary_feature_override(
|
||||
FeatureName.JSON_SCHEMA_FOR_FUNC_DECL, False
|
||||
):
|
||||
|
||||
@click.command()
|
||||
@feature_options()
|
||||
def test_cmd():
|
||||
enabled_features.append(
|
||||
is_feature_enabled(FeatureName.JSON_SCHEMA_FOR_FUNC_DECL)
|
||||
)
|
||||
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(test_cmd, [], catch_exceptions=False)
|
||||
assert result.exit_code == 0
|
||||
assert enabled_features == [False]
|
||||
|
||||
def test_preserves_function_metadata(self):
|
||||
"""Decorator preserves the wrapped function's metadata."""
|
||||
|
||||
@click.command()
|
||||
@feature_options()
|
||||
def my_test_command():
|
||||
"""My docstring."""
|
||||
pass
|
||||
|
||||
# The callback should have preserved metadata
|
||||
assert (
|
||||
"my_test_command" in my_test_command.name
|
||||
or my_test_command.callback.__name__ == "my_test_command"
|
||||
)
|
||||
|
||||
def test_decorator_adds_disable_features_option(self):
|
||||
"""Decorator adds --disable_features option to command."""
|
||||
|
||||
@click.command()
|
||||
@feature_options()
|
||||
def test_cmd():
|
||||
pass
|
||||
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(test_cmd, ["--help"])
|
||||
assert "--disable_features" in result.output
|
||||
|
||||
def test_disable_features_applied_before_command(self):
|
||||
"""Features are disabled before the command function runs."""
|
||||
# First enable the feature via override
|
||||
_apply_feature_overrides(enable_features=("JSON_SCHEMA_FOR_FUNC_DECL",))
|
||||
|
||||
feature_was_disabled = []
|
||||
|
||||
@click.command()
|
||||
@feature_options()
|
||||
def test_cmd():
|
||||
feature_was_disabled.append(
|
||||
not is_feature_enabled(FeatureName.JSON_SCHEMA_FOR_FUNC_DECL)
|
||||
)
|
||||
|
||||
runner = CliRunner()
|
||||
runner.invoke(
|
||||
test_cmd,
|
||||
["--disable_features=JSON_SCHEMA_FOR_FUNC_DECL"],
|
||||
catch_exceptions=False,
|
||||
)
|
||||
assert feature_was_disabled == [True]
|
||||
|
||||
def test_enable_and_disable_together(self):
|
||||
"""Both --enable_features and --disable_features work together."""
|
||||
feature_states = []
|
||||
|
||||
@click.command()
|
||||
@feature_options()
|
||||
def test_cmd():
|
||||
feature_states.append(
|
||||
is_feature_enabled(FeatureName.JSON_SCHEMA_FOR_FUNC_DECL)
|
||||
)
|
||||
feature_states.append(
|
||||
is_feature_enabled(FeatureName.PROGRESSIVE_SSE_STREAMING)
|
||||
)
|
||||
|
||||
runner = CliRunner()
|
||||
runner.invoke(
|
||||
test_cmd,
|
||||
[
|
||||
"--enable_features=JSON_SCHEMA_FOR_FUNC_DECL",
|
||||
"--disable_features=PROGRESSIVE_SSE_STREAMING",
|
||||
],
|
||||
catch_exceptions=False,
|
||||
)
|
||||
# JSON_SCHEMA_FOR_FUNC_DECL should be enabled
|
||||
# PROGRESSIVE_SSE_STREAMING should be disabled
|
||||
assert feature_states == [True, False]
|
||||
Reference in New Issue
Block a user