Skip to content

ci: enable long-running RETRY conformance tests in nightly contract tests - #212

Merged
tanderson-ld merged 1 commit into
mainfrom
ta/SDK-3007/nightly-long-running-tests
Sep 10, 2026
Merged

tanderson-ld merged 1 commit into
mainfrom
ta/SDK-3007/nightly-long-running-tests

Conversation

@tanderson-ld

@tanderson-ld tanderson-ld commented Sep 4, 2026 •

Copy link
Copy Markdown
Contributor

Requirements

  • I have followed the repository's pull request submission guidelines
  • I have added test coverage for new or changed functionality — n/a, CI configuration only
  • I have validated my changes against all supported platform versions — n/a, the nightly runs a single JDK, unchanged

Related issues

SDK-3007

Describe the solution you've provided

The nightly contract test job has been passing -enable-long-running-tests to the v3 harness step only. The harness's long-running RETRY-conformance tests live on the v2 line (released in harness v2.41.0), so every one of them has been skipping every night. From the 2026-09-03 nightly log:

SKIPPED: streaming/retry behavior/retry after unexpected HTTP error on initial connect (use -enable-long-running-tests to run)
SKIPPED: streaming/retry behavior/retry after unexpected HTTP error on reconnect (use -enable-long-running-tests to run)
SKIPPED: streaming/retry behavior/enters extended-regime backoff after unexpected HTTP error (use -enable-long-running-tests to run)
SKIPPED: streaming/retry behavior/does not permanently stop under sustained unexpected HTTP errors (use -enable-long-running-tests to run)
SKIPPED: streaming/retry behavior/returns to normal-regime backoff after healthy operation (use -enable-long-running-tests to run)
SKIPPED: polling/retry behavior (use -enable-long-running-tests to run)

The test service has declared retry-conformance-fdv1-streaming and retry-conformance-fdv1-polling since #200, so these tests were ready to run — they simply were not being asked to.

Changes:

  • v2 step gets -enable-long-running-tests. This is the substantive change; everything else supports it.
  • timeout-minutes: 120. The job goes from ~11 min to an estimated ~60–90 min, and the 6-hour default is too permissive for a suite whose failure mode is waiting.
  • -junit on both harness steps, at distinct paths, plus if: always() artifact uploads of the results and the test service log. Triaging an hour-long run from raw step logs is impractical.
  • New "Create JUnit output directory" step. The harness writes its JUnit file with os.WriteFile and does not create parent directories; a write error aborts the run, so -junit requires the directory to exist first.
  • Notify on any non-clean pass rather than only failure, with the actual result included in the message, so a timeout or cancellation is not silently swallowed.

