github.com/cs3org/reva/v2@v2.27.7/pkg/share/manager/jsoncs3/jsoncs3_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 jsoncs3_test
    20  
    21  import (
    22  	"context"
    23  	"encoding/json"
    24  	"os"
    25  	"path/filepath"
    26  	"sync"
    27  
    28  	gatewayv1beta1 "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
    29  	groupv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1"
    30  	userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
    31  	collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
    32  	provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
    33  	providerv1beta1 "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
    34  	"github.com/cs3org/reva/v2/pkg/conversions"
    35  	ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
    36  	"github.com/cs3org/reva/v2/pkg/rgrpc/status"
    37  	"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
    38  	sharespkg "github.com/cs3org/reva/v2/pkg/share"
    39  	"github.com/cs3org/reva/v2/pkg/share/manager/jsoncs3"
    40  	"github.com/cs3org/reva/v2/pkg/share/manager/jsoncs3/sharecache"
    41  	"github.com/cs3org/reva/v2/pkg/share/manager/jsoncs3/shareid"
    42  	"github.com/cs3org/reva/v2/pkg/storage/utils/metadata"
    43  	"github.com/cs3org/reva/v2/pkg/utils"
    44  	"github.com/cs3org/reva/v2/tests/cs3mocks/mocks"
    45  	"github.com/stretchr/testify/mock"
    46  	"google.golang.org/grpc"
    47  	"google.golang.org/protobuf/testing/protocmp"
    48  	"google.golang.org/protobuf/types/known/fieldmaskpb"
    49  
    50  	. "github.com/onsi/ginkgo/v2"
    51  	. "github.com/onsi/gomega"
    52  )
    53  
    54  var _ = Describe("Jsoncs3", func() {
    55  	var (
    56  		user1 = &userpb.User{
    57  			Id: &userpb.UserId{
    58  				Idp:      "https://localhost:9200",
    59  				OpaqueId: "admin",
    60  			},
    61  		}
    62  		user2 = &userpb.User{
    63  			Id: &userpb.UserId{
    64  				Idp:      "https://localhost:9200",
    65  				OpaqueId: "einstein",
    66  			},
    67  			Groups: []string{"group1"},
    68  		}
    69  
    70  		sharedResource = &providerv1beta1.ResourceInfo{
    71  			Id: &providerv1beta1.ResourceId{
    72  				StorageId: "storageid",
    73  				SpaceId:   "spaceid",
    74  				OpaqueId:  "opaqueid",
    75  			},
    76  		}
    77  
    78  		sharedResource2 = &providerv1beta1.ResourceInfo{
    79  			Id: &providerv1beta1.ResourceId{
    80  				StorageId: "storageid2",
    81  				SpaceId:   "spaceid2",
    82  				OpaqueId:  "opaqueid2",
    83  			},
    84  		}
    85  
    86  		grantee = &userpb.User{
    87  			Id:     user2.Id,
    88  			Groups: []string{"users"},
    89  		}
    90  		grant *collaboration.ShareGrant
    91  
    92  		groupGrant = &collaboration.ShareGrant{
    93  			Grantee: &provider.Grantee{
    94  				Type: provider.GranteeType_GRANTEE_TYPE_GROUP,
    95  				Id: &provider.Grantee_GroupId{GroupId: &groupv1beta1.GroupId{
    96  					OpaqueId: "group1",
    97  				}},
    98  			},
    99  			Permissions: &collaboration.SharePermissions{
   100  				Permissions: &providerv1beta1.ResourcePermissions{
   101  					InitiateFileUpload: false,
   102  				},
   103  			},
   104  		}
   105  		storage metadata.Storage
   106  		client  *mocks.GatewayAPIClient
   107  		tmpdir  string
   108  		m       *jsoncs3.Manager
   109  
   110  		ctx        = ctxpkg.ContextSetUser(context.Background(), user1)
   111  		granteeCtx = ctxpkg.ContextSetUser(context.Background(), user2)
   112  		otherCtx   = ctxpkg.ContextSetUser(context.Background(), &userpb.User{Id: &userpb.UserId{OpaqueId: "otheruser"}})
   113  
   114  		// helper functions
   115  		shareBykey = func(key *collaboration.ShareKey) *collaboration.Share {
   116  			s, err := m.GetShare(ctx, &collaboration.ShareReference{
   117  				Spec: &collaboration.ShareReference_Key{
   118  					Key: key,
   119  				},
   120  			})
   121  			ExpectWithOffset(1, err).ToNot(HaveOccurred())
   122  			ExpectWithOffset(1, s).ToNot(BeNil())
   123  			return s
   124  		}
   125  
   126  		mockStat = func(ref *provider.Reference, info *provider.ResourceInfo) {
   127  			client.On("Stat", mock.Anything, mock.MatchedBy(func(req *provider.StatRequest) bool {
   128  				return utils.ResourceIDEqual(req.Ref.ResourceId, ref.ResourceId) &&
   129  					(ref.Path == "" || req.Ref.Path == ref.Path)
   130  			})).Return(&provider.StatResponse{
   131  				Status: status.NewOK(ctx),
   132  				Info:   info,
   133  			}, nil)
   134  		}
   135  	)
   136  
   137  	BeforeEach(func() {
   138  		grant = &collaboration.ShareGrant{
   139  			Grantee: &provider.Grantee{
   140  				Type: provider.GranteeType_GRANTEE_TYPE_USER,
   141  				Id:   &provider.Grantee_UserId{UserId: grantee.GetId()},
   142  			},
   143  			Permissions: &collaboration.SharePermissions{
   144  				Permissions: &providerv1beta1.ResourcePermissions{
   145  					InitiateFileUpload: false,
   146  				},
   147  			},
   148  		}
   149  
   150  		var err error
   151  		tmpdir, err = os.MkdirTemp("", "jsoncs3-test")
   152  		Expect(err).ToNot(HaveOccurred())
   153  
   154  		err = os.MkdirAll(tmpdir, 0755)
   155  		Expect(err).ToNot(HaveOccurred())
   156  
   157  		storage, err = metadata.NewDiskStorage(tmpdir)
   158  		Expect(err).ToNot(HaveOccurred())
   159  
   160  		pool.RemoveSelector("GatewaySelector" + "com.owncloud.api.gateway")
   161  		client = &mocks.GatewayAPIClient{}
   162  		gatewaySelector := pool.GetSelector[gatewayv1beta1.GatewayAPIClient](
   163  			"GatewaySelector",
   164  			"com.owncloud.api.gateway",
   165  			func(cc grpc.ClientConnInterface) gatewayv1beta1.GatewayAPIClient {
   166  				return client
   167  			},
   168  		)
   169  		m, err = jsoncs3.New(storage, gatewaySelector, 0, nil, 0)
   170  		Expect(err).ToNot(HaveOccurred())
   171  	})
   172  
   173  	AfterEach(func() {
   174  		if tmpdir != "" {
   175  			os.RemoveAll(tmpdir)
   176  		}
   177  	})
   178  
   179  	Describe("Load", func() {
   180  		It("loads shares including state and mountpoint information", func() {
   181  
   182  			sharesChan := make(chan *collaboration.Share)
   183  			receivedChan := make(chan sharespkg.ReceivedShareWithUser)
   184  
   185  			share := &collaboration.Share{
   186  				Id:         &collaboration.ShareId{OpaqueId: "1iaeiae$vlcvlcvlc!pzbpzbpzb"},
   187  				ResourceId: &provider.ResourceId{StorageId: "1iaeiae", SpaceId: "vlcvlcvlc", OpaqueId: "abcd"},
   188  				Creator:    user1.GetId(),
   189  				Grantee: &provider.Grantee{
   190  					Type: provider.GranteeType_GRANTEE_TYPE_USER,
   191  					Id:   &provider.Grantee_UserId{UserId: grantee.GetId()},
   192  				},
   193  				Permissions: &collaboration.SharePermissions{
   194  					Permissions: &provider.ResourcePermissions{
   195  						GetPath:              true,
   196  						InitiateFileDownload: true,
   197  						ListFileVersions:     true,
   198  						ListContainer:        true,
   199  						Stat:                 true,
   200  					},
   201  				},
   202  			}
   203  
   204  			wg := sync.WaitGroup{}
   205  			wg.Add(2)
   206  			go func() {
   207  				err := m.Load(ctx, sharesChan, receivedChan)
   208  				Expect(err).ToNot(HaveOccurred())
   209  				wg.Done()
   210  			}()
   211  			go func() {
   212  				sharesChan <- share
   213  				close(sharesChan)
   214  				close(receivedChan)
   215  				wg.Done()
   216  			}()
   217  			wg.Wait()
   218  			Eventually(sharesChan).Should(BeClosed())
   219  			Eventually(receivedChan).Should(BeClosed())
   220  
   221  			s, err := m.GetShare(ctx, &collaboration.ShareReference{Spec: &collaboration.ShareReference_Id{
   222  				Id: share.Id,
   223  			}})
   224  
   225  			Expect(err).ToNot(HaveOccurred())
   226  			Expect(s.ResourceId.OpaqueId).To(Equal(share.ResourceId.OpaqueId))
   227  		})
   228  	})
   229  
   230  	Describe("Share", func() {
   231  		It("fails if the share already exists", func() {
   232  			_, err := m.Share(ctx, sharedResource, grant)
   233  			Expect(err).ToNot(HaveOccurred())
   234  			_, err = m.Share(ctx, sharedResource, grant)
   235  			Expect(err).To(HaveOccurred())
   236  		})
   237  
   238  		It("creates a user share", func() {
   239  			share, err := m.Share(ctx, sharedResource, grant)
   240  			Expect(err).ToNot(HaveOccurred())
   241  
   242  			Expect(share).ToNot(BeNil())
   243  			Expect(share.ResourceId).To(Equal(sharedResource.Id))
   244  		})
   245  
   246  		It("creates a group share", func() {
   247  			share, err := m.Share(ctx, sharedResource, groupGrant)
   248  			Expect(err).ToNot(HaveOccurred())
   249  
   250  			Expect(share).ToNot(BeNil())
   251  			Expect(share.ResourceId).To(Equal(sharedResource.Id))
   252  		})
   253  
   254  		It("persists the share", func() {
   255  			_, err := m.Share(ctx, sharedResource, grant)
   256  			Expect(err).ToNot(HaveOccurred())
   257  
   258  			s := shareBykey(&collaboration.ShareKey{
   259  				ResourceId: sharedResource.Id,
   260  				Grantee:    grant.Grantee,
   261  			})
   262  			Expect(s).ToNot(BeNil())
   263  
   264  			m, err = jsoncs3.New(storage, nil, 0, nil, 0) // Reset in-memory cache
   265  			Expect(err).ToNot(HaveOccurred())
   266  
   267  			s = shareBykey(&collaboration.ShareKey{
   268  				ResourceId: sharedResource.Id,
   269  				Grantee:    grant.Grantee,
   270  			})
   271  			Expect(s).ToNot(BeNil())
   272  		})
   273  	})
   274  
   275  	Context("with a space manager", func() {
   276  		var (
   277  			share *collaboration.Share
   278  
   279  			manager = &userpb.User{
   280  				Id: &userpb.UserId{
   281  					Idp:      "https://localhost:9200",
   282  					OpaqueId: "spacemanager",
   283  				},
   284  			}
   285  			managerCtx context.Context
   286  		)
   287  
   288  		BeforeEach(func() {
   289  			managerCtx = ctxpkg.ContextSetUser(context.Background(), manager)
   290  
   291  			var err error
   292  			share, err = m.Share(ctx, sharedResource, grant)
   293  			Expect(err).ToNot(HaveOccurred())
   294  
   295  			_, err = m.Share(ctx, &providerv1beta1.ResourceInfo{
   296  				Id: &providerv1beta1.ResourceId{
   297  					StorageId: "storageid",
   298  					SpaceId:   "spaceid",
   299  					OpaqueId:  "spaceid",
   300  				},
   301  			}, &collaboration.ShareGrant{
   302  				Grantee: &providerv1beta1.Grantee{
   303  					Type: provider.GranteeType_GRANTEE_TYPE_USER,
   304  					Id:   &providerv1beta1.Grantee_UserId{UserId: manager.Id},
   305  				},
   306  				Permissions: &collaboration.SharePermissions{
   307  					Permissions: conversions.NewManagerRole().CS3ResourcePermissions(),
   308  				},
   309  			})
   310  			Expect(err).ToNot(HaveOccurred())
   311  		})
   312  
   313  		Describe("ListShares", func() {
   314  			BeforeEach(func() {
   315  				mockStat(
   316  					&provider.Reference{ResourceId: sharedResource.Id},
   317  					&providerv1beta1.ResourceInfo{PermissionSet: &providerv1beta1.ResourcePermissions{ListGrants: true}},
   318  				)
   319  			})
   320  			It("returns the share requested by id even though it's not owned or created by the manager", func() {
   321  
   322  				shares, err := m.ListShares(managerCtx, []*collaboration.Filter{
   323  					{
   324  						Type: collaboration.Filter_TYPE_RESOURCE_ID,
   325  						Term: &collaboration.Filter_ResourceId{
   326  							ResourceId: sharedResource.Id,
   327  						},
   328  					},
   329  				})
   330  				Expect(err).ToNot(HaveOccurred())
   331  				Expect(shares).To(HaveLen(1))
   332  				Expect(shares[0].Id).To(Equal(share.Id))
   333  			})
   334  		})
   335  	})
   336  
   337  	Context("with an existing share", func() {
   338  		var (
   339  			share    *collaboration.Share
   340  			shareRef *collaboration.ShareReference
   341  		)
   342  
   343  		BeforeEach(func() {
   344  			var err error
   345  			share, err = m.Share(ctx, sharedResource, grant)
   346  			Expect(err).ToNot(HaveOccurred())
   347  
   348  			shareRef = &collaboration.ShareReference{
   349  				Spec: &collaboration.ShareReference_Id{
   350  					Id: &collaboration.ShareId{
   351  						OpaqueId: share.Id.OpaqueId,
   352  					},
   353  				},
   354  			}
   355  
   356  		})
   357  
   358  		Describe("GetShare", func() {
   359  			BeforeEach(func() {
   360  				mockStat(
   361  					&provider.Reference{ResourceId: sharedResource.Id},
   362  					&providerv1beta1.ResourceInfo{PermissionSet: &providerv1beta1.ResourcePermissions{ListGrants: false}},
   363  				)
   364  			})
   365  			It("handles unknown ids", func() {
   366  				s, err := m.GetShare(ctx, &collaboration.ShareReference{
   367  					Spec: &collaboration.ShareReference_Id{
   368  						Id: &collaboration.ShareId{
   369  							OpaqueId: "unknown-id",
   370  						},
   371  					},
   372  				})
   373  				Expect(s).To(BeNil())
   374  				Expect(err).To(HaveOccurred())
   375  			})
   376  
   377  			It("handles unknown keys", func() {
   378  				s, err := m.GetShare(ctx, &collaboration.ShareReference{
   379  					Spec: &collaboration.ShareReference_Key{
   380  						Key: &collaboration.ShareKey{
   381  							ResourceId: &providerv1beta1.ResourceId{
   382  								OpaqueId: "unknown",
   383  							},
   384  							Grantee: grant.Grantee,
   385  						},
   386  					},
   387  				})
   388  				Expect(s).To(BeNil())
   389  				Expect(err).To(HaveOccurred())
   390  			})
   391  
   392  			It("considers the resource id part of the key", func() {
   393  				s, err := m.GetShare(ctx, &collaboration.ShareReference{
   394  					Spec: &collaboration.ShareReference_Key{
   395  						Key: &collaboration.ShareKey{
   396  							ResourceId: &providerv1beta1.ResourceId{
   397  								StorageId: "storageid",
   398  								SpaceId:   "spaceid",
   399  								OpaqueId:  "unknown",
   400  							},
   401  							Grantee: grant.Grantee,
   402  						},
   403  					},
   404  				})
   405  				Expect(s).To(BeNil())
   406  				Expect(err).To(HaveOccurred())
   407  			})
   408  
   409  			It("retrieves an existing share by id", func() {
   410  				s, err := m.GetShare(ctx, shareRef)
   411  				Expect(err).ToNot(HaveOccurred())
   412  				Expect(s).ToNot(BeNil())
   413  				Expect(share.ResourceId).To(Equal(sharedResource.Id))
   414  			})
   415  
   416  			It("retrieves an existing share by key", func() {
   417  				s := shareBykey(&collaboration.ShareKey{
   418  					ResourceId: sharedResource.Id,
   419  					Grantee:    grant.Grantee,
   420  				})
   421  				Expect(s.ResourceId).To(BeComparableTo(sharedResource.Id, protocmp.Transform()))
   422  				Expect(s.Id.OpaqueId).To(Equal(share.Id.OpaqueId))
   423  			})
   424  
   425  			It("reloads the provider cache when it is outdated", func() {
   426  				s, err := m.GetShare(ctx, shareRef)
   427  				Expect(err).ToNot(HaveOccurred())
   428  				Expect(s).ToNot(BeNil())
   429  				Expect(s.Permissions.Permissions.InitiateFileUpload).To(BeFalse())
   430  
   431  				// Change providercache on disk
   432  				spaces, ok := m.Cache.Providers.Load("storageid")
   433  				Expect(ok).To(BeTrue())
   434  				cache, ok := spaces.Spaces.Load("spaceid")
   435  				Expect(ok).To(BeTrue())
   436  				cache.Shares[share.Id.OpaqueId].Permissions.Permissions.InitiateFileUpload = true
   437  				bytes, err := json.Marshal(cache)
   438  				Expect(err).ToNot(HaveOccurred())
   439  				Expect(storage.SimpleUpload(context.Background(), "storages/storageid/spaceid.json", bytes)).To(Succeed())
   440  				Expect(err).ToNot(HaveOccurred())
   441  
   442  				// Reset providercache in memory
   443  				cache.Shares[share.Id.OpaqueId].Permissions.Permissions.InitiateFileUpload = false
   444  
   445  				// Set local cache etag to something other then on disk
   446  				cache.Etag = "reset1" // trigger reload
   447  				s, err = m.GetShare(ctx, shareRef)
   448  				Expect(err).ToNot(HaveOccurred())
   449  				Expect(s).ToNot(BeNil())
   450  				Expect(s.Permissions.Permissions.InitiateFileUpload).To(BeTrue())
   451  			})
   452  
   453  			It("loads the cache when it doesn't have an entry", func() {
   454  				m, err := jsoncs3.New(storage, nil, 0, nil, 0) // Reset in-memory cache
   455  				Expect(err).ToNot(HaveOccurred())
   456  
   457  				s, err := m.GetShare(ctx, shareRef)
   458  				Expect(err).ToNot(HaveOccurred())
   459  				Expect(s).ToNot(BeNil())
   460  			})
   461  
   462  			It("does not return other users' shares", func() {
   463  				s, err := m.GetShare(otherCtx, shareRef)
   464  				Expect(err).To(HaveOccurred())
   465  				Expect(s).To(BeNil())
   466  			})
   467  		})
   468  
   469  		Describe("UnShare", func() {
   470  			It("does not remove shares of other users", func() {
   471  				err := m.Unshare(otherCtx, &collaboration.ShareReference{
   472  					Spec: &collaboration.ShareReference_Id{
   473  						Id: &collaboration.ShareId{
   474  							OpaqueId: share.Id.OpaqueId,
   475  						},
   476  					},
   477  				})
   478  
   479  				Expect(err).To(HaveOccurred())
   480  			})
   481  
   482  			It("removes an existing share", func() {
   483  				err := m.Unshare(ctx, &collaboration.ShareReference{
   484  					Spec: &collaboration.ShareReference_Id{
   485  						Id: &collaboration.ShareId{
   486  							OpaqueId: share.Id.OpaqueId,
   487  						},
   488  					},
   489  				})
   490  				Expect(err).ToNot(HaveOccurred())
   491  
   492  				s, err := m.GetShare(ctx, &collaboration.ShareReference{
   493  					Spec: &collaboration.ShareReference_Key{
   494  						Key: &collaboration.ShareKey{
   495  							ResourceId: sharedResource.Id,
   496  							Grantee:    grant.Grantee,
   497  						},
   498  					},
   499  				})
   500  				Expect(err).To(HaveOccurred())
   501  				Expect(s).To(BeNil())
   502  			})
   503  
   504  			It("removes an existing share from the storage", func() {
   505  				err := m.Unshare(ctx, &collaboration.ShareReference{
   506  					Spec: &collaboration.ShareReference_Id{
   507  						Id: &collaboration.ShareId{
   508  							OpaqueId: share.Id.OpaqueId,
   509  						},
   510  					},
   511  				})
   512  				Expect(err).ToNot(HaveOccurred())
   513  
   514  				m, err = jsoncs3.New(storage, nil, 0, nil, 0) // Reset in-memory cache
   515  				Expect(err).ToNot(HaveOccurred())
   516  
   517  				s, err := m.GetShare(ctx, &collaboration.ShareReference{
   518  					Spec: &collaboration.ShareReference_Key{
   519  						Key: &collaboration.ShareKey{
   520  							ResourceId: sharedResource.Id,
   521  							Grantee:    grant.Grantee,
   522  						},
   523  					},
   524  				})
   525  				Expect(err).To(HaveOccurred())
   526  				Expect(s).To(BeNil())
   527  			})
   528  		})
   529  
   530  		Describe("UpdateShare", func() {
   531  			BeforeEach(func() {
   532  				mockStat(
   533  					&provider.Reference{ResourceId: sharedResource.Id},
   534  					&providerv1beta1.ResourceInfo{PermissionSet: &providerv1beta1.ResourcePermissions{ListGrants: false}},
   535  				)
   536  			})
   537  			It("does not update shares of other users", func() {
   538  				_, err := m.UpdateShare(otherCtx, &collaboration.ShareReference{
   539  					Spec: &collaboration.ShareReference_Id{
   540  						Id: &collaboration.ShareId{
   541  							OpaqueId: share.Id.OpaqueId,
   542  						},
   543  					},
   544  				}, &collaboration.SharePermissions{
   545  					Permissions: &providerv1beta1.ResourcePermissions{
   546  						InitiateFileUpload: true,
   547  					},
   548  				}, nil, nil)
   549  				Expect(err).To(HaveOccurred())
   550  			})
   551  
   552  			It("updates an existing share", func() {
   553  				s := shareBykey(&collaboration.ShareKey{
   554  					ResourceId: sharedResource.Id,
   555  					Grantee:    grant.Grantee,
   556  				})
   557  				Expect(s.GetPermissions().GetPermissions().InitiateFileUpload).To(BeFalse())
   558  
   559  				// enhance privileges
   560  				us, err := m.UpdateShare(ctx, &collaboration.ShareReference{
   561  					Spec: &collaboration.ShareReference_Id{
   562  						Id: &collaboration.ShareId{
   563  							OpaqueId: share.Id.OpaqueId,
   564  						},
   565  					},
   566  				}, &collaboration.SharePermissions{
   567  					Permissions: &providerv1beta1.ResourcePermissions{
   568  						InitiateFileUpload: true,
   569  					},
   570  				}, nil, nil)
   571  				Expect(err).ToNot(HaveOccurred())
   572  				Expect(us).ToNot(BeNil())
   573  				Expect(us.GetPermissions().GetPermissions().InitiateFileUpload).To(BeTrue())
   574  
   575  				s = shareBykey(&collaboration.ShareKey{
   576  					ResourceId: sharedResource.Id,
   577  					Grantee:    grant.Grantee,
   578  				})
   579  				Expect(s.GetPermissions().GetPermissions().InitiateFileUpload).To(BeTrue())
   580  
   581  				// reduce privileges
   582  				us, err = m.UpdateShare(ctx, &collaboration.ShareReference{
   583  					Spec: &collaboration.ShareReference_Id{
   584  						Id: &collaboration.ShareId{
   585  							OpaqueId: share.Id.OpaqueId,
   586  						},
   587  					},
   588  				}, &collaboration.SharePermissions{
   589  					Permissions: &providerv1beta1.ResourcePermissions{
   590  						InitiateFileUpload: false,
   591  					},
   592  				}, nil, nil)
   593  				Expect(err).ToNot(HaveOccurred())
   594  				Expect(us).ToNot(BeNil())
   595  				Expect(us.GetPermissions().GetPermissions().InitiateFileUpload).To(BeFalse())
   596  
   597  				s = shareBykey(&collaboration.ShareKey{
   598  					ResourceId: sharedResource.Id,
   599  					Grantee:    grant.Grantee,
   600  				})
   601  				Expect(s.GetPermissions().GetPermissions().InitiateFileUpload).To(BeFalse())
   602  			})
   603  
   604  			It("persists the change", func() {
   605  				s := shareBykey(&collaboration.ShareKey{
   606  					ResourceId: sharedResource.Id,
   607  					Grantee:    grant.Grantee,
   608  				})
   609  				Expect(s.GetPermissions().GetPermissions().InitiateFileUpload).To(BeFalse())
   610  
   611  				// enhance privileges
   612  				us, err := m.UpdateShare(ctx, &collaboration.ShareReference{
   613  					Spec: &collaboration.ShareReference_Id{
   614  						Id: &collaboration.ShareId{
   615  							OpaqueId: share.Id.OpaqueId,
   616  						},
   617  					},
   618  				}, &collaboration.SharePermissions{
   619  					Permissions: &providerv1beta1.ResourcePermissions{
   620  						InitiateFileUpload: true,
   621  					},
   622  				}, nil, nil)
   623  				Expect(err).ToNot(HaveOccurred())
   624  				Expect(us).ToNot(BeNil())
   625  				Expect(us.GetPermissions().GetPermissions().InitiateFileUpload).To(BeTrue())
   626  
   627  				m, err = jsoncs3.New(storage, nil, 0, nil, 0) // Reset in-memory cache
   628  				Expect(err).ToNot(HaveOccurred())
   629  
   630  				s = shareBykey(&collaboration.ShareKey{
   631  					ResourceId: sharedResource.Id,
   632  					Grantee:    grant.Grantee,
   633  				})
   634  				Expect(s.GetPermissions().GetPermissions().InitiateFileUpload).To(BeTrue())
   635  			})
   636  		})
   637  
   638  		Describe("ListShares", func() {
   639  			It("lists an existing share", func() {
   640  				shares, err := m.ListShares(ctx, nil)
   641  				Expect(err).ToNot(HaveOccurred())
   642  				Expect(shares).To(HaveLen(1))
   643  
   644  				Expect(shares[0].Id).To(Equal(share.Id))
   645  			})
   646  
   647  			It("syncronizes the provider cache before listing", func() {
   648  				shares, err := m.ListShares(ctx, nil)
   649  				Expect(err).ToNot(HaveOccurred())
   650  				Expect(len(shares)).To(Equal(1))
   651  				Expect(shares[0].Id.OpaqueId).To(Equal(share.Id.OpaqueId))
   652  				Expect(shares[0].Permissions.Permissions.InitiateFileUpload).To(BeFalse())
   653  
   654  				// Change providercache on disk
   655  				spaces, ok := m.Cache.Providers.Load("storageid")
   656  				Expect(ok).To(BeTrue())
   657  				cache, ok := spaces.Spaces.Load("spaceid")
   658  				Expect(ok).To(BeTrue())
   659  				cache.Shares[share.Id.OpaqueId].Permissions.Permissions.InitiateFileUpload = true
   660  				bytes, err := json.Marshal(cache)
   661  				Expect(err).ToNot(HaveOccurred())
   662  				Expect(storage.SimpleUpload(context.Background(), "storages/storageid/spaceid.json", bytes)).To(Succeed())
   663  				Expect(err).ToNot(HaveOccurred())
   664  
   665  				// Reset providercache in memory
   666  				cache.Shares[share.Id.OpaqueId].Permissions.Permissions.InitiateFileUpload = false
   667  
   668  				cache.Etag = "reset1" // trigger reload
   669  				shares, err = m.ListShares(ctx, nil)
   670  				Expect(err).ToNot(HaveOccurred())
   671  				Expect(len(shares)).To(Equal(1))
   672  				Expect(shares[0].Id.OpaqueId).To(Equal(share.Id.OpaqueId))
   673  				Expect(shares[0].Permissions.Permissions.InitiateFileUpload).To(BeTrue())
   674  			})
   675  
   676  			It("syncronizes the share cache before listing", func() {
   677  				shares, err := m.ListShares(ctx, nil)
   678  				Expect(err).ToNot(HaveOccurred())
   679  				Expect(len(shares)).To(Equal(1))
   680  
   681  				// Add a second cache to the provider cache so it can be referenced
   682  				secondShareID := "storageid" + shareid.IDDelimiter + "spaceid" + shareid.IDDelimiter + "secondshare"
   683  				Expect(m.Cache.Add(ctx, "storageid", "spaceid", secondShareID, &collaboration.Share{
   684  					Id:      &collaboration.ShareId{OpaqueId: secondShareID},
   685  					Creator: user1.Id,
   686  				})).To(Succeed())
   687  
   688  				cache := sharecache.UserShareCache{
   689  					Etag: "etag1",
   690  					UserShares: map[string]*sharecache.SpaceShareIDs{
   691  						"storageid" + shareid.IDDelimiter + "spaceid": {
   692  							IDs: map[string]struct{}{
   693  								shares[0].Id.OpaqueId: {},
   694  								"storageid" + shareid.IDDelimiter + "spaceid" + shareid.IDDelimiter + "secondshare": {},
   695  							},
   696  						},
   697  					},
   698  				}
   699  				bytes, err := json.Marshal(cache)
   700  				Expect(err).ToNot(HaveOccurred())
   701  				err = os.WriteFile(filepath.Join(tmpdir, "users/admin/created.json"), bytes, 0x755)
   702  				Expect(err).ToNot(HaveOccurred())
   703  
   704  				cc, _ := m.CreatedCache.UserShares.Load("admin")
   705  				cc.Etag = "reset1" // trigger reload
   706  				shares, err = m.ListShares(ctx, nil)
   707  				Expect(err).ToNot(HaveOccurred())
   708  				Expect(len(shares)).To(Equal(2))
   709  			})
   710  
   711  			It("filters by resource id", func() {
   712  				shares, err := m.ListShares(ctx, []*collaboration.Filter{
   713  					{
   714  						Type: collaboration.Filter_TYPE_RESOURCE_ID,
   715  						Term: &collaboration.Filter_ResourceId{
   716  							ResourceId: &providerv1beta1.ResourceId{
   717  								StorageId: "storageid",
   718  								SpaceId:   "spaceid",
   719  								OpaqueId:  "somethingelse",
   720  							},
   721  						},
   722  					},
   723  				})
   724  				Expect(err).ToNot(HaveOccurred())
   725  				Expect(shares).To(HaveLen(0))
   726  			})
   727  		})
   728  
   729  		Describe("ListReceivedShares", func() {
   730  			It("lists the received shares", func() {
   731  				received, err := m.ListReceivedShares(granteeCtx, []*collaboration.Filter{}, nil)
   732  				Expect(err).ToNot(HaveOccurred())
   733  				Expect(len(received)).To(Equal(1))
   734  				Expect(received[0].Share.ResourceId).To(BeComparableTo(sharedResource.Id, protocmp.Transform()))
   735  				Expect(received[0].State).To(Equal(collaboration.ShareState_SHARE_STATE_PENDING))
   736  			})
   737  
   738  			It("syncronizes the provider cache before listing", func() {
   739  				received, err := m.ListReceivedShares(granteeCtx, []*collaboration.Filter{}, nil)
   740  				Expect(err).ToNot(HaveOccurred())
   741  				Expect(len(received)).To(Equal(1))
   742  				Expect(received[0].Share.Permissions.Permissions.InitiateFileUpload).To(BeFalse())
   743  
   744  				// Change providercache on disk
   745  				spaces, ok := m.Cache.Providers.Load("storageid")
   746  				Expect(ok).To(BeTrue())
   747  				cache, ok := spaces.Spaces.Load("spaceid")
   748  				Expect(ok).To(BeTrue())
   749  				cache.Shares[share.Id.OpaqueId].Permissions.Permissions.InitiateFileUpload = true
   750  				bytes, err := json.Marshal(cache)
   751  				Expect(err).ToNot(HaveOccurred())
   752  				Expect(storage.SimpleUpload(context.Background(), "storages/storageid/spaceid.json", bytes)).To(Succeed())
   753  				Expect(err).ToNot(HaveOccurred())
   754  
   755  				// Reset providercache in memory
   756  				cache.Shares[share.Id.OpaqueId].Permissions.Permissions.InitiateFileUpload = false
   757  
   758  				cache.Etag = "reset1" // trigger reload
   759  				received, err = m.ListReceivedShares(granteeCtx, []*collaboration.Filter{}, nil)
   760  				Expect(err).ToNot(HaveOccurred())
   761  				Expect(len(received)).To(Equal(1))
   762  				Expect(received[0].Share.Permissions.Permissions.InitiateFileUpload).To(BeTrue())
   763  			})
   764  
   765  			It("syncronizes the user received cache before listing", func() {
   766  				m, err := jsoncs3.New(storage, nil, 0, nil, 0) // Reset in-memory cache
   767  				Expect(err).ToNot(HaveOccurred())
   768  
   769  				received, err := m.ListReceivedShares(granteeCtx, []*collaboration.Filter{}, nil)
   770  				Expect(err).ToNot(HaveOccurred())
   771  				Expect(len(received)).To(Equal(1))
   772  			})
   773  
   774  			It("filters by resource id", func() {
   775  				share2, err := m.Share(ctx, sharedResource2, grant)
   776  				Expect(err).ToNot(HaveOccurred())
   777  
   778  				received, err := m.ListReceivedShares(granteeCtx, []*collaboration.Filter{}, nil)
   779  				Expect(err).ToNot(HaveOccurred())
   780  				Expect(len(received)).To(Equal(2))
   781  
   782  				received, err = m.ListReceivedShares(granteeCtx, []*collaboration.Filter{
   783  					{
   784  						Type: collaboration.Filter_TYPE_RESOURCE_ID,
   785  						Term: &collaboration.Filter_ResourceId{
   786  							ResourceId: sharedResource.Id,
   787  						},
   788  					},
   789  				}, nil)
   790  				Expect(err).ToNot(HaveOccurred())
   791  				Expect(len(received)).To(Equal(1))
   792  				Expect(received[0].Share.ResourceId).To(BeComparableTo(sharedResource.Id, protocmp.Transform()))
   793  				Expect(received[0].State).To(Equal(collaboration.ShareState_SHARE_STATE_PENDING))
   794  				Expect(received[0].Share.Id).To(Equal(share.Id))
   795  
   796  				received, err = m.ListReceivedShares(granteeCtx, []*collaboration.Filter{
   797  					{
   798  						Type: collaboration.Filter_TYPE_RESOURCE_ID,
   799  						Term: &collaboration.Filter_ResourceId{
   800  							ResourceId: sharedResource2.Id,
   801  						},
   802  					},
   803  				}, nil)
   804  				Expect(err).ToNot(HaveOccurred())
   805  				Expect(len(received)).To(Equal(1))
   806  				Expect(received[0].Share.ResourceId).To(BeComparableTo(sharedResource2.Id, protocmp.Transform()))
   807  				Expect(received[0].State).To(Equal(collaboration.ShareState_SHARE_STATE_PENDING))
   808  				Expect(received[0].Share.Id).To(Equal(share2.Id))
   809  			})
   810  
   811  			Context("with a group share", func() {
   812  				var (
   813  					gshare *collaboration.Share
   814  				)
   815  
   816  				BeforeEach(func() {
   817  					var err error
   818  					gshare, err = m.Share(ctx, sharedResource, groupGrant)
   819  					Expect(err).ToNot(HaveOccurred())
   820  				})
   821  
   822  				It("lists the group share", func() {
   823  					received, err := m.ListReceivedShares(granteeCtx, []*collaboration.Filter{}, nil)
   824  					Expect(err).ToNot(HaveOccurred())
   825  					Expect(len(received)).To(Equal(2))
   826  					ids := []string{}
   827  					for _, s := range received {
   828  						ids = append(ids, s.Share.Id.OpaqueId)
   829  					}
   830  					Expect(ids).To(ConsistOf(share.Id.OpaqueId, gshare.Id.OpaqueId))
   831  				})
   832  
   833  				It("syncronizes the group received cache before listing", func() {
   834  					m, err := jsoncs3.New(storage, nil, 0, nil, 0) // Reset in-memory cache
   835  					Expect(err).ToNot(HaveOccurred())
   836  
   837  					received, err := m.ListReceivedShares(granteeCtx, []*collaboration.Filter{}, nil)
   838  					Expect(err).ToNot(HaveOccurred())
   839  					Expect(len(received)).To(Equal(2))
   840  					ids := []string{}
   841  					for _, s := range received {
   842  						ids = append(ids, s.Share.Id.OpaqueId)
   843  					}
   844  					Expect(ids).To(ConsistOf(share.Id.OpaqueId, gshare.Id.OpaqueId))
   845  				})
   846  
   847  				It("merges the user state with the group share", func() {
   848  					rs, err := m.GetReceivedShare(granteeCtx, &collaboration.ShareReference{
   849  						Spec: &collaboration.ShareReference_Id{
   850  							Id: gshare.Id,
   851  						},
   852  					})
   853  					Expect(err).ToNot(HaveOccurred())
   854  
   855  					rs.State = collaboration.ShareState_SHARE_STATE_ACCEPTED
   856  					_, err = m.UpdateReceivedShare(granteeCtx, rs, &fieldmaskpb.FieldMask{Paths: []string{"state"}}, nil)
   857  					Expect(err).ToNot(HaveOccurred())
   858  
   859  					received, err := m.ListReceivedShares(granteeCtx, []*collaboration.Filter{}, nil)
   860  					Expect(err).ToNot(HaveOccurred())
   861  					Expect(len(received)).To(Equal(2))
   862  				})
   863  			})
   864  		})
   865  
   866  		Describe("GetReceivedShare", func() {
   867  			It("gets the state", func() {
   868  				rs, err := m.GetReceivedShare(granteeCtx, &collaboration.ShareReference{
   869  					Spec: &collaboration.ShareReference_Id{
   870  						Id: share.Id,
   871  					},
   872  				})
   873  				Expect(err).ToNot(HaveOccurred())
   874  				Expect(rs.State).To(Equal(collaboration.ShareState_SHARE_STATE_PENDING))
   875  			})
   876  
   877  			It("syncs the cache", func() {
   878  				m, err := jsoncs3.New(storage, nil, 0, nil, 0) // Reset in-memory cache
   879  				Expect(err).ToNot(HaveOccurred())
   880  
   881  				rs, err := m.GetReceivedShare(granteeCtx, &collaboration.ShareReference{
   882  					Spec: &collaboration.ShareReference_Id{
   883  						Id: share.Id,
   884  					},
   885  				})
   886  				Expect(err).ToNot(HaveOccurred())
   887  				Expect(rs.State).To(Equal(collaboration.ShareState_SHARE_STATE_PENDING))
   888  			})
   889  
   890  			Context("with a group share", func() {
   891  				var (
   892  					gshare *collaboration.Share
   893  				)
   894  
   895  				BeforeEach(func() {
   896  					var err error
   897  					gshare, err = m.Share(ctx, sharedResource, groupGrant)
   898  					Expect(err).ToNot(HaveOccurred())
   899  				})
   900  
   901  				It("gets the group share", func() {
   902  					rs, err := m.GetReceivedShare(granteeCtx, &collaboration.ShareReference{
   903  						Spec: &collaboration.ShareReference_Id{
   904  							Id: gshare.Id,
   905  						},
   906  					})
   907  					Expect(err).ToNot(HaveOccurred())
   908  					Expect(rs).ToNot(BeNil())
   909  				})
   910  
   911  				It("syncs the cache", func() {
   912  					m, err := jsoncs3.New(storage, nil, 0, nil, 0) // Reset in-memory cache
   913  					Expect(err).ToNot(HaveOccurred())
   914  
   915  					rs, err := m.GetReceivedShare(granteeCtx, &collaboration.ShareReference{
   916  						Spec: &collaboration.ShareReference_Id{
   917  							Id: gshare.Id,
   918  						},
   919  					})
   920  					Expect(err).ToNot(HaveOccurred())
   921  					Expect(rs).ToNot(BeNil())
   922  				})
   923  			})
   924  		})
   925  
   926  		Describe("UpdateReceivedShare", func() {
   927  			It("updates the state", func() {
   928  				rs, err := m.GetReceivedShare(granteeCtx, &collaboration.ShareReference{
   929  					Spec: &collaboration.ShareReference_Id{
   930  						Id: share.Id,
   931  					},
   932  				})
   933  				Expect(err).ToNot(HaveOccurred())
   934  				Expect(rs.State).To(Equal(collaboration.ShareState_SHARE_STATE_PENDING))
   935  
   936  				rs.State = collaboration.ShareState_SHARE_STATE_ACCEPTED
   937  				rs, err = m.UpdateReceivedShare(granteeCtx, rs, &fieldmaskpb.FieldMask{Paths: []string{"state"}}, nil)
   938  				Expect(err).ToNot(HaveOccurred())
   939  				Expect(rs.State).To(Equal(collaboration.ShareState_SHARE_STATE_ACCEPTED))
   940  
   941  				rs, err = m.GetReceivedShare(granteeCtx, &collaboration.ShareReference{
   942  					Spec: &collaboration.ShareReference_Id{
   943  						Id: share.Id,
   944  					},
   945  				})
   946  				Expect(err).ToNot(HaveOccurred())
   947  				Expect(rs.State).To(Equal(collaboration.ShareState_SHARE_STATE_ACCEPTED))
   948  			})
   949  
   950  			It("updates the mountpoint", func() {
   951  				rs, err := m.GetReceivedShare(granteeCtx, &collaboration.ShareReference{
   952  					Spec: &collaboration.ShareReference_Id{
   953  						Id: share.Id,
   954  					},
   955  				})
   956  				Expect(err).ToNot(HaveOccurred())
   957  				Expect(rs.MountPoint).To(BeNil())
   958  
   959  				rs.MountPoint = &providerv1beta1.Reference{
   960  					Path: "newMP",
   961  				}
   962  				rs, err = m.UpdateReceivedShare(granteeCtx, rs, &fieldmaskpb.FieldMask{Paths: []string{"mount_point"}}, nil)
   963  				Expect(err).ToNot(HaveOccurred())
   964  				Expect(rs.MountPoint.Path).To(Equal("newMP"))
   965  
   966  				rs, err = m.GetReceivedShare(granteeCtx, &collaboration.ShareReference{
   967  					Spec: &collaboration.ShareReference_Id{
   968  						Id: share.Id,
   969  					},
   970  				})
   971  				Expect(err).ToNot(HaveOccurred())
   972  				Expect(rs.MountPoint.Path).To(Equal("newMP"))
   973  				Expect(rs.Hidden).To(Equal(false))
   974  			})
   975  
   976  			It("hides the share", func() {
   977  				rs, err := m.GetReceivedShare(granteeCtx, &collaboration.ShareReference{
   978  					Spec: &collaboration.ShareReference_Id{
   979  						Id: share.Id,
   980  					},
   981  				})
   982  				Expect(err).ToNot(HaveOccurred())
   983  				Expect(rs.MountPoint).To(BeNil())
   984  
   985  				rs.MountPoint = &providerv1beta1.Reference{
   986  					Path: "newMP",
   987  				}
   988  				rs.Hidden = true
   989  
   990  				rs, err = m.UpdateReceivedShare(granteeCtx, rs, &fieldmaskpb.FieldMask{Paths: []string{"hidden", "mount_point"}}, nil)
   991  				Expect(err).ToNot(HaveOccurred())
   992  				Expect(rs.MountPoint.Path).To(Equal("newMP"))
   993  				Expect(rs.Hidden).To(Equal(true))
   994  
   995  				rs, err = m.GetReceivedShare(granteeCtx, &collaboration.ShareReference{
   996  					Spec: &collaboration.ShareReference_Id{
   997  						Id: share.Id,
   998  					},
   999  				})
  1000  				Expect(err).ToNot(HaveOccurred())
  1001  				Expect(rs.MountPoint.Path).To(Equal("newMP"))
  1002  				Expect(rs.Hidden).To(Equal(true))
  1003  			})
  1004  
  1005  			It("handles invalid field masks", func() {
  1006  				rs, err := m.GetReceivedShare(granteeCtx, &collaboration.ShareReference{
  1007  					Spec: &collaboration.ShareReference_Id{
  1008  						Id: share.Id,
  1009  					},
  1010  				})
  1011  				Expect(err).ToNot(HaveOccurred())
  1012  
  1013  				_, err = m.UpdateReceivedShare(granteeCtx, rs, &fieldmaskpb.FieldMask{Paths: []string{"invalid"}}, nil)
  1014  				Expect(err).To(HaveOccurred())
  1015  			})
  1016  
  1017  			Context("with a group share", func() {
  1018  				var (
  1019  					gshare *collaboration.Share
  1020  				)
  1021  
  1022  				BeforeEach(func() {
  1023  					var err error
  1024  					gshare, err = m.Share(ctx, sharedResource, groupGrant)
  1025  					Expect(err).ToNot(HaveOccurred())
  1026  				})
  1027  
  1028  				It("updates the received group share", func() {
  1029  					rs, err := m.GetReceivedShare(granteeCtx, &collaboration.ShareReference{
  1030  						Spec: &collaboration.ShareReference_Id{
  1031  							Id: gshare.Id,
  1032  						},
  1033  					})
  1034  					Expect(err).ToNot(HaveOccurred())
  1035  					Expect(rs.State).To(Equal(collaboration.ShareState_SHARE_STATE_PENDING))
  1036  
  1037  					rs.State = collaboration.ShareState_SHARE_STATE_ACCEPTED
  1038  					rs, err = m.UpdateReceivedShare(granteeCtx, rs, &fieldmaskpb.FieldMask{Paths: []string{"state"}}, nil)
  1039  					Expect(err).ToNot(HaveOccurred())
  1040  					Expect(rs.State).To(Equal(collaboration.ShareState_SHARE_STATE_ACCEPTED))
  1041  
  1042  					rs, err = m.GetReceivedShare(granteeCtx, &collaboration.ShareReference{
  1043  						Spec: &collaboration.ShareReference_Id{
  1044  							Id: gshare.Id,
  1045  						},
  1046  					})
  1047  					Expect(err).ToNot(HaveOccurred())
  1048  					Expect(rs.State).To(Equal(collaboration.ShareState_SHARE_STATE_ACCEPTED))
  1049  				})
  1050  
  1051  				It("persists the change", func() {
  1052  					rs, err := m.GetReceivedShare(granteeCtx, &collaboration.ShareReference{
  1053  						Spec: &collaboration.ShareReference_Id{
  1054  							Id: gshare.Id,
  1055  						},
  1056  					})
  1057  					Expect(err).ToNot(HaveOccurred())
  1058  					Expect(rs.State).To(Equal(collaboration.ShareState_SHARE_STATE_PENDING))
  1059  
  1060  					rs.State = collaboration.ShareState_SHARE_STATE_ACCEPTED
  1061  					rs, err = m.UpdateReceivedShare(granteeCtx, rs, &fieldmaskpb.FieldMask{Paths: []string{"state"}}, nil)
  1062  					Expect(err).ToNot(HaveOccurred())
  1063  					Expect(rs.State).To(Equal(collaboration.ShareState_SHARE_STATE_ACCEPTED))
  1064  
  1065  					m, err := jsoncs3.New(storage, nil, 0, nil, 0) // Reset in-memory cache
  1066  					Expect(err).ToNot(HaveOccurred())
  1067  
  1068  					rs, err = m.GetReceivedShare(granteeCtx, &collaboration.ShareReference{
  1069  						Spec: &collaboration.ShareReference_Id{
  1070  							Id: gshare.Id,
  1071  						},
  1072  					})
  1073  					Expect(err).ToNot(HaveOccurred())
  1074  					Expect(rs.State).To(Equal(collaboration.ShareState_SHARE_STATE_ACCEPTED))
  1075  				})
  1076  
  1077  				It("hides share and persists the change", func() {
  1078  					rs, err := m.GetReceivedShare(granteeCtx, &collaboration.ShareReference{
  1079  						Spec: &collaboration.ShareReference_Id{
  1080  							Id: gshare.Id,
  1081  						},
  1082  					})
  1083  					Expect(err).ToNot(HaveOccurred())
  1084  					Expect(rs.State).To(Equal(collaboration.ShareState_SHARE_STATE_PENDING))
  1085  
  1086  					rs.State = collaboration.ShareState_SHARE_STATE_ACCEPTED
  1087  					rs.Hidden = true
  1088  					rs, err = m.UpdateReceivedShare(granteeCtx, rs, &fieldmaskpb.FieldMask{Paths: []string{"state", "hidden"}}, nil)
  1089  					Expect(err).ToNot(HaveOccurred())
  1090  					Expect(rs.State).To(Equal(collaboration.ShareState_SHARE_STATE_ACCEPTED))
  1091  					Expect(rs.Hidden).To(Equal(true))
  1092  
  1093  					m, err := jsoncs3.New(storage, nil, 0, nil, 0) // Reset in-memory cache
  1094  					Expect(err).ToNot(HaveOccurred())
  1095  
  1096  					rs, err = m.GetReceivedShare(granteeCtx, &collaboration.ShareReference{
  1097  						Spec: &collaboration.ShareReference_Id{
  1098  							Id: gshare.Id,
  1099  						},
  1100  					})
  1101  					Expect(rs.Hidden).To(Equal(true))
  1102  					Expect(err).ToNot(HaveOccurred())
  1103  					Expect(rs.State).To(Equal(collaboration.ShareState_SHARE_STATE_ACCEPTED))
  1104  				})
  1105  
  1106  				It("hides and unhides the share and persists the change", func() {
  1107  					rs, err := m.GetReceivedShare(granteeCtx, &collaboration.ShareReference{
  1108  						Spec: &collaboration.ShareReference_Id{
  1109  							Id: gshare.Id,
  1110  						},
  1111  					})
  1112  					Expect(err).ToNot(HaveOccurred())
  1113  					Expect(rs.State).To(Equal(collaboration.ShareState_SHARE_STATE_PENDING))
  1114  
  1115  					rs.State = collaboration.ShareState_SHARE_STATE_ACCEPTED
  1116  					rs.Hidden = true
  1117  					rs, err = m.UpdateReceivedShare(granteeCtx, rs, &fieldmaskpb.FieldMask{Paths: []string{"state", "hidden"}}, nil)
  1118  					Expect(err).ToNot(HaveOccurred())
  1119  					Expect(rs.State).To(Equal(collaboration.ShareState_SHARE_STATE_ACCEPTED))
  1120  					Expect(rs.Hidden).To(Equal(true))
  1121  
  1122  					m, err := jsoncs3.New(storage, nil, 0, nil, 0) // Reset in-memory cache
  1123  					Expect(err).ToNot(HaveOccurred())
  1124  
  1125  					rs, err = m.GetReceivedShare(granteeCtx, &collaboration.ShareReference{
  1126  						Spec: &collaboration.ShareReference_Id{
  1127  							Id: gshare.Id,
  1128  						},
  1129  					})
  1130  					Expect(rs.Hidden).To(Equal(true))
  1131  					Expect(err).ToNot(HaveOccurred())
  1132  					Expect(rs.State).To(Equal(collaboration.ShareState_SHARE_STATE_ACCEPTED))
  1133  
  1134  					rs.Hidden = false
  1135  					rs, err = m.UpdateReceivedShare(granteeCtx, rs, &fieldmaskpb.FieldMask{Paths: []string{"state", "hidden"}}, nil)
  1136  					Expect(err).ToNot(HaveOccurred())
  1137  					Expect(rs.State).To(Equal(collaboration.ShareState_SHARE_STATE_ACCEPTED))
  1138  					Expect(rs.Hidden).To(Equal(false))
  1139  
  1140  					rs, err = m.GetReceivedShare(granteeCtx, &collaboration.ShareReference{
  1141  						Spec: &collaboration.ShareReference_Id{
  1142  							Id: gshare.Id,
  1143  						},
  1144  					})
  1145  					Expect(rs.Hidden).To(Equal(false))
  1146  					Expect(err).ToNot(HaveOccurred())
  1147  					Expect(rs.State).To(Equal(collaboration.ShareState_SHARE_STATE_ACCEPTED))
  1148  				})
  1149  			})
  1150  		})
  1151  	})
  1152  })