github.com/cs3org/reva/v2@v2.27.7/pkg/share/manager/cs3/cs3_test.go (about)

     1  // Copyright 2018-2022 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 cs3_test
    20  
    21  import (
    22  	"context"
    23  	"encoding/json"
    24  	"net/url"
    25  	"path"
    26  	"sync"
    27  
    28  	groupv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1"
    29  	userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
    30  	collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
    31  	provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
    32  	ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
    33  	"github.com/cs3org/reva/v2/pkg/errtypes"
    34  	sharespkg "github.com/cs3org/reva/v2/pkg/share"
    35  	"github.com/cs3org/reva/v2/pkg/share/manager/cs3"
    36  	indexerpkg "github.com/cs3org/reva/v2/pkg/storage/utils/indexer"
    37  	indexermocks "github.com/cs3org/reva/v2/pkg/storage/utils/indexer/mocks"
    38  	storagemocks "github.com/cs3org/reva/v2/pkg/storage/utils/metadata/mocks"
    39  	"github.com/stretchr/testify/mock"
    40  	"google.golang.org/protobuf/testing/protocmp"
    41  	"google.golang.org/protobuf/types/known/fieldmaskpb"
    42  
    43  	. "github.com/onsi/ginkgo/v2"
    44  	. "github.com/onsi/gomega"
    45  )
    46  
    47  var _ = Describe("Manager", func() {
    48  	var (
    49  		storage    *storagemocks.Storage
    50  		indexer    *indexermocks.Indexer
    51  		user       *userpb.User
    52  		grantee    *userpb.User
    53  		share      *collaboration.Share
    54  		share2     *collaboration.Share
    55  		groupShare *collaboration.Share
    56  		grant      *collaboration.ShareGrant
    57  		ctx        context.Context
    58  		granteeCtx context.Context
    59  
    60  		granteeFn string
    61  		groupFn   string
    62  	)
    63  
    64  	BeforeEach(func() {
    65  		storage = &storagemocks.Storage{}
    66  		storage.On("Init", mock.Anything, mock.Anything).Return(nil)
    67  		storage.On("MakeDirIfNotExist", mock.Anything, mock.Anything).Return(nil)
    68  		storage.On("SimpleUpload", mock.Anything, mock.Anything, mock.Anything).Return(nil)
    69  		indexer = &indexermocks.Indexer{}
    70  		indexer.On("AddIndex", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil)
    71  		indexer.On("Add", mock.Anything).Return([]indexerpkg.IdxAddResult{}, nil)
    72  		indexer.On("Delete", mock.Anything).Return(nil)
    73  
    74  		user = &userpb.User{
    75  			Id: &userpb.UserId{
    76  				Idp:      "localhost:1111",
    77  				OpaqueId: "1",
    78  			},
    79  		}
    80  		grantee = &userpb.User{
    81  			Id: &userpb.UserId{
    82  				Idp:      "localhost:1111",
    83  				OpaqueId: "2",
    84  			},
    85  			Groups: []string{"users"},
    86  		}
    87  		granteeFn = url.QueryEscape("user:" + grantee.Id.Idp + ":" + grantee.Id.OpaqueId)
    88  		groupFn = url.QueryEscape("group:users")
    89  
    90  		grant = &collaboration.ShareGrant{
    91  			Grantee: &provider.Grantee{
    92  				Type: provider.GranteeType_GRANTEE_TYPE_USER,
    93  				Id:   &provider.Grantee_UserId{UserId: grantee.GetId()},
    94  			},
    95  			Permissions: &collaboration.SharePermissions{
    96  				Permissions: &provider.ResourcePermissions{
    97  					GetPath:              true,
    98  					InitiateFileDownload: true,
    99  					ListFileVersions:     true,
   100  					ListContainer:        true,
   101  					Stat:                 true,
   102  				},
   103  			},
   104  		}
   105  		share = &collaboration.Share{
   106  			Id:         &collaboration.ShareId{OpaqueId: "1"},
   107  			ResourceId: &provider.ResourceId{OpaqueId: "abcd"},
   108  			Owner:      user.GetId(),
   109  			Grantee: &provider.Grantee{
   110  				Type: provider.GranteeType_GRANTEE_TYPE_USER,
   111  				Id:   &provider.Grantee_UserId{UserId: grantee.GetId()},
   112  			},
   113  			Permissions: &collaboration.SharePermissions{
   114  				Permissions: &provider.ResourcePermissions{
   115  					GetPath:              true,
   116  					InitiateFileDownload: true,
   117  					ListFileVersions:     true,
   118  					ListContainer:        true,
   119  					Stat:                 true,
   120  				},
   121  			},
   122  		}
   123  		share2 = &collaboration.Share{
   124  			Id:         &collaboration.ShareId{OpaqueId: "2"},
   125  			ResourceId: &provider.ResourceId{OpaqueId: "efgh"},
   126  			Owner:      user.GetId(),
   127  			Grantee: &provider.Grantee{
   128  				Type: provider.GranteeType_GRANTEE_TYPE_USER,
   129  				Id:   &provider.Grantee_UserId{UserId: grantee.GetId()},
   130  			},
   131  			Permissions: &collaboration.SharePermissions{
   132  				Permissions: &provider.ResourcePermissions{
   133  					GetPath:              true,
   134  					InitiateFileDownload: true,
   135  					ListFileVersions:     true,
   136  					ListContainer:        true,
   137  					Stat:                 true,
   138  				},
   139  			},
   140  		}
   141  		groupShare = &collaboration.Share{
   142  			Id:         &collaboration.ShareId{OpaqueId: "3"},
   143  			ResourceId: &provider.ResourceId{OpaqueId: "ijkl"},
   144  			Owner:      user.GetId(),
   145  			Grantee: &provider.Grantee{
   146  				Type: provider.GranteeType_GRANTEE_TYPE_GROUP,
   147  				Id: &provider.Grantee_GroupId{GroupId: &groupv1beta1.GroupId{
   148  					Idp:      "localhost:1111",
   149  					OpaqueId: "users",
   150  				}},
   151  			},
   152  			Permissions: &collaboration.SharePermissions{
   153  				Permissions: &provider.ResourcePermissions{
   154  					GetPath:              true,
   155  					InitiateFileDownload: true,
   156  					ListFileVersions:     true,
   157  					ListContainer:        true,
   158  					Stat:                 true,
   159  				},
   160  			},
   161  		}
   162  		ctx = ctxpkg.ContextSetUser(context.Background(), user)
   163  		granteeCtx = ctxpkg.ContextSetUser(context.Background(), grantee)
   164  	})
   165  
   166  	Describe("New", func() {
   167  		JustBeforeEach(func() {
   168  			m, err := cs3.New(nil, storage, indexer)
   169  			Expect(err).ToNot(HaveOccurred())
   170  			Expect(m).ToNot(BeNil())
   171  		})
   172  
   173  		It("does not initialize the storage yet", func() {
   174  			storage.AssertNotCalled(GinkgoT(), "Init", mock.Anything, mock.Anything)
   175  		})
   176  	})
   177  
   178  	Describe("Load", func() {
   179  		It("loads shares including state and mountpoint information", func() {
   180  			m, err := cs3.New(nil, storage, indexer)
   181  			Expect(err).ToNot(HaveOccurred())
   182  
   183  			sharesChan := make(chan *collaboration.Share)
   184  			receivedChan := make(chan sharespkg.ReceivedShareWithUser)
   185  
   186  			wg := sync.WaitGroup{}
   187  			wg.Add(2)
   188  			go func() {
   189  				err := m.Load(ctx, sharesChan, receivedChan)
   190  				Expect(err).ToNot(HaveOccurred())
   191  				wg.Done()
   192  			}()
   193  			go func() {
   194  				sharesChan <- share
   195  				close(sharesChan)
   196  				close(receivedChan)
   197  				wg.Done()
   198  			}()
   199  			wg.Wait()
   200  			Eventually(sharesChan).Should(BeClosed())
   201  			Eventually(receivedChan).Should(BeClosed())
   202  
   203  			expectedPath := path.Join("shares", share.Id.OpaqueId)
   204  			storage.AssertCalled(GinkgoT(), "SimpleUpload", mock.Anything, expectedPath, mock.Anything)
   205  		})
   206  	})
   207  
   208  	Context("with a manager instance and a share", func() {
   209  		var (
   210  			m              *cs3.Manager
   211  			sharedResource = &provider.ResourceInfo{
   212  				Id: &provider.ResourceId{
   213  					StorageId: "storageid",
   214  					OpaqueId:  "opaqueid",
   215  				},
   216  			}
   217  		)
   218  
   219  		JustBeforeEach(func() {
   220  			var err error
   221  			m, err = cs3.New(nil, storage, indexer)
   222  			Expect(err).ToNot(HaveOccurred())
   223  			data, err := json.Marshal(share)
   224  			Expect(err).ToNot(HaveOccurred())
   225  			storage.On("SimpleDownload", mock.Anything, path.Join("shares", share.Id.OpaqueId)).Return(data, nil)
   226  			data, err = json.Marshal(share2)
   227  			Expect(err).ToNot(HaveOccurred())
   228  			storage.On("SimpleDownload", mock.Anything, path.Join("shares", share2.Id.OpaqueId)).Return(data, nil)
   229  			data, err = json.Marshal(groupShare)
   230  			Expect(err).ToNot(HaveOccurred())
   231  			storage.On("SimpleDownload", mock.Anything, path.Join("shares", groupShare.Id.OpaqueId)).Return(data, nil)
   232  			data, err = json.Marshal(&cs3.ReceivedShareMetadata{
   233  				State: collaboration.ShareState_SHARE_STATE_PENDING,
   234  				MountPoint: &provider.Reference{
   235  					ResourceId: &provider.ResourceId{
   236  						StorageId: "storageid",
   237  						OpaqueId:  "opaqueid",
   238  					},
   239  					Path: "path",
   240  				},
   241  			})
   242  			Expect(err).ToNot(HaveOccurred())
   243  			storage.On("SimpleDownload", mock.Anything, path.Join("metadata", share2.Id.OpaqueId, granteeFn)).
   244  				Return(data, nil)
   245  			storage.On("SimpleDownload", mock.Anything, mock.Anything).Return(nil, errtypes.NotFound(""))
   246  		})
   247  
   248  		Describe("Share", func() {
   249  			var (
   250  				share *collaboration.Share
   251  			)
   252  
   253  			JustBeforeEach(func() {
   254  				var err error
   255  				share, err = m.Share(ctx, sharedResource, grant)
   256  				Expect(err).ToNot(HaveOccurred())
   257  			})
   258  
   259  			It("returns a share holding the share information", func() {
   260  				Expect(share).ToNot(BeNil())
   261  				Expect(share.ResourceId).To(Equal(sharedResource.Id))
   262  				Expect(share.Creator).To(Equal(user.Id))
   263  				Expect(share.Grantee).To(Equal(grant.Grantee))
   264  				Expect(share.Permissions).To(Equal(grant.Permissions))
   265  			})
   266  
   267  			It("stores the share in the storage using the id as the filename", func() {
   268  				expectedPath := path.Join("shares", share.Id.OpaqueId)
   269  				storage.AssertCalled(GinkgoT(), "SimpleUpload", mock.Anything, expectedPath, mock.Anything)
   270  			})
   271  
   272  			It("indexes the share", func() {
   273  				indexer.AssertCalled(GinkgoT(), "Add", mock.AnythingOfType("*collaborationv1beta1.Share"))
   274  			})
   275  		})
   276  
   277  		Describe("Unshare", func() {
   278  			It("deletes the share", func() {
   279  				storage.On("Delete", mock.Anything, mock.Anything).Return(nil)
   280  				err := m.Unshare(ctx, &collaboration.ShareReference{Spec: &collaboration.ShareReference_Id{Id: share.Id}})
   281  				Expect(err).ToNot(HaveOccurred())
   282  				expectedPath := path.Join("shares", share.Id.OpaqueId)
   283  				storage.AssertCalled(GinkgoT(), "Delete", mock.Anything, expectedPath)
   284  			})
   285  
   286  			It("removes the share from the index", func() {
   287  				storage.On("Delete", mock.Anything, mock.Anything).Return(nil)
   288  				err := m.Unshare(ctx, &collaboration.ShareReference{Spec: &collaboration.ShareReference_Id{Id: share.Id}})
   289  				Expect(err).ToNot(HaveOccurred())
   290  				indexer.AssertCalled(GinkgoT(), "Delete", mock.AnythingOfType("*collaborationv1beta1.Share"))
   291  			})
   292  
   293  			It("still tries to delete the share from the index when the share couldn't be found", func() {
   294  				storage.On("Delete", mock.Anything, mock.Anything).Return(errtypes.NotFound(""))
   295  				err := m.Unshare(ctx, &collaboration.ShareReference{Spec: &collaboration.ShareReference_Id{Id: share.Id}})
   296  				Expect(err).ToNot(HaveOccurred())
   297  				indexer.AssertCalled(GinkgoT(), "Delete", mock.AnythingOfType("*collaborationv1beta1.Share"))
   298  			})
   299  		})
   300  
   301  		Describe("UpdateShare", func() {
   302  			It("updates the share", func() {
   303  				Expect(share.Permissions.Permissions.AddGrant).To(BeFalse())
   304  				s, err := m.UpdateShare(ctx,
   305  					&collaboration.ShareReference{Spec: &collaboration.ShareReference_Id{Id: share.Id}},
   306  					&collaboration.SharePermissions{Permissions: &provider.ResourcePermissions{AddGrant: true}}, nil, nil)
   307  				Expect(err).ToNot(HaveOccurred())
   308  				Expect(s).ToNot(BeNil())
   309  				Expect(s.Permissions.Permissions.AddGrant).To(BeTrue())
   310  			})
   311  		})
   312  		Describe("GetShare", func() {
   313  			Context("when the share is a user share ", func() {
   314  				Context("when requesting the share by id", func() {
   315  					It("returns NotFound", func() {
   316  						returnedShare, err := m.GetShare(ctx, &collaboration.ShareReference{
   317  							Spec: &collaboration.ShareReference_Id{Id: &collaboration.ShareId{OpaqueId: "1000"}},
   318  						})
   319  						Expect(err).To(HaveOccurred())
   320  						Expect(returnedShare).To(BeNil())
   321  					})
   322  
   323  					It("returns the share", func() {
   324  						returnedShare, err := m.GetShare(ctx, &collaboration.ShareReference{
   325  							Spec: &collaboration.ShareReference_Id{Id: &collaboration.ShareId{OpaqueId: "1"}},
   326  						})
   327  						Expect(err).ToNot(HaveOccurred())
   328  						Expect(returnedShare).ToNot(BeNil())
   329  						Expect(returnedShare.Id.OpaqueId).To(Equal(share.Id.OpaqueId))
   330  						Expect(returnedShare.Owner).To(BeComparableTo(share.Owner, protocmp.Transform()))
   331  						Expect(returnedShare.Grantee).To(BeComparableTo(share.Grantee, protocmp.Transform()))
   332  						Expect(returnedShare.Permissions).To(BeComparableTo(share.Permissions, protocmp.Transform()))
   333  					})
   334  				})
   335  
   336  				Context("when requesting the share by key", func() {
   337  					It("returns NotFound", func() {
   338  						indexer.On("FindBy", mock.Anything,
   339  							indexerpkg.NewField("OwnerId", url.QueryEscape(share.Owner.Idp+":"+share.Owner.OpaqueId)),
   340  						).
   341  							Return([]string{share.Id.OpaqueId, share2.Id.OpaqueId}, nil)
   342  						indexer.On("FindBy", mock.Anything,
   343  							indexerpkg.NewField("GranteeId", url.QueryEscape("user:"+grantee.Id.Idp+":"+grantee.Id.OpaqueId)),
   344  						).
   345  							Return([]string{}, nil)
   346  						returnedShare, err := m.GetShare(ctx, &collaboration.ShareReference{
   347  							Spec: &collaboration.ShareReference_Key{
   348  								Key: &collaboration.ShareKey{
   349  									Owner:      share2.Owner,
   350  									ResourceId: share2.ResourceId,
   351  									Grantee:    share2.Grantee,
   352  								},
   353  							},
   354  						})
   355  						Expect(err).To(HaveOccurred())
   356  						Expect(returnedShare).To(BeNil())
   357  					})
   358  					It("gets the share", func() {
   359  						indexer.On("FindBy", mock.Anything,
   360  							indexerpkg.NewField("OwnerId", url.QueryEscape(share.Owner.Idp+":"+share.Owner.OpaqueId)),
   361  						).
   362  							Return([]string{share.Id.OpaqueId, share2.Id.OpaqueId}, nil)
   363  						indexer.On("FindBy", mock.Anything,
   364  							indexerpkg.NewField("GranteeId", url.QueryEscape("user:"+grantee.Id.Idp+":"+grantee.Id.OpaqueId)),
   365  						).
   366  							Return([]string{share2.Id.OpaqueId}, nil)
   367  						returnedShare, err := m.GetShare(ctx, &collaboration.ShareReference{
   368  							Spec: &collaboration.ShareReference_Key{
   369  								Key: &collaboration.ShareKey{
   370  									Owner:      share2.Owner,
   371  									ResourceId: share2.ResourceId,
   372  									Grantee:    share2.Grantee,
   373  								},
   374  							},
   375  						})
   376  						Expect(err).ToNot(HaveOccurred())
   377  						Expect(returnedShare).ToNot(BeNil())
   378  						Expect(returnedShare.Id.OpaqueId).To(Equal(share2.Id.OpaqueId))
   379  						Expect(returnedShare.Owner).To(BeComparableTo(share2.Owner, protocmp.Transform()))
   380  						Expect(returnedShare.Grantee).To(BeComparableTo(share2.Grantee, protocmp.Transform()))
   381  						Expect(returnedShare.Permissions).To(BeComparableTo(share2.Permissions, protocmp.Transform()))
   382  					})
   383  				})
   384  			})
   385  
   386  			Context("when the share is a group share ", func() {
   387  				BeforeEach(func() {
   388  					share.Grantee = &provider.Grantee{
   389  						Type: provider.GranteeType_GRANTEE_TYPE_GROUP,
   390  						Id: &provider.Grantee_GroupId{
   391  							GroupId: &groupv1beta1.GroupId{OpaqueId: "1000"},
   392  						},
   393  					}
   394  				})
   395  
   396  				It("returns a group share", func() {
   397  					returnedShare, err := m.GetShare(ctx, &collaboration.ShareReference{
   398  						Spec: &collaboration.ShareReference_Id{Id: &collaboration.ShareId{OpaqueId: "1"}},
   399  					})
   400  					Expect(err).ToNot(HaveOccurred())
   401  					Expect(returnedShare).ToNot(BeNil())
   402  					Expect(returnedShare.Id.OpaqueId).To(Equal(share.Id.OpaqueId))
   403  					Expect(returnedShare.Owner).To(BeComparableTo(share.Owner, protocmp.Transform()))
   404  					Expect(returnedShare.Grantee).To(BeComparableTo(share.Grantee, protocmp.Transform()))
   405  					Expect(returnedShare.Permissions).To(Equal(share.Permissions))
   406  				})
   407  			})
   408  		})
   409  
   410  		Describe("ListShares", func() {
   411  			JustBeforeEach(func() {
   412  				indexer.On("FindBy", mock.Anything,
   413  					mock.MatchedBy(func(input indexerpkg.Field) bool {
   414  						return input.Name == "OwnerId"
   415  					}),
   416  					mock.MatchedBy(func(input indexerpkg.Field) bool {
   417  						return input.Name == "CreatorId"
   418  					}),
   419  				).Return([]string{share.Id.OpaqueId, share2.Id.OpaqueId}, nil)
   420  				indexer.On("FindBy", mock.Anything,
   421  					mock.MatchedBy(func(input indexerpkg.Field) bool {
   422  						return input.Name == "ResourceId" && input.Value == "!abcd"
   423  					}),
   424  				).Return([]string{share.Id.OpaqueId}, nil)
   425  			})
   426  			It("uses the index to get the owned shares", func() {
   427  				shares, err := m.ListShares(ctx, []*collaboration.Filter{})
   428  				Expect(err).ToNot(HaveOccurred())
   429  				Expect(len(shares)).To(Equal(2))
   430  				Expect(shares[0].Id.OpaqueId).To(Equal("1"))
   431  				Expect(shares[1].Id.OpaqueId).To(Equal("2"))
   432  			})
   433  
   434  			It("applies resource id filters", func() {
   435  				shares, err := m.ListShares(ctx, []*collaboration.Filter{
   436  					{
   437  						Type: collaboration.Filter_TYPE_RESOURCE_ID,
   438  						Term: &collaboration.Filter_ResourceId{
   439  							ResourceId: share.ResourceId,
   440  						},
   441  					},
   442  				})
   443  				Expect(err).ToNot(HaveOccurred())
   444  				Expect(len(shares)).To(Equal(1))
   445  				Expect(shares[0].Id.OpaqueId).To(Equal("1"))
   446  			})
   447  		})
   448  
   449  		Describe("ListReceivedShares", func() {
   450  			Context("with a received user share", func() {
   451  				BeforeEach(func() {
   452  					indexer.On("FindBy", mock.Anything,
   453  						mock.MatchedBy(func(input indexerpkg.Field) bool {
   454  							return input.Name == "GranteeId" && input.Value == granteeFn
   455  						}),
   456  					).
   457  						Return([]string{share2.Id.OpaqueId}, nil)
   458  					indexer.On("FindBy", mock.Anything,
   459  						mock.MatchedBy(func(input indexerpkg.Field) bool {
   460  							return input.Name == "GranteeId"
   461  						}),
   462  					).
   463  						Return([]string{}, nil)
   464  				})
   465  
   466  				It("list the user shares", func() {
   467  					rshares, err := m.ListReceivedShares(granteeCtx, []*collaboration.Filter{}, nil)
   468  					Expect(err).ToNot(HaveOccurred())
   469  					Expect(rshares).ToNot(BeNil())
   470  					Expect(len(rshares)).To(Equal(1))
   471  
   472  					rshare := rshares[0]
   473  					Expect(rshare.State).To(Equal(collaboration.ShareState_SHARE_STATE_PENDING))
   474  					Expect(rshare.MountPoint.ResourceId.StorageId).To(Equal("storageid"))
   475  					Expect(rshare.MountPoint.ResourceId.OpaqueId).To(Equal("opaqueid"))
   476  					Expect(rshare.MountPoint.Path).To(Equal("path"))
   477  				})
   478  			})
   479  
   480  			Context("with a received group share", func() {
   481  				BeforeEach(func() {
   482  					indexer.On("FindBy", mock.Anything,
   483  						mock.MatchedBy(func(input indexerpkg.Field) bool {
   484  							return input.Name == "GranteeId" && input.Value == groupFn
   485  						}),
   486  					).
   487  						Return([]string{share2.Id.OpaqueId}, nil)
   488  					indexer.On("FindBy", mock.Anything,
   489  						mock.MatchedBy(func(input indexerpkg.Field) bool {
   490  							return input.Name == "GranteeId"
   491  						}),
   492  					).
   493  						Return([]string{}, nil)
   494  				})
   495  
   496  				It("list the group share", func() {
   497  					rshares, err := m.ListReceivedShares(granteeCtx, []*collaboration.Filter{}, nil)
   498  					Expect(err).ToNot(HaveOccurred())
   499  					Expect(rshares).ToNot(BeNil())
   500  					Expect(len(rshares)).To(Equal(1))
   501  
   502  					rshare := rshares[0]
   503  					Expect(rshare.State).To(Equal(collaboration.ShareState_SHARE_STATE_PENDING))
   504  					Expect(rshare.MountPoint.ResourceId.StorageId).To(Equal("storageid"))
   505  					Expect(rshare.MountPoint.ResourceId.OpaqueId).To(Equal("opaqueid"))
   506  					Expect(rshare.MountPoint.Path).To(Equal("path"))
   507  				})
   508  			})
   509  
   510  			Context("with a received user and group share", func() {
   511  				BeforeEach(func() {
   512  					indexer.On("FindBy", mock.Anything,
   513  						mock.MatchedBy(func(input indexerpkg.Field) bool {
   514  							return input.Name == "GranteeId" && input.Value == granteeFn
   515  						}),
   516  					).
   517  						Return([]string{share.Id.OpaqueId}, nil)
   518  
   519  					indexer.On("FindBy", mock.Anything,
   520  						mock.MatchedBy(func(input indexerpkg.Field) bool {
   521  							return input.Name == "GranteeId" && input.Value == groupFn
   522  						}),
   523  					).
   524  						Return([]string{groupShare.Id.OpaqueId}, nil)
   525  
   526  					indexer.On("FindBy", mock.Anything,
   527  						mock.MatchedBy(func(input indexerpkg.Field) bool {
   528  							return input.Name == "GranteeId"
   529  						}),
   530  					).
   531  						Return([]string{}, nil)
   532  				})
   533  
   534  				It("list the user and shares", func() {
   535  					rshares, err := m.ListReceivedShares(granteeCtx, []*collaboration.Filter{}, nil)
   536  					Expect(err).ToNot(HaveOccurred())
   537  					Expect(rshares).ToNot(BeNil())
   538  					Expect(len(rshares)).To(Equal(2))
   539  				})
   540  
   541  				It("list only the user when user filter is given ", func() {
   542  					rshares, err := m.ListReceivedShares(granteeCtx, []*collaboration.Filter{
   543  						{
   544  							Type: collaboration.Filter_TYPE_GRANTEE_TYPE,
   545  							Term: &collaboration.Filter_GranteeType{
   546  								GranteeType: provider.GranteeType_GRANTEE_TYPE_USER,
   547  							},
   548  						},
   549  					}, nil)
   550  					Expect(err).ToNot(HaveOccurred())
   551  					Expect(rshares).ToNot(BeNil())
   552  					Expect(len(rshares)).To(Equal(1))
   553  					Expect(rshares[0].Share.Grantee.Type).To(Equal(provider.GranteeType_GRANTEE_TYPE_USER))
   554  				})
   555  
   556  				It("list only the group when group filter is given ", func() {
   557  					rshares, err := m.ListReceivedShares(granteeCtx, []*collaboration.Filter{
   558  						{
   559  							Type: collaboration.Filter_TYPE_GRANTEE_TYPE,
   560  							Term: &collaboration.Filter_GranteeType{
   561  								GranteeType: provider.GranteeType_GRANTEE_TYPE_GROUP,
   562  							},
   563  						},
   564  					}, nil)
   565  					Expect(err).ToNot(HaveOccurred())
   566  					Expect(rshares).ToNot(BeNil())
   567  					Expect(len(rshares)).To(Equal(1))
   568  					Expect(rshares[0].Share.Grantee.Type).To(Equal(provider.GranteeType_GRANTEE_TYPE_GROUP))
   569  				})
   570  			})
   571  		})
   572  
   573  		Describe("GetReceivedShare", func() {
   574  			Context("when the share is a user share ", func() {
   575  				Context("when requesting the share by id", func() {
   576  					It("returns NotFound", func() {
   577  						rshare, err := m.GetReceivedShare(granteeCtx, &collaboration.ShareReference{
   578  							Spec: &collaboration.ShareReference_Id{Id: &collaboration.ShareId{OpaqueId: "1000"}},
   579  						})
   580  						Expect(err).To(HaveOccurred())
   581  						Expect(rshare).To(BeNil())
   582  					})
   583  
   584  					It("returns the share", func() {
   585  						rshare, err := m.GetReceivedShare(granteeCtx, &collaboration.ShareReference{
   586  							Spec: &collaboration.ShareReference_Id{Id: &collaboration.ShareId{OpaqueId: share2.Id.OpaqueId}},
   587  						})
   588  						Expect(err).ToNot(HaveOccurred())
   589  						Expect(rshare).ToNot(BeNil())
   590  						Expect(rshare.Share.Id.OpaqueId).To(Equal(share2.Id.OpaqueId))
   591  						Expect(rshare.Share.Owner).To(BeComparableTo(share2.Owner, protocmp.Transform()))
   592  						Expect(rshare.Share.Grantee).To(BeComparableTo(share2.Grantee, protocmp.Transform()))
   593  						Expect(rshare.Share.Permissions).To(BeComparableTo(share2.Permissions, protocmp.Transform()))
   594  						Expect(rshare.State).To(Equal(collaboration.ShareState_SHARE_STATE_PENDING))
   595  						Expect(rshare.MountPoint.ResourceId.StorageId).To(Equal("storageid"))
   596  						Expect(rshare.MountPoint.ResourceId.OpaqueId).To(Equal("opaqueid"))
   597  						Expect(rshare.MountPoint.Path).To(Equal("path"))
   598  					})
   599  				})
   600  			})
   601  		})
   602  
   603  		Describe("UpdateReceivedShare", func() {
   604  			It("updates the share", func() {
   605  				rs, err := m.GetReceivedShare(granteeCtx, &collaboration.ShareReference{Spec: &collaboration.ShareReference_Id{Id: share2.Id}})
   606  				Expect(err).ToNot(HaveOccurred())
   607  
   608  				Expect(rs.State).To(Equal(collaboration.ShareState_SHARE_STATE_PENDING))
   609  				rs.State = collaboration.ShareState_SHARE_STATE_ACCEPTED
   610  				rs.MountPoint.Path = "newPath/"
   611  
   612  				rrs, err := m.UpdateReceivedShare(granteeCtx,
   613  					rs, &fieldmaskpb.FieldMask{Paths: []string{"state", "mount_point"}}, nil)
   614  				Expect(err).ToNot(HaveOccurred())
   615  				Expect(rrs).ToNot(BeNil())
   616  				Expect(rrs.Share.ResourceId).ToNot(BeNil())
   617  				storage.AssertCalled(GinkgoT(), "SimpleUpload", mock.Anything, "metadata/2/"+granteeFn, mock.MatchedBy(func(data []byte) bool {
   618  					meta := cs3.ReceivedShareMetadata{}
   619  					err := json.Unmarshal(data, &meta)
   620  					Expect(err).ToNot(HaveOccurred())
   621  					return meta.MountPoint != nil && meta.State == collaboration.ShareState_SHARE_STATE_ACCEPTED && meta.MountPoint.Path == "newPath/"
   622  				}))
   623  			})
   624  
   625  			It("does not update fields that aren't part of the fieldmask", func() {
   626  				rs, err := m.GetReceivedShare(granteeCtx, &collaboration.ShareReference{Spec: &collaboration.ShareReference_Id{Id: share2.Id}})
   627  				Expect(err).ToNot(HaveOccurred())
   628  
   629  				Expect(rs.State).To(Equal(collaboration.ShareState_SHARE_STATE_PENDING))
   630  				rs.State = collaboration.ShareState_SHARE_STATE_ACCEPTED
   631  				rs.MountPoint.Path = "newPath/"
   632  
   633  				rrs, err := m.UpdateReceivedShare(granteeCtx,
   634  					rs, &fieldmaskpb.FieldMask{Paths: []string{"mount_point"}}, nil)
   635  				Expect(err).ToNot(HaveOccurred())
   636  				Expect(rrs).ToNot(BeNil())
   637  				Expect(rrs.Share.ResourceId).ToNot(BeNil())
   638  				storage.AssertCalled(GinkgoT(), "SimpleUpload", mock.Anything, "metadata/2/"+granteeFn, mock.MatchedBy(func(data []byte) bool {
   639  					meta := cs3.ReceivedShareMetadata{}
   640  					err := json.Unmarshal(data, &meta)
   641  					Expect(err).ToNot(HaveOccurred())
   642  					return meta.MountPoint != nil && meta.State == collaboration.ShareState_SHARE_STATE_PENDING && meta.MountPoint.Path == "newPath/"
   643  				}))
   644  			})
   645  		})
   646  	})
   647  })