Testing
| Kind | Command | Notes |
|---|---|---|
| Unit | make test (Go repositories), pnpm test (apps, entrosity-ui) | Fast; no Docker. |
| Integration | make test-integration (backends) | //go:build integration; testcontainers for Postgres, MinIO and Samba AD. The database is migrated once per package; tests run in rolled-back transactions where possible. |
| LDAP | make test-ldap (entrosity-axis-connector) | LDAPS, StartTLS, paging, OU include/exclude, error codes against Samba. |
| Connector smoke | make smoke-connector (entrosity-infra) | Real connector + Samba + Entrosity Hub + backend: enroll, test connection, sync, AD-only devices, push reaching the connector. |
| End-to-end | make e2e (entrosity-infra) | Both Playwright suites, Axis's (entrosity-axis.frontend/e2e/) and the Hub's (entrosity-hub.frontend/e2e/), against one throwaway stack of Entrosity Hub and Axis. |
| Windows | CI (agent and connector ci.yml, entrosity-infra integration.yml) | //go:build windows tests, MSI install/uninstall, a real agent deploying 7-Zip. |
Access-control tests
- Every portal route has an entry in
entrosity-axis.backend/internal/http/portal/access.go.TestEveryRouteHasAccessRulefails for a route without one, and unclassified routes are refused at runtime. entrosity-axis.backend/internal/http/rbac_matrix_test.gois a table of every route × caller (anonymous, global admin, tenant admin, technician, viewer, other-tenant admin). Add a row whenever you add a route; the test fails if a route has none.- An authorization fuzz test covers 82 cross-tenant cases.
- The matrix and the fuzz test call Axis with product tokens signed by the test harness's fake Hub, as in production.
- Entrosity Hub has its own matrix,
entrosity-hub.backend/internal/http/rbac_matrix_integration_test.go: every route × anonymous, platform admin, organization admin, member and an admin of another organization (organization routes answer 404 to outsiders). Rules live inentrosity-hub.backend/internal/http/api/access.go.
Integration test helpers
testutil.NewServer(t, pg) builds the real application (internal/app)
with production wiring behind a fake Entrosity Hub, and captures e-mails
in srv.Mail:
srv.Platformsigns product and step-up tokens with a key the server trusts, andsrv.PlatformData.Setpublishes an access snapshot forsrv.App.PlatformSync.Sync. The seeding helpers inseed.go(CreateTenant,CreateUser,AddMembership) write users, tenants and roles as the sync would, andsrv.Login(email, …)returns a product token for a seeded user.- Options:
WithStorage,WithReleaseSigning,WithClock,WithMinAgentVersion,WithRemoteTiming,WithRemoteSweep. - The Hub's harness (
entrosity-hub.backend/internal/testutil) has the same shape:NewServer, browser-like clients with a cookie jar (srv.NewClient().MustLogin(email)), captured mail, a settable clock, and seeding helpers for users, organizations and memberships.
Without Docker
Point the tests at an existing PostgreSQL 16 (an owner or superuser URL) and MinIO instead of containers. Each test binary creates and drops its own database; run packages one at a time:
TEST_POSTGRES_URL='postgres://postgres:secret@localhost:5432/postgres?sslmode=disable' \
TEST_MINIO_URL='http://minioadmin:[email protected]:9000' \
go test -p 1 -tags integration ./... # in entrosity-axis.backend or entrosity-hub.backend
Buckets of an external MinIO are emptied once per test binary.
End-to-end specs
| Spec | Covers |
|---|---|
phase1.spec.ts | A platform admin creates organizations with Axis on the Hub; the tenant admin onboarded there is confined to their tenant in Axis. |
phase2.spec.ts | Creates an enrollment token in the UI, starts rmm-simagent (built from entrosity-axis.backend), follows the devices live. |
phase3.spec.ts | Installs a simulated connector, runs the AD wizard, syncs and pushes with live per-target progress. |
phase4.spec.ts | Uploads the fixture MSI, deploys it to simulated agents, follows the progress. |
phase5.spec.ts | Runs a parameterized script on three devices with live output; a low-disk rule opens alerts that are acknowledged and resolve when the rule is relaxed. |
entrosity-infra's scripts/e2e.sh (make e2e) prepares one stack for both suites:
Postgres, mailpit and MinIO (bucket rmm-e2e, winget refresh off);
throwaway databases platform_e2e and rmm_e2e; the Hub's migrations and
first platform admin (E2E_ADMIN_EMAIL, E2E_ADMIN_PASSWORD); the Hub's
API on :8092 (internal :8093) and Axis's API on :8082, which syncs from
the Hub every 2 s. Each suite starts the two Vite servers itself: Axis on
:5177 and the Hub on :5176, which is the browser's origin (the Hub at /,
Axis at /axis, as in production). Both suites run even when the first
fails; logs are dist/e2e-hub.log and dist/e2e-axis.log. The shared
helpers in entrosity-axis.frontend/e2e/hub.ts sign in on the Hub and create tenants as
Hub organizations. Arguments are passed to both playwright test runs.
| Hub spec | Covers |
|---|---|
entrosity-hub.frontend/e2e/hub.spec.ts | A platform admin creates an organization with Axis and invites its admin (and opens Axis's administration); the admin creates an account from the e-mail, opens Axis for the organization from the product list, finds its user pages pointing to the Hub, and signs out in Axis, which ends the Hub session. |
Focused suites
- Deployment engine:
entrosity-axis.backend/internal/deploy/scheduler_integration_test.gosimulates a fleet across time zones, windows, retries and reconnects;targets_integration_test.gocovers target resolution. MSI metadata tests useentrosity-axis.backend/internal/deploy/testdata/rmm-test.msi. - Agent:
entrosity-axis-agent/internal/testserveris a fake backend (enroll, WebSocket, HTTP fallbacks) for testing the full agent loop. Windows collector parsers are tested against recorded PowerShell output inentrosity-axis-agent/internal/inventory/testdata/.GOOS=windows go vet ./agent/...checks Windows-only code on any OS.