Files
cleveragents-core/features/steps/aimodelscredentials_steps.py
freemo eaf15dd17c fix(ci): restore all CI quality gates to passing on master
Apply remaining fixes not covered by the 4278ba91 commit:

1. src/cleveragents/cli/main.py:
   info and diagnostics commands now call configure_structlog(WARNING)
   before build_info_data()/build_diagnostics_data() when non-rich format
   is requested. This prevents debug-level structlog messages from
   corrupting --format json/yaml output in integration tests.

2. robot/helper_config_cli.py:
   Call configure_structlog(WARNING) before importing cleveragents CLI
   commands so plugin_manager debug messages don't pollute CliRunner
   captured output (fixes Config List JSON Format test).

3. features/steps/aimodelscredentials_steps.py:
   ModelProviderOption config checks now use getattr fallback so they
   work both when context.model_config is set (via explicit 'I examine
   the ModelProviderOption model_config' step) and when context.model_instance
   is set (via 'I create a ModelProviderOption with only priority set to N').

4. features/steps/plan_namespaced_name_tdd_steps.py:
   @when steps now set context.error and context.lsp_error in addition to
   context.exception so the existing @then steps from service_steps.py
   and lsp_registry_steps.py match and validate correctly.

No quality gates suppressed. All changes are to test and source files.

ISSUES CLOSED: #2597
2026-04-04 20:38:16 +00:00

480 lines
17 KiB
Python

"""Step definitions for AI Models Credentials coverage tests."""
from behave import given, then, when
from pydantic import ValidationError
from cleveragents.domain.models.aimodelsproviders.ai_models_providers import (
ModelProviderConfigSchema,
)
from cleveragents.domain.models.core.enums import ModelPublisher
@given("the cleveragents package is available")
def step_package_available(context):
"""Verify the cleveragents package is available."""
import cleveragents
assert cleveragents is not None
@when("I import ModelProviderOption from aimodelscredentials")
def step_import_model_provider_option(context):
"""Import ModelProviderOption class."""
from cleveragents.domain.models.aimodelscredentials.ai_models_credentials import (
ModelProviderOption,
)
context.model_provider_option_class = ModelProviderOption
context.imported_class = ModelProviderOption
@then("the ModelProviderOption class should be available")
def step_verify_class_available(context):
"""Verify ModelProviderOption class is available."""
assert context.model_provider_option_class is not None
assert context.model_provider_option_class.__name__ == "ModelProviderOption"
@then("I can create a ModelProviderOption with publishers, config, and priority")
def step_create_full_model(context):
"""Create a ModelProviderOption with all fields."""
ModelProviderOption = context.model_provider_option_class
# Create a sample config
from cleveragents.domain.models.core.enums import ModelProvider
config = ModelProviderConfigSchema(
provider=ModelProvider.OPENAI, baseUrl="https://api.openai.com/v1"
)
# Create publishers dictionary
publishers = {
"provider1": {ModelPublisher.OPENAI: True, ModelPublisher.ANTHROPIC: False},
"provider2": {ModelPublisher.GOOGLE: True},
}
# Create the model
model = ModelProviderOption(publishers=publishers, config=config, priority=1)
assert model.priority == 1
assert model.publishers == publishers
assert model.config == config
@when("I create a ModelProviderOption with only priority set to {priority:d}")
def step_create_minimal_model(context, priority):
"""Create a ModelProviderOption with minimal fields."""
from cleveragents.domain.models.aimodelscredentials.ai_models_credentials import (
ModelProviderOption,
)
context.model_instance = ModelProviderOption(priority=priority)
@then("the ModelProviderOption should have priority {priority:d}")
def step_verify_priority(context, priority):
"""Verify the priority field value."""
assert context.model_instance.priority == priority
@then("the publishers dictionary should be empty")
def step_verify_publishers_empty(context):
"""Verify publishers dictionary is empty."""
assert context.model_instance.publishers == {}
@then("the config should be None")
def step_verify_config_none(context):
"""Verify config is None."""
assert context.model_instance.config is None
@when("I create a ModelProviderOption with complex publishers structure")
def step_create_complex_publishers(context):
"""Create a ModelProviderOption with complex publishers."""
from cleveragents.domain.models.aimodelscredentials.ai_models_credentials import (
ModelProviderOption,
)
publishers = {
"primary": {
ModelPublisher.OPENAI: True,
ModelPublisher.ANTHROPIC: True,
ModelPublisher.GOOGLE: False,
},
"secondary": {ModelPublisher.MISTRAL: True, ModelPublisher.PERPLEXITY: False},
"tertiary": {ModelPublisher.OPENAI: False},
}
context.model_instance = ModelProviderOption(publishers=publishers, priority=2)
context.expected_publishers = publishers
@then("the publishers field should contain the expected dictionary structure")
def step_verify_publishers_structure(context):
"""Verify the publishers structure."""
assert context.model_instance.publishers == context.expected_publishers
@then("the ModelPublisher enum values should be properly handled")
def step_verify_enum_handling(context):
"""Verify enum values are handled correctly."""
# Check that enum values are properly stored
for _provider, publisher_dict in context.model_instance.publishers.items():
for _publisher, enabled in publisher_dict.items():
# With use_enum_values=True, the enum values should be used
assert isinstance(enabled, bool)
@when("I create a ModelProviderOption with a config object")
def step_create_with_config(context):
"""Create a ModelProviderOption with config."""
from cleveragents.domain.models.aimodelscredentials.ai_models_credentials import (
ModelProviderOption,
)
from cleveragents.domain.models.core.enums import ModelProvider
config = ModelProviderConfigSchema(
provider=ModelProvider.OPENAI, baseUrl="https://api.openai.com/v1"
)
context.model_instance = ModelProviderOption(config=config, priority=3)
context.expected_config = config
@then("the config field should contain the ModelProviderConfigSchema instance")
def step_verify_config_instance(context):
"""Verify config contains the right instance."""
assert context.model_instance.config == context.expected_config
@then("the config should be properly validated")
def step_verify_config_validated(context):
"""Verify config is validated."""
from cleveragents.domain.models.core.enums import ModelProvider
assert context.model_instance.config.provider == ModelProvider.OPENAI
assert context.model_instance.config.base_url == "https://api.openai.com/v1"
@when("I create a ModelProviderOption with strings containing whitespace")
def step_create_with_whitespace(context):
"""Create model with whitespace in strings."""
from cleveragents.domain.models.aimodelscredentials.ai_models_credentials import (
ModelProviderOption,
)
# Note: The model doesn't have direct string fields, but we'll test with config
from cleveragents.domain.models.core.enums import ModelProvider
config = ModelProviderConfigSchema(
provider=ModelProvider.OPENAI, baseUrl=" https://api.openai.com/v1 "
)
context.model_instance = ModelProviderOption(config=config, priority=4)
@then("the string fields should have whitespace stripped")
def step_verify_whitespace_stripped(context):
"""Verify whitespace is stripped from strings."""
# The ModelProviderConfigSchema should handle its own whitespace stripping
# based on its model_config settings
assert context.model_instance.config.base_url == "https://api.openai.com/v1"
@when("I create a ModelProviderOption instance")
def step_create_instance(context):
"""Create a basic ModelProviderOption instance."""
from cleveragents.domain.models.aimodelscredentials.ai_models_credentials import (
ModelProviderOption,
)
context.model_instance = ModelProviderOption(priority=5)
@when("I update its fields with new values")
def step_update_fields(context):
"""Update model fields with new values."""
context.model_instance.priority = 10
context.model_instance.publishers = {"updated": {ModelPublisher.OPENAI: True}}
@then("the assignment validation should be triggered")
def step_verify_assignment_validation(context):
"""Verify assignment validation works."""
# The values should be updated and validated
assert context.model_instance.priority == 10
@then("the values should be properly validated")
def step_verify_values_validated(context):
"""Verify values are validated on assignment."""
assert context.model_instance.publishers == {
"updated": {ModelPublisher.OPENAI: True}
}
@when("I create a ModelProviderOption using field aliases")
def step_create_with_aliases(context):
"""Create model using field aliases (populate_by_name)."""
from cleveragents.domain.models.aimodelscredentials.ai_models_credentials import (
ModelProviderOption,
)
# With populate_by_name=True, we can use field names directly
data = {"priority": 6, "publishers": {}, "config": None}
context.model_instance = ModelProviderOption(**data)
@then("the fields should be populated correctly by name")
def step_verify_populate_by_name(context):
"""Verify fields are populated by name."""
assert context.model_instance.priority == 6
assert context.model_instance.publishers == {}
assert context.model_instance.config is None
@when("I create a ModelProviderOption with ModelPublisher enums")
def step_create_with_enums(context):
"""Create model with enum values."""
from cleveragents.domain.models.aimodelscredentials.ai_models_credentials import (
ModelProviderOption,
)
publishers = {
"test": {ModelPublisher.OPENAI: True, ModelPublisher.ANTHROPIC: False}
}
context.model_instance = ModelProviderOption(publishers=publishers, priority=7)
@then("the enum values should be used in serialization")
def step_verify_enum_serialization(context):
"""Verify enum values in serialization."""
data = context.model_instance.model_dump()
# With use_enum_values=True, enums should be serialized as their values
assert isinstance(data["publishers"], dict)
@then("the model should handle enum values properly")
def step_verify_enum_handling_proper(context):
"""Verify proper enum handling."""
# The model should work with enum values
assert context.model_instance.publishers["test"][ModelPublisher.OPENAI] is True
@when("I create a ModelProviderOption with default fields")
def step_create_with_defaults(context):
"""Create model with default fields."""
from cleveragents.domain.models.aimodelscredentials.ai_models_credentials import (
ModelProviderOption,
)
context.model_instance = ModelProviderOption(priority=8)
@then("publishers should default to an empty dictionary")
def step_verify_publishers_default(context):
"""Verify publishers defaults to empty dict."""
assert context.model_instance.publishers == {}
@then("config should default to None")
def step_verify_config_default(context):
"""Verify config defaults to None."""
assert context.model_instance.config is None
@when("I try to create a ModelProviderOption with invalid priority")
def step_create_invalid_priority(context):
"""Try to create model with invalid priority."""
from cleveragents.domain.models.aimodelscredentials.ai_models_credentials import (
ModelProviderOption,
)
try:
# Priority should be an integer, not a string
context.model_instance = ModelProviderOption(priority="invalid")
context.validation_error = None
except ValidationError as e:
context.validation_error = e
@then("a ModelProviderOption validation error should be raised")
def step_verify_validation_error(context):
"""Verify validation error is raised."""
assert context.validation_error is not None
@then("the error should indicate the priority field issue")
def step_verify_priority_error(context):
"""Verify error is about priority field."""
error_dict = context.validation_error.errors()[0]
assert "priority" in str(error_dict)
@when("I examine the ModelProviderOption model_config")
def step_examine_model_config(context):
"""Examine the model_config settings."""
from cleveragents.domain.models.aimodelscredentials.ai_models_credentials import (
ModelProviderOption,
)
context.model_config = ModelProviderOption.model_config
@then("the ModelProviderOption str_strip_whitespace should be True")
def step_verify_strip_whitespace_mpo(context):
"""Verify str_strip_whitespace setting for ModelProviderOption."""
cfg = getattr(context, "model_config", None) or context.model_instance.model_config
assert cfg.get("str_strip_whitespace") is True
@then("the ModelProviderOption validate_assignment should be True")
def step_verify_validate_assignment_mpo(context):
"""Verify validate_assignment setting for ModelProviderOption."""
cfg = getattr(context, "model_config", None) or context.model_instance.model_config
assert cfg.get("validate_assignment") is True
@then("the ModelProviderOption arbitrary_types_allowed should be False")
def step_verify_arbitrary_types_mpo(context):
"""Verify arbitrary_types_allowed setting for ModelProviderOption."""
cfg = getattr(context, "model_config", None) or context.model_instance.model_config
assert cfg.get("arbitrary_types_allowed") is False
@then("the ModelProviderOption populate_by_name should be True")
def step_verify_populate_by_name_setting_mpo(context):
"""Verify populate_by_name setting for ModelProviderOption."""
cfg = getattr(context, "model_config", None) or context.model_instance.model_config
assert cfg.get("populate_by_name") is True
@then("the ModelProviderOption use_enum_values should be True")
def step_verify_use_enum_values_mpo(context):
"""Verify use_enum_values setting for ModelProviderOption."""
cfg = getattr(context, "model_config", None) or context.model_instance.model_config
assert cfg.get("use_enum_values") is True
@when("I create a ModelProviderOption with nested publisher dictionaries")
def step_create_nested_publishers(context):
"""Create model with nested publisher structures."""
from cleveragents.domain.models.aimodelscredentials.ai_models_credentials import (
ModelProviderOption,
)
publishers = {
"level1": {ModelPublisher.OPENAI: True, ModelPublisher.ANTHROPIC: False},
"level2": {ModelPublisher.GOOGLE: True, ModelPublisher.MISTRAL: True},
}
context.model_instance = ModelProviderOption(publishers=publishers, priority=9)
context.nested_publishers = publishers
@then("the nested structure should be properly maintained")
def step_verify_nested_structure(context):
"""Verify nested structure is maintained."""
assert context.model_instance.publishers == context.nested_publishers
@then("the ModelPublisher boolean values should work correctly")
def step_verify_boolean_values(context):
"""Verify boolean values work correctly."""
assert context.model_instance.publishers["level1"][ModelPublisher.OPENAI] is True
assert (
context.model_instance.publishers["level1"][ModelPublisher.ANTHROPIC] is False
)
assert context.model_instance.publishers["level2"][ModelPublisher.GOOGLE] is True
@when("I serialize a ModelProviderOption to dict")
def step_serialize_to_dict(context):
"""Serialize ModelProviderOption to dictionary."""
from cleveragents.domain.models.aimodelscredentials.ai_models_credentials import (
ModelProviderOption,
)
from cleveragents.domain.models.core.enums import ModelProvider
config = ModelProviderConfigSchema(
provider=ModelProvider.OPENAI, baseUrl="https://api.openai.com/v1"
)
model = ModelProviderOption(
publishers={"test": {ModelPublisher.OPENAI: True}}, config=config, priority=10
)
context.original_model = model
context.serialized_data = model.model_dump()
@when("I deserialize it back to ModelProviderOption")
def step_deserialize_from_dict(context):
"""Deserialize dictionary back to ModelProviderOption."""
from cleveragents.domain.models.aimodelscredentials.ai_models_credentials import (
ModelProviderOption,
)
context.deserialized_model = ModelProviderOption(**context.serialized_data)
@then("the round-trip should preserve all data")
def step_verify_round_trip(context):
"""Verify round-trip preserves data."""
assert context.deserialized_model.priority == context.original_model.priority
# Note: Direct comparison might fail due to enum serialization
assert (
context.deserialized_model.model_dump() == context.original_model.model_dump()
)
@when("I explicitly set config to None in ModelProviderOption")
def step_set_config_none(context):
"""Explicitly set config to None."""
from cleveragents.domain.models.aimodelscredentials.ai_models_credentials import (
ModelProviderOption,
)
context.model_instance = ModelProviderOption(config=None, priority=11)
@then("the config field should accept None value")
def step_verify_config_accepts_none(context):
"""Verify config accepts None."""
assert context.model_instance.config is None
@then("the model should be valid")
def step_verify_model_valid(context):
"""Verify model is valid."""
# Model should be valid with None config
assert context.model_instance.priority == 11
@when("I try to create a ModelProviderOption without priority")
def step_create_without_priority(context):
"""Try to create model without required priority field."""
from cleveragents.domain.models.aimodelscredentials.ai_models_credentials import (
ModelProviderOption,
)
try:
context.model_instance = ModelProviderOption()
context.validation_error = None
except ValidationError as e:
context.validation_error = e
@then(
"a ModelProviderOption validation error should be raised for missing required field"
)
def step_verify_missing_field_error(context):
"""Verify error for missing required field."""
assert context.validation_error is not None
error_dict = context.validation_error.errors()[0]
assert "priority" in str(error_dict)
assert "required" in str(error_dict).lower() or "missing" in str(error_dict).lower()