package oltp
import (
"errors"
"testing"
)
func heldDB(t *testing.T) *DB {
t.Helper()
db := testDB(t)
if err := db.AddRepo("proj", t.TempDir(), "", Public); err != nil {
t.Fatal(err)
}
if err := db.SetOwner("proj", "alice"); err != nil {
t.Fatal(err)
}
return db
}
// A disable may be escalated to a hold, a hold is never quietly
// replaced, and each end names the strength it ends.
func TestTakedownsMoveOnlyAlongTheRule(t *testing.T) {
db := heldDB(t)
dis := Takedown{Repo: "proj", Strength: Disabled, Category: "copyright", Notice: "N-1", Actor: "dmestas"}
if err := db.SetTakedown(dis); err != nil {
t.Fatal(err)
}
if err := db.SetTakedown(dis); !errors.Is(err, ErrTakedownState) {
t.Errorf("FAIL: disabling twice: %v", err)
}
if err := db.EndTakedown("proj", LegalHold, "dmestas", "", ""); !errors.Is(err, ErrTakedownState) {
t.Errorf("FAIL: lifting a hold that is a disable: %v", err)
}
hold := Takedown{Repo: "proj", Strength: LegalHold, Category: "child-abuse", Actor: "dmestas"}
if err := db.SetTakedown(hold); err != nil {
t.Errorf("FAIL: escalating to a hold: %v", err)
}
if err := db.SetTakedown(dis); !errors.Is(err, ErrTakedownState) {
t.Errorf("FAIL: a disable replaced a hold: %v", err)
}
if err := db.EndTakedown("proj", Disabled, "dmestas", "", ""); !errors.Is(err, ErrTakedownState) {
t.Errorf("FAIL: restoring lifted a hold: %v", err)
}
if got, ok, _ := db.TakedownOf("proj"); !ok || got.Strength != LegalHold {
t.Errorf("FAIL: current %+v %v", got, ok)
}
if err := db.EndTakedown("proj", LegalHold, "dmestas", "", "report filed"); err != nil {
t.Fatal(err)
}
if _, ok, _ := db.TakedownOf("proj"); ok {
t.Error("FAIL: still taken down after the lift")
}
if err := db.SetTakedown(Takedown{Repo: "proj", Strength: Disabled, Category: "nonsense", Actor: "x"}); !errors.Is(err, ErrTakedownState) {
t.Errorf("FAIL: an unknown category: %v", err)
}
if err := db.SetTakedown(Takedown{Repo: "nope", Strength: Disabled, Category: "copyright", Actor: "x"}); !errors.Is(err, ErrTakedownState) {
t.Errorf("FAIL: a repository nobody serves: %v", err)
}
}
// The rule every surface asks.
func TestTakedownRefuses(t *testing.T) {
for _, c := range []struct {
strength string
admin bool
want bool
}{{Disabled, false, true}, {Disabled, true, false}, {LegalHold, false, true}, {LegalHold, true, true}} {
if got := (Takedown{Strength: c.strength}).Refuses(c.admin); got != c.want {
t.Errorf("FAIL: %s admin=%v refuses %v", c.strength, c.admin, got)
}
}
}
// Delete and stop serving both end in one of these two, so a takedown
// is never destroyed by either.
func TestATakenDownRepositoryIsNotDropped(t *testing.T) {
for _, strength := range []string{Disabled, LegalHold} {
db := heldDB(t)
if err := db.SetTakedown(Takedown{Repo: "proj", Strength: strength, Category: "copyright", Actor: "dmestas"}); err != nil {
t.Fatal(err)
}
if err := db.PurgeRepo("proj"); !errors.Is(err, ErrHeld) {
t.Errorf("FAIL: %s: purge: %v", strength, err)
}
if err := db.DeleteRepo("proj"); !errors.Is(err, ErrHeld) {
t.Errorf("FAIL: %s: delete: %v", strength, err)
}
if _, ok, _ := db.RepoByName("proj"); !ok {
t.Errorf("FAIL: %s: the registration went", strength)
}
}
}
// The log takes one row per act, keeps the owner of the day, refuses
// to be edited, and outlives the repository.
func TestTheTakedownLogIsAppendOnly(t *testing.T) {
db := heldDB(t)
if err := db.SetTakedown(Takedown{Repo: "proj", Strength: Disabled, Category: "copyright", Notice: "N-7", Actor: "dmestas", Via: "web"}); err != nil {
t.Fatal(err)
}
if err := db.EndTakedown("proj", Disabled, "dmestas", "web", "counter-notice"); err != nil {
t.Fatal(err)
}
if err := db.PurgeRepo("proj"); err != nil {
t.Fatal(err)
}
acts, err := db.TakedownLog("proj", 10)
if err != nil {
t.Fatal(err)
}
if len(acts) != 2 || acts[0].Act != "restore" || acts[1].Act != "disable" || acts[1].Owner != "alice" || acts[1].Notice != "N-7" {
t.Fatalf("FAIL: log %+v", acts)
}
if _, err := db.w.Exec(`UPDATE takedown_log SET actor = 'x'`); err == nil {
t.Error("FAIL: the log took an update")
}
if _, err := db.w.Exec(`DELETE FROM takedown_log`); err == nil {
t.Error("FAIL: the log took a delete")
}
if all, _ := db.TakedownLog("", 10); len(all) != 2 {
t.Errorf("FAIL: forge-wide log %d rows", len(all))
}
}