diff options
Diffstat (limited to 'internal/storage/roleconfig_test.go')
| -rw-r--r-- | internal/storage/roleconfig_test.go | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/internal/storage/roleconfig_test.go b/internal/storage/roleconfig_test.go new file mode 100644 index 0000000..b18eaef --- /dev/null +++ b/internal/storage/roleconfig_test.go @@ -0,0 +1,151 @@ +package storage + +import ( + "database/sql" + "errors" + "testing" +) + +func TestCreateRoleConfig_AssignsIncrementingVersions(t *testing.T) { + db := testDB(t) + + v1, err := db.CreateRoleConfig("coder", `{"role":"coder"}`, "human") + if err != nil { + t.Fatalf("CreateRoleConfig v1: %v", err) + } + if v1.Version != 1 { + t.Errorf("expected version 1, got %d", v1.Version) + } + if v1.Status != "draft" { + t.Errorf("expected status draft, got %q", v1.Status) + } + + v2, err := db.CreateRoleConfig("coder", `{"role":"coder","system_prompt":"v2"}`, "human") + if err != nil { + t.Fatalf("CreateRoleConfig v2: %v", err) + } + if v2.Version != 2 { + t.Errorf("expected version 2, got %d", v2.Version) + } + + // A different role starts its own version sequence at 1. + other, err := db.CreateRoleConfig("reviewer", `{"role":"reviewer"}`, "human") + if err != nil { + t.Fatalf("CreateRoleConfig other role: %v", err) + } + if other.Version != 1 { + t.Errorf("expected version 1 for a new role, got %d", other.Version) + } +} + +func TestGetActiveRoleConfig_NoneActive_ReturnsErrNoRows(t *testing.T) { + db := testDB(t) + if _, err := db.CreateRoleConfig("coder", `{"role":"coder"}`, "human"); err != nil { + t.Fatalf("CreateRoleConfig: %v", err) + } + _, err := db.GetActiveRoleConfig("coder") + if !errors.Is(err, sql.ErrNoRows) { + t.Fatalf("expected sql.ErrNoRows, got %v", err) + } +} + +func TestListRoleConfigVersions_OrderedByVersion(t *testing.T) { + db := testDB(t) + for i := 0; i < 3; i++ { + if _, err := db.CreateRoleConfig("coder", `{"role":"coder"}`, "human"); err != nil { + t.Fatalf("CreateRoleConfig: %v", err) + } + } + versions, err := db.ListRoleConfigVersions("coder") + if err != nil { + t.Fatalf("ListRoleConfigVersions: %v", err) + } + if len(versions) != 3 { + t.Fatalf("expected 3 versions, got %d", len(versions)) + } + for i, v := range versions { + if v.Version != i+1 { + t.Errorf("versions[%d].Version = %d, want %d", i, v.Version, i+1) + } + } +} + +// TestActivateRoleConfigVersion_ExactlyOneActive is the invariant test called +// out in the phase spec: activating version 2 while version 1 is active must +// atomically flip version 1 to retired. +func TestActivateRoleConfigVersion_ExactlyOneActive(t *testing.T) { + db := testDB(t) + + v1, err := db.CreateRoleConfig("coder", `{"role":"coder","system_prompt":"v1"}`, "human") + if err != nil { + t.Fatalf("CreateRoleConfig v1: %v", err) + } + v2, err := db.CreateRoleConfig("coder", `{"role":"coder","system_prompt":"v2"}`, "human") + if err != nil { + t.Fatalf("CreateRoleConfig v2: %v", err) + } + + if err := db.ActivateRoleConfigVersion("coder", v1.Version); err != nil { + t.Fatalf("activate v1: %v", err) + } + active, err := db.GetActiveRoleConfig("coder") + if err != nil { + t.Fatalf("GetActiveRoleConfig: %v", err) + } + if active.Version != v1.Version { + t.Fatalf("expected active version %d, got %d", v1.Version, active.Version) + } + if active.ActivatedAt == nil { + t.Errorf("expected ActivatedAt to be set") + } + + // Now activate v2 — v1 must atomically flip to retired, and v2 becomes + // the sole active row. + if err := db.ActivateRoleConfigVersion("coder", v2.Version); err != nil { + t.Fatalf("activate v2: %v", err) + } + + active, err = db.GetActiveRoleConfig("coder") + if err != nil { + t.Fatalf("GetActiveRoleConfig after v2 activation: %v", err) + } + if active.Version != v2.Version { + t.Fatalf("expected active version %d, got %d", v2.Version, active.Version) + } + + all, err := db.ListRoleConfigVersions("coder") + if err != nil { + t.Fatalf("ListRoleConfigVersions: %v", err) + } + activeCount := 0 + for _, row := range all { + if row.Status == "active" { + activeCount++ + } + if row.Version == v1.Version { + if row.Status != "retired" { + t.Errorf("expected v1 to be retired, got %q", row.Status) + } + if row.RetiredAt == nil { + t.Errorf("expected v1 RetiredAt to be set") + } + } + } + if activeCount != 1 { + t.Fatalf("expected exactly 1 active row, got %d", activeCount) + } +} + +func TestActivateRoleConfigVersion_UnknownVersion_Errors(t *testing.T) { + db := testDB(t) + if _, err := db.CreateRoleConfig("coder", `{"role":"coder"}`, "human"); err != nil { + t.Fatalf("CreateRoleConfig: %v", err) + } + if err := db.ActivateRoleConfigVersion("coder", 99); err == nil { + t.Fatalf("expected error activating unknown version") + } + // No row should have been left active. + if _, err := db.GetActiveRoleConfig("coder"); !errors.Is(err, sql.ErrNoRows) { + t.Fatalf("expected sql.ErrNoRows, got %v", err) + } +} |
