package aioe import ( "context" "errors" "testing" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgconn" "github.com/missionworkforce/missionmatch/internal/modules/matching/engine" ) // fakeRow serves one scripted answer to LoadActiveWeightsOnTx: either an error, or a weight map plus a // profile version. It is the whole surface the loader touches, so the loader's decision logic is provable // without a database. type fakeRow struct { err error raw map[string]string version int } func (r fakeRow) Scan(dest ...any) error { if r.err != nil { return r.err } if len(dest) != 2 { return errors.New("fakeRow: unexpected destination count") } m, ok := dest[0].(*map[string]string) if !ok { return errors.New("fakeRow: first destination is not a weight map") } v, ok := dest[1].(*int) if !ok { return errors.New("fakeRow: second destination is not a version") } *m = r.raw *v = r.version return nil } // fakeTx satisfies pgx.Tx so the loader can be exercised in a pure unit test. Only QueryRow is real; // every other method panics, which is a test only assertion that the loader touches nothing else. This is // test scaffolding, not a request path, so the CLAUDE.md no panics rule does not apply here. type fakeTx struct{ row fakeRow } func (t fakeTx) QueryRow(context.Context, string, ...any) pgx.Row { return t.row } func (fakeTx) Begin(context.Context) (pgx.Tx, error) { panic("unused") } func (fakeTx) Commit(context.Context) error { panic("unused") } func (fakeTx) Rollback(context.Context) error { panic("unused") } func (fakeTx) CopyFrom(context.Context, pgx.Identifier, []string, pgx.CopyFromSource) (int64, error) { panic("unused") } func (fakeTx) SendBatch(context.Context, *pgx.Batch) pgx.BatchResults { panic("unused") } func (fakeTx) LargeObjects() pgx.LargeObjects { panic("unused") } func (fakeTx) Prepare(context.Context, string, string) (*pgconn.StatementDescription, error) { panic("unused") } func (fakeTx) Exec(context.Context, string, ...any) (pgconn.CommandTag, error) { panic("unused") } func (fakeTx) Query(context.Context, string, ...any) (pgx.Rows, error) { panic("unused") } func (fakeTx) Conn() *pgx.Conn { panic("unused") } func goodWeights() map[string]string { out := make(map[string]string, len(Dimensions)) for dim, d := range DefaultWeightsMap() { out[dim] = d.String() } return out } // TestLoadActiveWeightsNoProfileReturnsDefaults pins the ONE case that legitimately falls back: the tenant // has no active profile at all, so the frozen global default is the truth and the global.default label is // an accurate statement in the audit trail. func TestLoadActiveWeightsNoProfileReturnsDefaults(t *testing.T) { w, label, err := LoadActiveWeightsOnTx(context.Background(), fakeTx{row: fakeRow{err: pgx.ErrNoRows}}) if err != nil { t.Fatalf("no active profile is not an error, got %v", err) } if label != engine.GlobalDefaultProfileVersion { t.Fatalf("label = %q, want %q", label, engine.GlobalDefaultProfileVersion) } if err := w.Validate(); err != nil { t.Fatalf("default weights must validate: %v", err) } } // TestLoadActiveWeightsSurfacesUnreadableProfile is the regression this fix exists for. Every one of these // inputs means an active profile EXISTS and could not be turned into usable weights. Swallowing any of // them scored every candidate in the request on default weights while the audit trail stamped // weight_profile global.default, a false record for an automated employment decision tool: it claims no // tenant profile was in effect when one was. func TestLoadActiveWeightsSurfacesUnreadableProfile(t *testing.T) { missingDim := goodWeights() delete(missingDim, "skills") badDecimal := goodWeights() badDecimal["clearance"] = "not a decimal at all" notNormalized := goodWeights() notNormalized["clearance"] = "0.90" // the six weights no longer sum to one, so Validate rejects them cases := []struct { name string row fakeRow }{ {"scan failed on a malformed jsonb", fakeRow{err: errors.New("cannot scan jsonb into map[string]string")}}, {"connection failed mid read", fakeRow{err: errors.New("conn closed")}}, {"a dimension is missing", fakeRow{raw: missingDim, version: 3}}, {"a dimension is not a decimal", fakeRow{raw: badDecimal, version: 3}}, {"the weights fail engine validation", fakeRow{raw: notNormalized, version: 3}}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { _, label, err := LoadActiveWeightsOnTx(context.Background(), fakeTx{row: tc.row}) if err == nil { t.Fatal("an unreadable ACTIVE profile must be an error, never a silent default") } if !errors.Is(err, ErrActiveProfileUnreadable) { t.Fatalf("error must be typed ErrActiveProfileUnreadable so callers can tell it from no profile, got %v", err) } if label != "" { t.Fatalf("a failed load must stamp no profile label at all, got %q", label) } }) } } // TestLoadActiveWeightsReturnsTenantProfile proves the happy path still stamps the tenant version, so the // fix did not turn a usable profile into a failure. func TestLoadActiveWeightsReturnsTenantProfile(t *testing.T) { w, label, err := LoadActiveWeightsOnTx(context.Background(), fakeTx{row: fakeRow{raw: goodWeights(), version: 7}}) if err != nil { t.Fatalf("a readable active profile must load: %v", err) } if label != ProfileLabel(7) { t.Fatalf("label = %q, want %q", label, ProfileLabel(7)) } if err := w.Validate(); err != nil { t.Fatalf("loaded weights must validate: %v", err) } }