carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1package seeds
2
3import (
4 "context"
5 "errors"
6 "os"
7 "strings"
8 "testing"
9
10 "github.com/carlosframework/platform/internal/release"
11)
12
13func putOwners(t *testing.T, s release.Store, body, ifMatch string) string {
14 t.Helper()
15 etag, err := s.Put(context.Background(), LegacyOwnersKey, []byte(body), ifMatch)
16 if err != nil {
17 t.Fatal(err)
18 }
19 return etag
20}
21
22func TestLegacyOwners(t *testing.T) {
23 ctx := context.Background()
24 s := release.NewDirStore(t.TempDir())
25 o, etag, err := ReadLegacyOwners(ctx, s)
26 if err != nil || etag != "" || o == nil || len(o.Names) != 0 {
27 t.Fatalf("absent = %+v %q %v", o, etag, err)
28 }
29 if _, ok := o.Lookup("shop"); ok {
30 t.Fatal("a name resolved from an absent file")
31 }
32 etag = putOwners(t, s, `{"v":1,"names":{"shop":{"account":"abc","app":"shop"}}}`, "")
33 o, got, err := ReadLegacyOwners(ctx, s)
34 if err != nil || got == "" || got != etag {
35 t.Fatalf("read = %q (put %q) %v", got, etag, err)
36 }
37 if got, ok := o.Lookup("shop"); !ok || got != (LegacyOwner{Account: "abc", App: "shop"}) {
38 t.Fatalf("lookup = %+v %v", got, ok)
39 }
40 if _, ok := o.Lookup("other"); ok {
41 t.Fatal("an unassigned name resolved")
42 }
43 if _, _, err := ReadLegacyOwners(ctx, s); err != nil {
44 t.Fatal(err)
45 }
46 putOwners(t, s, `{garbage`, etag)
47 if _, _, err := ReadLegacyOwners(ctx, s); err == nil {
48 t.Fatal("garbage read as no assignments")
49 }
50}
51
52func TestLegacyOwnersEmptySet(t *testing.T) {
53 s := release.NewDirStore(t.TempDir())
54 putOwners(t, s, `{"v":1}`, "")
55 o, etag, err := ReadLegacyOwners(context.Background(), s)
56 if err != nil || etag == "" || o == nil || o.Names == nil || len(o.Names) != 0 {
57 t.Fatalf("empty v1 file = %+v %q %v", o, etag, err)
58 }
59 if _, ok := o.Lookup("shop"); ok {
60 t.Fatal("a name resolved from an empty set")
61 }
62}
63
64// Every present-but-unusable file is an error and no owners, never an empty
65// set: the swap treats "no assignment" as a refusal it can explain, and a
66// read it cannot trust as a failure of its own.
67func TestLegacyOwnersFailClosed(t *testing.T) {
68 good := `"names":{"shop":{"account":"abc","app":"shop"}}`
69 cases := map[string]string{
70 "garbage": `{garbage`,
71 "empty body": ``,
72 "not an object": `[]`,
73 "null": `null`,
74 "version missing": `{` + good + `}`,
75 "version zero": `{"v":0,` + good + `}`,
76 "version unknown": `{"v":2,` + good + `}`,
77 "version negative": `{"v":-1,` + good + `}`,
78 "version a string": `{"v":"1",` + good + `}`,
79 "names a list": `{"v":1,"names":[]}`,
80 "entry a string": `{"v":1,"names":{"shop":"abc/shop"}}`,
81 "entry no account": `{"v":1,"names":{"shop":{"app":"shop"}}}`,
82 "entry no app": `{"v":1,"names":{"shop":{"account":"abc"}}}`,
83 "entry null": `{"v":1,"names":{"shop":null}}`,
84 "empty name": `{"v":1,"names":{"":{"account":"abc","app":"shop"}}}`,
85 "unknown field": `{"v":1,"extra":true,` + good + `}`,
86 "unknown entry key": `{"v":1,"names":{"shop":{"account":"abc","app":"shop","x":1}}}`,
87 "trailing object": `{"v":1,` + good + `}{"v":1}`,
88 "trailing garbage": `{"v":1,` + good + `}x`,
89 }
90 for name, body := range cases {
91 t.Run(name, func(t *testing.T) {
92 s := release.NewDirStore(t.TempDir())
93 putOwners(t, s, body, "")
94 o, etag, err := ReadLegacyOwners(context.Background(), s)
95 if err == nil {
96 t.Fatalf("read %q = %+v, want an error", body, o)
97 }
98 if o != nil || etag != "" {
99 t.Fatalf("an error came with owners %+v / etag %q", o, etag)
100 }
101 if errors.Is(err, os.ErrNotExist) {
102 t.Fatalf("a bad file reads as absent: %v", err)
103 }
104 if !strings.Contains(err.Error(), "legacy route owners") {
105 t.Fatalf("error does not say what failed: %v", err)
106 }
107 })
108 }
109}
110
111// A store error other than not-found is an error too.
112func TestLegacyOwnersReadError(t *testing.T) {
113 boom := errors.New("bucket unreachable")
114 o, etag, err := ReadLegacyOwners(context.Background(), failingStore{Store: release.NewDirStore(t.TempDir()), err: boom})
115 if !errors.Is(err, boom) || o != nil || etag != "" {
116 t.Fatalf("read error = %+v %q %v", o, etag, err)
117 }
118 var nilOwners *LegacyOwners
119 if _, ok := nilOwners.Lookup("shop"); ok {
120 t.Fatal("a nil set resolved a name")
121 }
122}
123
124type failingStore struct {
125 release.Store
126 err error
127}
128
129func (f failingStore) Get(context.Context, string) ([]byte, string, error) {
130 return nil, "", f.err
131}
132