2960: Merge branch 'main' into 2960-keepstore-streaming
[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, cmd.EXIT_INVALIDARGUMENT)
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 `
73         code := CheckCommand.RunCommand("arvados config-check", []string{"-config", "-"}, bytes.NewBufferString(in), &stdout, &stderr)
74         c.Check(code, check.Equals, 0)
75         c.Check(stdout.String(), check.Equals, "")
76         c.Check(stderr.String(), check.Equals, "")
77 }
78
79 func (s *CommandSuite) TestCheck_VocabularyErrors(c *check.C) {
80         tmpFile, err := ioutil.TempFile("", "")
81         c.Assert(err, check.IsNil)
82         defer os.Remove(tmpFile.Name())
83         _, err = tmpFile.WriteString(`
84 {
85  "tags": {
86   "IDfoo": {
87    "labels": [
88     {"label": "foo"}
89    ]
90   },
91   "IDfoo": {
92    "labels": [
93     {"label": "baz"}
94    ]
95   }
96  }
97 }`)
98         c.Assert(err, check.IsNil)
99         tmpFile.Close()
100         vocPath := tmpFile.Name()
101         var stdout, stderr bytes.Buffer
102         in := `
103 Clusters:
104  z1234:
105   ManagementToken: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
106   SystemRootToken: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
107   API:
108     MaxItemsPerResponse: 1234
109     VocabularyPath: ` + vocPath + `
110   Collections:
111     BlobSigningKey: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
112   PostgreSQL:
113     Connection:
114       sslmode: require
115   Services:
116     RailsAPI:
117       InternalURLs:
118         "http://0.0.0.0:8000": {}
119   Workbench:
120     UserProfileFormFields:
121       color:
122         Type: select
123         Options:
124           fuchsia: {}
125 `
126         code := CheckCommand.RunCommand("arvados config-check", []string{"-config", "-"}, bytes.NewBufferString(in), &stdout, &stderr)
127         c.Check(code, check.Equals, 1)
128         c.Check(stderr.String(), check.Matches, `(?ms).*Error loading vocabulary file.*for cluster.*duplicate JSON key.*tags.IDfoo.*`)
129 }
130
131 func (s *CommandSuite) TestCheck_DeprecatedKeys(c *check.C) {
132         var stdout, stderr bytes.Buffer
133         in := `
134 Clusters:
135  z1234:
136   RequestLimits:
137     MaxItemsPerResponse: 1234
138 `
139         code := CheckCommand.RunCommand("arvados config-check", []string{"-config", "-"}, bytes.NewBufferString(in), &stdout, &stderr)
140         c.Check(code, check.Equals, 1)
141         c.Check(stdout.String(), check.Matches, `(?ms).*\n\- +.*MaxItemsPerResponse: 1000\n\+ +MaxItemsPerResponse: 1234\n.*`)
142 }
143
144 func (s *CommandSuite) TestCheck_OldKeepstoreConfigFile(c *check.C) {
145         f, err := ioutil.TempFile("", "")
146         c.Assert(err, check.IsNil)
147         defer os.Remove(f.Name())
148
149         io.WriteString(f, "Listen: :12345\nDebug: true\n")
150
151         var stdout, stderr bytes.Buffer
152         in := `
153 Clusters:
154  z1234:
155   SystemLogs:
156     LogLevel: info
157 `
158         code := CheckCommand.RunCommand("arvados config-check", []string{"-config", "-", "-legacy-keepstore-config", f.Name()}, bytes.NewBufferString(in), &stdout, &stderr)
159         c.Check(code, check.Equals, 1)
160         c.Check(stdout.String(), check.Matches, `(?ms).*\n\- +.*LogLevel: info\n\+ +LogLevel: debug\n.*`)
161         c.Check(stderr.String(), check.Matches, `(?ms).*you should remove the legacy keepstore config file.*\n`)
162 }
163
164 func (s *CommandSuite) TestCheck_UnknownKey(c *check.C) {
165         var stdout, stderr bytes.Buffer
166         in := `
167 Clusters:
168  z1234:
169   Bogus1: foo
170   BogusSection:
171     Bogus2: foo
172   API:
173     Bogus3:
174      Bogus4: true
175   PostgreSQL:
176     ConnectionPool:
177       {Bogus5: true}
178 `
179         code := CheckCommand.RunCommand("arvados config-check", []string{"-config", "-"}, bytes.NewBufferString(in), &stdout, &stderr)
180         c.Log(stderr.String())
181         c.Check(code, check.Equals, 1)
182         c.Check(stderr.String(), check.Matches, `(?ms).*deprecated or unknown config entry: Clusters.z1234.Bogus1"\n.*`)
183         c.Check(stderr.String(), check.Matches, `(?ms).*deprecated or unknown config entry: Clusters.z1234.BogusSection"\n.*`)
184         c.Check(stderr.String(), check.Matches, `(?ms).*deprecated or unknown config entry: Clusters.z1234.API.Bogus3"\n.*`)
185         c.Check(stderr.String(), check.Matches, `(?ms).*unexpected object in config entry: Clusters.z1234.PostgreSQL.ConnectionPool"\n.*`)
186 }
187
188 func (s *CommandSuite) TestCheck_DuplicateWarnings(c *check.C) {
189         var stdout, stderr bytes.Buffer
190         in := `
191 Clusters:
192  z1234: {}
193 `
194         code := CheckCommand.RunCommand("arvados config-check", []string{"-config", "-"}, bytes.NewBufferString(in), &stdout, &stderr)
195         c.Check(code, check.Equals, 1)
196         c.Check(stderr.String(), check.Matches, `(?ms).*SystemRootToken.*`)
197         c.Check(stderr.String(), check.Not(check.Matches), `(?ms).*SystemRootToken.*SystemRootToken.*`)
198 }
199
200 func (s *CommandSuite) TestDump_Formatting(c *check.C) {
201         var stdout, stderr bytes.Buffer
202         in := `
203 Clusters:
204  z1234:
205   Containers:
206    CloudVMs:
207     TimeoutBooting: 600s
208   Services:
209    Controller:
210     InternalURLs:
211      http://localhost:12345: {}
212 `
213         code := DumpCommand.RunCommand("arvados config-dump", []string{"-config", "-"}, bytes.NewBufferString(in), &stdout, &stderr)
214         c.Check(code, check.Equals, 0)
215         c.Check(stdout.String(), check.Matches, `(?ms).*TimeoutBooting: 10m\n.*`)
216         c.Check(stdout.String(), check.Matches, `(?ms).*http://localhost:12345/:\n +ListenURL: ""\n.*`)
217 }
218
219 func (s *CommandSuite) TestDump_UnknownKey(c *check.C) {
220         var stdout, stderr bytes.Buffer
221         in := `
222 Clusters:
223  z1234:
224   UnknownKey: foobar
225   ManagementToken: secret
226 `
227         code := DumpCommand.RunCommand("arvados config-dump", []string{"-config", "-"}, bytes.NewBufferString(in), &stdout, &stderr)
228         c.Check(code, check.Equals, 0)
229         c.Check(stderr.String(), check.Matches, `(?ms).*deprecated or unknown config entry: Clusters.z1234.UnknownKey.*`)
230         c.Check(stdout.String(), check.Matches, `(?ms)(.*\n)?Clusters:\n  z1234:\n.*`)
231         c.Check(stdout.String(), check.Matches, `(?ms).*\n *ManagementToken: secret\n.*`)
232         c.Check(stdout.String(), check.Not(check.Matches), `(?ms).*UnknownKey.*`)
233 }
234
235 func (s *CommandSuite) TestDump_KeyOrder(c *check.C) {
236         in := `
237 Clusters:
238  z1234:
239   Login:
240    Test:
241     Users:
242      a: {}
243      d: {}
244      c: {}
245      b: {}
246      e: {}
247 `
248         for trial := 0; trial < 20; trial++ {
249                 var stdout, stderr bytes.Buffer
250                 code := DumpCommand.RunCommand("arvados config-dump", []string{"-config", "-"}, bytes.NewBufferString(in), &stdout, &stderr)
251                 c.Assert(code, check.Equals, 0)
252                 if !c.Check(stdout.String(), check.Matches, `(?ms).*a:.*b:.*c:.*d:.*e:.*`) {
253                         c.Logf("config-dump did not use lexical key order on trial %d", trial)
254                         c.Log("stdout:\n", stdout.String())
255                         c.Log("stderr:\n", stderr.String())
256                         c.FailNow()
257                 }
258         }
259 }
260
261 func (s *CommandSuite) TestCheck_KeyOrder(c *check.C) {
262         in := `
263 Clusters:
264  z1234:
265   ManagementToken: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
266   SystemRootToken: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
267   Collections:
268    BlobSigningKey: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
269   InstanceTypes:
270    a32a: {}
271    a48a: {}
272    a4a: {}
273 `
274         for trial := 0; trial < 20; trial++ {
275                 var stdout, stderr bytes.Buffer
276                 code := CheckCommand.RunCommand("arvados config-check", []string{"-config=-", "-strict=true"}, bytes.NewBufferString(in), &stdout, &stderr)
277                 if !c.Check(code, check.Equals, 0) || stdout.String() != "" || stderr.String() != "" {
278                         c.Logf("config-check returned error or non-empty output on trial %d", trial)
279                         c.Log("stdout:\n", stdout.String())
280                         c.Log("stderr:\n", stderr.String())
281                         c.FailNow()
282                 }
283         }
284 }