TestServices Internals
TestServices is an experimental bootstrap JavaScript layer in stdlib/sloppy/testservices.js. It deliberately stays small: Docker process control, provider-backed readiness, SQL setup helpers, diagnostics, and cleanup.
Architecture
test code
|
v
TestServices.postgres/sqlServer
|
+-- sloppy/os Process.run -> docker CLI
+-- sloppy/data provider bridge -> readiness/query/migration/reset
+-- TestHost provider/env handoffThe Docker backend is CLI-based. Sloppy does not depend on npm testcontainers, Docker SDK packages, or shell scripts per app.
Docker Backend
The backend calls Docker with argv arrays:
version --format {{json .}}image inspect <image>pull <image>create --name <name> -e ... -p 127.0.0.1::<port> <image>start <container>inspect <container>logs --tail <n> <container>stop --time <seconds> <container>rm --force <container>
Docker assigns host ports unless the caller supplies hostPort. The mapped port is read from docker inspect; TestServices does not reserve a local port by binding and closing it.
Readiness
Readiness is provider-backed:
- PostgreSQL opens
data.postgresand runsselect 1. - SQL Server opens
data.sqlserver, creates the database if missing, and runsselect 1.
If the native provider bridge is unavailable, startup fails with SLOPPY_E_TESTSERVICES_PROVIDER_UNAVAILABLE. This preserves the contract that TestServices proves real database behavior and never returns a fake provider.
Lifecycle
Startup records container id/name, mapped port, readiness attempts, last readiness error, log tail, cleanup errors, and timestamps. Startup failure removes the partial container unless keepContainerOnFailure is set, and records cleanup failures in diagnostics and startup errors.
Service disposal:
- closes provider objects returned by
provider(); - stops the container with a bounded timeout;
- force-removes it;
- records cleanup failures in diagnostics;
- marks disposal complete only after removal succeeds.
dispose() is idempotent after successful removal and is also attached to Symbol.asyncDispose when the runtime provides it. A remove failure makes dispose() throw unless keepContainerOnFailure is set for debugging.
Migrations And Reset
Glob migrations delegate to Migrations.apply. Single .sql files are read through sloppy/fs and executed directly. Lists are sorted before applying.
Reset is intentionally provider-specific:
- PostgreSQL drops and recreates
public. - SQL Server recreates the test database from
master, then reconnects before rerunning migrations.
Redaction
Diagnostics and startup errors redact known passwords and provider connection strings before returning text. The service never places raw passwords in container names.
Docker logs can still contain database image messages outside Sloppy's control; TestServices redacts known service secrets before exposing log tails.
Test Policy
tests/integration/execution/testservices_runtime runs through sloppy run --artifacts for default CI. It uses a fake Docker backend for the deterministic provider-unavailable path and only probes the real Docker CLI as status. Live containers remain opt-in through an explicit environment gate and require Docker plus a V8/native-provider runtime.