18794: Merge branch 'main'
[arvados.git] / lib / config / cmd_test.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 package config
6
7 import (
8         "bytes"
9         "io"
10         "io/ioutil"
11         "os"
12
13         "git.arvados.org/arvados.git/lib/cmd"
14         check "gopkg.in/check.v1"
15 )
16
17 var _ = check.Suite(&CommandSuite{})
18
19 var (
20         // Commands must satisfy cmd.Handler interface
21         _ cmd.Handler = dumpCommand{}
22         _ cmd.Handler = checkCommand{}
23 )
24
25 type CommandSuite struct{}
26
27 func (s *CommandSuite) SetUpSuite(c *check.C) {
28         os.Unsetenv("ARVADOS_API_HOST")
29         os.Unsetenv("ARVADOS_API_HOST_INSECURE")
30         os.Unsetenv("ARVADOS_API_TOKEN")
31 }
32
33 func (s *CommandSuite) TestDump_BadArg(c *check.C) {
34         var stderr bytes.Buffer
35         code := DumpCommand.RunCommand("arvados config-dump", []string{"-badarg"}, bytes.NewBuffer(nil), bytes.NewBuffer(nil), &stderr)
36         c.Check(code, check.Equals, 2)
37         c.Check(stderr.String(), check.Equals, "error parsing command line arguments: flag provided but not defined: -badarg (try -help)\n")
38 }
39
40 func (s *CommandSuite) TestDump_EmptyInput(c *check.C) {
41         var stdout, stderr bytes.Buffer
42         code := DumpCommand.RunCommand("arvados config-dump", []string{"-config", "-"}, &bytes.Buffer{}, &stdout, &stderr)
43         c.Check(code, check.Equals, 1)
44         c.Check(stderr.String(), check.Matches, `config does not define any clusters\n`)
45 }
46
47 func (s *CommandSuite) TestCheck_NoWarnings(c *check.C) {
48         var stdout, stderr bytes.Buffer
49         in := `
50 Clusters:
51  z1234:
52   ManagementToken: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
53   SystemRootToken: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
54   API:
55     MaxItemsPerResponse: 1234
56     VocabularyPath: /this/path/does/not/exist
57   Collections:
58     BlobSigningKey: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
59   PostgreSQL:
60     Connection:
61       sslmode: require
62   Services:
63     RailsAPI:
64       InternalURLs:
65         "http://0.0.0.0:8000": {}
66   Workbench:
67     UserProfileFormFields:
68       color:
69         Type: select
70         Options:
71           fuchsia: {}
72     ApplicationMimetypesWithViewIcon:
73       whitespace: {}
74 `
75         code := CheckCommand.RunCommand("arvados config-check", []string{"-config", "-"}, bytes.NewBufferString(in), &stdout, &stderr)
76         c.Check(code, check.Equals, 0)
77         c.Check(stdout.String(), check.Equals, "")
78         c.Check(stderr.String(), check.Equals, "")
79 }
80
81 func (s *CommandSuite) TestCheck_VocabularyErrors(c *check.C) {
82         tmpFile, err := ioutil.TempFile("", "")
83         c.Assert(err, check.IsNil)
84         defer os.Remove(tmpFile.Name())
85         _, err = tmpFile.WriteString(`
86 {
87  "tags": {
88   "IDfoo": {
89    "labels": [
90     {"label": "foo"}
91    ]
92   },
93   "IDfoo": {
94    "labels": [
95     {"label": "baz"}
96    ]
97   }
98  }
99 }`)
100         c.Assert(err, check.IsNil)
101         tmpFile.Close()
102         vocPath := tmpFile.Name()
103         var stdout, stderr bytes.Buffer
104         in := `
105 Clusters:
106  z1234:
107   ManagementToken: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
108   SystemRootToken: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
109   API:
110     MaxItemsPerResponse: 1234
111     VocabularyPath: ` + vocPath + `
112   Collections:
113     BlobSigningKey: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
114   PostgreSQL:
115     Connection:
116       sslmode: require
117   Services:
118     RailsAPI:
119       InternalURLs:
120         "http://0.0.0.0:8000": {}
121   Workbench:
122     UserProfileFormFields:
123       color:
124         Type: select
125         Options:
126           fuchsia: {}
127     ApplicationMimetypesWithViewIcon:
128       whitespace: {}
129 `
130         code := CheckCommand.RunCommand("arvados config-check", []string{"-config", "-"}, bytes.NewBufferString(in), &stdout, &stderr)
131         c.Check(code, check.Equals, 1)
132         c.Check(stderr.String(), check.Matches, `(?ms).*Error loading vocabulary file.*for cluster.*duplicate JSON key.*tags.IDfoo.*`)
133 }
134
135 func (s *CommandSuite) TestCheck_DeprecatedKeys(c *check.C) {
136         var stdout, stderr bytes.Buffer
137         in := `
138 Clusters:
139  z1234:
140   RequestLimits:
141     MaxItemsPerResponse: 1234
142 `
143         code := CheckCommand.RunCommand("arvados config-check", []string{"-config", "-"}, bytes.NewBufferString(in), &stdout, &stderr)
144         c.Check(code, check.Equals, 1)
145         c.Check(stdout.String(), check.Matches, `(?ms).*\n\- +.*MaxItemsPerResponse: 1000\n\+ +MaxItemsPerResponse: 1234\n.*`)
146 }
147
148 func (s *CommandSuite) TestCheck_OldKeepstoreConfigFile(c *check.C) {
149         f, err := ioutil.TempFile("", "")
150         c.Assert(err, check.IsNil)
151         defer os.Remove(f.Name())
152
153         io.WriteString(f, "Listen: :12345\nDebug: true\n")
154
155         var stdout, stderr bytes.Buffer
156         in := `
157 Clusters:
158  z1234:
159   SystemLogs:
160     LogLevel: info
161 `
162         code := CheckCommand.RunCommand("arvados config-check", []string{"-config", "-", "-legacy-keepstore-config", f.Name()}, bytes.NewBufferString(in), &stdout, &stderr)
163         c.Check(code, check.Equals, 1)
164         c.Check(stdout.String(), check.Matches, `(?ms).*\n\- +.*LogLevel: info\n\+ +LogLevel: debug\n.*`)
165         c.Check(stderr.String(), check.Matches, `(?ms).*you should remove the legacy keepstore config file.*\n`)
166 }
167
168 func (s *CommandSuite) TestCheck_UnknownKey(c *check.C) {
169         var stdout, stderr bytes.Buffer
170         in := `
171 Clusters:
172  z1234:
173   Bogus1: foo
174   BogusSection:
175     Bogus2: foo
176   API:
177     Bogus3:
178      Bogus4: true
179   PostgreSQL:
180     ConnectionPool:
181       {Bogus5: true}
182 `
183         code := CheckCommand.RunCommand("arvados config-check", []string{"-config", "-"}, bytes.NewBufferString(in), &stdout, &stderr)
184         c.Log(stderr.String())
185         c.Check(code, check.Equals, 1)
186         c.Check(stderr.String(), check.Matches, `(?ms).*deprecated or unknown config entry: Clusters.z1234.Bogus1"\n.*`)
187         c.Check(stderr.String(), check.Matches, `(?ms).*deprecated or unknown config entry: Clusters.z1234.BogusSection"\n.*`)
188         c.Check(stderr.String(), check.Matches, `(?ms).*deprecated or unknown config entry: Clusters.z1234.API.Bogus3"\n.*`)
189         c.Check(stderr.String(), check.Matches, `(?ms).*unexpected object in config entry: Clusters.z1234.PostgreSQL.ConnectionPool"\n.*`)
190 }
191
192 func (s *CommandSuite) TestCheck_DuplicateWarnings(c *check.C) {
193         var stdout, stderr bytes.Buffer
194         in := `
195 Clusters:
196  z1234: {}
197 `
198         code := CheckCommand.RunCommand("arvados config-check", []string{"-config", "-"}, bytes.NewBufferString(in), &stdout, &stderr)
199         c.Check(code, check.Equals, 1)
200         c.Check(stderr.String(), check.Matches, `(?ms).*SystemRootToken.*`)
201         c.Check(stderr.String(), check.Not(check.Matches), `(?ms).*SystemRootToken.*SystemRootToken.*`)
202 }
203
204 func (s *CommandSuite) TestDump_Formatting(c *check.C) {
205         var stdout, stderr bytes.Buffer
206         in := `
207 Clusters:
208  z1234:
209   Containers:
210    CloudVMs:
211     TimeoutBooting: 600s
212   Services:
213    Controller:
214     InternalURLs:
215      http://localhost:12345: {}
216 `
217         code := DumpCommand.RunCommand("arvados config-dump", []string{"-config", "-"}, bytes.NewBufferString(in), &stdout, &stderr)
218         c.Check(code, check.Equals, 0)
219         c.Check(stdout.String(), check.Matches, `(?ms).*TimeoutBooting: 10m\n.*`)
220         c.Check(stdout.String(), check.Matches, `(?ms).*http://localhost:12345/: {}\n.*`)
221 }
222
223 func (s *CommandSuite) TestDump_UnknownKey(c *check.C) {
224         var stdout, stderr bytes.Buffer
225         in := `
226 Clusters:
227  z1234:
228   UnknownKey: foobar
229   ManagementToken: secret
230 `
231         code := DumpCommand.RunCommand("arvados config-dump", []string{"-config", "-"}, bytes.NewBufferString(in), &stdout, &stderr)
232         c.Check(code, check.Equals, 0)
233         c.Check(stderr.String(), check.Matches, `(?ms).*deprecated or unknown config entry: Clusters.z1234.UnknownKey.*`)
234         c.Check(stdout.String(), check.Matches, `(?ms)(.*\n)?Clusters:\n  z1234:\n.*`)
235         c.Check(stdout.String(), check.Matches, `(?ms).*\n *ManagementToken: secret\n.*`)
236         c.Check(stdout.String(), check.Not(check.Matches), `(?ms).*UnknownKey.*`)
237 }
238
239 func (s *CommandSuite) TestDump_KeyOrder(c *check.C) {
240         in := `
241 Clusters:
242  z1234:
243   Login:
244    Test:
245     Users:
246      a: {}
247      d: {}
248      c: {}
249      b: {}
250      e: {}
251 `
252         for trial := 0; trial < 20; trial++ {
253                 var stdout, stderr bytes.Buffer
254                 code := DumpCommand.RunCommand("arvados config-dump", []string{"-config", "-"}, bytes.NewBufferString(in), &stdout, &stderr)
255                 c.Assert(code, check.Equals, 0)
256                 if !c.Check(stdout.String(), check.Matches, `(?ms).*a:.*b:.*c:.*d:.*e:.*`) {
257                         c.Logf("config-dump did not use lexical key order on trial %d", trial)
258                         c.Log("stdout:\n", stdout.String())
259                         c.Log("stderr:\n", stderr.String())
260                         c.FailNow()
261                 }
262         }
263 }
264
265 func (s *CommandSuite) TestCheck_KeyOrder(c *check.C) {
266         in := `
267 Clusters:
268  z1234:
269   ManagementToken: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
270   SystemRootToken: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
271   Collections:
272    BlobSigningKey: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
273   InstanceTypes:
274    a32a: {}
275    a48a: {}
276    a4a: {}
277 `
278         for trial := 0; trial < 20; trial++ {
279                 var stdout, stderr bytes.Buffer
280                 code := CheckCommand.RunCommand("arvados config-check", []string{"-config=-", "-strict=true"}, bytes.NewBufferString(in), &stdout, &stderr)
281                 if !c.Check(code, check.Equals, 0) || stdout.String() != "" || stderr.String() != "" {
282                         c.Logf("config-check returned error or non-empty output on trial %d", trial)
283                         c.Log("stdout:\n", stdout.String())
284                         c.Log("stderr:\n", stderr.String())
285                         c.FailNow()
286                 }
287         }
288 }