carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package console
2
3import (
4 "bytes"
5 "log"
6 "net/http"
7 "net/url"
8 "os"
9 "strings"
10 "testing"
11 "time"
12
13 "github.com/carlosframework/platform/internal/domains"
14 "github.com/carlosframework/platform/internal/release"
15)
16
17// devAccountID is the id whose sqid is "dev" (#285).
18const devAccountID = int64(1168)
19
20// Every console door that creates an account (landing's personal-account
21// mint, POST /accounts/new, POST /auth/cli/accounts) mints through
22// domains.MintAccount, so none of them can hand out the reserved "dev". Each
23// door is driven against a bucket whose highest account is 1167, so the next
24// plain id would be 1168.
25func TestConsoleCreationDoorsSkipReservedSqids(t *testing.T) {
26 doors := map[string]func(t *testing.T, fx *consoleFixture) (owner string){
27 "landing": func(t *testing.T, fx *consoleFixture) string {
28 fx.setUser("newbie@keymail.dev")
29 defer fx.setUser("paul@keymail.dev")
30 c := newBrowser(t)
31 signUp(t, fx, c, "code-new")
32 if st, loc, _ := get(t, c, fx.ts.URL+"/"); st != http.StatusFound || !strings.HasPrefix(loc, "/a/") {
33 t.Fatalf("landing = %d -> %q, want 302 into an account", st, loc)
34 }
35 return "newbie@keymail.dev"
36 },
37 "POST /accounts/new": func(t *testing.T, fx *consoleFixture) string {
38 c := signInPaul(t, fx)
39 csrf := sessionToken(t, fx, c)
40 if st, loc, _ := postForm(t, c, fx.ts.URL+"/accounts/new",
41 url.Values{"csrf": {csrf}, "name": {"shop"}}); st != http.StatusSeeOther {
42 t.Fatalf("create = %d -> %q, want 303", st, loc)
43 }
44 return "paul@keymail.dev"
45 },
46 "POST /auth/cli/accounts": func(t *testing.T, fx *consoleFixture) string {
47 token := cliToken(t, fx, "paul@keymail.dev", "code-acct")
48 if st, out := postJSON(t, fx.ts.URL+"/auth/cli/accounts", map[string]string{"name": "shop"}, token); st != http.StatusOK {
49 t.Fatalf("accounts create = %d %v", st, out)
50 }
51 return "paul@keymail.dev"
52 },
53 }
54 for name, door := range doors {
55 t.Run(name, func(t *testing.T) {
56 fx := newConsoleFixture(t)
57 ctx := t.Context()
58 if err := WriteAccountManifest(ctx, fx.rel, devAccountID-1, domains.Sqid(devAccountID-1),
59 "neighbour", time.Unix(1700000000, 0)); err != nil {
60 t.Fatal(err)
61 }
62 owner := door(t, fx)
63
64 accts, err := fx.st.AccountsFor(owner)
65 if err != nil {
66 t.Fatal(err)
67 }
68 var made *Account
69 for i := range accts {
70 if accts[i].ID > devAccountID-1 {
71 made = &accts[i]
72 }
73 }
74 if made == nil {
75 t.Fatalf("no new account for %s in %+v", owner, accts)
76 }
77 if made.ID != devAccountID+1 || made.Sqid != "dew" {
78 t.Fatalf("minted (%d, %q), want (%d, \"dew\"): the door skipped the reserved-sqid rule",
79 made.ID, made.Sqid, devAccountID+1)
80 }
81 if _, _, err := fx.rel.Get(ctx, AccountManifestKey("dev")); err == nil {
82 t.Fatal("a manifest landed at accounts/dev/")
83 }
84 if a, err := fx.st.AccountBySqid("dev"); err != nil || a != nil {
85 t.Fatalf("AccountBySqid(dev) = %+v %v, want none", a, err)
86 }
87 })
88 }
89}
90
91// The ruling leaves existing accounts alone, so an account that already holds
92// a reserved sqid (the list grew over it, or a manifest was written by hand)
93// is materialized as usual and named in the log, once per pass. A tombstoned
94// one is not named: it serves nothing.
95func TestMaterializeFlagsALiveReservedSqid(t *testing.T) {
96 var logged bytes.Buffer
97 log.SetOutput(&logged)
98 t.Cleanup(func() { log.SetOutput(os.Stderr) })
99
100 st := openTestStore(t)
101 rel := release.NewDirStore(t.TempDir())
102 ctx := t.Context()
103 created := time.Unix(1700000000, 0).UTC()
104 edgeID := int64(49868) // Sqid "edge"
105 for _, a := range []struct {
106 id int64
107 name string
108 }{{devAccountID, "held"}, {devAccountID + 1, "plain"}, {edgeID, "retired"}} {
109 if err := WriteAccountManifest(ctx, rel, a.id, domains.Sqid(a.id), a.name, created); err != nil {
110 t.Fatal(err)
111 }
112 }
113 if err := domains.TombstoneAccount(ctx, rel, "edge", created); err != nil {
114 t.Fatal(err)
115 }
116
117 if _, err := MaterializeAccounts(ctx, rel, st); err != nil {
118 t.Fatal(err)
119 }
120 if a, err := st.AccountBySqid("dev"); err != nil || a == nil || a.ID != devAccountID {
121 t.Fatalf("AccountBySqid(dev) = %+v %v: an existing account must be left as it is", a, err)
122 }
123 out := logged.String()
124 if !strings.Contains(out, "account dev (id 1168) has a reserved sqid") {
125 t.Errorf("no reserved-sqid line for the live dev account:\n%s", out)
126 }
127 flagged := 0
128 for _, line := range strings.Split(out, "\n") {
129 if !strings.Contains(line, "reserved sqid") {
130 continue
131 }
132 flagged++
133 if strings.Contains(line, "—") {
134 t.Errorf("the reserved-sqid log line carries an em dash: %s", line)
135 }
136 }
137 if flagged != 1 {
138 t.Errorf("%d reserved-sqid lines, want exactly one (dev; not the plain dew, not the retired edge):\n%s", flagged, out)
139 }
140}
141