eaf15dd17c
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
480 lines
17 KiB
Python
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()
|