6b80be2117
CI / lint (pull_request) Successful in 42s
CI / integration_tests (pull_request) Successful in 49s
CI / quality (pull_request) Successful in 53s
CI / build (pull_request) Successful in 50s
CI / typecheck (pull_request) Successful in 54s
CI / security (pull_request) Successful in 1m12s
CI / unit_tests (pull_request) Successful in 3m53s
CI / coverage (pull_request) Successful in 3m50s
CI / status-check (pull_request) Successful in 3s
CI / lint (push) Successful in 43s
CI / quality (push) Successful in 46s
CI / security (push) Successful in 47s
CI / typecheck (push) Successful in 48s
CI / build (push) Successful in 50s
CI / integration_tests (push) Successful in 54s
CI / unit_tests (push) Successful in 3m49s
CI / coverage (push) Successful in 3m42s
CI / status-check (push) Successful in 3s
Implement a new module-level merge_configs() function in
src/cleveractors/config_utils.py that exposes the §3.1 deep-merge
algorithm as a public, importable API.
Motivation: The internal ReactiveConfigParser._merge_configs() method
mutates its base dict in place and only accepts two dicts. The
CleverThis router (wave 2 of cleveragents/cleveragents-webapp#275)
needs a public merge_configs() to combine platform base configs with
actor configs from the database without side-effects.
Implementation:
- merge_configs(*dicts) accumulates into a fresh dict, applying each
overlay using the §3.1 rules:
* Key absent → add via deep copy.
* Both mappings → deep-merge recursively (_apply_merge helper).
* Both sequences → extend (existing + deep copy of new).
* Otherwise → replace with deep copy of new value.
- Runtime type guard: non-dict arguments raise TypeError immediately
(fail-fast per CONTRIBUTING.md argument validation guidelines).
- Zero-argument call returns {}.
- Inputs are never mutated (copy.deepcopy used for all stored values).
- Internal _merge_configs on ReactiveConfigParser is unchanged.
Exports: merge_configs added to cleveractors/__init__.py import and
__all__ so consumers can use 'from cleveractors import merge_configs'.
Tests:
- 15 Behave BDD scenarios in features/merge_configs.feature covering
zero-args, single-dict deep copy (including nested identity),
empty-dict arguments, TypeError on None, absent-key insertion,
scalar override, recursive mapping merge, sequence append,
three-dict chained merge, deep nesting, input mutation guard,
result-mutation independence from inputs, and type-mismatch
replacement.
- 4 Robot Framework integration tests in robot/config.robot with
strengthened assertions (len check, overlay immutability).
- 5 ASV benchmarks with realistically sized three-way merge fixtures
(50 keys each with overlap).
Project files: Added CONTRIBUTORS.md per CONTRIBUTING.md §PR Process
rule 8.
Coverage: 97% (config_utils.py: 100%).
Quality gates: ruff lint ✓, pyright strict ✓ (0 errors),
all BDD/Robot tests ✓.
ISSUES CLOSED: #11
81 lines
3.2 KiB
Plaintext
81 lines
3.2 KiB
Plaintext
*** Settings ***
|
|
Documentation Integration tests for configuration and schema validation
|
|
Library OperatingSystem
|
|
Library CleverActorsLib.py
|
|
Suite Setup No Operation
|
|
Suite Teardown No Operation
|
|
|
|
*** Variables ***
|
|
${FIXTURES} ${CURDIR}${/}..${/}tests${/}fixtures
|
|
|
|
*** Test Cases ***
|
|
Config Manager Can Be Created
|
|
[Documentation] Verify ConfigurationManager initialises cleanly
|
|
Create Config Manager
|
|
No Operation
|
|
|
|
Config Manager Loads YAML File
|
|
[Documentation] Verify a single YAML config file loads without error
|
|
Create Config Manager
|
|
Load Config Files ${FIXTURES}${/}test_config.yaml
|
|
Config Path Exists agents.test_agent
|
|
|
|
Config Manager Reads Nested Value
|
|
[Documentation] Verify deep config path access
|
|
Create Config Manager
|
|
Load Config Files ${FIXTURES}${/}test_config.yaml
|
|
Config Value Equals agents.test_agent.type llm
|
|
|
|
Config Manager Loads Simple Echo Config
|
|
[Documentation] Verify the simple echo fixture loads correctly
|
|
Create Config Manager
|
|
Load Config Files ${FIXTURES}${/}simple_echo_config.yaml
|
|
Config Path Exists agents.echo
|
|
Config Path Exists routes.main
|
|
|
|
Config Manager Handles Missing File
|
|
[Documentation] Verify error is raised for non-existent config file
|
|
Load Config Should Raise ${FIXTURES}${/}nonexistent.yaml
|
|
|
|
Config Manager Interpolates Environment Variables
|
|
[Documentation] Verify ${ENV_VAR} interpolation works
|
|
${prev}= Get Environment Variable CA_TEST_VAR default=${EMPTY}
|
|
Set Environment Variable CA_TEST_VAR interpolated_value
|
|
Create Config Manager
|
|
Interpolate Env Var CA_TEST_VAR interpolated_value
|
|
[Teardown] Run Keyword Set Environment Variable CA_TEST_VAR ${prev}
|
|
|
|
Config Manager Serialises To Dict
|
|
[Documentation] Verify to_dict() produces expected structure
|
|
Create Config Manager
|
|
Load Config Files ${FIXTURES}${/}test_config.yaml
|
|
No Operation
|
|
|
|
Merge Configs Returns Empty Dict For No Args
|
|
[Documentation] Verify merge_configs() with no arguments returns {}
|
|
Merge Configs Returns Empty For No Args
|
|
|
|
Merge Configs Combines Two Dicts
|
|
[Documentation] Verify merge_configs(base, overlay) merges keys from both dicts
|
|
Merge Configs Two Dicts platform_key platform_val actor_key actor_val
|
|
|
|
Merge Configs Deep Merges Nested Dicts
|
|
[Documentation] Verify merge_configs deep-merges nested mappings per §3.1
|
|
Merge Configs Deep Merge
|
|
|
|
Merge Configs Appends Sequences
|
|
[Documentation] Verify merge_configs appends lists when both values are sequences
|
|
Merge Configs Sequence Append
|
|
|
|
Merge Configs Through Config Pipeline
|
|
[Documentation] End-to-end test: load YAML via ConfigurationManager, merge overlay via merge_configs
|
|
Merge Configs Through Config Pipeline injected_key injected_value
|
|
|
|
Schema Validator Accepts Minimum Config
|
|
[Documentation] Verify schema validation passes for minimal valid config
|
|
Schema Validator Accepts Minimum Config
|
|
|
|
Schema Validator Rejects Missing Required Sections
|
|
[Documentation] Verify empty config fails schema validation
|
|
Schema Validator Rejects key: value
|