Files
hurui200320 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
feat(merge_configs): expose public merge_configs(*dicts) API per §3.1 deep-merge algorithm
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
2026-06-03 14:44:18 +00:00

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