e2e/adminusersweb_test.go
80 lines · 3375 bytes
1package e2e
2
3import (
4 "net/url"
5 "strings"
6 "testing"
7)
8
9// /admin/users lists accounts and runs the account commands, which the
10// web can reach now that nothing is held back from it (#234). Demote
11// and disable carry the typed-name check.
12func TestAdminUsersWeb(t *testing.T) {
13 inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n")
14 rootKey := inst.newKey(t, "root")
15 aliceKey := inst.newKey(t, "alice")
16 inst.admin(t, "admin", "user", "create", "root", "--key", rootKey+".pub", "--admin",
17 "--email", "root@example.test", "--verified")
18 inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub",
19 "--email", "alice@example.test", "--verified")
20
21 // A non-admin sees neither the page nor a hint that it exists.
22 if status, _ := browserGet(t, inst.login(t, aliceKey), inst.base()+"/admin/users"); status != 404 {
23 t.Fatalf("non-admin reached the account list: %d", status)
24 }
25
26 root := inst.login(t, rootKey)
27 page := inst.base() + "/admin/users"
28 _, body := browserGet(t, root, page)
29 for _, want := range []string{">alice<", ">root<", "Promote", "Disable"} {
30 if !strings.Contains(body, want) {
31 t.Fatalf("account list missing %q:\n%s", want, body)
32 }
33 }
34 // The admin page links here.
35 if _, admin := browserGet(t, root, inst.base()+"/admin"); !strings.Contains(admin, `href="/admin/users"`) {
36 t.Fatalf("admin page does not link the account list:\n%s", admin)
37 }
38
39 post := func(v url.Values) string {
40 t.Helper()
41 status, body := browserPost(t, root, page, v)
42 if status != 200 {
43 t.Fatalf("post %v: %d", v, status)
44 }
45 return body
46 }
47
48 // Disable needs the typed name: the wrong one changes nothing.
49 post(url.Values{"field": {"disable"}, "user": {"alice"}, "confirm": {"alicce"}})
50 if out, _, _ := inst.ssh(t, rootKey, "", "admin", "user", "show", "alice", "--json"); !strings.Contains(out, `"state":"active"`) {
51 t.Fatalf("a mistyped confirm still disabled the account: %s", out)
52 }
53 post(url.Values{"field": {"disable"}, "user": {"alice"}, "confirm": {"alice"}})
54 if out, _, _ := inst.ssh(t, rootKey, "", "admin", "user", "show", "alice", "--json"); !strings.Contains(out, `"state":"disabled"`) {
55 t.Fatalf("disable did not take: %s", out)
56 }
57 post(url.Values{"field": {"enable"}, "user": {"alice"}})
58 post(url.Values{"field": {"promote"}, "user": {"alice"}})
59 if out, _, _ := inst.ssh(t, rootKey, "", "admin", "user", "show", "alice", "--json"); !strings.Contains(out, `"admin":true`) {
60 t.Fatalf("promote did not take: %s", out)
61 }
62 post(url.Values{"field": {"demote"}, "user": {"alice"}, "confirm": {"alice"}})
63 if out, _, _ := inst.ssh(t, rootKey, "", "admin", "user", "show", "alice", "--json"); strings.Contains(out, `"admin":true`) {
64 t.Fatalf("demote did not take: %s", out)
65 }
66
67 // The command's own refusals reach the page: the last admin stays.
68 b := post(url.Values{"field": {"demote"}, "user": {"root"}, "confirm": {"root"}})
69 if !strings.Contains(b, "admin") {
70 t.Fatalf("no message after demoting the last admin:\n%s", b)
71 }
72 if out, _, _ := inst.ssh(t, rootKey, "", "admin", "user", "show", "root", "--json"); !strings.Contains(out, `"admin":true`) {
73 t.Fatalf("the last admin was demoted: %s", out)
74 }
75
76 // The state filter narrows the list.
77 if _, body := browserGet(t, root, page+"?state=admin"); strings.Contains(body, ">alice<") {
78 t.Fatalf("the admin filter listed a non-admin:\n%s", body)
79 }
80}