Files
at-container-registry/pkg/appview/authgate/testhelpers_test.go
T
Evan JarrettandClaude Fable 5.1 0080957a21 remove the runtime test_mode switch; the testmode build tag is the only one
server.test_mode survived the build-tag refactor only to feed five
behavioral branches: the registry's fall-back to the default hold when
the user's hold is unreachable, backfill warning suppression for
external holds, the appview listener close on shutdown, the hold's
relay-crawl skip, and the hold's appview-issuer tolerance. Every one of
them is a "this is a local development build" decision, which is what
the tag already says, and local development has to build with the tag
or nothing resolves. So they read atproto.TestModeBuild now, and the
flag, SetTestMode, IsTestMode, the middleware option, the backfill
constructor parameter, the never-read field on RemoteHoldAuthorizer,
the example and template YAML lines, and the docker-compose env vars
are gone. The registry keeps the fallback as a field seeded from the
constant so the production-path tests can pin it off under the tag.

The 24 SetTestMode calls in tests were dead already: stripping them and
running the affected packages tagged changed nothing.

Tests that resolve a loopback did:web used to t.Fatal naming the tag,
which left a bare `go test ./...` permanently red in five packages.
They now live under `//go:build testmode`: whole-file constraints where
every test needs it, and sibling *_testmode_test.go files holding the
moved tests plus their fixtures where a file mixed. The harness carries
the constraint too, with its package doc in an untagged doc.go so the
package still exists without it. An untagged run compiles those tests
out and passes; make test keeps the tag and runs everything.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UwYzaG3Yy7uA8FbZ5qk3tQ
2026-09-11 11:09:44 -05:00

88 lines
3.1 KiB
Go

package authgate
import (
"context"
"database/sql"
"testing"
"atcr.io/pkg/appview/db"
"atcr.io/pkg/atproto"
"atcr.io/pkg/auth"
)
// newTestDB returns an in-memory libsql DB with the full appview schema
// applied. Tears down on test completion.
func newTestDB(t *testing.T) *sql.DB {
t.Helper()
testDB, err := db.InitDB(":memory:", db.LibsqlConfig{})
if err != nil {
t.Fatalf("InitDB: %v", err)
}
t.Cleanup(func() { _ = testDB.Close() })
return testDB
}
// seedUser upserts a users row and optionally sets default_hold_did.
// Pass "" for defaultHold to leave it NULL.
func seedUser(t *testing.T, d *sql.DB, did, handle, defaultHold string) {
t.Helper()
if err := db.UpsertUser(d, &db.User{DID: did, Handle: handle, PDSEndpoint: "https://pds.example/" + did}); err != nil {
t.Fatalf("UpsertUser(%s): %v", did, err)
}
if defaultHold != "" {
if err := db.UpdateUserDefaultHold(d, did, defaultHold); err != nil {
t.Fatalf("UpdateUserDefaultHold(%s, %s): %v", did, defaultHold, err)
}
}
}
// seedCaptain inserts a single hold_captain_records row.
func seedCaptain(t *testing.T, d *sql.DB, holdDID, ownerDID string) {
t.Helper()
if err := db.BatchUpsertCaptainRecords(d, []db.HoldCaptainRecord{
{HoldDID: holdDID, OwnerDID: ownerDID, Public: false, AllowAllCrew: false},
}); err != nil {
t.Fatalf("BatchUpsertCaptainRecords(%s, %s): %v", holdDID, ownerDID, err)
}
}
// seedCrewMember inserts a single hold_crew_members row with the given
// permissions JSON (pass "" to leave permissions NULL — note that the
// underlying schema may coerce empty strings; pass `"[]"` for an empty
// permissions array).
func seedCrewMember(t *testing.T, d *sql.DB, holdDID, memberDID, permsJSON string) {
t.Helper()
if err := db.BatchUpsertCrewMembers(d, []db.CrewMember{
{HoldDID: holdDID, MemberDID: memberDID, Rkey: "rkey-" + memberDID, Role: "crew", Permissions: permsJSON},
}); err != nil {
t.Fatalf("BatchUpsertCrewMembers(%s, %s): %v", holdDID, memberDID, err)
}
}
// fakeHoldAuthorizer is a no-op auth.HoldAuthorizer stub. The Authorize
// orchestration tests don't exercise the reconciliation closure (the
// closure is nil for our purposes because we don't supply a refresher
// and don't go through ResolveIdentity), so we don't need atomic
// counters — just zero-value returns.
type fakeHoldAuthorizer struct{}
func (fakeHoldAuthorizer) CheckReadAccess(_ context.Context, _, _ string) (bool, error) {
return true, nil
}
func (fakeHoldAuthorizer) CheckWriteAccess(_ context.Context, _, _ string) (bool, error) {
return true, nil
}
func (fakeHoldAuthorizer) GetCaptainRecord(_ context.Context, _ string) (*atproto.CaptainRecord, error) {
return nil, nil
}
func (fakeHoldAuthorizer) IsCrewMember(_ context.Context, _, _ string) (bool, error) {
return false, nil
}
func (fakeHoldAuthorizer) ClearCrewDenial(_ context.Context, _, _ string) error { return nil }
func (fakeHoldAuthorizer) IsCachedCrewMember(_ context.Context, _, _ string) (bool, error) {
return false, nil
}
func (fakeHoldAuthorizer) RecordCrewApproval(_ context.Context, _, _ string) error { return nil }
var _ auth.HoldAuthorizer = fakeHoldAuthorizer{}