Skip to content

chore: more stable outbox metrics tests - #445

Closed
sjvans wants to merge 19 commits into
developfrom
more-stable-outbox-metrics-tests
Closed

chore: more stable outbox metrics tests#445
sjvans wants to merge 19 commits into
developfrom
more-stable-outbox-metrics-tests

Conversation

@sjvans

@sjvans sjvans commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Improve Stability of Outbox Metrics Tests with State-Based Polling

Test

♻️ Refactor: Replaced all fixed-duration wait(150)/wait(600) sleeps in outbox metrics tests with a deterministic, state-based expectEventually() helper that polls via forceFlush(), eliminating race conditions in slower CI environments.

The expectEventually(assertion) function forces the OpenTelemetry metric pipeline to flush (metrics.getMeterProvider().forceFlush?.()) and then re-evaluates the assertion, retrying at short intervals until it passes or a timeout is reached. This ensures assertions are evaluated only after metrics are actually available, rather than relying on arbitrary sleep durations.

Changes

  • test/metrics-outbox.test.js: Added expectEventually() helper and ATTEMPTS_TO_FAIL = 3 named constant; replaced all await wait(...) + bare assertion blocks with await expectEventually(() => { ... }) calls. Comments clarify the rationale for the one remaining wall-clock wait (storage time gauges requiring ≥1 second elapsed).
  • test/metrics-outbox-multitenant.test.js: Same treatment for multi-tenant scenarios — introduced expectEventually(), replaced polling loops and fixed sleeps, removed unused didProcess state tracking, and updated the retry count threshold to use ATTEMPTS_TO_FAIL.
  • test/metrics-outbox-disabled.test.js: Replaced await wait(150) with await metrics.getMeterProvider().forceFlush?.() to deterministically drain the metric pipeline before asserting no metrics were emitted. Also updated the comment describing the console.dir mock.
  • 🔄 Regenerate and Update Summary
PR Bot Information

Version: 1.26.11

  • File Content Strategy: Full file content
  • Correlation ID: 7f9204b3-fd3f-42c5-a682-592d8b722f47
  • Event Trigger: pull_request.edited
  • Summary Prompt: Default Prompt
  • Output Template: Default Template
  • LLM: anthropic--claude-4.6-sonnet

sjvans and others added 17 commits June 25, 2026 21:08
Adds HTTP semantic convention attributes to remote service spans by
wrapping `fetchClient.executeHttpRequest`.

Alternative considered: Using `@opentelemetry/instrumentation-undici`
response hooks to propagate attributes from HTTP child spans. This
approach was rejected as it requires an additional dependency and
creates duplicate spans.

---------

Co-authored-by: D050513 <sebastian.van.syckel@sap.com>
Co-authored-by: sjvans <30337871+sjvans@users.noreply.github.com>
- [x] traces
- [x] metrics
- [x] logs
- [x] #442

---------

Co-authored-by: I548646 <paul.erlenwein@sap.com>
Co-authored-by: Paul <paul.erlenwein@gmail.com>
)

# Improve `VCAP_SERVICES` Service Binding Resolution with Greedy
Matchers

### Chore

🔧 Updated service instance matching for SAP Cloud Logging and Dynatrace
to use greedy (array-based) VCAP matchers, extending the default
matching without breaking existing behavior. Error messages and
documentation have been updated to guide users toward the correct
configuration.

### Changes

* `package.json`: Updated `vcap` matching for `telemetry-to-dynatrace`
and `telemetry-to-cloud-logging` from a single object to an array of
matchers. Dynatrace now matches by `label: "dynatrace"` or `tag:
"dynatrace"`; Cloud Logging matches by `label: "cloud-logging"` or `tag:
"Cloud Logging"`.

* `lib/utils.js`: Improved inline comments to clearly document the
legacy compatibility behavior for `getCredsForDTAsUPS()` and
`getCredsForCLSAsUPS()`. Updated the warning message for Cloud Logging
user-provided services to recommend only the `"Cloud Logging"` tag
(dropped `"cloud-logging"` from the recommendation).

* `lib/logging/index.js`, `lib/metrics/index.js`,
`lib/tracing/index.js`: Improved error messages when credentials are not
found — now explicitly instruct users to ensure the bound service
instance uses the correct tag (`"Cloud Logging"` or `"dynatrace"`).

* `README.md`: Clarified that user-provided service instances for SAP
Cloud Logging must use the tag `"Cloud Logging"` (removed reference to
the legacy `cloud-logging` tag). Added a tip with the `cf
update-user-provided-service` command and a link to CAP's service
binding documentation.

