package web
import (
"regexp"
"strings"
"testing"
)
// A repository's settings are reachable from the repository.
//
// The cog was gated on IsAdmin, which is the SITE admin flag —
// sessions.Allow(user, "", ops.Admin), resolved against the empty
// repository, and its own comment says it exists to draw the fleet
// link. So the people who administer a repository could not reach its
// settings from it: the page was there and nothing linked it, which is
// half of f44e0c66.
//
// RepoAdmin is the `a` letter on THIS repository, with a site admin
// still clearing it the way every other gate lets them.
func TestARepoAdminCanReachTheSettingsFromTheRepo(t *testing.T) {
cog := regexp.MustCompile(`class="cog aux1[^"]*"[^>]*href="[^"]*/settings"`)
render := func(d pageData) string {
var b strings.Builder
if err := navFragPage.ExecuteTemplate(&b, "repo-tabs", d); err != nil {
t.Fatal(err)
}
return b.String()
}
base := pageData{Repo: "alpha", SignedIn: "dan", Section: "tree"}
if got := render(base); cog.MatchString(got) {
t.Error("FAIL: a reader with no letters is offered the settings cog")
}
admin := base
admin.RepoAdmin = true
if got := render(admin); !cog.MatchString(got) {
t.Error("FAIL: a repository's own admin is not offered its settings; the page " +
"exists and nothing links it")
}
// And the site admin keeps it, which is the fallback that made the
// old gate look like it worked.
site := base
site.IsAdmin, site.RepoAdmin = true, true
if got := render(site); !cog.MatchString(got) {
t.Error("FAIL: a site admin lost the settings cog")
}
}
// The site flag and the repository letter are different questions, and
// the nav must not read one for the other.
func TestTheSiteFlagDoesNotStandInForTheRepoLetter(t *testing.T) {
src := webSource(t)
if strings.Contains(src, `{{if .IsAdmin}}<a class="cog aux1`) {
t.Error("FAIL: the repository settings cog reads IsAdmin, the SITE flag; a " +
"repository's own admin does not clear it")
}
}
// /login names somebody to ask.
//
// The template already had the sentence and "an admin" as its else
// branch; the handler never filled Admins, so the one page a person
// without an account reaches always took the anonymous branch. An
// invite-only forge that names nobody to ask is a dead end.
func TestLoginNamesSomebodyToAsk(t *testing.T) {
var named, anon strings.Builder
if err := loginPage.ExecuteTemplate(&named, "content",
pageData{Title: "Sign in", InviteOnly: true, Admins: []string{"dmestas"}}); err != nil {
t.Fatal(err)
}
if !strings.Contains(named.String(), `/people/dmestas`) {
t.Error("FAIL: the sign-in page does not link the admin it tells people to ask")
}
if err := loginPage.ExecuteTemplate(&anon, "content",
pageData{Title: "Sign in", InviteOnly: true}); err != nil {
t.Fatal(err)
}
if !strings.Contains(anon.String(), "an admin") {
t.Error("FAIL: with no admins known the page says nothing about how to get in")
}
// The handler has to ask, or the branch above is unreachable.
if !strings.Contains(webSource(t), "admins, inviteOnly := siteAdmins(r, req)\n\t\t\trender(r, w, req, loginPage") {
t.Error("FAIL: GET /login does not resolve the admins, so the naming branch " +
"can never be taken")
}
}