package oltp
import (
"strings"
"testing"
)
// RFC 0008 bulletproofing: you cannot lock yourself out, and a
// repository cannot be left without an admin by anyone but a site
// admin, who is told.
func TestGuardRefusesSelfLockoutAndLastAdmin(t *testing.T) {
db := testDB(t)
for _, n := range []string{"alice", "bob"} {
if err := db.AddAccount(n, "pw12345678", false); err != nil {
t.Fatal(err)
}
}
if err := db.AddAccount("root", "pw12345678", true); err != nil {
t.Fatal(err)
}
if err := db.Grant("alice", "repo", RepoAdmin); err != nil {
t.Fatal(err)
}
if err := db.Grant("bob", "repo", Write); err != nil {
t.Fatal(err)
}
if _, err := db.GuardCaps("alice", "alice", "repo", Write.Caps()); !IsRefusal(err) || !strings.Contains(err.Error(), "your own admin") {
t.Fatalf("self-demotion: %v", err)
}
if _, err := db.GuardCaps("alice", "bob", "repo", Maintain.Caps()); err != nil {
t.Fatalf("promoting bob: %v", err)
}
if err := db.Grant("bob", "repo", RepoAdmin); err != nil {
t.Fatal(err)
}
if _, err := db.GuardCaps("alice", "alice", "repo", Write.Caps()); err == nil {
t.Fatal("still your own admin, even with bob there")
}
if _, err := db.GuardCaps("bob", "alice", "repo", Write.Caps()); err != nil {
t.Fatalf("bob demoting alice with bob remaining: %v", err)
}
if err := db.Grant("alice", "repo", Write); err != nil {
t.Fatal(err)
}
// Only bob is admin now. alice may not remove it; root may, and hears.
if _, err := db.GuardCaps("alice", "bob", "repo", Write.Caps()); !IsRefusal(err) || !strings.Contains(err.Error(), "no admin") {
t.Fatalf("last admin by a non-site-admin: %v", err)
}
warn, err := db.GuardCaps("root", "bob", "repo", Write.Caps())
if err != nil || !strings.Contains(warn, "no admin of its own") {
t.Fatalf("site admin removing the last admin: warn=%q err=%v", warn, err)
}
if warn, err := db.GuardCaps("root", "root", "repo", ""); err != nil || warn != "" {
t.Fatalf("site admin editing self: warn=%q err=%v", warn, err)
}
}
func TestMinimalAndChange(t *testing.T) {
if got := Minimal("uv23bBC7"); got != "uv3bBC7" {
t.Fatalf("Minimal dropped the wrong letters: %q", got)
}
if got := Minimal("wrcn"); got != "w" {
t.Fatalf("w implies rcn: %q", got)
}
if got := Change("uv3bBC7", "uv3bBC7"); got != "" {
t.Fatalf("no change said %q", got)
}
got := Change("", Write.Caps())
if !strings.HasPrefix(got, "added as Developer") {
t.Fatalf("adding: %q", got)
}
got = Change(Write.Caps(), Maintain.Caps())
if !strings.HasPrefix(got, "Developer → Maintainer; gains: ") {
t.Fatalf("promotion: %q", got)
}
if got := Change(Write.Caps(), ""); got != "removed from the repository" {
t.Fatalf("removal: %q", got)
}
}