carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1package main
2
3import (
4 "go/ast"
5 "go/parser"
6 "go/token"
7 "os"
8 "path/filepath"
9 "sort"
10 "strconv"
11 "strings"
12 "testing"
13)
14
15// Region HA spec 2 §25: the provider boundary. Spec 2's core names no
16// cloud provider; its AWS parts are adapters in files named for AWS. Each
17// plan task that adds a core file lists it here in the same commit.
18
19// regionHACoreFiles are spec 2's provider-neutral files. None may import
20// an AWS package.
21var regionHACoreFiles = []string{
22 "internal/lbhealth/lbhealth.go",
23 "internal/hostactors/roles.go",
24 "internal/boxchoice/policy.go",
25 "internal/host/boxaddress.go",
26 "internal/edgesfile/private.go",
27 "internal/edge/lbhealth.go",
28 "internal/console/apiboxroles.go",
29 "system_roles.go",
30 "internal/console/nocapacity.go",
31 "internal/hostops/chosen.go",
32 "internal/console/regioncapacity.go",
33 "internal/hostenv/hostenv.go",
34 "internal/hostenv/cli.go",
35 "internal/hostenv/write_linux.go",
36 "internal/hostenv/write_other.go",
37 "internal/host/installchannel.go",
38 "internal/hostactors/membershipread.go",
39 "internal/hostactors/groupref.go",
40 "internal/hostactors/autoenroll.go",
41 "internal/console/enrollpass.go",
42 "internal/host/joinmode.go",
43 "internal/host/boxreference.go",
44 "internal/status/fleet.go",
45 "internal/host/joinroot.go",
46 "internal/host/joining.go",
47}
48
49// regionHAAdapterFiles are spec 2's AWS adapters. Each is named for AWS so
50// a reader can see where the provider lives.
51var regionHAAdapterFiles = []string{
52 "internal/host/awsaddr.go",
53 "internal/console/awsregionmetric.go",
54 "internal/hostenv/awsssm.go",
55 "internal/hostactors/awsmembership/awsmembership.go",
56 "internal/console/awsmembership.go",
57}
58
59// regionHAPackages are the packages spec 2 touches. Every S3 client built
60// in them goes through s3compat.Options(), so CARLOS_S3_ENDPOINT applies.
61var regionHAPackages = []string{
62 "internal/activator",
63 "internal/boxchoice",
64 "internal/console",
65 "internal/edge",
66 "internal/edgesfile",
67 "internal/host",
68 "internal/hostactors",
69 "internal/hostactors/awsmembership",
70 "internal/hostenv",
71 "internal/hostops",
72 "internal/lbhealth",
73}
74
75// regionHAS3Exceptions are S3 clients on main that skip s3compat, each
76// with the discussion that fixes it outside spec 2. A listed file that has
77// since been fixed passes.
78var regionHAS3Exceptions = map[string]string{
79 "internal/host/claimproduction_marker.go": "#298",
80}
81
82func TestRegionHACoreImportsNoAWS(t *testing.T) {
83 for _, f := range regionHACoreFiles {
84 file, err := parser.ParseFile(token.NewFileSet(), f, nil, parser.ImportsOnly)
85 if err != nil {
86 t.Fatalf("%s: %v", f, err)
87 }
88 for _, imp := range file.Imports {
89 path, _ := strconv.Unquote(imp.Path.Value)
90 if strings.HasPrefix(path, "github.com/aws/") {
91 t.Errorf("%s imports %s: spec 2's core names no provider (§25); move it to an AWS adapter", f, path)
92 }
93 }
94 }
95}
96
97func TestRegionHAAdaptersAreNamedForAWS(t *testing.T) {
98 for _, f := range regionHAAdapterFiles {
99 if _, err := os.Stat(f); err != nil {
100 t.Errorf("%s: %v", f, err)
101 }
102 if !strings.Contains(filepath.Base(f), "aws") && !strings.Contains(filepath.Dir(f), "aws") {
103 t.Errorf("%s is an AWS adapter but its name does not say so", f)
104 }
105 }
106}
107
108// s3NewFromConfigCalls returns the line of each s3.NewFromConfig call in
109// src that does not pass s3compat.Options() as an argument.
110func s3NewFromConfigCalls(t *testing.T, path string) []int {
111 t.Helper()
112 fset := token.NewFileSet()
113 f, err := parser.ParseFile(fset, path, nil, 0)
114 if err != nil {
115 t.Fatalf("%s: %v", path, err)
116 }
117 s3Names, compatNames := map[string]bool{}, map[string]bool{}
118 for _, imp := range f.Imports {
119 p, _ := strconv.Unquote(imp.Path.Value)
120 name := filepath.Base(p)
121 if imp.Name != nil {
122 name = imp.Name.Name
123 }
124 switch p {
125 case "github.com/aws/aws-sdk-go-v2/service/s3":
126 s3Names[name] = true
127 case "github.com/carlosframework/platform/internal/s3compat":
128 compatNames[name] = true
129 }
130 }
131 var bad []int
132 ast.Inspect(f, func(n ast.Node) bool {
133 call, ok := n.(*ast.CallExpr)
134 if !ok {
135 return true
136 }
137 sel, ok := call.Fun.(*ast.SelectorExpr)
138 if !ok || sel.Sel.Name != "NewFromConfig" {
139 return true
140 }
141 pkg, ok := sel.X.(*ast.Ident)
142 if !ok || !s3Names[pkg.Name] {
143 return true
144 }
145 for _, arg := range call.Args {
146 inner, ok := arg.(*ast.CallExpr)
147 if !ok {
148 continue
149 }
150 isel, ok := inner.Fun.(*ast.SelectorExpr)
151 if !ok || isel.Sel.Name != "Options" {
152 continue
153 }
154 if id, ok := isel.X.(*ast.Ident); ok && compatNames[id.Name] {
155 return true
156 }
157 }
158 bad = append(bad, fset.Position(call.Pos()).Line)
159 return true
160 })
161 return bad
162}
163
164func TestRegionHAS3ClientsUseS3Compat(t *testing.T) {
165 for _, dir := range regionHAPackages {
166 paths, err := filepath.Glob(filepath.Join(dir, "*.go"))
167 if err != nil {
168 t.Fatal(err)
169 }
170 sort.Strings(paths)
171 for _, p := range paths {
172 if strings.HasSuffix(p, "_test.go") {
173 continue
174 }
175 if _, ok := regionHAS3Exceptions[filepath.ToSlash(p)]; ok {
176 continue
177 }
178 for _, line := range s3NewFromConfigCalls(t, p) {
179 t.Errorf("%s:%d builds an S3 client without s3compat.Options() (§25): CARLOS_S3_ENDPOINT would not apply", p, line)
180 }
181 }
182 }
183}
184
185// The checker itself: a bare client is caught, one with Options() is not,
186// whatever the import names.
187func TestRegionHAS3CheckerCatchesABareClient(t *testing.T) {
188 dir := t.TempDir()
189 write := func(name, body string) string {
190 p := filepath.Join(dir, name)
191 if err := os.WriteFile(p, []byte(body), 0o644); err != nil {
192 t.Fatal(err)
193 }
194 return p
195 }
196 bare := write("bare.go", `package x
197import awss3 "github.com/aws/aws-sdk-go-v2/service/s3"
198func f(cfg any) { _ = awss3.NewFromConfig(cfg) }
199`)
200 good := write("good.go", `package x
201import (
202 "github.com/aws/aws-sdk-go-v2/service/s3"
203 "github.com/carlosframework/platform/internal/s3compat"
204)
205func f(cfg any) { _ = s3.NewFromConfig(cfg, s3compat.Options()) }
206`)
207 if got := s3NewFromConfigCalls(t, bare); len(got) != 1 {
208 t.Fatalf("bare client: %v", got)
209 }
210 if got := s3NewFromConfigCalls(t, good); len(got) != 0 {
211 t.Fatalf("compat client flagged: %v", got)
212 }
213}
214