3 Commits
Author SHA1 Message Date
cgalo5758 eb4a7552bd Pin every route's pattern and answer through the router
No production file changes. authtest gains Cookie, which commits a session
and returns its cookie, for a handler wrapped in the session middleware,
such as the whole router, where Get and Post cannot put the session on the
request's context. docs/testing.md names it and the kit table's authtest
row says "signed-in sessions, their cookies, and in-process requests".

internal/server/new_handler_test.go (no database) builds the router from a
configured profile and a bare one (no Stripe key), with a fake route mount
and two UI mounts, and adds five tests. TestNewHandlerRouteTable writes one
block per registered pattern (the 97 literal HandleFunc patterns the lint
scan finds in internal/server and internal/auth, plus the two static-file
Handle registrations and the fake mount's three routes) to
testdata/routes.golden: the pattern the mux resolves a probe path to, and
the answer to an anonymous request, a cross-site request for a method that
changes state, and a signed-in member where the handler answers before any
read; then eight extra probes and the bare profile's checkout row. The
golden was written once with -update and read against the code: every
operator row answers 302 /login anonymously and 403 Forbidden to the
member, the cross-site writes answer the CSRF refusal except the fake
webhook (204), the two wrong methods and the bare checkout resolve to / and
the styled 404, and the body one byte over 1 MiB answers 413.
TestNewHandlerTrustsTheBaseURLOrigin, TestNewHandlerRefusedSignInIsStyled,
TestNewHandlerRefusesAMountTemplateOutsideItsKey and
TestNewHandlerPassesDepsToMounts cover the base URL's origin, the styled
refused sign-in, the key-prefix refusal and the Deps a mount is handed.

Shown to change no output: no production file is touched, and the names and
results of internal/server and internal/testkit equal the parent's apart
from the five new tests, which pass three runs in a row. The 47 breaks of
the plan, each applied to the new side after a green control run, are all
caught.

Left unprobed:
- The answers the golden records that code outside the router produces
  (each handler's own answer, the auth handlers, the operator role guard,
  each middleware's behaviour): each has its own tests, and no edit to the
  router changes them; the golden holds them so a change shows.
- middleware.Timeout(32s): a short value races fast handlers, and a probe of
  the real value waits 32 seconds.
- middleware.Logging and the order of RequestID before it: they write a log
  line no test reads.
- The http.Server fields: Start keeps them, and nothing builds the server in
  a test.
- The dashboard's root-only check: a later commit probes it.
- The real integrations' routes (FedWiki, the Stripe webhook, Discourse):
  they mount from cmd/start.go, and the fake mount stands in.
- The Config cmd/start.go builds (including StripeKeyMode and BaseURL) and
  the Start call with its exit path: no test builds the command's Config;
  these tests build their own.
2026-10-09 21:23:00 -05:00
cgalo5758 3ebe977eb8 Build the plan-management e2e test through the kit
TestMVPPlanManagement and TestMVPPlanManagement_ViaHTTP build their sets,
products, ladder, tiers, user, person, organization and pool through world,
which fails at the verb on any error; the writes whose errors were
discarded now stop the test. world gains Ladder (a ladder and its tiers in
argument order, one materializing transaction), OrgType (the one raw INSERT;
the key is the name, a hyphen and the last twelve digits of the World's
suffix, because the column holds twenty characters, and the display name
carries the whole suffix) and DefaultLadder (the console's
UpdateOrgTypeDefaultPlanLadder, so the raw INSERT writes only what no console
act writes). The operator session comes from authtest.NewSessionManager and
authtest.SignIn, with the operator role added by the harness. doGet and
doPost become authtest.Get and Post, with authtest.PathValue in place of
SetPathValue; Post sends the form content type and no HX-Request, so a native
create still answers 303. The ViaHTTP test's eight phases are methods on the
harness, called in order, with their state on the harness; no subtests are
added. The gocognit exclusion for ViaHTTP and its step header leave
.golangci.yml.

A comment that called the failed expiration scheduling "simply skipped" now
says the page answers 200 with the failure banner (a comment fix that rides
along). No assertion is tightened.

TestMVPPlanManagement's fixtures used to roll back with its transaction; they
are committed now and stay in the e2e database, and ViaHTTP runs on top of
them. No ViaHTTP assertion reads them. The acts after the fixtures still run
in the test's rolled-back transaction.

Rows differ from the old fixtures in ways no assertion reads: names carry the
World's suffix (the old products had none) and the person is HTTPOperator;
sets are active (were inactive); persons are unverified (were verified); the
pool is the default pool (Default, key default; was default with no key);
org type keys are name plus twelve digits; the first test's type gets its
default by an update (was one INSERT); the session holds every key a sign-in
writes. Fixture dumps before and after are equal apart from these.

A fixture failure now names the verb: the old tests failed later and
elsewhere (the next checked call in the aborted transaction, a panic in
uuid.MustParse on an empty id, or phase 2's 422), the new ones fail at the
verb. Failure messages of the checked writes change with the move into the
builder ("create org: ..." becomes "create organization HTTP Org: ...").

32 breaks, each failed the new test; 31 failed the old test at the parent
(the 32nd breaks world.DefaultLadder, new in this commit). They are one
handler break per phase (two for phase 1), one per fixture verb in each test,
and one per request helper (form content type, HX-Request, path values on
POST and GET) and for the session, each on both sides. Phase 7 drives no
handler; its break caps the transitions read, and it failed both tests.
2026-10-08 18:46:10 -05:00
cgalo5758 f8f9551ddd Build the FedWiki tests' fixtures through the kit
Adds internal/testkit/world (New, Providers, Person, Org, Workspace,
Product, Rule, Confer, Person.SignIn), internal/testkit/authtest
(NewSessionManager, SignIn) and internal/integrations/fedwiki/fedwikitest
(the environment, tenant, limit and usage, operator root, site rows), and
moves the FedWiki fixtures onto them: newReqEnv, setupQuotaFixture,
newReconcileTestEnv, siblingWorkspace, governFedwikiLimit (Product, Rule,
Confer, no materialization), newSiteEnv, newClaimTestDB (its raw provider
insert goes), seedOperatorSites, newMemberWorkspace, seedUnderstatedQuota,
newTestWorkspace, seedCountedWorkspace and addSiblingWorkspace.
newReconcileDomainsDB and setupReconcileRoot had nothing left to move. The
six sessions the FedWiki web tests build go through authtest. The import
guard covers the three packages, and scripts/deadcode-testonly.txt lists
them.

The six hand-written lock-wait loops become dbtest.AwaitLockWait
(lifecycle_db_test.go, registration_db_test.go, invoice_reconcile_test.go,
stamp_db_test.go, and the two record-swap tests in requests_db_test.go and
swap_record_db_test.go). Backend gains BlockedBy, Query and Abort. The
registration loop is not a verbatim move: its select matches by query text
within the current database and its done check becomes the Abort probe, as
do the two record-swap loops, each keeping its message ("registration
finished (%v) while the first key was held", "the record finished without
writing the activated site's status: %v", "the record finished without
waiting on the parked request: %v"). Kept weaker on purpose: the
never-waited messages are now the helper's, which names the selection
("backend N never waited on a lock" for the pid loops, "no backend waited on
a lock held by backend N" for the record swaps, "no backend running a
statement containing %q waited on a lock" for the registration and invoice
loops), the record-swap and stamp bounds are the helper's ten seconds (were
the tests' thirty), the stamp loop accepts any waiting count (was exactly
one for its pid), and the invoice loop matches the statement text anywhere
in the query (was its prefix). TestDispatchStampsLockRecordsInOneOrder drops
from cognitive complexity 39 to 31; its pin is re-pinned to 31.

Names and results of the three FedWiki packages, internal/integration,
internal/workflows/desiredstate and internal/integrations/stripe/workflows
equal the parent's apart from the new tests (the import guard's forbidden
list with its three subtests, and the lock helper's selection test with its
three subtests and its Abort test) and one change: the three
TestReconcileDomains* tests in internal/integrations/fedwiki now pass on a
freshly reset database. They failed there at the parent, alone and in the
package run, because nothing had registered FedWiki; the fixture now does
(#33).

Fixture equivalence (each fixture run alone on a reset database, every table
of core, fedwiki and domains dumped before and after). Differences, none
read by an assertion: names and addresses carry the builder's shape
(organization "<name> <suffix>", email "<name>-<suffix>@example.test",
subject "sub-<name>-<suffix>"; the display name is the label for tenant
fixtures); the pool is the organization's default pool (name "Default", key
default, auto-managed) where the fixtures wrote a bare one; a workspace now
sits in the organization's default pool through a pool assignment where
newMemberWorkspace, seedOperatorSites and the claim fixtures wrote neither
(seedOperatorSites gains two pools and two assignments); every FedWiki
fixture registers FedWiki and the System tenant, which adds the provider row
(or fills operator_surface_path on the row a claim fixture inserted), the
operations, connection, state and outbox rows, the System tenant's user,
person, 'system' organization type, organization and workspace, and
refreshes the fedwiki_sites resource key; archived sites carry archived_at,
as the status query sets it; sites are minted under a database-minted id;
governing a limit goes through the rule-change function, which adds a
set-change row. Claim tokens are random in both.

25 breaks: 19 failed the old test at the parent and the new test here (one
code break per FedWiki test file in the function it pins, and one per
converted lock wait with the lock removed; the three loops with an Abort
probe fail through it with their own message), and six on the kit alone
failed the new test. No assertion in a test body changed.
2026-10-08 02:43:55 -05:00