github.com/cs3org/reva/v2@v2.27.7/pkg/storage/registry/spaces/spaces_test.go (about) 1 // Copyright 2018-2021 CERN 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 // In applying this license, CERN does not waive the privileges and immunities 16 // granted to it by virtue of its status as an Intergovernmental Organization 17 // or submit itself to any jurisdiction. 18 19 package spaces_test 20 21 import ( 22 "context" 23 "encoding/json" 24 "fmt" 25 26 userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" 27 rpcv1beta1 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" 28 provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" 29 ctxpkg "github.com/cs3org/reva/v2/pkg/ctx" 30 "github.com/cs3org/reva/v2/pkg/storage" 31 "github.com/cs3org/reva/v2/pkg/storage/registry/spaces" 32 "github.com/cs3org/reva/v2/pkg/storage/registry/spaces/mocks" 33 "github.com/cs3org/reva/v2/pkg/storagespace" 34 "github.com/stretchr/testify/mock" 35 "google.golang.org/grpc" 36 37 . "github.com/onsi/ginkgo/v2" 38 . "github.com/onsi/gomega" 39 ) 40 41 var _ = Describe("Spaces", func() { 42 var ( 43 handler storage.Registry 44 ctxAlice context.Context 45 fooClient *mocks.StorageProviderClient 46 barClient *mocks.StorageProviderClient 47 bazClient *mocks.StorageProviderClient 48 49 rules map[string]interface{} 50 51 getClientFunc func(addr string) (spaces.StorageProviderClient, error) 52 53 alice = &userpb.User{ 54 Id: &userpb.UserId{ 55 OpaqueId: "alice", 56 }, 57 Username: "alice", 58 } 59 ) 60 61 BeforeEach(func() { 62 fooClient = &mocks.StorageProviderClient{} 63 barClient = &mocks.StorageProviderClient{} 64 bazClient = &mocks.StorageProviderClient{} 65 66 fooClient.On("ListStorageSpaces", mock.Anything, mock.Anything).Return( 67 func(_ context.Context, req *provider.ListStorageSpacesRequest, _ ...grpc.CallOption) *provider.ListStorageSpacesResponse { 68 rid := &provider.ResourceId{StorageId: "provider-1", SpaceId: "foospace", OpaqueId: "foospace"} 69 spaces := []*provider.StorageSpace{ 70 { 71 Id: &provider.StorageSpaceId{OpaqueId: storagespace.FormatResourceID(rid)}, 72 Root: rid, 73 Name: "Foo space", 74 SpaceType: "personal", 75 Owner: alice, 76 }, 77 } 78 for _, f := range req.Filters { 79 if f.Type == provider.ListStorageSpacesRequest_Filter_TYPE_ID && f.GetId().OpaqueId != "provider-1$foospace!foospace" { 80 spaces = []*provider.StorageSpace{} 81 } 82 } 83 return &provider.ListStorageSpacesResponse{ 84 Status: &rpcv1beta1.Status{Code: rpcv1beta1.Code_CODE_OK}, 85 StorageSpaces: spaces, 86 } 87 }, nil) 88 barClient.On("ListStorageSpaces", mock.Anything, mock.Anything).Return( 89 func(_ context.Context, req *provider.ListStorageSpacesRequest, _ ...grpc.CallOption) *provider.ListStorageSpacesResponse { 90 rid := &provider.ResourceId{StorageId: "provider-1", SpaceId: "barspace", OpaqueId: "barspace"} 91 spaces := []*provider.StorageSpace{ 92 { 93 Id: &provider.StorageSpaceId{OpaqueId: storagespace.FormatResourceID(rid)}, 94 Root: rid, 95 Name: "Bar space", 96 SpaceType: "personal", 97 Owner: alice, 98 }, 99 } 100 for _, f := range req.Filters { 101 if f.Type == provider.ListStorageSpacesRequest_Filter_TYPE_ID && f.GetId().OpaqueId != "barspace!barspace" { 102 spaces = []*provider.StorageSpace{} 103 } 104 } 105 return &provider.ListStorageSpacesResponse{ 106 Status: &rpcv1beta1.Status{Code: rpcv1beta1.Code_CODE_OK}, 107 StorageSpaces: spaces, 108 } 109 }, nil) 110 bazClient.On("ListStorageSpaces", mock.Anything, mock.Anything).Return( 111 func(_ context.Context, req *provider.ListStorageSpacesRequest, _ ...grpc.CallOption) *provider.ListStorageSpacesResponse { 112 rid1 := &provider.ResourceId{StorageId: "provider-1", SpaceId: "bazspace1", OpaqueId: "bazspace1"} 113 rid2 := &provider.ResourceId{StorageId: "provider-1", SpaceId: "bazspace2", OpaqueId: "bazspace2"} 114 space1 := &provider.StorageSpace{ 115 Id: &provider.StorageSpaceId{OpaqueId: storagespace.FormatResourceID(rid1)}, 116 Root: rid1, 117 Name: "Baz space 1", 118 SpaceType: "project", 119 Owner: alice, 120 } 121 space2 := &provider.StorageSpace{ 122 Id: &provider.StorageSpaceId{OpaqueId: storagespace.FormatResourceID(rid2)}, 123 Root: rid2, 124 Name: "Baz space 2", 125 SpaceType: "project", 126 Owner: alice, 127 } 128 spaces := []*provider.StorageSpace{space1, space2} 129 for _, f := range req.Filters { 130 if f.Type == provider.ListStorageSpacesRequest_Filter_TYPE_ID { 131 if f.GetId().OpaqueId == "provider-1$bazspace1!bazspace2" { 132 spaces = []*provider.StorageSpace{space1} 133 } else if f.GetId().OpaqueId == "provider-1$bazspace2!bazspace2" { 134 spaces = []*provider.StorageSpace{space2} 135 } else { 136 spaces = []*provider.StorageSpace{} 137 } 138 } 139 } 140 return &provider.ListStorageSpacesResponse{ 141 Status: &rpcv1beta1.Status{Code: rpcv1beta1.Code_CODE_OK}, 142 StorageSpaces: spaces, 143 } 144 }, nil) 145 146 getClientFunc = func(addr string) (spaces.StorageProviderClient, error) { 147 switch addr { 148 case "127.0.0.1:13020": 149 return fooClient, nil 150 case "127.0.0.1:13021": 151 return barClient, nil 152 case "127.0.0.1:13022": 153 return bazClient, nil 154 } 155 return nil, fmt.Errorf("Nooooo") 156 } 157 158 ctxAlice = ctxpkg.ContextSetUser(context.Background(), alice) 159 }) 160 161 JustBeforeEach(func() { 162 var err error 163 handler, err = spaces.New(rules, getClientFunc) 164 Expect(err).ToNot(HaveOccurred()) 165 }) 166 167 Describe("NewDefault", func() { 168 It("returns a new instance", func() { 169 _, err := spaces.NewDefault(rules) 170 Expect(err).ToNot(HaveOccurred()) 171 }) 172 }) 173 174 Describe("New", func() { 175 It("uses the path as the pathtemplate if no template is set (e.g. in cases like the publicstorageprovider which returns a single space)", func() { 176 rules = map[string]interface{}{ 177 "providers": map[string]interface{}{ 178 "127.0.0.1:13020": map[string]interface{}{ 179 "spaces": map[string]interface{}{ 180 "personal": map[string]interface{}{ 181 "mount_point": "/thepath", 182 }, 183 }, 184 }, 185 }, 186 } 187 188 handler, err := spaces.New(rules, getClientFunc) 189 Expect(err).ToNot(HaveOccurred()) 190 191 providers, err := handler.ListProviders(ctxAlice, map[string]string{"path": "/thepath"}) 192 Expect(err).ToNot(HaveOccurred()) 193 Expect(len(providers)).To(Equal(1)) 194 p := providers[0] 195 Expect(p.Address).To(Equal("127.0.0.1:13020")) 196 197 spaces := []*provider.StorageSpace{} 198 err = json.Unmarshal(p.Opaque.Map["spaces"].Value, &spaces) 199 Expect(err).ToNot(HaveOccurred()) 200 Expect(len(spaces)).To(Equal(1)) 201 202 Expect(spaces[0].Opaque.Map["path"].Decoder).To(Equal("plain")) 203 spacePath := string(spaces[0].Opaque.Map["path"].Value) 204 Expect(spacePath).To(Equal("/thepath")) 205 }) 206 }) 207 208 Context("with a simple setup", func() { 209 BeforeEach(func() { 210 rules = map[string]interface{}{ 211 "home_provider": "/users/{{.Id.OpaqueId}}", 212 "providers": map[string]interface{}{ 213 "127.0.0.1:13020": map[string]interface{}{ 214 "spaces": map[string]interface{}{ 215 "personal": map[string]interface{}{ 216 "mount_point": "/users/[a-k]", 217 "path_template": "/users/{{.Space.Owner.Username}}", 218 }, 219 }, 220 }, 221 "127.0.0.1:13021": map[string]interface{}{ 222 "spaces": map[string]interface{}{ 223 "personal": map[string]interface{}{ 224 "mount_point": "/users/[l-z]", 225 "path_template": "/users/{{.Space.Owner.Username}}", 226 }, 227 }, 228 }, 229 "127.0.0.1:13022": map[string]interface{}{ 230 "spaces": map[string]interface{}{ 231 "project": map[string]interface{}{ 232 "mount_point": "/projects", 233 "path_template": "/projects/{{.Space.Name}}", 234 }, 235 }, 236 }, 237 }, 238 } 239 }) 240 241 Describe("GetProvider", func() { 242 It("returns an error when no provider was found", func() { 243 space := &provider.StorageSpace{ 244 Owner: &userpb.User{ 245 Username: "bob", 246 }, 247 SpaceType: "somethingfancy", 248 } 249 p, err := handler.GetProvider(ctxAlice, space) 250 Expect(err).To(HaveOccurred()) 251 Expect(p).To(BeNil()) 252 }) 253 254 It("filters by space type", func() { 255 space := &provider.StorageSpace{ 256 SpaceType: "personal", 257 } 258 p, err := handler.GetProvider(ctxAlice, space) 259 Expect(err).ToNot(HaveOccurred()) 260 Expect(p).ToNot(BeNil()) 261 }) 262 263 It("filters by space type and owner", func() { 264 space := &provider.StorageSpace{ 265 Owner: &userpb.User{ 266 Username: "alice", 267 }, 268 SpaceType: "personal", 269 } 270 p, err := handler.GetProvider(ctxAlice, space) 271 Expect(err).ToNot(HaveOccurred()) 272 Expect(p).ToNot(BeNil()) 273 Expect(p.Address).To(Equal("127.0.0.1:13020")) 274 275 space = &provider.StorageSpace{ 276 Owner: &userpb.User{ 277 Username: "zacharias", 278 }, 279 SpaceType: "personal", 280 } 281 p, err = handler.GetProvider(ctxAlice, space) 282 Expect(err).ToNot(HaveOccurred()) 283 Expect(p).ToNot(BeNil()) 284 Expect(p.Address).To(Equal("127.0.0.1:13021")) 285 }) 286 }) 287 288 Describe("ListProviders", func() { 289 It("returns all providers when no filter is set", func() { 290 filters := map[string]string{} 291 providers, err := handler.ListProviders(ctxAlice, filters) 292 Expect(err).ToNot(HaveOccurred()) 293 Expect(len(providers)).To(Equal(3)) 294 }) 295 296 It("filters by path", func() { 297 filters := map[string]string{ 298 "path": "/projects", 299 } 300 providers, err := handler.ListProviders(ctxAlice, filters) 301 Expect(err).ToNot(HaveOccurred()) 302 Expect(len(providers)).To(Equal(1)) 303 p := providers[0] 304 Expect(p.Address).To(Equal("127.0.0.1:13022")) 305 306 spaces := []*provider.StorageSpace{} 307 err = json.Unmarshal(p.Opaque.Map["spaces"].Value, &spaces) 308 Expect(err).ToNot(HaveOccurred()) 309 Expect(len(spaces)).To(Equal(2)) 310 311 baz1Found, baz2Found := false, false 312 for _, space := range spaces { 313 spacePath := string(space.Opaque.Map["path"].Value) 314 switch space.Id.OpaqueId { 315 case "provider-1$bazspace1!bazspace1": 316 baz1Found = true 317 Expect(spacePath).To(Equal("/projects/Baz space 1")) 318 case "provider-1$bazspace2!bazspace2": 319 baz2Found = true 320 Expect(spacePath).To(Equal("/projects/Baz space 2")) 321 default: 322 Fail("unexpected space id") 323 } 324 } 325 Expect(baz1Found).To(BeTrue()) 326 Expect(baz2Found).To(BeTrue()) 327 }) 328 329 It("returns an empty list when a non-existent id is given", func() { 330 filters := map[string]string{ 331 "storage_id": "invalid", 332 "space_id": "invalid", 333 "opaque_id": "barspace", 334 } 335 providers, err := handler.ListProviders(ctxAlice, filters) 336 Expect(err).ToNot(HaveOccurred()) 337 Expect(len(providers)).To(Equal(0)) 338 }) 339 340 It("filters by id", func() { 341 filters := map[string]string{ 342 "storage_id": "provider-1", 343 "space_id": "foospace", 344 "opaque_id": "foospace", 345 } 346 providers, err := handler.ListProviders(ctxAlice, filters) 347 Expect(err).ToNot(HaveOccurred()) 348 Expect(len(providers)).To(Equal(1)) 349 p := providers[0] 350 Expect(p.Address).To(Equal("127.0.0.1:13020")) 351 352 spaces := []*provider.StorageSpace{} 353 err = json.Unmarshal(p.Opaque.Map["spaces"].Value, &spaces) 354 Expect(err).ToNot(HaveOccurred()) 355 Expect(len(spaces)).To(Equal(1)) 356 357 Expect(spaces[0].Id.OpaqueId).To(Equal("provider-1$foospace!foospace")) 358 Expect(spaces[0].Opaque.Map["path"].Decoder).To(Equal("plain")) 359 spacePath := string(spaces[0].Opaque.Map["path"].Value) 360 Expect(spacePath).To(Equal("/users/alice")) 361 362 filters = map[string]string{ 363 "storage_id": "provider-1", 364 "space_id": "bazspace2", 365 "opaque_id": "bazspace2", 366 } 367 providers, err = handler.ListProviders(ctxAlice, filters) 368 Expect(err).ToNot(HaveOccurred()) 369 Expect(len(providers)).To(Equal(1)) 370 p = providers[0] 371 Expect(p.Address).To(Equal("127.0.0.1:13022")) 372 373 err = json.Unmarshal(p.Opaque.Map["spaces"].Value, &spaces) 374 Expect(err).ToNot(HaveOccurred()) 375 Expect(len(spaces)).To(Equal(1)) 376 Expect(spaces[0].Id.OpaqueId).To(Equal("provider-1$bazspace2!bazspace2")) 377 Expect(spaces[0].Opaque.Map["path"].Decoder).To(Equal("plain")) 378 spacePath = string(spaces[0].Opaque.Map["path"].Value) 379 Expect(spacePath).To(Equal("/projects/Baz space 2")) 380 }) 381 }) 382 }) 383 384 Context("with a nested setup", func() { 385 BeforeEach(func() { 386 rules = map[string]interface{}{ 387 "home_provider": "/users/{{.Id.OpaqueId}}", 388 "providers": map[string]interface{}{ 389 "127.0.0.1:13020": map[string]interface{}{ 390 "spaces": map[string]interface{}{ 391 "personal": map[string]interface{}{ 392 "mount_point": "/foo", 393 "path_template": "/foo", 394 }, 395 }, 396 }, 397 "127.0.0.1:13021": map[string]interface{}{ 398 "spaces": map[string]interface{}{ 399 "personal": map[string]interface{}{ 400 "mount_point": "/foo/bar", 401 "path_template": "/foo/bar", 402 }, 403 }, 404 }, 405 "127.0.0.1:13022": map[string]interface{}{ 406 "spaces": map[string]interface{}{ 407 "project": map[string]interface{}{ 408 "mount_point": "/foo/bar/baz", 409 "path_template": "/foo/bar/baz", 410 }, 411 }, 412 }, 413 }, 414 } 415 }) 416 417 Describe("ListProviders", func() { 418 It("includes all spaces below the requested path", func() { 419 filters := map[string]string{ 420 "path": "/foo", 421 } 422 providers, err := handler.ListProviders(ctxAlice, filters) 423 Expect(err).ToNot(HaveOccurred()) 424 Expect(len(providers)).To(Equal(3)) 425 }) 426 427 It("includes all spaces below the requested path but not the one above", func() { 428 filters := map[string]string{ 429 "path": "/foo/bar", 430 } 431 providers, err := handler.ListProviders(ctxAlice, filters) 432 Expect(err).ToNot(HaveOccurred()) 433 Expect(len(providers)).To(Equal(2)) 434 addresses := []string{} 435 for _, p := range providers { 436 addresses = append(addresses, p.Address) 437 } 438 Expect(addresses).To(ConsistOf("127.0.0.1:13021", "127.0.0.1:13022")) 439 }) 440 441 It("includes the space for the requested path", func() { 442 filters := map[string]string{ 443 "path": "/foo/bar/baz", 444 } 445 providers, err := handler.ListProviders(ctxAlice, filters) 446 Expect(err).ToNot(HaveOccurred()) 447 Expect(len(providers)).To(Equal(1)) 448 Expect(providers[0].Address).To(Equal("127.0.0.1:13022")) 449 450 filters = map[string]string{ 451 "path": "/foo/bar/baz/qux", 452 } 453 providers, err = handler.ListProviders(ctxAlice, filters) 454 Expect(err).ToNot(HaveOccurred()) 455 Expect(len(providers)).To(Equal(1)) 456 Expect(providers[0].Address).To(Equal("127.0.0.1:13022")) 457 }) 458 459 It("includes the space for the requested path", func() { 460 filters := map[string]string{ 461 "path": "/foo/bar/bif", 462 } 463 providers, err := handler.ListProviders(ctxAlice, filters) 464 Expect(err).ToNot(HaveOccurred()) 465 Expect(len(providers)).To(Equal(1)) 466 Expect(providers[0].Address).To(Equal("127.0.0.1:13021")) 467 }) 468 }) 469 }) 470 })