- [ ] 🔄 Regenerate and Update Summary



<details>
<summary>PR Bot Information</summary>

**Version:** `1.26.5`

- Correlation ID: `81bbd7c7-2290-4812-89e9-d178ac318c25`
- Event Trigger: `issue_comment.edited`
</details>

---------

Co-authored-by: sjvans <30337871+sjvans@users.noreply.github.com>
# Fix: Workaround for `cds.cli.command` Bug with `build` Command

### Bug Fix

🐛 Added a workaround to prevent the telemetry plugin from loading when
the `cds build` command is invoked. Due to a bug in `cds.cli.command`,
the `build` command incorrectly resolves to an empty string (`''`),
causing the plugin initialization check to pass unintentionally.

### Changes

* `cds-plugin.js`: Added an early return guard that checks if `build` is
present in `process.argv`. This ensures the plugin exits before
proceeding with initialization when the `cds build` command is used,
mirroring the existing workaround for `cds add`.

- [ ] 🔄 Regenerate and Update Summary



<details>
<summary>PR Bot Information</summary>

**Version:** `1.26.5`

- Correlation ID: `4743ca7e-193a-4675-a529-8872b09ede9e`
- Summary Prompt: [Default
Prompt](https://github.tools.sap/intelligent-insights/i2-pull-request/blob/main/src/services/llm/prompts/summary_instructions_prompt.md)
- LLM: `anthropic--claude-4.6-sonnet`
- Output Template: [Default
Template](https://github.tools.sap/intelligent-insights/i2-pull-request/blob/main/src/services/llm/prompts/summary_default_output_template.md)
- Event Trigger: `pull_request.ready_for_review`
- File Content Strategy: Full file content
</details>

---------

Co-authored-by: hyperspace-insights[bot] <209611008+hyperspace-insights[bot]@users.noreply.github.com>
# Chore: Upgrade to `cds^10` — Migrate Test Config to `.cdsrc.json` and
CDS Profiles

### Refactor

♻️ Migrates test configuration from inline `process.env` overrides to a
dedicated `.cdsrc.json` file and CDS CLI profiles, aligning with the
`cds^10` approach for environment/profile-based configuration. Also
includes test timing optimizations and minor bug fixes.

### Changes

* `.github/workflows/ci.yml`: Commented out the `cds@8` downgrade step;
updated comment to reference `cds@9`.
* `.github/workflows/release.yml`: Added a `REVISIT` comment to remove
the `better-sqlite3` install workaround with `cds^10`.
* `.gitignore`: Removed `test/bookshop/.cdsrc.json` from the ignore list
so it can be tracked in version control.
* `test/bookshop/.cdsrc.json`: New file defining CDS profiles
(`logging`, `metrics`, `metrics-outbox`, `metrics-outbox-disabled`,
`tracing-attributes`, `persistent-outbox`, `without-outbox`)
consolidating telemetry, messaging, and metrics settings previously
scattered across test files.
* `test/bookshop/package.json`: Removed `_outbox` and profile-specific
`[metrics-outbox]`/`[metrics-outbox-disabled]` blocks (now in
`.cdsrc.json`); added `_scheduling: true`.
* `test/logging.test.js`: Removed inline `process.env` overrides for
telemetry/log format; switched to `cds.test(..., '--profile',
'logging')` with a minimal remaining env override for
`cls_custom_fields`.
* `test/metrics.test.js`: Removed `exportIntervalMillis` env override;
switched to `cds.test(..., '--profile', 'metrics')`.
* `test/metrics-outbox.test.js` /
`test/metrics-outbox-multitenant.test.js`: Reduced metric collection
wait times from `300ms` to `150ms`; fixed retry loop bug where both
loops checked `E1` instead of `E1`/`E2` respectively.
* `test/tracing-attributes.test.js`: Removed inline exporter env var;
switched to `cds.test(..., '--profile', 'tracing-attributes')`.
* `test/tracing-messaging-persistent-outbox.test.js`: Renamed `CASE` to
`persistent-outbox`; simplified env setup; marked `describe` block as
`skip` pending vitest migration.
* `test/tracing-messaging-without-outbox.test.js`: Renamed `CASE` to
`without-outbox`; simplified env setup using `outboxed: false`.
* `test/tracing-messaging-with-in-memory-outbox.test.js`: Removed this
test file entirely.
* `test/tracing-messaging.js`: Switched from `cds.test().in(...)` to
`cds.test(..., '--profile', CASE)`.
* `test/tracing.test.js`: Switched from `cds.test().in(...)` to
`cds.test(...)`.

- [ ] 🔄 Regenerate and Update Summary



<details>
<summary>PR Bot Information</summary>

**Version:** `1.26.11`

- Summary Prompt: [Default
Prompt](https://github.tools.sap/intelligent-insights/i2-pull-request/blob/main/src/services/llm/prompts/summary_instructions_prompt.md)
- Correlation ID: `14c5ae4d-4c97-4eff-a004-330c9fdcf2fe`
- Event Trigger: `pull_request.edited`
- File Content Strategy: Full file content
- Output Template: [Default
Template](https://github.tools.sap/intelligent-insights/i2-pull-request/blob/main/src/services/llm/prompts/summary_default_output_template.md)
- LLM: `anthropic--claude-4.6-sonnet`
</details>
@sjvans
sjvans requested a review from PDT42 June 27, 2026 11:35
hyperspace-pr-bot[bot]

This comment was marked as outdated.

Base automatically changed from 2 to main June 29, 2026 17:50
Comment thread .github/workflows/ci.yml Outdated
Comment thread test/bookshop/package.json Outdated
Co-authored-by: sjvans <30337871+sjvans@users.noreply.github.com>
@sjvans
sjvans changed the base branch from main to develop August 7, 2026 07:28
@sjvans

sjvans commented Aug 11, 2026

Copy link
Copy Markdown
Contributor Author

Folding this into #478 (replace console spying with in-memory exporters). Your expectEventually()/forceFlush() polling is exactly right for the timing flakiness and will be carried over there, combined with a new in-memory metric reader (so both the sleeps and the console.dir spy go away). These 3 files were rewritten by #465 since this PR, so it's cleaner to absorb the approach into #478 than to rebase this standalone — will close once #478's metrics work lands. Thanks!

@sjvans

sjvans commented Aug 11, 2026

Copy link
Copy Markdown
Contributor Author

Superseded by #479, which folds this PR's expectEventually() state-based polling together with the in-memory metric reader (the metrics counterpart to #465's span exporter) — replacing both the fixed wait() sleeps and the console.dir spy in one pass. Will close this once #479 lands on develop.

sjvans added a commit that referenced this pull request Aug 11, 2026
… ConsoleMetricExporter (#479)

## What

Consolidates all outbox/metrics test-quality work into one PR (formerly
split as #479 + the stacked #480).

- **In-memory metric reader** —
`test/bookshop/lib/MyInMemoryMetricReader.js`, the metrics counterpart
to `MyInMemorySpanExporter` (#465). Mirrors production **DELTA**
temporality: SUM counters are accumulated across flushes into per-series
running totals; GAUGE datapoints keep the latest absolute value. Wired
via the `metrics-outbox`, `metrics-outbox-disabled`, and `metrics`
profiles in `.cdsrc.json`.
- **Outbox suites off console spying** — the three
`metrics-outbox*.test.js` suites drop the `console.dir` spy and fixed
`wait()` sleeps in favor of the reader + an `expectEventually()`
force-flush polling helper (fails fast if the meter provider isn't
wired). Folds in #445's polling approach.
- **ConsoleMetricExporter unit test** — new
`test/console-metric-exporter.test.js`, a pure unit test of the
exporter's formatting (db.pool table, queue table, other
single-vs-array, tenant variants, host-metrics aggregation,
shutdown→FAILED), mirroring `console-span-exporter.test.js`.
- **`metrics.test.js`** converted from scraping `cds.test.log()` output
to asserting on the in-memory reader's datapoints.

Metrics testing now mirrors the tracing side exactly: a to-console unit
test **plus** in-memory-exporter–based integration tests.

## Why

Follow-up to #465 (span test infra): eliminate console/log spying in the
metrics suite and give `ConsoleMetricExporter` direct unit coverage.

## Review addressed

- Bot review triaged: explicit `COUNTER_METRIC_NAMES` dispatch for
`isCounter`; real wall-clock debounce in the multitenant test; isolation
NOTE on the module-level singletons.
- Dropped the unused debug-log silencer in the multitenant suite (never
asserted). Kept the single-tenant `debugLog` mock — it backs a real
`unknown service` assertion.

Test-only change (no `lib/` change), so no CHANGELOG entry — consistent
with #465/#474/#476.

closes #478

Supersedes #445 and #480 (both folded in here) — I'll close them once
this merges.
@sjvans

sjvans commented Aug 11, 2026

Copy link
Copy Markdown
Contributor Author

Folded into #479 (merged) — its expectEventually state-based polling now lives there alongside the in-memory metric reader. Thanks!

@sjvans sjvans closed this Aug 11, 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