1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
5 package recovercollection
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"
21 func Test(t *testing.T) {
25 var _ = check.Suite(&Suite{})
29 func (*Suite) SetUpSuite(c *check.C) {
30 arvadostest.StartAPI()
31 arvadostest.StartKeep(2, true)
34 func (*Suite) TestUnrecoverableBlock(c *check.C) {
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".*`)
49 func (*Suite) TestUntrashAndTouchBlock(c *check.C) {
51 mfile := tmp + "/manifest"
52 ioutil.WriteFile(mfile, []byte(". dcd0348cb2532ee90c99f1b846efaee7+13 0:13:test.txt\n"), 0777)
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)
61 for _, v := range cluster.Volumes {
65 err := json.Unmarshal(v.DriverParameters, ¶ms)
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) {
75 c.Logf("keepstore datadirs are %q", datadirs)
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() {
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)
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.*`)
104 for _, datadir := range datadirs {
105 buf, err := ioutil.ReadFile(datadir + "/dcd/dcd0348cb2532ee90c99f1b846efaee7")
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)
116 c.Check(found, check.Equals, true)
119 func (*Suite) TestUnusableManifestSourceArg(c *check.C) {
120 for _, trial := range []struct {
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.*`},
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)