Merge branch 'master' into 14930-arvput-trash-at
[arvados.git] / sdk / go / arvados / fs_project_test.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: Apache-2.0
4
5 package arvados
6
7 import (
8         "bytes"
9         "encoding/json"
10         "io"
11         "os"
12         "path/filepath"
13         "strings"
14
15         check "gopkg.in/check.v1"
16 )
17
18 type spiedRequest struct {
19         method string
20         path   string
21         params map[string]interface{}
22 }
23
24 type spyingClient struct {
25         *Client
26         calls []spiedRequest
27 }
28
29 func (sc *spyingClient) RequestAndDecode(dst interface{}, method, path string, body io.Reader, params interface{}) error {
30         var paramsCopy map[string]interface{}
31         var buf bytes.Buffer
32         json.NewEncoder(&buf).Encode(params)
33         json.NewDecoder(&buf).Decode(&paramsCopy)
34         sc.calls = append(sc.calls, spiedRequest{
35                 method: method,
36                 path:   path,
37                 params: paramsCopy,
38         })
39         return sc.Client.RequestAndDecode(dst, method, path, body, params)
40 }
41
42 func (s *SiteFSSuite) TestCurrentUserHome(c *check.C) {
43         s.fs.MountProject("home", "")
44         s.testHomeProject(c, "/home")
45 }
46
47 func (s *SiteFSSuite) TestUsersDir(c *check.C) {
48         s.testHomeProject(c, "/users/active")
49 }
50
51 func (s *SiteFSSuite) testHomeProject(c *check.C, path string) {
52         f, err := s.fs.Open(path)
53         c.Assert(err, check.IsNil)
54         fis, err := f.Readdir(-1)
55         c.Check(len(fis), check.Not(check.Equals), 0)
56
57         ok := false
58         for _, fi := range fis {
59                 c.Check(fi.Name(), check.Not(check.Equals), "")
60                 if fi.Name() == "A Project" {
61                         ok = true
62                 }
63         }
64         c.Check(ok, check.Equals, true)
65
66         f, err = s.fs.Open(path + "/A Project/..")
67         c.Assert(err, check.IsNil)
68         fi, err := f.Stat()
69         c.Assert(err, check.IsNil)
70         c.Check(fi.IsDir(), check.Equals, true)
71         _, basename := filepath.Split(path)
72         c.Check(fi.Name(), check.Equals, basename)
73
74         f, err = s.fs.Open(path + "/A Project/A Subproject")
75         c.Assert(err, check.IsNil)
76         fi, err = f.Stat()
77         c.Assert(err, check.IsNil)
78         c.Check(fi.IsDir(), check.Equals, true)
79
80         for _, nx := range []string{
81                 path + "/Unrestricted public data",
82                 path + "/Unrestricted public data/does not exist",
83                 path + "/A Project/does not exist",
84         } {
85                 c.Log(nx)
86                 f, err = s.fs.Open(nx)
87                 c.Check(err, check.NotNil)
88                 c.Check(os.IsNotExist(err), check.Equals, true)
89         }
90 }
91
92 func (s *SiteFSSuite) TestProjectReaddirAfterLoadOne(c *check.C) {
93         f, err := s.fs.Open("/users/active/A Project/A Subproject")
94         c.Assert(err, check.IsNil)
95         defer f.Close()
96         f, err = s.fs.Open("/users/active/A Project/Project does not exist")
97         c.Assert(err, check.NotNil)
98         f, err = s.fs.Open("/users/active/A Project/A Subproject")
99         c.Assert(err, check.IsNil)
100         defer f.Close()
101         f, err = s.fs.Open("/users/active/A Project")
102         c.Assert(err, check.IsNil)
103         defer f.Close()
104         fis, err := f.Readdir(-1)
105         c.Assert(err, check.IsNil)
106         c.Logf("%#v", fis)
107         var foundSubproject, foundCollection bool
108         for _, fi := range fis {
109                 switch fi.Name() {
110                 case "A Subproject":
111                         foundSubproject = true
112                 case "collection_to_move_around":
113                         foundCollection = true
114                 }
115         }
116         c.Check(foundSubproject, check.Equals, true)
117         c.Check(foundCollection, check.Equals, true)
118 }
119
120 func (s *SiteFSSuite) TestSlashInName(c *check.C) {
121         badCollection := Collection{
122                 Name:      "bad/collection",
123                 OwnerUUID: fixtureAProjectUUID,
124         }
125         err := s.client.RequestAndDecode(&badCollection, "POST", "arvados/v1/collections", s.client.UpdateBody(&badCollection), nil)
126         c.Assert(err, check.IsNil)
127         defer s.client.RequestAndDecode(nil, "DELETE", "arvados/v1/collections/"+badCollection.UUID, nil, nil)
128
129         badProject := Group{
130                 Name:       "bad/project",
131                 GroupClass: "project",
132                 OwnerUUID:  fixtureAProjectUUID,
133         }
134         err = s.client.RequestAndDecode(&badProject, "POST", "arvados/v1/groups", s.client.UpdateBody(&badProject), nil)
135         c.Assert(err, check.IsNil)
136         defer s.client.RequestAndDecode(nil, "DELETE", "arvados/v1/groups/"+badProject.UUID, nil, nil)
137
138         dir, err := s.fs.Open("/users/active/A Project")
139         c.Assert(err, check.IsNil)
140         fis, err := dir.Readdir(-1)
141         c.Check(err, check.IsNil)
142         for _, fi := range fis {
143                 c.Logf("fi.Name() == %q", fi.Name())
144                 c.Check(strings.Contains(fi.Name(), "/"), check.Equals, false)
145         }
146 }
147
148 func (s *SiteFSSuite) TestProjectUpdatedByOther(c *check.C) {
149         s.fs.MountProject("home", "")
150
151         project, err := s.fs.OpenFile("/home/A Project", 0, 0)
152         c.Assert(err, check.IsNil)
153
154         _, err = s.fs.Open("/home/A Project/oob")
155         c.Check(err, check.NotNil)
156
157         oob := Collection{
158                 Name:      "oob",
159                 OwnerUUID: fixtureAProjectUUID,
160         }
161         err = s.client.RequestAndDecode(&oob, "POST", "arvados/v1/collections", s.client.UpdateBody(&oob), nil)
162         c.Assert(err, check.IsNil)
163         defer s.client.RequestAndDecode(nil, "DELETE", "arvados/v1/collections/"+oob.UUID, nil, nil)
164
165         err = project.Sync()
166         c.Check(err, check.IsNil)
167         f, err := s.fs.Open("/home/A Project/oob")
168         c.Assert(err, check.IsNil)
169         fi, err := f.Stat()
170         c.Assert(err, check.IsNil)
171         c.Check(fi.IsDir(), check.Equals, true)
172         f.Close()
173
174         wf, err := s.fs.OpenFile("/home/A Project/oob/test.txt", os.O_CREATE|os.O_RDWR, 0700)
175         c.Assert(err, check.IsNil)
176         _, err = wf.Write([]byte("hello oob\n"))
177         c.Check(err, check.IsNil)
178         err = wf.Close()
179         c.Check(err, check.IsNil)
180
181         // Delete test.txt behind s.fs's back by updating the
182         // collection record with the old (empty) ManifestText.
183         err = s.client.RequestAndDecode(nil, "PATCH", "arvados/v1/collections/"+oob.UUID, s.client.UpdateBody(&oob), nil)
184         c.Assert(err, check.IsNil)
185
186         err = project.Sync()
187         c.Check(err, check.IsNil)
188         _, err = s.fs.Open("/home/A Project/oob/test.txt")
189         c.Check(err, check.NotNil)
190         _, err = s.fs.Open("/home/A Project/oob")
191         c.Check(err, check.IsNil)
192
193         err = s.client.RequestAndDecode(nil, "DELETE", "arvados/v1/collections/"+oob.UUID, nil, nil)
194         c.Assert(err, check.IsNil)
195
196         err = project.Sync()
197         c.Check(err, check.IsNil)
198         _, err = s.fs.Open("/home/A Project/oob")
199         c.Check(err, check.NotNil)
200 }