183 lines
7.6 KiB
Gherkin
183 lines
7.6 KiB
Gherkin
Feature: Config service with multi-level resolution
|
|
As a developer
|
|
I want a config service that resolves values through a precedence chain
|
|
So that CLI flags, env vars, project scope, global config, and defaults all work correctly
|
|
|
|
Background:
|
|
Given a clean config service test environment
|
|
|
|
# --- Resolution levels ---
|
|
|
|
Scenario: Default value is returned when nothing else is set
|
|
When I resolve config key "core.log_level"
|
|
Then the resolved value should be "INFO"
|
|
And the resolved source should be "default"
|
|
|
|
Scenario: Global config file overrides default
|
|
Given I have written global config key "core.log_level" with value "DEBUG"
|
|
When I resolve config key "core.log_level"
|
|
Then the resolved value should be "DEBUG"
|
|
And the resolved source should be "global"
|
|
|
|
Scenario: Environment variable overrides global config
|
|
Given I have written global config key "core.log_level" with value "DEBUG"
|
|
And the environment variable "CLEVERAGENTS_CORE_LOG_LEVEL" is set to "WARNING"
|
|
When I resolve config key "core.log_level"
|
|
Then the resolved value should be "WARNING"
|
|
And the resolved source should be "env_var"
|
|
|
|
Scenario: CLI flag overrides environment variable
|
|
Given the environment variable "CLEVERAGENTS_CORE_LOG_LEVEL" is set to "WARNING"
|
|
When I resolve config key "core.log_level" with CLI value "ERROR"
|
|
Then the resolved value should be "ERROR"
|
|
And the resolved source should be "cli_flag"
|
|
|
|
Scenario: Project-scoped value overrides global config
|
|
Given I have written global config key "core.log_level" with value "DEBUG"
|
|
And I have written project "myproj" config key "core.log_level" with value "TRACE"
|
|
When I resolve config key "core.log_level" for project "myproj"
|
|
Then the resolved value should be "TRACE"
|
|
And the resolved source should be "project"
|
|
|
|
Scenario: Env var still overrides project-scoped value
|
|
Given I have written project "myproj" config key "core.log_level" with value "TRACE"
|
|
And the environment variable "CLEVERAGENTS_CORE_LOG_LEVEL" is set to "ERROR"
|
|
When I resolve config key "core.log_level" for project "myproj"
|
|
Then the resolved value should be "ERROR"
|
|
And the resolved source should be "env_var"
|
|
|
|
# --- Env var interpolation ---
|
|
|
|
Scenario: Env var name matches CLEVERAGENTS convention
|
|
When I look up the env var for key "core.log_level"
|
|
Then the env var name should be "CLEVERAGENTS_CORE_LOG_LEVEL"
|
|
|
|
Scenario: Env var interpolation for plan keys
|
|
When I look up the env var for key "plan.max_retries"
|
|
Then the env var name should be "CLEVERAGENTS_PLAN_MAX_RETRIES"
|
|
|
|
Scenario: Env var interpolation for provider keys
|
|
When I look up the env var for key "provider.temperature"
|
|
Then the env var name should be "CLEVERAGENTS_PROVIDER_TEMPERATURE"
|
|
|
|
# --- Unknown key rejection ---
|
|
|
|
Scenario: Resolving an unknown key raises an error
|
|
When I attempt to resolve unknown key "bogus.nonexistent"
|
|
Then the config ValueError message should contain "Unknown configuration key"
|
|
|
|
Scenario: Validating an unknown key raises an error
|
|
When I attempt to validate unknown key "invalid.key"
|
|
Then the config ValueError message should contain "Unknown configuration key"
|
|
|
|
# --- Type validation ---
|
|
|
|
Scenario: Integer value is coerced from string
|
|
Given the environment variable "CLEVERAGENTS_CORE_SERVER_PORT" is set to "9090"
|
|
When I resolve config key "core.server_port"
|
|
Then the resolved value should be integer 9090
|
|
|
|
Scenario: Boolean value true is coerced from string
|
|
Given the environment variable "CLEVERAGENTS_CORE_DEBUG_ENABLED" is set to "true"
|
|
When I resolve config key "core.debug_enabled"
|
|
Then the resolved value should be boolean true
|
|
|
|
Scenario: Boolean value false is coerced from string
|
|
Given the environment variable "CLEVERAGENTS_CORE_DEBUG_ENABLED" is set to "false"
|
|
When I resolve config key "core.debug_enabled"
|
|
Then the resolved value should be boolean false
|
|
|
|
Scenario: Float value is coerced from string
|
|
Given the environment variable "CLEVERAGENTS_PROVIDER_TEMPERATURE" is set to "0.9"
|
|
When I resolve config key "provider.temperature"
|
|
Then the resolved value should be float 0.9
|
|
|
|
Scenario: Invalid boolean string raises TypeError
|
|
When I attempt to validate type for key "core.debug_enabled" with value "notabool"
|
|
Then the config TypeError message should contain "Cannot convert"
|
|
|
|
Scenario: Invalid integer string raises TypeError
|
|
When I attempt to validate type for key "core.server_port" with value "notanumber"
|
|
Then the config TypeError message should contain "Type mismatch"
|
|
|
|
# --- Verbose resolution chain ---
|
|
|
|
Scenario: Verbose mode returns full resolution chain
|
|
When I resolve config key "core.log_level" with verbose mode
|
|
Then the resolution chain should have 5 entries
|
|
And the chain should include source "cli_flag"
|
|
And the chain should include source "env_var"
|
|
And the chain should include source "project"
|
|
And the chain should include source "global"
|
|
And the chain should include source "default"
|
|
|
|
# --- Key registry ---
|
|
|
|
Scenario: Registry contains core keys
|
|
Then the registry should contain key "core.log_level"
|
|
And the registry should contain key "core.debug_enabled"
|
|
And the registry should contain key "core.env"
|
|
|
|
Scenario: Registry contains plan keys
|
|
Then the registry should contain key "plan.auto_apply"
|
|
And the registry should contain key "plan.max_retries"
|
|
And the registry should contain key "plan.timeout_seconds"
|
|
|
|
Scenario: Registry contains provider keys
|
|
Then the registry should contain key "provider.default_provider"
|
|
And the registry should contain key "provider.default_model"
|
|
And the registry should contain key "provider.temperature"
|
|
|
|
Scenario: Registry contains sandbox keys
|
|
Then the registry should contain key "sandbox.strategy"
|
|
And the registry should contain key "sandbox.auto_cleanup"
|
|
And the registry should contain key "sandbox.max_age_hours"
|
|
|
|
Scenario: Registry contains context keys
|
|
Then the registry should contain key "context.max_files"
|
|
And the registry should contain key "context.max_tokens"
|
|
|
|
Scenario: Registry contains index keys
|
|
Then the registry should contain key "index.enabled"
|
|
And the registry should contain key "index.backend"
|
|
|
|
# --- TOML file management ---
|
|
|
|
Scenario: Writing and reading TOML config roundtrips
|
|
Given I write config data with key "core.log_level" and value "TRACE"
|
|
When I read the config file
|
|
Then the config data should contain key "core.log_level" with value "TRACE"
|
|
|
|
Scenario: Config directory is auto-created
|
|
When I write config data to a new directory
|
|
Then the config directory should exist
|
|
|
|
Scenario: Non-project-scopable keys ignore project scope
|
|
Given I have written project "proj" config key "core.database_url" with value "sqlite:///other.db"
|
|
When I resolve config key "core.database_url" for project "proj"
|
|
Then the resolved source should be "default"
|
|
|
|
# --- Resolve all ---
|
|
|
|
Scenario: Resolve all returns all registered keys
|
|
When I resolve all keys
|
|
Then the result should contain all registered keys
|
|
|
|
# --- Set value ---
|
|
|
|
Scenario: Set value persists to TOML file
|
|
When I set config value "core.log_level" to "CRITICAL"
|
|
And I read the config file
|
|
Then the config data should contain key "core.log_level" with value "CRITICAL"
|
|
|
|
# --- Entry lookup ---
|
|
|
|
Scenario: Get entry returns ConfigEntry for valid key
|
|
When I get entry for key "core.log_level"
|
|
Then the entry should have section "core"
|
|
And the entry should have python type "str"
|
|
|
|
Scenario: Get entry returns None for unknown key
|
|
When I get entry for key "nonexistent.key"
|
|
Then the entry should be None
|