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.StartKeep(2, true)
33 func (*Suite) TestUnrecoverableBlock(c *check.C) {
35 mfile := tmp + "/manifest"
36 ioutil.WriteFile(mfile, []byte(". aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa+410 0:410:Gone\n"), 0777)
37 var stdout, stderr bytes.Buffer
38 exitcode := Command.RunCommand("recovercollection.test", []string{"-log-level=debug", mfile}, &bytes.Buffer{}, &stdout, &stderr)
39 c.Check(exitcode, check.Equals, 1)
40 c.Check(stdout.String(), check.Equals, "")
41 c.Log(stderr.String())
42 c.Check(stderr.String(), check.Matches, `(?ms).*msg="not found" block=aaaaa.*`)
43 c.Check(stderr.String(), check.Matches, `(?ms).*msg="untrash failed" block=aaaaa.*`)
44 c.Check(stderr.String(), check.Matches, `(?ms).*msg=unrecoverable block=aaaaa.*`)
45 c.Check(stderr.String(), check.Matches, `(?ms).*msg="recovery failed".*`)
48 func (*Suite) TestUntrashAndTouchBlock(c *check.C) {
50 mfile := tmp + "/manifest"
51 ioutil.WriteFile(mfile, []byte(". dcd0348cb2532ee90c99f1b846efaee7+13 0:13:test.txt\n"), 0777)
53 logger := ctxlog.TestLogger(c)
54 loader := config.NewLoader(&bytes.Buffer{}, logger)
55 cfg, err := loader.Load()
56 c.Assert(err, check.IsNil)
57 cluster, err := cfg.GetCluster("")
58 c.Assert(err, check.IsNil)
60 for _, v := range cluster.Volumes {
64 err := json.Unmarshal(v.DriverParameters, ¶ms)
65 c.Assert(err, check.IsNil)
66 if params.Root != "" {
67 datadirs = append(datadirs, params.Root)
68 err := os.Remove(params.Root + "/dcd/dcd0348cb2532ee90c99f1b846efaee7")
69 if err != nil && !os.IsNotExist(err) {
74 c.Logf("keepstore datadirs are %q", datadirs)
76 // Currently StartKeep(2, true) uses dirs called "keep0" and
77 // "keep1" so we could just put our fake trashed file in keep0
78 // ... but we don't want to rely on arvadostest's
79 // implementation details, so we put a trashed file in every
80 // dir that keepstore might be using.
81 for _, datadir := range datadirs {
82 if fi, err := os.Stat(datadir); err != nil || !fi.IsDir() {
85 c.Logf("placing backdated trashed block in datadir %q", datadir)
86 trashfile := datadir + "/dcd/dcd0348cb2532ee90c99f1b846efaee7.trash.999999999"
87 os.Mkdir(datadir+"/dcd", 0777)
88 err = ioutil.WriteFile(trashfile, []byte("undelete test"), 0777)
89 c.Assert(err, check.IsNil)
90 t := time.Now().Add(-time.Hour * 24 * 365)
91 err = os.Chtimes(trashfile, t, t)
92 c.Assert(err, check.IsNil)
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)