package oltp
import (
"reflect"
"strings"
"testing"
)
// RFC 0009 §verdicts: required checks match branches the way protection
// does — names or globs, every matching rule applies — and a rule with
// no checks is a removed rule.
func TestRequiredChecksMatchLikeProtection(t *testing.T) {
db := testDB(t)
must := func(err error) {
t.Helper()
if err != nil {
t.Fatal(err)
}
}
must(db.SetCheckRule("r", "trunk", []string{"test", "build"}, ""))
must(db.SetCheckRule("r", "release-*", []string{"test", "sign"}, "premerge"))
if got := db.RequiredChecks("r", "trunk"); !reflect.DeepEqual(got, []string{"build", "test"}) {
t.Fatalf("trunk: %v", got)
}
if got := db.RequiredChecks("r", "release-1.2"); !reflect.DeepEqual(got, []string{"sign", "test"}) {
t.Fatalf("glob: %v", got)
}
if got := db.RequiredChecks("r", "feature"); got != nil {
t.Fatalf("unmatched branch requires %v", got)
}
if db.PremergeMode("r", "trunk") || !db.PremergeMode("r", "release-1.2") {
t.Fatal("premerge mode does not follow the matching rules")
}
// Overlapping rules union without repeating.
must(db.SetCheckRule("r", "*", []string{"lint", "test"}, ""))
if got := db.RequiredChecks("r", "trunk"); !reflect.DeepEqual(got, []string{"lint", "test", "build"}) {
t.Fatalf("union: %v", got)
}
// Blanking removes.
must(db.SetCheckRule("r", "*", nil, ""))
must(db.SetCheckRule("r", "trunk", nil, ""))
if got := db.RequiredChecks("r", "trunk"); got != nil {
t.Fatalf("removed but requires %v", got)
}
}
// RFC 0009 §external-ci: tokens authenticate reports; states are the
// closed commit-status vocabulary; newest report per context wins.
func TestReporterTokensAndExternalChecks(t *testing.T) {
db := testDB(t)
tok, err := db.MintReporterToken("r", "jenkins")
if err != nil || !strings.HasPrefix(tok, "qcr_") {
t.Fatalf("mint: %q %v", tok, err)
}
if !db.CheckReporterToken("r", tok) || db.CheckReporterToken("other", tok) || db.CheckReporterToken("r", "qcr_wrong") {
t.Fatal("token scope wrong")
}
list, err := db.ReporterTokens("r")
if err != nil || len(list) != 1 || list[0].Label != "jenkins" || strings.Contains(list[0].Hash, tok) {
t.Fatalf("list: %v %v", list, err)
}
if err := db.RevokeReporterToken("r", list[0].Hash); err != nil || db.CheckReporterToken("r", tok) {
t.Fatal("revoke did not")
}
if err := db.UpsertExternalCheck("r", ExternalCheck{Subject: "abc", Context: "jenkins/test", State: "sparkling"}); err == nil {
t.Fatal("open state vocabulary")
}
must := func(err error) {
t.Helper()
if err != nil {
t.Fatal(err)
}
}
must(db.UpsertExternalCheck("r", ExternalCheck{Subject: "abc", Context: "jenkins/test", State: "pending"}))
must(db.UpsertExternalCheck("r", ExternalCheck{Subject: "abc", Context: "jenkins/test", State: "success", URL: "https://ci.example/1"}))
cs, err := db.ExternalChecks("r", "abc")
if err != nil || len(cs) != 1 || cs[0].State != "success" || cs[0].URL != "https://ci.example/1" {
t.Fatalf("upsert: %v %v", cs, err)
}
}
// RFC 0009 §verdict-tags: ” follows the fleet, on/off are the repo's.
func TestCITagsModeRoundtrips(t *testing.T) {
db := testDB(t)
if err := db.EnsureRepo("r", t.TempDir()); err != nil {
t.Fatal(err)
}
if got := db.CITagsMode("r"); got != "" {
t.Fatalf("fresh repo mode %q", got)
}
for _, m := range []string{"on", "off", ""} {
if err := db.SetCITagsMode("r", m); err != nil {
t.Fatal(err)
}
if got := db.CITagsMode("r"); got != m {
t.Fatalf("mode %q read back %q", m, got)
}
}
if err := db.SetCITagsMode("r", "sideways"); err != nil {
t.Fatal(err)
}
if got := db.CITagsMode("r"); got != "" {
t.Fatalf("junk mode stored: %q", got)
}
}