5628dcc9c43b42ef6560ddfa1eba2bc0482001d3
[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         var badCollection Collection
122         err := s.client.RequestAndDecode(&badCollection, "POST", "arvados/v1/collections", nil, map[string]interface{}{
123                 "collection": map[string]string{
124                         "name":       "bad/collection",
125                         "owner_uuid": fixtureAProjectUUID,
126                 },
127         })
128         c.Assert(err, check.IsNil)
129         defer s.client.RequestAndDecode(nil, "DELETE", "arvados/v1/collections/"+badCollection.UUID, nil, nil)
130
131         var badProject Group
132         err = s.client.RequestAndDecode(&badProject, "POST", "arvados/v1/groups", nil, map[string]interface{}{
133                 "group": map[string]string{
134                         "name":        "bad/project",
135                         "group_class": "project",
136                         "owner_uuid":  fixtureAProjectUUID,
137                 },
138         })
139         c.Assert(err, check.IsNil)
140         defer s.client.RequestAndDecode(nil, "DELETE", "arvados/v1/groups/"+badProject.UUID, nil, nil)
141
142         dir, err := s.fs.Open("/users/active/A Project")
143         c.Assert(err, check.IsNil)
144         fis, err := dir.Readdir(-1)
145         c.Check(err, check.IsNil)
146         for _, fi := range fis {
147                 c.Logf("fi.Name() == %q", fi.Name())
148                 c.Check(strings.Contains(fi.Name(), "/"), check.Equals, false)
149         }
150
151         // Make a new fs (otherwise content will still be cached from
152         // above) and enable "/" replacement string.
153         s.fs = s.client.SiteFileSystem(s.kc)
154         s.fs.ForwardSlashNameSubstitution("___")
155         dir, err = s.fs.Open("/users/active/A Project/bad___collection")
156         if c.Check(err, check.IsNil) {
157                 _, err = dir.Readdir(-1)
158                 c.Check(err, check.IsNil)
159         }
160         dir, err = s.fs.Open("/users/active/A Project/bad___project")
161         if c.Check(err, check.IsNil) {
162                 _, err = dir.Readdir(-1)
163                 c.Check(err, check.IsNil)
164         }
165 }
166
167 func (s *SiteFSSuite) TestProjectUpdatedByOther(c *check.C) {
168         s.fs.MountProject("home", "")
169
170         project, err := s.fs.OpenFile("/home/A Project", 0, 0)
171         c.Assert(err, check.IsNil)
172
173         _, err = s.fs.Open("/home/A Project/oob")
174         c.Check(err, check.NotNil)
175
176         var oob Collection
177         err = s.client.RequestAndDecode(&oob, "POST", "arvados/v1/collections", nil, map[string]interface{}{
178                 "collection": map[string]string{
179                         "name":       "oob",
180                         "owner_uuid": fixtureAProjectUUID,
181                 },
182         })
183         c.Assert(err, check.IsNil)
184         defer s.client.RequestAndDecode(nil, "DELETE", "arvados/v1/collections/"+oob.UUID, nil, nil)
185
186         err = project.Sync()
187         c.Check(err, check.IsNil)
188         f, err := s.fs.Open("/home/A Project/oob")
189         c.Assert(err, check.IsNil)
190         fi, err := f.Stat()
191         c.Assert(err, check.IsNil)
192         c.Check(fi.IsDir(), check.Equals, true)
193         f.Close()
194
195         wf, err := s.fs.OpenFile("/home/A Project/oob/test.txt", os.O_CREATE|os.O_RDWR, 0700)
196         c.Assert(err, check.IsNil)
197         _, err = wf.Write([]byte("hello oob\n"))
198         c.Check(err, check.IsNil)
199         err = wf.Close()
200         c.Check(err, check.IsNil)
201
202         // Delete test.txt behind s.fs's back by updating the
203         // collection record with an empty ManifestText.
204         err = s.client.RequestAndDecode(nil, "PATCH", "arvados/v1/collections/"+oob.UUID, nil, map[string]interface{}{
205                 "collection": map[string]string{
206                         "manifest_text":      "",
207                         "portable_data_hash": "d41d8cd98f00b204e9800998ecf8427e+0",
208                 },
209         })
210         c.Assert(err, check.IsNil)
211
212         err = project.Sync()
213         c.Check(err, check.IsNil)
214         _, err = s.fs.Open("/home/A Project/oob/test.txt")
215         c.Check(err, check.NotNil)
216         _, err = s.fs.Open("/home/A Project/oob")
217         c.Check(err, check.IsNil)
218
219         err = s.client.RequestAndDecode(nil, "DELETE", "arvados/v1/collections/"+oob.UUID, nil, nil)
220         c.Assert(err, check.IsNil)
221
222         err = project.Sync()
223         c.Check(err, check.IsNil)
224         _, err = s.fs.Open("/home/A Project/oob")
225         c.Check(err, check.NotNil)
226 }