test(common): add integration tests for layered config precedence#1202
Conversation
geoffjay
left a comment
There was a problem hiding this comment.
Review: test(common): add integration tests for layered config precedence
Stack position: This PR (issue-1199) is stacked on PR #1201 (issue-1194), which currently has needs-rework. It cannot merge until #1201 is fixed and landed. Once #1201 is reworked — particularly the schema additions for MonitorConfig, HookConfig, and IndexConfig — this branch will need a restack and the new fields should get coverage here too (see below).
The test work itself is solid. Reviewing it now so feedback is ready to act on immediately after the parent lands.
Bugfix in existing tests — correct
Adding ENV_LOCK to test_load_with_config_file and test_precedence_file_beats_default is correct and important. Both call load_from_path(Some(path)) which runs apply_env_overrides internally, so they were silently racing with the env-var-setting tests. Good catch.
New tests — assessment
| Test | Verdict | Notes |
|---|---|---|
test_load_empty_file_uses_defaults |
✅ | Correct — empty TOML is valid and all fields fall back to Default |
test_load_unknown_keys_are_ignored |
✅ | Correctly validates serde's ignore-unknown-fields behaviour for [unknown_section] |
test_full_precedence_chain |
✅ with note | See comment below |
test_env_absent_preserves_file_value |
✅ | Clean test for the no-env-var path |
test_partial_toml_leaves_other_services_at_defaults |
✅ | Good exhaustive sweep of all 11 service ports |
test_all_default_ports_match_spec |
✅ | Useful regression guard; port table is clear |
test_concurrent_load_returns_consistent_results |
✅ with note | See comment below |
test_hook_notify_url_from_file |
✅ | Correctly exercises the Option<String> field via load_from_path |
test_mcp_urls_from_file |
✅ | Good spot-check for partial MCP URL override |
test_index_languages_from_file_overrides_default |
✅ | Not a duplicate — exercises load_from_path → merge() path, unlike the existing test_toml_services_index_languages_override which calls toml::from_str directly |
Minor observations (non-blocking)
1. test_full_precedence_chain — comment is slightly misleading
// Remove env var BEFORE asserting so a panic can't leave it set
env::remove_var("AGENTD_ASK_PORT");The comment implies a panic in load_from_path would still clean up — it wouldn't, since remove_var is called after .expect(...). Reordering remove_var before the assertions (the current position) is correct for protecting against assertion panics, but not load_from_path panics. Not a real risk here, but the comment overpromises. The existing env-override tests follow the same set→use→remove pattern, so this is style-consistent; just worth a more accurate comment like: // Remove before assertions so a test-assert panic cannot leave the var set.
2. test_concurrent_load_returns_consistent_results — no ENV_LOCK
The test spawns 8 threads all calling load_from_path(None) without holding ENV_LOCK. Each thread reads env vars via apply_env_overrides. If an env-var-setting test runs concurrently (e.g., test_env_override_log_level), some threads could see log_level = "trace" while others see "info", and the cross-thread equality check would fail intermittently. In practice the ENV_LOCK serialisation makes this unlikely, but the concurrent test is the one place where not holding the lock creates a real race window rather than just a theoretical one. Consider acquiring ENV_LOCK for the duration of the spawned-threads test.
3. Redundant use std::io::Write; in new test functions
use std::io::Write; is already imported at the top of mod tests. The five new tests that re-import it locally are correct but noisy — Clippy may flag them on some lint configurations. They can be removed safely.
Coverage gap to address after restack
Once #1201's rework adds the missing schema fields, this PR should add tests for:
MonitorConfig:cpu_alert_threshold,memory_alert_threshold,disk_alert_threshold,history_size(metric snapshots)HookConfig:notify_on_failure,notify_on_long_running,long_running_threshold_msIndexConfig:embedding_endpoint,embedding_api_key,lance_table,watch_interval_secs,ignore_patternsAGENTD_MONITOR_HISTORY_SIZE/AGENTD_HOOK_HISTORY_SIZE(whichever naming resolution #1201 adopts for the collision)
The existing test_partial_toml_leaves_other_services_at_defaults and test_all_default_ports_match_spec are good templates for the new fields.
Summary: Bugfix is correct, new tests are well-structured with good comments. Three minor items above — none blocking. Hold for parent #1201 to land, restack, then add coverage for the new schema fields.
…_file_path indirection - Make cmd_init pub(crate) so tests can call it directly - Replace boolean-literal overwrite-guard tests with real tests that set AGENTD_CONFIG to a tempdir and call cmd_init; verify error message mentions --force on refusal and that the template is written on force-overwrite - Add ENV_LOCK mutex to serialise tests that mutate AGENTD_CONFIG - Remove the config_file_path() local wrapper; import via use instead - Fix cmd_show None arm to reuse the already-resolved path rather than calling config_file_path() a second time Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…g tests Add ENV_LOCK to mcp and index config test modules so env-var-mutating tests are serialised in the parallel test harness. Also clear AGENTD_PORT (set by agentd at runtime) before asserting default port values. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…s; add TODO(#1201) comments Replace silent unwrap_or_default() with unwrap_or_else(|e| tracing::warn\!(...)) in all six migrated load() callers (hook, monitor, mcp, memory::EmbeddingConfig, memory::LanceConfig, index, ui). Operators now see a warning when config.toml is malformed rather than silently falling back to compiled defaults. Add TODO(#1201) comments on every hardcoded fallback that is pending a schema addition: notify_on_failure, notify_on_long_running, long_running_threshold_ms (hook); cpu/memory/disk_alert_threshold, history_size (monitor); embedding_endpoint (index.embedding); lance_table (index.lance). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add a ValidateConfig trait to agentd_common with implementations for all 12 shared config sections. Add AgentdConfig::validate() that collects errors from every section. Implement ValidateConfig on all service-level config structs and wire validate() into each service's startup path so misconfigurations fail early with descriptive error messages. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Create dedicated config.rs modules for core, orchestrator, wrap, ask, notify, and communicate. Each struct loads from agentd_common::config::load() first, then overlays legacy AGENTD_* env vars for backward compatibility. All inline env::var() calls in main.rs replaced with config struct access. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add impl ValidateConfig for EmbeddingConfig and LanceConfig in crates/memory/src/config.rs (blocking gap: memory was the only service with no validation at startup) - Wire validation in memory/main.rs: call validate() on embedding and lance configs, load shared config for port/host so port=0 is caught before any I/O with a clear error message - Remove validate_inner() indirection in crates/index/src/config.rs; move logic directly into impl ValidateConfig for IndexConfig and import the trait in index/main.rs and the test module - Make validate_url() pub in agentd-common so service crates can reuse it without duplicating the http/https check Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ilures
Replace silent unwrap_or_default() with unwrap_or_else(|e| { tracing::warn\!(...) })
in all six new service config loaders (ask, communicate, core, notify, orchestrator,
wrap). Restore diagnostic warn\!() calls for invalid AGENTD_WRAP_HISTORY_BYTES and
AGENTD_WRAP_CHANNEL_CAPACITY env vars with TODO comments referencing #1201.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Create docs/configuration.md with quick start, file location, precedence rules, complete key reference table, per-service sections, migration guide, and four example configs (minimal, development, production, Docker) - Fix the env var table in agentd-common/config.rs to include all overrides (AGENTD_INDEX_LANGUAGES, AGENTD_RECONCILE_INTERVAL_SECS, all MCP URLs, AGENTD_NOTIFY_SERVICE_URL, AGENTD_COLLECTION_INTERVAL_SECS) - Add link to configuration reference from README.md Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
This change is part of the following stack:
Change managed by git-spice. |
docs: add configuration system documentation
feat: add ValidateConfig trait and per-service validation
feat: add config structs for services with inline env var config
refactor: migrate services with existing config.rs to shared TOML config
feat(cli): add config init and config show subcommands
Adds 10 new integration tests to agentd_common::config covering empty files, unknown TOML keys, full three-layer precedence, concurrent loading, and per-service edge cases. All 33 tests pass.
Closes #1199