package store import ( "context" "github.com/barerepo/server/internal/token" "strings" "testing" ) func indexed(t *testing.T, db *DB, repo, kind, path, title, body string, public bool, readers string) { t.Helper() if err := db.PutDoc(context.Background(), Doc{Repo: repo, Kind: kind, Path: path, Title: title, Body: body}, public, readers); err != nil { t.Fatal(err) } } // A query is text, not syntax, so LIKE's own wildcards must not reach the database as wildcards. func TestAQueryWithAWildcardInItIsText(t *testing.T) { ctx := context.Background() db := open(t) indexed(t, db, "john/johnbot", Code, "a.go", "", "cover 100% of the branches", true, "") indexed(t, db, "john/johnbot", Code, "b.go", "", "nothing to do with coverage", true, "") // Unescaped, a percent stands for anything, so this query would reach b.go through "coverage". docs, err := db.FindDocs(ctx, "", "c%e", 10) if err != nil { t.Fatal(err) } if len(docs) != 0 { t.Errorf("c%%e matched %d documents, and it is a string that appears in neither", len(docs)) } if docs, err := db.FindDocs(ctx, "", "100%", 10); err != nil || len(docs) != 1 { t.Errorf("the literal 100%% found %d documents, wanted a.go alone: %v", len(docs), err) } // An underscore is LIKE's single character wildcard, and here it is a character. indexed(t, db, "john/johnbot", Code, "c.go", "", "func readXall() error", true, "") docs, err = db.FindDocs(ctx, "", "read_all", 10) if err != nil { t.Fatal(err) } if len(docs) != 0 { t.Errorf("read_all matched readXall, so the underscore reached the database as a wildcard") } } // The read set is a string of names between pipes, so one name must never match inside another. func TestOneReaderNameNeverMatchesInsideAnother(t *testing.T) { ctx := context.Background() db := open(t) indexed(t, db, "johnson/vault", Code, "s.go", "", "const launchCode = 1", false, Readers("johnson", nil)) if docs, err := db.FindDocs(ctx, "johnson", "launchCode", 10); err != nil || len(docs) != 1 { t.Errorf("johnson cannot read her own repository: %d, %v", len(docs), err) } for _, who := range []string{"", "lisa", "ami", "a"} { docs, err := db.FindDocs(ctx, who, "launchCode", 10) if err != nil { t.Fatal(err) } if len(docs) != 0 { t.Errorf("%q read a private repository they have no part in", who) } } } // Chapter 18 grants read to [access] push as well as the owner, and the index carries both. func TestTheReadSetCarriesTheOwnerAndThePushList(t *testing.T) { got := Readers("john", []string{"lisa", "mark", "john"}) if !strings.HasPrefix(got, "|john|") { t.Errorf("the owner is not first in %q", got) } if strings.Count(got, "|john|") != 1 { t.Errorf("the owner is listed twice in %q", got) } for _, name := range []string{"lisa", "mark"} { if !strings.Contains(got, "|"+name+"|") { t.Errorf("%s is missing from %q", name, got) } } } // Ranking is code, then threads, then repositories, per chapter 17. func TestCodeRanksAboveThreadsAboveRepositories(t *testing.T) { ctx := context.Background() db := open(t) indexed(t, db, "john/johnbot", Repository, "", "john/johnbot", "a backoff bot", true, "") indexed(t, db, "john/johnbot", Thread, "44", "backoff is wrong", "it spins", true, "") indexed(t, db, "john/johnbot", Code, "retry.go", "", "func backoff() {}", true, "") docs, err := db.FindDocs(ctx, "", "backoff", 10) if err != nil { t.Fatal(err) } var order []string for _, d := range docs { order = append(order, d.Kind) } want := []string{Code, Thread, Repository} if len(order) != len(want) { t.Fatalf("got %v, wanted %v", order, want) } for i := range want { if order[i] != want[i] { t.Fatalf("got %v, wanted %v", order, want) } } } // Chapter 24 puts a run count and a status on every runner row, and both come from the jobs table. func TestWorkOfCountsRunsAndFindsTheBusyMachine(t *testing.T) { ctx := context.Background() db := open(t) if _, err := db.CreateAccount(ctx, "john", keyA, false); err != nil { t.Fatal(err) } _, tok, err := db.CreateToken(ctx, token.Runner, "john", "john/johnbot", "a runner") if err != nil { t.Fatal(err) } runner, err := db.AttachRunner(ctx, tok.ID, "john/johnbot", "uproar.local", "linux", "amd64", nil) if err != nil { t.Fatal(err) } if work, err := db.WorkOf(ctx, "john/johnbot"); err != nil || len(work) != 0 { t.Errorf("a machine that has run nothing counted %d, %v", len(work), err) } for i := 0; i < 3; i++ { if _, err := db.QueueJob(ctx, "john/johnbot", "refs/heads/master", "abc", "go test", ""); err != nil { t.Fatal(err) } job, err := db.TakeJob(ctx, "john/johnbot", *runner) if err != nil || job == nil { t.Fatalf("the runner could not take a job: %v", err) } // Two of the three finish, so the third leaves the machine busy. if i < 2 { if _, err := db.FinishJob(ctx, job.ID, runner.ID); err != nil { t.Fatal(err) } } } work, err := db.WorkOf(ctx, "john/johnbot") if err != nil { t.Fatal(err) } got := work[runner.ID] if got.Runs != 3 { t.Errorf("the machine counted %d runs, wanted 3", got.Runs) } if !got.Busy { t.Error("a machine holding a running job did not read as busy") } }