Files
cleveragents-core/features/steps/fallback_gemini_provider_steps.py
HAL9000 6eb9c41407
CI / build (pull_request) Successful in 44s
CI / helm (pull_request) Successful in 53s
CI / lint (pull_request) Successful in 59s
CI / quality (pull_request) Successful in 1m0s
CI / push-validation (pull_request) Successful in 44s
CI / typecheck (pull_request) Successful in 1m9s
CI / security (pull_request) Successful in 1m10s
CI / unit_tests (pull_request) Successful in 5m47s
CI / docker (pull_request) Successful in 1m34s
CI / integration_tests (pull_request) Successful in 8m33s
CI / coverage (pull_request) Successful in 9m9s
CI / status-check (pull_request) Successful in 4s
fix(providers): resolve gemini fallback test/lint failures
Address reviewer blocking issues on PR #11003:

1. Remove unused `import os` and inner `MagicMock` re-import from the
   gemini fallback step definitions (ruff F401).
2. Remove `@tdd_expected_fail` from the TDD feature now that the
   registry fix makes the scenario pass; keep `@tdd_issue` /
   `@tdd_issue_4750` as permanent regression markers.
3. Rewrite three feature step texts to use the env-var step defs that
   already exist in `provider_registry_steps.py` instead of duplicating
   them (drops the `env var` phrasing the original feature used and that
   had no matching step def).
4. Add `"gemini"` to `FallbackSelector.DEFAULT_FALLBACK_ORDER` after
   `"google"` so the actor-configured fallback chain mirrors the
   registry-level fix.
5. Rename three of the new feature/step pairs to avoid ambiguous-step
   collisions that crashed every behave-parallel worker at module-load
   time (the root cause of the "8 features errored, 0 scenarios"
   pattern):
   - `the result should be ProviderType "GEMINI"` collided with
     `cli_steps.py:138`'s `@then("the result should be {expected}")`;
     renamed to `the gemini fallback default should be
     ProviderType "GEMINI"`.
   - `the result should be None` had the same collision; renamed to
     `the clean gemini registry default should be None`.
   - `@given("I have the ProviderRegistry class")` was duplicated in
     `provider_registry_steps.py:186`; the duplicate is removed and the
     existing definition is reused.

ISSUES CLOSED: #10906
2026-06-14 23:37:20 -04:00

150 lines
4.9 KiB
Python

"""Step definitions for fallback_gemini_provider.feature.
Verifies that ProviderType.GEMINI is present in
ProviderRegistry.FALLBACK_ORDER and selected as the default provider when
only the Gemini API key is configured.
"""
from __future__ import annotations
from typing import Any
from behave import given, then, when # type: ignore[import-untyped]
from cleveragents.providers.registry import (
ProviderRegistry,
ProviderType,
)
# ---------------------------------------------------------------------------
# Helper
# ---------------------------------------------------------------------------
def _make_gemini_settings(
openai: str | None = None,
anthropic: str | None = None,
google: str | None = None,
gemini: str | None = None,
azure: str | None = None,
openrouter: str | None = None,
cohere: str | None = None,
groq: str | None = None,
together: str | None = None,
default_provider: str | None = None,
) -> object:
"""Return a minimal Settings-like mock for BDD steps."""
from unittest.mock import MagicMock
settings = MagicMock()
settings.openai_api_key = openai
settings.anthropic_api_key = anthropic
settings.google_api_key = google
settings.gemini_api_key = gemini
settings.azure_api_key = azure
settings.openrouter_api_key = openrouter
settings.cohere_api_key = cohere
settings.groq_api_key = groq
settings.together_api_key = together
settings.default_provider = default_provider
settings.default_model = None
return settings
# ---------------------------------------------------------------------------
# Given
# ---------------------------------------------------------------------------
@given('a registry with only gemini API key set to "{key}"')
def step_gemini_only_registry(context: Any, key: str) -> None:
settings = _make_gemini_settings(gemini=key)
context.gemini_registry = ProviderRegistry(settings=settings)
@given("a gemini-registry with no API keys configured")
def step_no_keys_gemini_registry(context: Any) -> None:
context.gemini_registry = ProviderRegistry(settings=_make_gemini_settings())
# ---------------------------------------------------------------------------
# When
# ---------------------------------------------------------------------------
@when("I check the FALLBACK_ORDER contents")
def step_check_fallback_order(context: Any) -> None:
"""Read the FALLBACK_ORDER class variable."""
context.fallback_order = list(ProviderRegistry.FALLBACK_ORDER)
@when("I request the default provider type")
def step_request_default_provider_type(context: Any) -> None:
result = context.gemini_registry.get_default_provider_type()
context.gemini_default = result
@when("I iterate through FALLBACK_ORDER and find the first configured provider")
def step_iterate_fallback_order(context: Any) -> None:
"""Manually walk FALLBACK_ORDER to verify GEMINI is checked."""
found = None
for pt in ProviderRegistry.FALLBACK_ORDER:
if context.gemini_registry.is_provider_configured(pt):
found = pt
break
context.fallback_iteration_result = found
@when("I request the default provider type from a clean registry")
def step_request_default_from_clean(context: Any) -> None:
result = context.gemini_registry.get_default_provider_type()
context.clean_default = result
# ---------------------------------------------------------------------------
# Then
# ---------------------------------------------------------------------------
@then("GEMINI should be present in the fallback order")
def step_gemini_in_fallback_order(context: Any) -> None:
assert ProviderType.GEMINI in context.fallback_order, (
f"Expected GEMINI in FALLBACK_ORDER={context.fallback_order}"
)
@then("OPENAI should still be first in the order")
def step_openai_first(context: Any) -> None:
assert context.fallback_order[0] == ProviderType.OPENAI, (
f"Expected OPENAI first, got {context.fallback_order[0]}"
)
@then("ANTHROPIC should still be second in the order")
def step_anthropic_second(context: Any) -> None:
assert context.fallback_order[1] == ProviderType.ANTHROPIC, (
f"Expected ANTHROPIC second, got {context.fallback_order[1]}"
)
@then('the gemini fallback default should be ProviderType "GEMINI"')
def step_result_is_gemini(context: Any) -> None:
assert context.gemini_default == ProviderType.GEMINI, (
f"Expected GEMINI, got {context.gemini_default!r}"
)
@then("GEMINI should be the first configured provider found")
def step_gemini_first_configured(context: Any) -> None:
assert context.fallback_iteration_result == ProviderType.GEMINI, (
f"Expected GEMINI as first found, got {context.fallback_iteration_result!r}"
)
@then("the clean gemini registry default should be None")
def step_result_is_none(context: Any) -> None:
assert context.clean_default is None, (
f"Expected None, got {context.clean_default!r}"
)