On the history here: the flag originally applied to both harness versions (#136) and was narrowed to v3-only the next day (#139). That was correct at the time — the v2 long-running tests did not exist yet. #164 faithfully preserved the narrowing when migrating to the shared action. This restores v2 coverage now that there is something there to run.

Describe alternatives you've considered

  • Splitting the long-running tests into a separate job, so a timing flake cannot mask the fast suite. Not done: it duplicates build and service startup, and the fast suite costs about a minute inside the slow job. Worth revisiting if the first couple of weeks show flakiness.
  • A concurrency group to stop a manual dispatch overlapping the scheduled run. Rejected: GitHub-hosted jobs each get their own ephemeral VM, so concurrent runs share no port and no state. A group would only queue a dispatch behind an in-flight ~90-minute run, or silently cancel a superseded pending run — which would obstruct the dispatch-based validation this change relies on.
  • run_tests: 'false' on the shared CI action to skip duplicate unit tests. Rejected after measuring: gradlew build already runs them (~3.5 min), and the separate Run Tests step is :test UP-TO-DATE in one second. It would have saved a second, not the ten minutes I initially assumed.

Additional context

  • Expect a much longer nightly. These tests wait on real RETRY backoff timing (a 5-minute extended-regime delay with up to 50% jitter) and the harness runs tests sequentially, so the runtime is almost entirely sleeping. Failures are slower than passes: a regression that stops retrying makes each scenario burn its full timeout instead of returning early.
  • Validation before merge: dispatch this workflow against this branch and confirm zero use -enable-long-running-tests to run lines —
    gh workflow run nightly-contract-tests.yml --ref ta/SDK-3007/nightly-long-running-tests. That run takes about an hour.
  • The Slack notification wiring is unchanged in shape. Note the webhook has not been functional, so failures are currently discoverable only from the Actions tab; fixing that is tracked separately and deliberately out of scope here.
  • The v3 harness step stays pinned at v3.0.0-alpha.6; bumping it would pull in new FDv2 tests and require re-validating the FDv2 suppressions.
  • actions/checkout@v3 in this workflow is flagged by actionlint as too old. Pre-existing on main and left alone here.

Note

Overview
The nightly contract test job now runs v2 harness long-running RETRY conformance tests by adding -enable-long-running-tests to the v2 step (they were previously skipped while only v3 had the flag).

To support ~hour-long runs, the main job gets a 120-minute timeout, JUnit output via -junit on both v2 and v3 steps (with a junit/ directory created first), and if: always() artifact uploads for JUnit XML and the contract test service log.

Slack notification now fires on any non-success outcome (timeout/cancel included) and reports the actual job result instead of only hard failures.

Reviewed by Cursor Bugbot for commit bd06463. Bugbot is set up for automated code reviews on this repo. Configure here.

…ests

The nightly job passed -enable-long-running-tests to the v3 harness only,
but the long-running RETRY-conformance tests live on the v2 line (harness
v2.41.0). All six groups were skipping every night.

Also adds a 120-minute job timeout, JUnit output on both harness steps at
distinct paths with artifact uploads, and broadens the Slack notification
to any non-clean pass. The harness writes its JUnit file with os.WriteFile
and does not create parent directories, so a mkdir step is required.

SDK-3007
@tanderson-ld
tanderson-ld requested a review from a team as a code owner September 4, 2026 20:21
@tanderson-ld
tanderson-ld merged commit c348d3f into main Sep 10, 2026
26 checks passed
@tanderson-ld
tanderson-ld deleted the ta/SDK-3007/nightly-long-running-tests branch September 10, 2026 17:39
tanderson-ld added a commit to launchdarkly/dotnet-core that referenced this pull request Oct 27, 2026
**Requirements**

- [x] I have followed the repository's [pull request submission
guidelines](../blob/main/CONTRIBUTING.md#submitting-pull-requests)
- [ ] I have added test coverage for new or changed functionality — n/a,
CI configuration only
- [ ] I have validated my changes against all supported platform
versions — n/a, the nightly runs a single target by design

**Related issues**

Tracked in Jira under the RETRY-conformance epic. The issue key is
omitted from this body and commit deliberately: the ticket also requires
the FDv2 failures below to be tracked, and that follow-up ticket does
not exist yet, so an auto-close on merge would be premature.

Counterparts already merged: java-core [PR
212](launchdarkly/java-core#212) and
go-server-sdk [PR
454](launchdarkly/go-server-sdk#454).

**Describe the solution you've provided**

The harness gates its RETRY-conformance and FDv2 long-running tests
behind `-enable-long-running-tests`, because they wait on real backoff
timing and take about an hour. Per-PR CI does not pass it, so none of
them have ever run for this SDK — even though the contract test service
has declared `retry-conformance-fdv1-streaming` and
`retry-conformance-fdv1-polling` since the RETRY work landed.

Two changes:

- **`.github/actions/contract-tests/action.yml`** — new
`enable_long_running_tests` input, appended to the params of both
harness legs. It defaults to `'false'`, so `sdk-server-ci.yml` and
`sdk-client-ci.yml` render byte-identical params to today.
- **`.github/workflows/sdk-server-nightly.yml`** — new. `schedule` at
04:00 UTC plus `workflow_dispatch`, single runner, `timeout-minutes:
120`, test service log uploaded on `always()`.

> [!WARNING]
> **This job is expected to fail on three tests**, all on the FDv2 leg:
> ```
> streaming/fdv2/recoverable fallback to secondary synchronizer
> streaming/fdv2/recoverable fallback with recovery
> streaming/fdv2/permanent fallback with recovery
> ```
> These are deliberately **not** suppressed. A nightly that goes red on
a real defect is the point — that is how the equivalent Go defect was
found and fixed. **More than three failures means something else
broke.**

Worth knowing: these are the *same three* tests java-core suppresses in
`test-supressions-fdv2.txt`, labelled there as "pending spec alignment
between Go and Java." That label looks wrong — go-server-sdk passes all
three, so this is a shared Java/.NET implementation gap rather than a
spec disagreement. A follow-up ticket covering both SDKs is pending.

**Describe alternatives you've considered**

- **Suppressing the three FDv2 failures** so the job is green from day
one. Rejected: it defeats the purpose, and java-core is the cautionary
case — the same three have been suppressed there since February and
never revisited.
- **A standalone nightly workflow** duplicating the build and launch
steps instead of extending the shared action. Rejected: the dotnet
build/launch sequence is non-trivial and already lives in the composite;
an additive input with a safe default keeps it in one place.
- **JUnit XML artifacts**, as the Java and Go nightlies emit. Dropped:
`-junit` is a harness flag unrelated to the .NET toolchain, GitHub
Actions does not parse an uploaded JUnit file without a separate
reporter action, and the harness already prints failing test names to
the job log.

**Additional context**

Verified locally against the real service (`dotnet-server-sdk
8.17.2.0`), replaying the exact params the composite renders:

- **v2 leg** (harness v2.41.0): all tests passed, 4912 total, 17
skipped, **4895 ran**.
- **v3 leg** (harness v3.2.0-alpha.13): 4930 total, 12 skipped, 4918
ran, **3 failures** — the three above.
- **Zero** `use -enable-long-running-tests to run` skip lines on either
leg, confirming the flag reaches both.

So the RETRY-conformance work in this SDK passes in full; the failures
are confined to FDv2 synchronizer fallback and recovery.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Overview**
> Adds a **nightly** Server SDK contract-test workflow and a way to turn
on harness tests that wait on real retry backoff (~1 hour), which per-PR
CI has never run.
> 
> The shared **`.github/actions/contract-tests`** composite gains an
**`enable_long_running_tests`** input (default **`false`**). When set to
**`true`**, both the standard and FDv2 harness legs append
**`-enable-long-running-tests`** to **`extra_params`**, so existing
**`sdk-server-ci`** / **`sdk-client-ci`** jobs stay unchanged.
> 
> **`sdk-server-nightly.yml`** runs daily at 04:00 UTC (plus
**`workflow_dispatch`** with optional branch), uses a **120-minute** job
timeout, invokes the composite with **`run_fdv2_tests`** and
**`enable_long_running_tests`** enabled, and always uploads
**`test-service.log`**.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
ac8a365. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
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.

2 participants