Skip to content

test(priceOracle): unit tests for median, anomaly detection, and aggregation#63

Open
storm-beyndtech wants to merge 1 commit into
SmartDropLabs:mainfrom
storm-beyndtech:test/price-oracle-unit-tests
Open

test(priceOracle): unit tests for median, anomaly detection, and aggregation#63
storm-beyndtech wants to merge 1 commit into
SmartDropLabs:mainfrom
storm-beyndtech:test/price-oracle-unit-tests

Conversation

@storm-beyndtech

Copy link
Copy Markdown

Summary

Adds unit test coverage for the core price oracle business logic in
src/services/priceOracle.js — median aggregation, temporal anomaly
detection, and multi-source fan-out. Closes #7.

Coverage for priceOracle.js: 98% (acceptance gate is 80%). The suite
mocks cache, the three price sources, config, and logger, so it needs
no external services.

Heads-up for the reviewer

  • A latent bug surfaced while writing these tests and is fixed here.
    fetchFreshPrice mapped a non-existent .name field over source results
    (which expose .source), so sources_attempted was always
    [undefined, …] on every fresh fetch — and that value was cached and
    served. It was never filed because the existing test/prices.test.js stubs
    the whole oracle, so this line had never run under assertion. Fixed in the
    same change since it lives in the function under test.
  • detectAnomaly is temporal and log-only. It compares the current
    aggregate against the last cached aggregate over time; it does not
    exclude an outlier source from the median, and its return value is
    discarded by fetchFreshPrice. The tests document this actual behavior
    rather than an assumed cross-source rejection scheme.

Changes

  • test/priceOracle.test.js — 34 tests:
    • median — empty/single/even/odd, non-mutation, numeric (not lexical)
      sort, single-outlier resistance
    • detectAnomaly — no-history, below / at / above the strict-> 20%
      threshold, symmetric down-moves, re-store-on-anomaly, issuer-scoped keys,
      cache read/write failure branches
    • fetchFromAllSources — all-succeed, partial failure, all-fail, null/zero
      filtering, single healthy source (no quorum rule)
    • getPrice — cache hit (fresh + stale is_stale flag), cache miss →
      fresh fetch + write-back, cache-read-throw → redis_unavailable
    • fetchFreshPrice — unavailable shape, anomaly path, redisUnavailable
      short-circuit, write-fail degradation
    • refreshAllCachedPrices — not-connected skip, scan + refresh (history
      keys excluded), scan-throw abort
  • src/services/priceOracle.js
    • Export median / detectAnomaly / fetchFromAllSources for unit testing
    • Fix r.namer.source in fetchFreshPrice (the bug above)
  • .gitignore — ignore generated coverage/ output

Test suite note

The repository's broader suite has pre-existing failures that require Redis /
Postgres (and a config.test.js that spawns subprocesses). For reference:

Failed suites Failed tests
main (baseline) 19 25
this branch 18 2

The branch is strictly better, and none of the remaining failures are
introduced here. The new priceOracle suite passes fully on its own.

Acceptance criteria

  • Test runner with npm test (Jest — already configured)
  • median fully tested (edge cases included)
  • detectAnomaly tested below/at/above threshold
  • fetchFromAllSources tested with partial failures
  • getPrice tested for cache hit and miss paths
  • Coverage ≥ 80% for priceOracle.js (98%)

…aggregation

Covers the core oracle business logic (closes SmartDropLabs#7):
- median: empty/single/even/odd, non-mutation, numeric sort, outlier resistance
- detectAnomaly: no-history, below/at/above the strict-`>` 20% threshold,
  symmetric down-moves, re-store-on-anomaly, issuer-scoped keys, cache
  read/write failure branches
- fetchFromAllSources: all-succeed, partial failure, all-fail, null/zero
  filtering, single healthy source (no quorum rule)
- getPrice: cache hit (fresh + stale flag), cache miss -> fresh fetch +
  write-back, cache-read-throw -> redis_unavailable
- fetchFreshPrice: unavailable shape, anomaly path, redisUnavailable
  short-circuit, write-fail degradation
- refreshAllCachedPrices: not-connected skip, scan + refresh (history keys
  excluded), scan-throw abort

Coverage for priceOracle.js: 98% (gate is 80%). Suite mocks cache, the three
price sources, config, and logger; needs no external services.

detectAnomaly is temporal (compares the aggregate to the last cached aggregate)
and log-only -- it does not exclude an outlier source from the median. Tests
document this actual behavior.

Also:
- Export median/detectAnomaly/fetchFromAllSources for unit testing.
- Fix latent bug: fetchFreshPrice mapped a non-existent `.name` field over
  source results (which expose `.source`), so sources_attempted was always
  [undefined, ...] on every fresh fetch and was cached and served. The new
  tests surfaced it.
- Ignore generated coverage/ output.
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.

Write unit tests for price oracle median aggregation and anomaly detection

1 participant