1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: Apache-2.0
15 check "gopkg.in/check.v1"
18 type spiedRequest struct {
21 params map[string]interface{}
24 type spyingClient struct {
29 func (sc *spyingClient) RequestAndDecode(dst interface{}, method, path string, body io.Reader, params interface{}) error {
30 var paramsCopy map[string]interface{}
32 json.NewEncoder(&buf).Encode(params)
33 json.NewDecoder(&buf).Decode(¶msCopy)
34 sc.calls = append(sc.calls, spiedRequest{
39 return sc.Client.RequestAndDecode(dst, method, path, body, params)
42 func (s *SiteFSSuite) TestFilterGroup(c *check.C) {
43 // Make sure that a collection and group that match the filter are present,
44 // and that a group that does not match the filter is not present.
45 s.fs.MountProject("fg", fixtureThisFilterGroupUUID)
47 _, err := s.fs.OpenFile("/fg/baz_file", 0, 0)
48 c.Assert(err, check.IsNil)
50 _, err = s.fs.OpenFile("/fg/A Subproject", 0, 0)
51 c.Assert(err, check.IsNil)
53 _, err = s.fs.OpenFile("/fg/A Project", 0, 0)
54 c.Assert(err, check.Not(check.IsNil))
56 // An empty filter means everything that is visible should be returned.
57 s.fs.MountProject("fg2", fixtureAFilterGroupTwoUUID)
59 _, err = s.fs.OpenFile("/fg2/baz_file", 0, 0)
60 c.Assert(err, check.IsNil)
62 _, err = s.fs.OpenFile("/fg2/A Subproject", 0, 0)
63 c.Assert(err, check.IsNil)
65 _, err = s.fs.OpenFile("/fg2/A Project", 0, 0)
66 c.Assert(err, check.IsNil)
68 // An 'is_a' 'arvados#collection' filter means only collections should be returned.
69 s.fs.MountProject("fg3", fixtureAFilterGroupThreeUUID)
71 _, err = s.fs.OpenFile("/fg3/baz_file", 0, 0)
72 c.Assert(err, check.IsNil)
74 _, err = s.fs.OpenFile("/fg3/A Subproject", 0, 0)
75 c.Assert(err, check.Not(check.IsNil))
78 func (s *SiteFSSuite) TestCurrentUserHome(c *check.C) {
79 s.fs.MountProject("home", "")
80 s.testHomeProject(c, "/home")
83 func (s *SiteFSSuite) TestUsersDir(c *check.C) {
84 s.testHomeProject(c, "/users/active")
87 func (s *SiteFSSuite) testHomeProject(c *check.C, path string) {
88 f, err := s.fs.Open(path)
89 c.Assert(err, check.IsNil)
90 fis, err := f.Readdir(-1)
91 c.Assert(err, check.IsNil)
92 c.Check(len(fis), check.Not(check.Equals), 0)
95 for _, fi := range fis {
96 c.Check(fi.Name(), check.Not(check.Equals), "")
97 if fi.Name() == "A Project" {
101 c.Check(ok, check.Equals, true)
103 f, err = s.fs.Open(path + "/A Project/..")
104 c.Assert(err, check.IsNil)
106 c.Assert(err, check.IsNil)
107 c.Check(fi.IsDir(), check.Equals, true)
108 _, basename := filepath.Split(path)
109 c.Check(fi.Name(), check.Equals, basename)
111 f, err = s.fs.Open(path + "/A Project/A Subproject")
112 c.Assert(err, check.IsNil)
114 c.Assert(err, check.IsNil)
115 c.Check(fi.IsDir(), check.Equals, true)
117 for _, nx := range []string{
118 path + "/Unrestricted public data",
119 path + "/Unrestricted public data/does not exist",
120 path + "/A Project/does not exist",
123 f, err = s.fs.Open(nx)
124 c.Check(err, check.NotNil)
125 c.Check(os.IsNotExist(err), check.Equals, true)
129 func (s *SiteFSSuite) TestProjectReaddirAfterLoadOne(c *check.C) {
130 f, err := s.fs.Open("/users/active/A Project/A Subproject")
131 c.Assert(err, check.IsNil)
133 f, err = s.fs.Open("/users/active/A Project/Project does not exist")
134 c.Assert(err, check.NotNil)
135 f, err = s.fs.Open("/users/active/A Project/A Subproject")
136 c.Assert(err, check.IsNil)
138 f, err = s.fs.Open("/users/active/A Project")
139 c.Assert(err, check.IsNil)
141 fis, err := f.Readdir(-1)
142 c.Assert(err, check.IsNil)
144 var foundSubproject, foundCollection bool
145 for _, fi := range fis {
148 foundSubproject = true
149 case "collection_to_move_around":
150 foundCollection = true
153 c.Check(foundSubproject, check.Equals, true)
154 c.Check(foundCollection, check.Equals, true)
157 func (s *SiteFSSuite) TestSlashInName(c *check.C) {
158 var badCollection Collection
159 err := s.client.RequestAndDecode(&badCollection, "POST", "arvados/v1/collections", nil, map[string]interface{}{
160 "collection": map[string]string{
161 "name": "bad/collection",
162 "owner_uuid": fixtureAProjectUUID,
165 c.Assert(err, check.IsNil)
166 defer s.client.RequestAndDecode(nil, "DELETE", "arvados/v1/collections/"+badCollection.UUID, nil, nil)
169 err = s.client.RequestAndDecode(&badProject, "POST", "arvados/v1/groups", nil, map[string]interface{}{
170 "group": map[string]string{
171 "name": "bad/project",
172 "group_class": "project",
173 "owner_uuid": fixtureAProjectUUID,
176 c.Assert(err, check.IsNil)
177 defer s.client.RequestAndDecode(nil, "DELETE", "arvados/v1/groups/"+badProject.UUID, nil, nil)
179 dir, err := s.fs.Open("/users/active/A Project")
180 c.Assert(err, check.IsNil)
181 fis, err := dir.Readdir(-1)
182 c.Check(err, check.IsNil)
183 for _, fi := range fis {
184 c.Logf("fi.Name() == %q", fi.Name())
185 c.Check(strings.Contains(fi.Name(), "/"), check.Equals, false)
188 // Make a new fs (otherwise content will still be cached from
189 // above) and enable "/" replacement string.
190 s.fs = s.client.SiteFileSystem(s.kc)
191 s.fs.ForwardSlashNameSubstitution("___")
192 dir, err = s.fs.Open("/users/active/A Project/bad___collection")
193 if c.Check(err, check.IsNil) {
194 _, err = dir.Readdir(-1)
195 c.Check(err, check.IsNil)
197 dir, err = s.fs.Open("/users/active/A Project/bad___project")
198 if c.Check(err, check.IsNil) {
199 _, err = dir.Readdir(-1)
200 c.Check(err, check.IsNil)
204 func (s *SiteFSSuite) TestProjectUpdatedByOther(c *check.C) {
205 s.fs.MountProject("home", "")
207 project, err := s.fs.OpenFile("/home/A Project", 0, 0)
208 c.Assert(err, check.IsNil)
210 _, err = s.fs.Open("/home/A Project/oob")
211 c.Check(err, check.NotNil)
214 err = s.client.RequestAndDecode(&oob, "POST", "arvados/v1/collections", nil, map[string]interface{}{
215 "collection": map[string]string{
217 "owner_uuid": fixtureAProjectUUID,
220 c.Assert(err, check.IsNil)
221 defer s.client.RequestAndDecode(nil, "DELETE", "arvados/v1/collections/"+oob.UUID, nil, nil)
224 c.Check(err, check.IsNil)
225 f, err := s.fs.Open("/home/A Project/oob")
226 c.Assert(err, check.IsNil)
228 c.Assert(err, check.IsNil)
229 c.Check(fi.IsDir(), check.Equals, true)
232 wf, err := s.fs.OpenFile("/home/A Project/oob/test.txt", os.O_CREATE|os.O_RDWR, 0700)
233 c.Assert(err, check.IsNil)
234 _, err = wf.Write([]byte("hello oob\n"))
235 c.Check(err, check.IsNil)
237 c.Check(err, check.IsNil)
240 c.Check(err, check.IsNil)
241 _, err = s.fs.Open("/home/A Project/oob/test.txt")
242 c.Check(err, check.IsNil)
244 // Sync again to mark the project dir as stale, so the
245 // collection gets reloaded from the controller on next
248 c.Check(err, check.IsNil)
250 // Ensure collection was flushed by Sync
251 var latest Collection
252 err = s.client.RequestAndDecode(&latest, "GET", "arvados/v1/collections/"+oob.UUID, nil, nil)
253 c.Check(err, check.IsNil)
254 c.Check(latest.ManifestText, check.Matches, `.*:test.txt.*\n`)
256 // Delete test.txt behind s.fs's back by updating the
257 // collection record with an empty ManifestText.
258 err = s.client.RequestAndDecode(nil, "PATCH", "arvados/v1/collections/"+oob.UUID, nil, map[string]interface{}{
259 "collection": map[string]string{
261 "portable_data_hash": "d41d8cd98f00b204e9800998ecf8427e+0",
264 c.Assert(err, check.IsNil)
266 _, err = s.fs.Open("/home/A Project/oob/test.txt")
267 c.Check(err, check.NotNil)
268 _, err = s.fs.Open("/home/A Project/oob")
269 c.Check(err, check.IsNil)
271 err = s.client.RequestAndDecode(nil, "DELETE", "arvados/v1/collections/"+oob.UUID, nil, nil)
272 c.Assert(err, check.IsNil)
275 c.Check(err, check.NotNil) // can't update the deleted collection
276 _, err = s.fs.Open("/home/A Project/oob")
277 c.Check(err, check.IsNil) // parent dir still has old collection -- didn't reload, because Sync failed
280 func (s *SiteFSSuite) TestProjectUnsupportedOperations(c *check.C) {
281 s.fs.MountByID("by_id")
282 s.fs.MountProject("home", "")
284 _, err := s.fs.OpenFile("/home/A Project/newfilename", os.O_CREATE|os.O_RDWR, 0)
285 c.Check(err, check.ErrorMatches, "invalid argument")
287 err = s.fs.Mkdir("/home/A Project/newdirname", 0)
288 c.Check(err, check.ErrorMatches, "invalid argument")
290 err = s.fs.Mkdir("/by_id/newdirname", 0)
291 c.Check(err, check.ErrorMatches, "invalid argument")
293 err = s.fs.Mkdir("/by_id/"+fixtureAProjectUUID+"/newdirname", 0)
294 c.Check(err, check.ErrorMatches, "invalid argument")
296 _, err = s.fs.OpenFile("/home/A Project", 0, 0)
297 c.Check(err, check.IsNil)