package oltp
import "testing"
// RFC 0021, Reach and following: a site agent holds its person's string
// on every repository the person owns, now and as they come, and on
// nothing else; a removal sticks; the deed moving moves it.
func TestASiteAgentFollowsItsPersonIntoTheirRepositories(t *testing.T) {
db := agentRig(t)
if err := db.NewForgeAgent("zg", "root"); err != nil {
t.Fatal(err)
}
if err := db.AddRepo("theirs", t.TempDir(), "", Public); err != nil {
t.Fatal(err)
}
for repo, owner := range map[string]string{"pub": "root", "theirs": "jva"} {
if err := db.SetOwner(repo, owner); err != nil {
t.Fatal(err)
}
if err := db.SetCaps(owner, repo, "a"); err != nil {
t.Fatal(err)
}
}
held := func(repo string) string { c, _ := db.CapsOf("zg", repo); return c }
if err := db.SetReach("zg", ReachSite); err != nil {
t.Fatal(err)
}
if held("pub") != "a" || !db.FollowedOn("zg", "pub") {
t.Errorf("FAIL: the site agent holds %q on its person's repository, want a, followed", held("pub"))
}
if held("theirs") != "" {
t.Errorf("FAIL: the site agent followed into somebody else's repository: %q", held("theirs"))
}
// A repository made later is followed into when its deed lands.
if err := db.AddRepo("later", t.TempDir(), "", Public); err != nil {
t.Fatal(err)
}
if err := db.SetOwner("later", "root"); err != nil {
t.Fatal(err)
}
if err := db.SetCaps("root", "later", "a"); err != nil {
t.Fatal(err)
}
if held("later") != "a" {
t.Errorf("FAIL: a new repository of its person's: %q, want a", held("later"))
}
// The person's string changing changes the follower's.
if err := db.SetCaps("root", "later", "uv"); err != nil {
t.Fatal(err)
}
if held("later") != "uv" {
t.Errorf("FAIL: after the person's string changed the follower holds %q, want uv", held("later"))
}
// The deed leaving the person takes the follower out.
if err := db.SetOwner("later", "jva"); err != nil {
t.Fatal(err)
}
if held("later") != "" {
t.Errorf("FAIL: the follower kept %q on a repository its person gave away", held("later"))
}
// An admin's removal sticks across a reconcile.
if _, err := db.SetCapsGuarded("root", "zg", "pub", ""); err != nil {
t.Fatal(err)
}
if err := db.ReconcileAllFollowing(); err != nil {
t.Fatal(err)
}
if held("pub") != "" {
t.Errorf("FAIL: a removed followed grant came back: %q", held("pub"))
}
// Granting by hand clears the removal, and the row is the admin's.
if _, err := db.SetCapsGuarded("root", "zg", "pub", "u"); err != nil {
t.Fatal(err)
}
if err := db.ReconcileAllFollowing(); err != nil {
t.Fatal(err)
}
if held("pub") != "u" || db.FollowedOn("zg", "pub") {
t.Errorf("FAIL: a hand grant reads %q followed=%v, want u and not followed", held("pub"), db.FollowedOn("zg", "pub"))
}
// Taking the reach away takes the followed grants with it, and
// leaves the hand grant.
if err := db.SetReach("zg", ""); err != nil {
t.Fatal(err)
}
if held("pub") != "u" {
t.Errorf("FAIL: clearing the reach removed a hand grant: %q", held("pub"))
}
}
func TestOnlyAnAgentHasAReachAndAPersonHasOneSiteAgent(t *testing.T) {
db := agentRig(t)
if err := db.SetReach("jva", ReachSite); !IsRefusal(err) {
t.Errorf("FAIL: a person took a reach: %v", err)
}
if err := db.SetReach("dmestas-coder", "everywhere"); !IsRefusal(err) {
t.Errorf("FAIL: an unknown reach was taken: %v", err)
}
if err := db.SetReach("dmestas-coder", ReachSite); err != nil {
t.Fatal(err)
}
if err := db.NewAgent("dmestas-other", "dmestas", -1); err != nil {
t.Fatal(err)
}
if err := db.SetReach("dmestas-other", ReachSite); !IsRefusal(err) {
t.Errorf("FAIL: a second site agent for one person: %v", err)
}
if got := db.SiteAgentOf("dmestas"); got != "dmestas-coder" {
t.Errorf("FAIL: SiteAgentOf = %q", got)
}
}