Files
nim-namespaced-logging/tests/README.md
T

67 lines
3.8 KiB
Markdown

# Regression tests
These tests assert the intended behavior. Known bugs are ordinary failures,
not expected failures: the tasks should become green as the defects are fixed.
Run from the repository root:
| Command | Coverage |
| --- | --- |
| `nimble test` | All unit, regression, and ThreadSanitizer tests under ORC with threads enabled |
| `nimble testUnit` | Existing embedded unit tests |
| `nimble testRegression` | Handle lifetime, configuration freshness, refresh failure recovery, appender-state cleanup, and writer shutdown |
| `nimble testThreadSafety` | Separate ThreadSanitizer processes for service ownership, last-owner teardown, reconfiguration, custom state, and formatter closures, plus an independent-service control |
`nimble test` attempts every suite even if an earlier suite fails to compile or
run, summarizes the failing suites, and exits unsuccessfully if any suite fails.
The subset commands use the same build and execution procedures as the full run.
Executables are generated in ignored `tests/bin/`. The shutdown child is built
with `-d:multithreaded`; `--threads:on` alone does not enable background writers.
The other tests do not need background I/O to exercise ownership.
The full run and the sanitizer subset require Linux, Bash, GNU `timeout`, and a
C compiler and runtime supporting `-fsanitize=thread`. The sanitizer instruments
the generated Nim C code, including the ORC runtime. A sanitizer report, timeout,
crash, or runtime startup failure causes a nonzero result; consult the diagnostic
to distinguish these.
Each scenario runs separately so one failure does not hide another. To inspect
one scenario after building:
```sh
TSAN_OPTIONS=halt_on_error=1:exitcode=66 timeout 30s tests/bin/thread_safety service
```
The worker start barrier ensures argument setup finishes before the concurrent
operations begin. In `service-lifetime`, workers first acquire local services;
the parent then releases the original handle before allowing them to proceed.
Thread arguments contain borrowed pointers so no hidden owning argument keeps
the service alive. Atomic construction/destruction counters verify that every
tracked appender is released exactly once after the workers join.
`service-reconfigure` exercises concurrent updates and local cache refresh.
The other scenarios retain parent owners until all workers join. Custom-state
and closure tests only read application data; their concurrent writes are the
implicit ownership operations caused by cloning and destruction. The independent
case creates a separate service inside each worker and should pass. Custom-state
and formatter cloning is serialized with a lock, matching configuration refresh;
the copied appenders are used and destroyed outside that lock.
The in-process regression tests are deterministic. The lifetime suite checks
copying, self-assignment, replacement, moving, container copies, and exporting a
handle from a local service. Shutdown tests launch
a fresh process for each destination and check all 10,000 messages after normal
exit, using isolated temporary paths and a 15-second deadline. They exercise the
real exit hook without sleeps to hide queued-message loss. Like the race tests,
the shutdown failure can depend on scheduling; a passing run is not proof of
thread safety or reliable draining.
This suite does not yet force an active producer/channel-close race, separately
exercise the shared `testutil.LoggedMessages` graph, or exhaust ORC cycle-collector
interleavings. It provides targeted regressions for the reproduced ownership
defects and the configuration, cleanup, and shutdown findings.
After the shared-handle implementation, the service sanitizer scenarios, lifetime
suite, and appender-state cleanup regression should pass. The custom-state and
formatter sanitizer cases, `isEnabled` freshness, failed-refresh recovery, and
writer shutdown remain failing regressions for subsequent work.