Development¶
Build and test¶
sbt compile # all published modules, Scala 3
sbt +test # Scala 2.13 and 3
sbt scalafmtAll # format
sbt conformance/test # the OpenFeature spec's gherkin suite, via Cucumber
sbt conformanceZioBdd/test # the same suite via zio-bdd (JDK 22+)
sbt mimaReportBinaryIssues # binary compatibility with the last release
The examples/ projects are not published, but CI compiles them:
| Project | What it shows |
|---|---|
examplesDocs |
Every code sample on this site, plus tests that run them |
examplesTestkitApp |
Unit-testing a flag-driven service with TestFeatureProvider |
examplesOfrepInitTimeout |
An OFREP-backed app with an init timeout and a circuit breaker |
Mutation testing¶
sbt core/stryker runs stryker4s on core: it makes
small deliberate changes to the code (flipping a condition, swapping an operator) and checks that some test fails for
each. The score and the surviving mutants are in core/target/stryker4s-report/. A full run takes hours, so CI runs it
weekly (the Mutation testing workflow, also startable by hand) and never on a pull request; the score is
informational and never fails the build. To try it on a few files, narrow mutate in stryker4s.conf locally.
Property tests¶
LifecycleModelSpec in the testkit generates sequences of lifecycle actions (swaps to providers that start, fail,
hang or start slowly, provider events, shutdown, an interrupted swap) and runs each against a real FeatureFlags,
checking after every step that the status, the provider name and the evaluations agree with a model written from
Lifecycle and events. It also checks that the scope closes within 5 seconds and leaves no fiber or
thread behind. Pull requests run 25 sequences; the weekly Property tests workflow (also startable by hand) runs 300.
Set LIFECYCLE_MODEL_SAMPLES to choose the count locally:
A failure prints the shrunk sequence. Add it to the spec's regressions suite as an explicit list, not as a seed.
Provider fault tests¶
provider-fault-tests runs the real OFREP and Optimizely providers through
rift-scala's in-process TLS intercept proxy, while scripted network
faults (rejected credentials, 503, 429, a connection reset, a stalled response, a truncated or non-JSON body)
play out. It asserts what the library does about each: a typed error or the fallback's answer, in bounded time. See
Testing real providers for the approach.
It is a dev-machine check, by design:
- It is not aggregated into the root project, so
sbt testandsbt +testnever run it. - CI only compiles it (
providerFaultTests/Test/compile). No CI job runs its tests, and none holds a secret for it. - It needs JDK 22 or later, for rift's native engine. On a JDK where the engine cannot load, the suites are reported as ignored. The tests make no external network calls: the proxy and the stand-in servers are in-process.
The module enables the sbt-rift plugin, which writes a throwaway CA and truststore under
provider-fault-tests/target/rift and points the forked test JVM at them.
The documentation site¶
The site is built with MkDocs Material from docs/, and published
to GitHub Pages from main.
Code samples are not written in the pages. They live in examples/docs/src/main/scala-3/snippets/ (and, for the rift
code on the real-providers page, provider-fault-tests/src/test/scala-3/snippets/), between
--8<-- "File.scala:name". So every sample compiles, and examples/docs/src/test runs the ones that can run on
their own and checks what the page says about them.
sbt examplesDocs/test # compile and check the samples
pip install -r requirements-docs.txt
mkdocs serve # preview at http://127.0.0.1:8000
mkdocs build --strict # what CI runs: fails on broken links and missing snippets
The animations are SVG files generated by the Python scripts in scripts/visuals/, one per animation, on top of the
small toolkit in hud.py. Edit the script, not the SVG, then regenerate:
CI fails if a committed SVG is out of date with its script.
Releasing¶
See RELEASING.md.