Skip to content

test(analytics-api): unit tests for pure-logic modules (threshold/query/metric/config)#1333

Closed
SharedQA wants to merge 8 commits into
constructorfabric:mainfrom
SharedQA:claude/unit-coverage
Closed

test(analytics-api): unit tests for pure-logic modules (threshold/query/metric/config)#1333
SharedQA wants to merge 8 commits into
constructorfabric:mainfrom
SharedQA:claude/unit-coverage

Conversation

@SharedQA

@SharedQA SharedQA commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Raises analytics-api unit coverage on the pure-logic modules (the part that doesn't need a DB/runtime).

Measured (cargo-llvm-cov, instrumented)

Test validity

Expected values are derived from documented intent — OData semantics, the in-code PATCH triple-state comment, the default_* fns — not from running the code. Negative/boundary cases included (unknown operator, missing required config, null-vs-absent PATCH, empty/oversized inputs).

One unit was found semantically suspect during review and flagged rather than locked in: threshold_matches's eq uses f64::EPSILON (magnitude-dependent equality) — see #1332. The test characterises current behaviour; the issue asks for the intended rule.

Coverage ceiling

Further unit gains are limited: the remaining uncovered analytics-api/oidc/clickhouse code is runtime/IO (validate_token needs JWKS, DB clients need ClickHouse/MariaDB, main/module wiring need the modkit runtime). Reaching ~80% requires the instrumented e2e profile (the rig running instrumented binaries — milestone 2.15), not more unit tests.

Related correctness findings from this pass: #1330 (duplicate/unstable data), #1331 (time formats), #1332 (threshold eq).

Summary by CodeRabbit

  • Tests
    • Added unit test coverage for analytics configuration precedence and required-field validation.
    • Added serialization/deserialization tests for metric update PATCH semantics and query/batch request behavior, including defaulting and JSON status formatting.
    • Added threshold evaluation and request deserialization tests covering supported operators, epsilon equality, invalid operator/level handling, and partial updates.

@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7686f291-15ed-4952-b3c6-2d3d81eb1c72

📥 Commits

Reviewing files that changed from the base of the PR and between 231ac7a and 188936b.

📒 Files selected for processing (3)
  • src/backend/services/analytics-api/src/config.rs
  • src/backend/services/analytics-api/src/domain/metric.rs
  • src/backend/services/analytics-api/src/domain/query.rs

📝 Walkthrough

Walkthrough

Adds #[cfg(test)] modules to four files in the analytics-api service: config.rs, domain/metric.rs, domain/query.rs, and domain/threshold.rs. No production logic is modified; only test coverage is introduced for configuration defaults, serde contracts, and threshold evaluation.

Changes

Analytics API Unit Test Coverage

Layer / File(s) Summary
AppConfig defaulting and Figment extraction tests
src/backend/services/analytics-api/src/config.rs
Tests verify that bind_addr and clickhouse_database can be overridden via inline YAML, and that extraction fails when the required clickhouse_url field is omitted.
Metric domain serde tests
src/backend/services/analytics-api/src/domain/metric.rs
Tests validate UpdateMetricRequest.description triple-state deserialization: absent field yields None, explicit null yields Some(None), and provided string yields Some(Some(value)).
Query and batch domain serde tests
src/backend/services/analytics-api/src/domain/query.rs
Tests validate OData field mapping ($filter, $orderby, $select, $top, $skip) into QueryRequest, default top value application on empty body, BatchQueryRequest nested deserialization with per-item query payload propagation, and BatchQueryResult::Ok lowercase "status" tag serialization.
Threshold evaluation and request deserialization tests
src/backend/services/analytics-api/src/domain/threshold.rs
Tests verify threshold_matches correctly evaluates all supported operators (gt, ge, lt, le, eq) with epsilon tolerance for floating-point equality, rejects unknown and case-mismatched operators, validate VALID_OPERATORS and VALID_LEVELS constant contents and their corresponding invalid-message text, and test CreateThresholdRequest and UpdateThresholdRequest JSON deserialization.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Suggested reviewers

  • cyberantonz

Poem

🐇 Hop, hop, hip hooray!
I tested configs today—
Defaults checked and thresholds true,
Serde contracts all shine through.
No null shall slip away! 🎉

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and clearly summarizes the main change: adding unit tests for four specific pure-logic modules (threshold, query, metric, config) in the analytics-api service.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@SharedQA SharedQA mentioned this pull request Jun 15, 2026
@SharedQA

Copy link
Copy Markdown
Contributor Author

Overlaps #1314 (migrate to gears) on domain/query.rs. Reconcile these unit tests with the gears changes once #1314 merges.

…e logic

threshold.rs (0%): operator matching incl. negative/unknown-operator cases.
query.rs: OData $-param mapping + defaults + batch flatten + lowercase status tag.
metric.rs: triple-state PATCH deserializer (absent/null/value) + summary never leaks SQL.
config.rs: figment defaults + required-field-missing error.

Expected values derived from documented intent (OData semantics, the PATCH-state
comment, default fns) — not from running the code — except threshold eq, whose
f64::EPSILON behaviour is characterised + flagged separately as semantically
suspect (magnitude-dependent equality). 19 tests; analytics-api 257 pass; clippy clean.

Signed-off-by: Kenan Salim <kenan.salim@rolos.com>
@SharedQA
SharedQA force-pushed the claude/unit-coverage branch from a85b3d9 to 7c4b483 Compare June 15, 2026 15:43
@SharedQA
SharedQA marked this pull request as ready for review June 15, 2026 16:39
@SharedQA
SharedQA requested a review from a team as a code owner June 22, 2026 19:36
Comment thread src/backend/services/analytics-api/src/domain/metric.rs
Comment thread src/backend/services/analytics-api/src/domain/metric.rs Outdated
Comment thread src/backend/services/analytics-api/src/domain/metric.rs Outdated
Comment thread src/backend/services/analytics-api/src/domain/query.rs Outdated
Comment thread src/backend/services/analytics-api/src/config.rs Outdated

@cyberantonz cyberantonz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs work

Kenan Salim and others added 5 commits June 23, 2026 15:39
…values

Addresses review (cyberantonz): the serialization tests built a struct and then
asserted the value just set was present in the JSON — that tests serde, not our
code. Replaced with tests that each guard a real, non-obvious invariant:

- none_description_is_omitted_not_null: skip_serializing_if omits None (the FE
  distinguishes absent from null — the other half of the triple-state contract).
- metric_summary_never_serializes_query_ref: security — the list/summary shape
  must never carry raw SQL; fires if anyone adds the field.
- create_request_requires_name_and_query_ref: required-field contract — a payload
  missing either is rejected at deserialization, not silently defaulted.

update_description_is_triple_state (the Option<Option> PATCH test) kept as-is.
Verified: cargo test -p analytics-api passes; clippy -D warnings clean.

Signed-off-by: Kenan Salim <ks@constructor.tech>
…gic ones

Addresses cyberantonz's review across the module: tests must be able to fail for
a reason about OUR code, not serde / a constant / an absent field.

Removed (tested the framework, not us):
- metric.rs: the serialize-and-find-the-value tests, the 'summary has no
  query_ref' test (the struct has no such field), the required-field test (serde
  behavior). Kept update_description_is_triple_state — it exercises our custom
  deserialize_optional_nullable (absent/null/value), which serde can't express.
- query.rs: default_top_is_25 (asserting a fn returns its own literal). The
  default stays covered by applies_defaults_when_empty, which proves the field is
  wired to default_top() through real deserialization.
- config.rs: default_helpers + applies_defaults_for_optional_fields (asserting
  defaults equal their literals). Kept explicit_values_override_defaults
  (layering precedence) and missing_required_field_errors (fail-fast on misconfig).

Kept in query.rs: the OData $top/$filter rename mapping, serde(flatten) batch
shape, and lowercase status tag — these guard the external wire contract the FE
depends on (a rename silently breaks it), not 'serde works'.

Verified: cargo test -p analytics-api passes; clippy -D warnings clean.
Signed-off-by: Kenan Salim <ks@constructor.tech>
@ktursunov

Copy link
Copy Markdown
Contributor

Already covered with unit tests coverage

@ktursunov ktursunov closed this Jul 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants