package oltp
import "testing"
// The bug RFC 0018 predicted: the settings roster asked "does this
// account have a stored string here" and dropped the row when it did
// not. A floor-only team member has no repo_caps row, so they vanished
// from the page while holding read access to a PRIVATE repository —
// the one case where the floor is their entire access.
func TestAFloorOnlyMemberAppearsAmongTheHolders(t *testing.T) {
db := teamDB(t)
if err := db.SetVisibility("secret", "Private"); err != nil {
t.Fatal(err)
}
if err := db.AddTeam("core", "", "", "dan"); err != nil {
t.Fatal(err)
}
if err := db.SetTeamRepo("core", "secret", "dan"); err != nil {
t.Fatal(err)
}
// lou is in the team with no string of their own.
if err := db.SetTeamMember("core", "lou", "", false, true); err != nil {
t.Fatal(err)
}
holders, err := db.CapHolders("secret")
if err != nil {
t.Fatal(err)
}
var lou, ann CapHolder
for _, h := range holders {
switch h.Account {
case "lou":
lou = h
case "ann":
ann = h
}
}
if !lou.Reaches() {
t.Error("FAIL: a floor-only team member does not read as reaching the repository")
}
if lou.Team != "core" {
t.Errorf("FAIL: lou's team = %q, want core", lou.Team)
}
if lou.Caps != "" {
t.Errorf("FAIL: lou has a stored string %q; the fixture is wrong", lou.Caps)
}
// And they really do hold access, which is why hiding them mattered.
if got := db.EffectiveCaps("lou", "secret"); got == "" {
t.Error("FAIL: the fixture grants nothing, so this proves nothing")
}
// Somebody in no team and holding nothing still does not reach it.
if ann.Reaches() {
t.Error("FAIL: a stranger reads as reaching a private repository")
}
}
// RFC 0018 requires the ROUTE to be nameable, not just the result.
// Three routes, three sentences.
func TestEachRouteNamesItself(t *testing.T) {
for _, tc := range []struct {
h CapHolder
want string
}{
{CapHolder{Caps: "a"}, "directly"},
{CapHolder{Team: "core"}, "by membership of core"},
{CapHolder{Team: "core", TeamCaps: "uv"}, "via core"},
{CapHolder{Caps: "a", Team: "core"}, "directly, and via core"},
{CapHolder{}, ""},
} {
if got := tc.h.Route(); got != tc.want {
t.Errorf("FAIL: Route(%+v) = %q, want %q", tc.h, got, tc.want)
}
}
}
// A repository under no team is the ordinary case: the team joins are
// LEFT, so no row is lost and no team is invented.
func TestTheTeamJoinsDoNotDropRows(t *testing.T) {
db := teamDB(t)
before, err := db.CapHolders("lonely")
if err != nil {
t.Fatal(err)
}
if len(before) != 3 {
t.Fatalf("FAIL: %d holders for a repo under no team, want the 3 accounts", len(before))
}
for _, h := range before {
if h.Team != "" || h.TeamCaps != "" {
t.Errorf("FAIL: %s was given team %q on a repo under none", h.Account, h.Team)
}
}
// And a team that does not hold this repository does not leak in.
if err := db.AddTeam("elsewhere", "", "", "dan"); err != nil {
t.Fatal(err)
}
if err := db.SetTeamMember("elsewhere", "lou", "i", false, true); err != nil {
t.Fatal(err)
}
after, err := db.CapHolders("lonely")
if err != nil {
t.Fatal(err)
}
for _, h := range after {
if h.Team != "" {
t.Errorf("FAIL: %s reached lonely via %q, which does not hold it", h.Account, h.Team)
}
}
}