Merge branch '16171-oidc-config'
[arvados.git] / lib / recovercollection / cmd_test.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 package recovercollection
6
7 import (
8         "bytes"
9         "encoding/json"
10         "io/ioutil"
11         "os"
12         "testing"
13         "time"
14
15         "git.arvados.org/arvados.git/lib/config"
16         "git.arvados.org/arvados.git/sdk/go/arvadostest"
17         "git.arvados.org/arvados.git/sdk/go/ctxlog"
18         "gopkg.in/check.v1"
19 )
20
21 func Test(t *testing.T) {
22         check.TestingT(t)
23 }
24
25 var _ = check.Suite(&Suite{})
26
27 type Suite struct{}
28
29 func (*Suite) SetUpSuite(c *check.C) {
30         arvadostest.StartAPI()
31         arvadostest.StartKeep(2, true)
32 }
33
34 func (*Suite) TestUnrecoverableBlock(c *check.C) {
35         tmp := c.MkDir()
36         mfile := tmp + "/manifest"
37         ioutil.WriteFile(mfile, []byte(". aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa+410 0:410:Gone\n"), 0777)
38         var stdout, stderr bytes.Buffer
39         exitcode := Command.RunCommand("recovercollection.test", []string{"-log-level=debug", mfile}, &bytes.Buffer{}, &stdout, &stderr)
40         c.Check(exitcode, check.Equals, 1)
41         c.Check(stdout.String(), check.Equals, "")
42         c.Log(stderr.String())
43         c.Check(stderr.String(), check.Matches, `(?ms).*msg="not found" block=aaaaa.*`)
44         c.Check(stderr.String(), check.Matches, `(?ms).*msg="untrash failed" block=aaaaa.*`)
45         c.Check(stderr.String(), check.Matches, `(?ms).*msg=unrecoverable block=aaaaa.*`)
46         c.Check(stderr.String(), check.Matches, `(?ms).*msg="recovery failed".*`)
47 }
48
49 func (*Suite) TestUntrashAndTouchBlock(c *check.C) {
50         tmp := c.MkDir()
51         mfile := tmp + "/manifest"
52         ioutil.WriteFile(mfile, []byte(". dcd0348cb2532ee90c99f1b846efaee7+13 0:13:test.txt\n"), 0777)
53
54         logger := ctxlog.TestLogger(c)
55         loader := config.NewLoader(&bytes.Buffer{}, logger)
56         cfg, err := loader.Load()
57         c.Assert(err, check.IsNil)
58         cluster, err := cfg.GetCluster("")
59         c.Assert(err, check.IsNil)
60         var datadirs []string
61         for _, v := range cluster.Volumes {
62                 var params struct {
63                         Root string
64                 }
65                 err := json.Unmarshal(v.DriverParameters, &params)
66                 c.Assert(err, check.IsNil)
67                 if params.Root != "" {
68                         datadirs = append(datadirs, params.Root)
69                         err := os.Remove(params.Root + "/dcd/dcd0348cb2532ee90c99f1b846efaee7")
70                         if err != nil && !os.IsNotExist(err) {
71                                 c.Error(err)
72                         }
73                 }
74         }
75         c.Logf("keepstore datadirs are %q", datadirs)
76
77         // Currently StartKeep(2, true) uses dirs called "keep0" and
78         // "keep1" so we could just put our fake trashed file in keep0
79         // ... but we don't want to rely on arvadostest's
80         // implementation details, so we put a trashed file in every
81         // dir that keepstore might be using.
82         for _, datadir := range datadirs {
83                 if fi, err := os.Stat(datadir); err != nil || !fi.IsDir() {
84                         continue
85                 }
86                 c.Logf("placing backdated trashed block in datadir %q", datadir)
87                 trashfile := datadir + "/dcd/dcd0348cb2532ee90c99f1b846efaee7.trash.999999999"
88                 os.Mkdir(datadir+"/dcd", 0777)
89                 err = ioutil.WriteFile(trashfile, []byte("undelete test"), 0777)
90                 c.Assert(err, check.IsNil)
91                 t := time.Now().Add(-time.Hour * 24 * 365)
92                 err = os.Chtimes(trashfile, t, t)
93         }
94
95         var stdout, stderr bytes.Buffer
96         exitcode := Command.RunCommand("recovercollection.test", []string{"-log-level=debug", mfile}, &bytes.Buffer{}, &stdout, &stderr)
97         c.Check(exitcode, check.Equals, 0)
98         c.Check(stdout.String(), check.Matches, `zzzzz-4zz18-.{15}\n`)
99         c.Log(stderr.String())
100         c.Check(stderr.String(), check.Matches, `(?ms).*msg=untrashed block=dcd0348.*`)
101         c.Check(stderr.String(), check.Matches, `(?ms).*msg="updated timestamp" block=dcd0348.*`)
102
103         found := false
104         for _, datadir := range datadirs {
105                 buf, err := ioutil.ReadFile(datadir + "/dcd/dcd0348cb2532ee90c99f1b846efaee7")
106                 if err == nil {
107                         found = true
108                         c.Check(buf, check.DeepEquals, []byte("undelete test"))
109                         fi, err := os.Stat(datadir + "/dcd/dcd0348cb2532ee90c99f1b846efaee7")
110                         if c.Check(err, check.IsNil) {
111                                 c.Logf("recovered block's modtime is %s", fi.ModTime())
112                                 c.Check(time.Now().Sub(fi.ModTime()) < time.Hour, check.Equals, true)
113                         }
114                 }
115         }
116         c.Check(found, check.Equals, true)
117 }
118
119 func (*Suite) TestUnusableManifestSourceArg(c *check.C) {
120         for _, trial := range []struct {
121                 srcArg    string
122                 errRegexp string
123         }{
124                 {"zzzzz-4zz18-aaaaaaaaaaaaaaa", `(?ms).*msg="log entry not found".*`},
125                 {"zzzzz-57u5n-aaaaaaaaaaaaaaa", `(?ms).*msg="log entry not found.*`},
126                 {"zzzzz-57u5n-containerlog006", `(?ms).*msg="log entry properties\.old_attributes\.manifest_text missing or empty".*`},
127                 {"zzzzz-j7d0g-aaaaaaaaaaaaaaa", `(?ms).*msg="looks like a UUID but not a log or collection UUID.*`},
128         } {
129                 var stdout, stderr bytes.Buffer
130                 exitcode := Command.RunCommand("recovercollection.test", []string{"-log-level=debug", trial.srcArg}, &bytes.Buffer{}, &stdout, &stderr)
131                 c.Check(exitcode, check.Equals, 1)
132                 c.Check(stdout.String(), check.Equals, "")
133                 c.Log(stderr.String())
134                 c.Check(stderr.String(), check.Matches, trial.errRegexp)
135         }
136 }