1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
15 "git.arvados.org/arvados.git/sdk/go/arvados"
16 "git.arvados.org/arvados.git/sdk/go/arvadosclient"
17 "git.arvados.org/arvados.git/sdk/go/arvadostest"
18 "git.arvados.org/arvados.git/sdk/go/keepclient"
22 func Test(t *testing.T) {
26 var _ = check.Suite(&Suite{})
30 func (s *Suite) TearDownSuite(c *check.C) {
31 // Undo any changes/additions to the database so they don't affect subsequent tests.
32 arvadostest.ResetEnv()
35 func (s *Suite) SetUpSuite(c *check.C) {
36 arvadostest.StartAPI()
37 arvadostest.StartKeep(2, true)
39 // Get the various arvados, arvadosclient, and keep client objects
40 ac := arvados.NewClientFromEnv()
41 arv, err := arvadosclient.MakeArvadosClient()
42 c.Assert(err, check.Equals, nil)
43 arv.ApiToken = arvadostest.ActiveToken
44 kc, err := keepclient.MakeKeepClient(arv)
45 c.Assert(err, check.Equals, nil)
47 standardE4sV3JSON := `{
48 "Name": "Standard_E4s_v3",
49 "ProviderType": "Standard_E4s_v3",
52 "Scratch": 64000000000,
53 "IncludedScratch": 64000000000,
58 standardD32sV3JSON := `{
59 "Name": "Standard_D32s_v3",
60 "ProviderType": "Standard_D32s_v3",
63 "Scratch": 256000000000,
64 "IncludedScratch": 256000000000,
70 standardA1V2JSON := `{
72 "ProviderType": "Standard_A1_v2",
75 "Scratch": 10000000000,
76 "IncludedScratch": 10000000000,
82 standardA2V2JSON := `{
84 "ProviderType": "Standard_A2_v2",
87 "Scratch": 20000000000,
88 "IncludedScratch": 20000000000,
98 "size": "Standard_D1_v2"
100 "total_cpu_cores": 1,
101 "total_ram_mb": 3418,
102 "total_scratch_mb": 51170
106 // Our fixtures do not actually contain file contents. Populate the log collections we're going to use with the node.json file
107 createNodeJSON(c, arv, ac, kc, arvadostest.CompletedContainerRequestUUID, arvadostest.LogCollectionUUID, standardE4sV3JSON)
108 createNodeJSON(c, arv, ac, kc, arvadostest.CompletedContainerRequestUUID2, arvadostest.LogCollectionUUID2, standardD32sV3JSON)
110 createNodeJSON(c, arv, ac, kc, arvadostest.CompletedDiagnosticsContainerRequest1UUID, arvadostest.DiagnosticsContainerRequest1LogCollectionUUID, standardA1V2JSON)
111 createNodeJSON(c, arv, ac, kc, arvadostest.CompletedDiagnosticsContainerRequest2UUID, arvadostest.DiagnosticsContainerRequest2LogCollectionUUID, standardA1V2JSON)
112 createNodeJSON(c, arv, ac, kc, arvadostest.CompletedDiagnosticsHasher1ContainerRequestUUID, arvadostest.Hasher1LogCollectionUUID, standardA1V2JSON)
113 createNodeJSON(c, arv, ac, kc, arvadostest.CompletedDiagnosticsHasher2ContainerRequestUUID, arvadostest.Hasher2LogCollectionUUID, standardA2V2JSON)
114 createNodeJSON(c, arv, ac, kc, arvadostest.CompletedDiagnosticsHasher3ContainerRequestUUID, arvadostest.Hasher3LogCollectionUUID, legacyD1V2JSON)
117 func createNodeJSON(c *check.C, arv *arvadosclient.ArvadosClient, ac *arvados.Client, kc *keepclient.KeepClient, crUUID string, logUUID string, nodeJSON string) {
119 var cr arvados.ContainerRequest
120 err := ac.RequestAndDecode(&cr, "GET", "arvados/v1/container_requests/"+crUUID, nil, nil)
121 c.Assert(err, check.Equals, nil)
122 c.Assert(cr.LogUUID, check.Equals, logUUID)
124 // Get the log collection
125 var coll arvados.Collection
126 err = ac.RequestAndDecode(&coll, "GET", "arvados/v1/collections/"+cr.LogUUID, nil, nil)
127 c.Assert(err, check.IsNil)
129 // Create a node.json file -- the fixture doesn't actually contain the contents of the collection.
130 fs, err := coll.FileSystem(ac, kc)
131 c.Assert(err, check.IsNil)
132 f, err := fs.OpenFile("node.json", os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
133 c.Assert(err, check.IsNil)
134 _, err = io.WriteString(f, nodeJSON)
135 c.Assert(err, check.IsNil)
137 c.Assert(err, check.IsNil)
139 // Flush the data to Keep
140 mtxt, err := fs.MarshalManifest(".")
141 c.Assert(err, check.IsNil)
142 c.Assert(mtxt, check.NotNil)
144 // Update collection record
145 err = ac.RequestAndDecode(&coll, "PUT", "arvados/v1/collections/"+cr.LogUUID, nil, map[string]interface{}{
146 "collection": map[string]interface{}{
147 "manifest_text": mtxt,
150 c.Assert(err, check.IsNil)
153 func (*Suite) TestUsage(c *check.C) {
154 var stdout, stderr bytes.Buffer
155 exitcode := Command.RunCommand("costanalyzer.test", []string{"-help", "-log-level=debug"}, &bytes.Buffer{}, &stdout, &stderr)
156 c.Check(exitcode, check.Equals, 1)
157 c.Check(stdout.String(), check.Equals, "")
158 c.Check(stderr.String(), check.Matches, `(?ms).*Usage:.*`)
161 func (*Suite) TestContainerRequestUUID(c *check.C) {
162 var stdout, stderr bytes.Buffer
163 resultsDir := c.MkDir()
164 // Run costanalyzer with 1 container request uuid
165 exitcode := Command.RunCommand("costanalyzer.test", []string{"-output", resultsDir, arvadostest.CompletedContainerRequestUUID}, &bytes.Buffer{}, &stdout, &stderr)
166 c.Check(exitcode, check.Equals, 0)
167 c.Assert(stderr.String(), check.Matches, "(?ms).*supplied uuids in .*")
169 uuidReport, err := ioutil.ReadFile(resultsDir + "/" + arvadostest.CompletedContainerRequestUUID + ".csv")
170 c.Assert(err, check.IsNil)
171 c.Check(string(uuidReport), check.Matches, "(?ms).*TOTAL,,,,,,,,,7.01302889")
172 re := regexp.MustCompile(`(?ms).*supplied uuids in (.*?)\n`)
173 matches := re.FindStringSubmatch(stderr.String()) // matches[1] contains a string like 'results/2020-11-02-18-57-45-aggregate-costaccounting.csv'
175 aggregateCostReport, err := ioutil.ReadFile(matches[1])
176 c.Assert(err, check.IsNil)
178 c.Check(string(aggregateCostReport), check.Matches, "(?ms).*TOTAL,7.01302889")
181 func (*Suite) TestCollectionUUID(c *check.C) {
182 var stdout, stderr bytes.Buffer
184 resultsDir := c.MkDir()
185 // Run costanalyzer with 1 collection uuid, without 'container_request' property
186 exitcode := Command.RunCommand("costanalyzer.test", []string{"-output", resultsDir, arvadostest.FooCollection}, &bytes.Buffer{}, &stdout, &stderr)
187 c.Check(exitcode, check.Equals, 2)
188 c.Assert(stderr.String(), check.Matches, "(?ms).*does not have a 'container_request' property.*")
190 // Update the collection, attach a 'container_request' property
191 ac := arvados.NewClientFromEnv()
192 var coll arvados.Collection
194 // Update collection record
195 err := ac.RequestAndDecode(&coll, "PUT", "arvados/v1/collections/"+arvadostest.FooCollection, nil, map[string]interface{}{
196 "collection": map[string]interface{}{
197 "properties": map[string]interface{}{
198 "container_request": arvadostest.CompletedContainerRequestUUID,
202 c.Assert(err, check.IsNil)
207 // Run costanalyzer with 1 collection uuid
208 resultsDir = c.MkDir()
209 exitcode = Command.RunCommand("costanalyzer.test", []string{"-output", resultsDir, arvadostest.FooCollection}, &bytes.Buffer{}, &stdout, &stderr)
210 c.Check(exitcode, check.Equals, 0)
211 c.Assert(stderr.String(), check.Matches, "(?ms).*supplied uuids in .*")
213 uuidReport, err := ioutil.ReadFile(resultsDir + "/" + arvadostest.CompletedContainerRequestUUID + ".csv")
214 c.Assert(err, check.IsNil)
215 c.Check(string(uuidReport), check.Matches, "(?ms).*TOTAL,,,,,,,,,7.01302889")
216 re := regexp.MustCompile(`(?ms).*supplied uuids in (.*?)\n`)
217 matches := re.FindStringSubmatch(stderr.String()) // matches[1] contains a string like 'results/2020-11-02-18-57-45-aggregate-costaccounting.csv'
219 aggregateCostReport, err := ioutil.ReadFile(matches[1])
220 c.Assert(err, check.IsNil)
222 c.Check(string(aggregateCostReport), check.Matches, "(?ms).*TOTAL,7.01302889")
225 func (*Suite) TestDoubleContainerRequestUUID(c *check.C) {
226 var stdout, stderr bytes.Buffer
227 resultsDir := c.MkDir()
228 // Run costanalyzer with 2 container request uuids
229 exitcode := Command.RunCommand("costanalyzer.test", []string{"-output", resultsDir, arvadostest.CompletedContainerRequestUUID, arvadostest.CompletedContainerRequestUUID2}, &bytes.Buffer{}, &stdout, &stderr)
230 c.Check(exitcode, check.Equals, 0)
231 c.Assert(stderr.String(), check.Matches, "(?ms).*supplied uuids in .*")
233 uuidReport, err := ioutil.ReadFile(resultsDir + "/" + arvadostest.CompletedContainerRequestUUID + ".csv")
234 c.Assert(err, check.IsNil)
235 c.Check(string(uuidReport), check.Matches, "(?ms).*TOTAL,,,,,,,,,7.01302889")
237 uuidReport2, err := ioutil.ReadFile(resultsDir + "/" + arvadostest.CompletedContainerRequestUUID2 + ".csv")
238 c.Assert(err, check.IsNil)
239 c.Check(string(uuidReport2), check.Matches, "(?ms).*TOTAL,,,,,,,,,42.27031111")
241 re := regexp.MustCompile(`(?ms).*supplied uuids in (.*?)\n`)
242 matches := re.FindStringSubmatch(stderr.String()) // matches[1] contains a string like 'results/2020-11-02-18-57-45-aggregate-costaccounting.csv'
244 aggregateCostReport, err := ioutil.ReadFile(matches[1])
245 c.Assert(err, check.IsNil)
247 c.Check(string(aggregateCostReport), check.Matches, "(?ms).*TOTAL,49.28334000")
251 // Now move both container requests into an existing project, and then re-run
252 // the analysis with the project uuid. The results should be identical.
253 ac := arvados.NewClientFromEnv()
254 var cr arvados.ContainerRequest
255 err = ac.RequestAndDecode(&cr, "PUT", "arvados/v1/container_requests/"+arvadostest.CompletedContainerRequestUUID, nil, map[string]interface{}{
256 "container_request": map[string]interface{}{
257 "owner_uuid": arvadostest.AProjectUUID,
260 c.Assert(err, check.IsNil)
261 err = ac.RequestAndDecode(&cr, "PUT", "arvados/v1/container_requests/"+arvadostest.CompletedContainerRequestUUID2, nil, map[string]interface{}{
262 "container_request": map[string]interface{}{
263 "owner_uuid": arvadostest.AProjectUUID,
266 c.Assert(err, check.IsNil)
268 // Run costanalyzer with the project uuid
269 resultsDir = c.MkDir()
270 exitcode = Command.RunCommand("costanalyzer.test", []string{"-cache=false", "-log-level", "debug", "-output", resultsDir, arvadostest.AProjectUUID}, &bytes.Buffer{}, &stdout, &stderr)
271 c.Check(exitcode, check.Equals, 0)
272 c.Assert(stderr.String(), check.Matches, "(?ms).*supplied uuids in .*")
274 uuidReport, err = ioutil.ReadFile(resultsDir + "/" + arvadostest.CompletedContainerRequestUUID + ".csv")
275 c.Assert(err, check.IsNil)
276 c.Check(string(uuidReport), check.Matches, "(?ms).*TOTAL,,,,,,,,,7.01302889")
278 uuidReport2, err = ioutil.ReadFile(resultsDir + "/" + arvadostest.CompletedContainerRequestUUID2 + ".csv")
279 c.Assert(err, check.IsNil)
280 c.Check(string(uuidReport2), check.Matches, "(?ms).*TOTAL,,,,,,,,,42.27031111")
282 re = regexp.MustCompile(`(?ms).*supplied uuids in (.*?)\n`)
283 matches = re.FindStringSubmatch(stderr.String()) // matches[1] contains a string like 'results/2020-11-02-18-57-45-aggregate-costaccounting.csv'
285 aggregateCostReport, err = ioutil.ReadFile(matches[1])
286 c.Assert(err, check.IsNil)
288 c.Check(string(aggregateCostReport), check.Matches, "(?ms).*TOTAL,49.28334000")
291 func (*Suite) TestMultipleContainerRequestUUIDWithReuse(c *check.C) {
292 var stdout, stderr bytes.Buffer
293 // Run costanalyzer with 2 container request uuids, without output directory specified
294 exitcode := Command.RunCommand("costanalyzer.test", []string{arvadostest.CompletedDiagnosticsContainerRequest1UUID, arvadostest.CompletedDiagnosticsContainerRequest2UUID}, &bytes.Buffer{}, &stdout, &stderr)
295 c.Check(exitcode, check.Equals, 0)
296 c.Assert(stderr.String(), check.Not(check.Matches), "(?ms).*supplied uuids in .*")
298 // Check that the total amount was printed to stdout
299 c.Check(stdout.String(), check.Matches, "0.01492030\n")
304 // Run costanalyzer with 2 container request uuids
305 resultsDir := c.MkDir()
306 exitcode = Command.RunCommand("costanalyzer.test", []string{"-output", resultsDir, arvadostest.CompletedDiagnosticsContainerRequest1UUID, arvadostest.CompletedDiagnosticsContainerRequest2UUID}, &bytes.Buffer{}, &stdout, &stderr)
307 c.Check(exitcode, check.Equals, 0)
308 c.Assert(stderr.String(), check.Matches, "(?ms).*supplied uuids in .*")
310 uuidReport, err := ioutil.ReadFile(resultsDir + "/" + arvadostest.CompletedDiagnosticsContainerRequest1UUID + ".csv")
311 c.Assert(err, check.IsNil)
312 c.Check(string(uuidReport), check.Matches, "(?ms).*TOTAL,,,,,,,,,0.00916192")
314 uuidReport2, err := ioutil.ReadFile(resultsDir + "/" + arvadostest.CompletedDiagnosticsContainerRequest2UUID + ".csv")
315 c.Assert(err, check.IsNil)
316 c.Check(string(uuidReport2), check.Matches, "(?ms).*TOTAL,,,,,,,,,0.00588088")
318 re := regexp.MustCompile(`(?ms).*supplied uuids in (.*?)\n`)
319 matches := re.FindStringSubmatch(stderr.String()) // matches[1] contains a string like 'results/2020-11-02-18-57-45-aggregate-costaccounting.csv'
321 aggregateCostReport, err := ioutil.ReadFile(matches[1])
322 c.Assert(err, check.IsNil)
324 c.Check(string(aggregateCostReport), check.Matches, "(?ms).*TOTAL,0.01492030")