github.com/cs3org/reva/v2@v2.27.7/tests/integration/grpc/storageprovider_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 grpc_test
    20  
    21  import (
    22  	"context"
    23  
    24  	"google.golang.org/grpc/metadata"
    25  
    26  	userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
    27  	rpcv1beta1 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
    28  	storagep "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
    29  	"github.com/cs3org/reva/v2/pkg/auth/scope"
    30  	ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
    31  	"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
    32  	"github.com/cs3org/reva/v2/pkg/storage"
    33  	"github.com/cs3org/reva/v2/pkg/storage/fs/nextcloud"
    34  	"github.com/cs3org/reva/v2/pkg/storage/fs/ocis"
    35  	"github.com/cs3org/reva/v2/pkg/storage/fs/registry"
    36  	jwt "github.com/cs3org/reva/v2/pkg/token/manager/jwt"
    37  	"github.com/cs3org/reva/v2/tests/helpers"
    38  	"github.com/google/uuid"
    39  
    40  	. "github.com/onsi/ginkgo/v2"
    41  	. "github.com/onsi/gomega"
    42  )
    43  
    44  func ref(provider string, path string) *storagep.Reference {
    45  	r := &storagep.Reference{
    46  		Path: path,
    47  	}
    48  	if provider == "ocis" {
    49  		r.ResourceId = &storagep.ResourceId{
    50  			SpaceId:  "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
    51  			OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
    52  		}
    53  	}
    54  	return r
    55  }
    56  
    57  func createFS(provider string, revads map[string]*Revad) (storage.FS, error) {
    58  	conf := make(map[string]interface{})
    59  	var f registry.NewFunc
    60  	switch provider {
    61  	case "ocis":
    62  		conf["root"] = revads["storage"].StorageRoot
    63  		conf["permissionssvc"] = revads["permissions"].GrpcAddress
    64  		f = ocis.New
    65  	case "nextcloud":
    66  		conf["endpoint"] = "http://localhost:8080/apps/sciencemesh/"
    67  		conf["mock_http"] = true
    68  		f = nextcloud.New
    69  	}
    70  	return f(conf, nil, nil)
    71  }
    72  
    73  // This test suite tests the gprc storageprovider interface using different
    74  // storage backends
    75  //
    76  // It uses the `startRevads` helper to spawn the according reva daemon and
    77  // other dependencies like a userprovider if needed.
    78  // It also sets up an authenticated context and a service client to the storage
    79  // provider to be used in the assertion functions.
    80  var _ = Describe("storage providers", func() {
    81  	var (
    82  		dependencies = []RevadConfig{}
    83  		variables    = map[string]string{}
    84  		revads       = map[string]*Revad{}
    85  
    86  		ctx            context.Context
    87  		providerClient storagep.ProviderAPIClient
    88  		spacesClient   storagep.SpacesAPIClient
    89  		user           = &userpb.User{
    90  			Id: &userpb.UserId{
    91  				Idp:      "0.0.0.0:19000",
    92  				OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
    93  				Type:     userpb.UserType_USER_TYPE_PRIMARY,
    94  			},
    95  			Username: "einstein",
    96  		}
    97  
    98  		homePath           = "/"
    99  		filePath           = "/file"
   100  		versionedFilePath  = "/versionedFile"
   101  		subdirPath         = "/subdir"
   102  		subdirRestoredPath = "/subdirRestored"
   103  		sharesPath         = "/Shares"
   104  	)
   105  
   106  	JustBeforeEach(func() {
   107  		var err error
   108  		ctx = context.Background()
   109  
   110  		// Add auth token
   111  		tokenManager, err := jwt.New(map[string]interface{}{"secret": "changemeplease"})
   112  		Expect(err).ToNot(HaveOccurred())
   113  		scope, err := scope.AddOwnerScope(nil)
   114  		Expect(err).ToNot(HaveOccurred())
   115  		t, err := tokenManager.MintToken(ctx, user, scope)
   116  		Expect(err).ToNot(HaveOccurred())
   117  		ctx = ctxpkg.ContextSetToken(ctx, t)
   118  		ctx = metadata.AppendToOutgoingContext(ctx, ctxpkg.TokenHeader, t)
   119  		ctx = ctxpkg.ContextSetUser(ctx, user)
   120  
   121  		revads, err = startRevads(dependencies, variables)
   122  		Expect(err).ToNot(HaveOccurred())
   123  		providerClient, err = pool.GetStorageProviderServiceClient(revads["storage"].GrpcAddress)
   124  		Expect(err).ToNot(HaveOccurred())
   125  		spacesClient, err = pool.GetSpacesProviderServiceClient(revads["storage"].GrpcAddress)
   126  		Expect(err).ToNot(HaveOccurred())
   127  	})
   128  
   129  	AfterEach(func() {
   130  		for _, r := range revads {
   131  			Expect(r.Cleanup(CurrentSpecReport().Failed())).To(Succeed())
   132  		}
   133  	})
   134  
   135  	assertCreateHome := func(provider string) {
   136  		It("creates a home directory", func() {
   137  			homeRef := ref(provider, homePath)
   138  			statRes, err := providerClient.Stat(ctx, &storagep.StatRequest{Ref: homeRef})
   139  			Expect(err).ToNot(HaveOccurred())
   140  			Expect(statRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_NOT_FOUND))
   141  
   142  			res, err := spacesClient.CreateStorageSpace(ctx, &storagep.CreateStorageSpaceRequest{
   143  				Owner: user,
   144  				Type:  "personal",
   145  				Name:  user.Id.OpaqueId,
   146  			})
   147  			Expect(err).ToNot(HaveOccurred())
   148  			Expect(res.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   149  
   150  			statRes, err = providerClient.Stat(ctx, &storagep.StatRequest{Ref: ref(provider, homePath)})
   151  			Expect(err).ToNot(HaveOccurred())
   152  			Expect(statRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   153  
   154  			// ghRes, err := serviceClient.GetHome(ctx, &storagep.GetHomeRequest{})
   155  			// Expect(err).ToNot(HaveOccurred())
   156  			// Expect(ghRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   157  		})
   158  	}
   159  
   160  	assertCreateContainer := func(provider string) {
   161  		It("creates a new directory", func() {
   162  			newRef := ref(provider, "/newdir")
   163  			_, err := providerClient.Stat(ctx, &storagep.StatRequest{Ref: newRef})
   164  			Expect(err).ToNot(HaveOccurred())
   165  			// Expect(statRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_NOT_FOUND))
   166  
   167  			res, err := providerClient.CreateContainer(ctx, &storagep.CreateContainerRequest{Ref: newRef})
   168  			Expect(res.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   169  			Expect(err).ToNot(HaveOccurred())
   170  
   171  			statRes, err := providerClient.Stat(ctx, &storagep.StatRequest{Ref: newRef})
   172  			Expect(err).ToNot(HaveOccurred())
   173  			Expect(statRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   174  		})
   175  	}
   176  
   177  	assertListContainer := func(provider string) {
   178  		It("lists a directory", func() {
   179  			listRes, err := providerClient.ListContainer(ctx, &storagep.ListContainerRequest{Ref: ref(provider, homePath)})
   180  			Expect(err).ToNot(HaveOccurred())
   181  			Expect(listRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   182  
   183  			switch provider {
   184  			case "ocis":
   185  				Expect(len(listRes.Infos)).To(Equal(1)) // subdir
   186  			case "nextcloud":
   187  				Expect(len(listRes.Infos)).To(Equal(1)) // subdir
   188  			default:
   189  				Fail("unknown provider")
   190  			}
   191  
   192  			for _, info := range listRes.Infos {
   193  				switch info.Path {
   194  				default:
   195  					Fail("unknown path: " + info.Path)
   196  				case "/.space":
   197  					Expect(info.Type).To(Equal(storagep.ResourceType_RESOURCE_TYPE_CONTAINER))
   198  				case subdirPath:
   199  					Expect(info.Type).To(Equal(storagep.ResourceType_RESOURCE_TYPE_CONTAINER))
   200  					Expect(info.Owner.OpaqueId).To(Equal("f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c"))
   201  
   202  				}
   203  			}
   204  		})
   205  	}
   206  
   207  	assertFileVersions := func(provider string) {
   208  		It("lists file versions", func() {
   209  			listRes, err := providerClient.ListFileVersions(ctx, &storagep.ListFileVersionsRequest{Ref: ref(provider, versionedFilePath)})
   210  			Expect(err).ToNot(HaveOccurred())
   211  			Expect(listRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   212  			Expect(len(listRes.Versions)).To(Equal(1))
   213  			Expect(listRes.Versions[0].Size).To(Equal(uint64(1)))
   214  		})
   215  
   216  		// FIXME flaky test?!?
   217  		It("restores a file version", func() {
   218  			vRef := ref(provider, versionedFilePath)
   219  			statRes, err := providerClient.Stat(ctx, &storagep.StatRequest{Ref: vRef})
   220  			Expect(err).ToNot(HaveOccurred())
   221  			Expect(statRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   222  			Expect(statRes.Info.Size).To(Equal(uint64(2))) // second version contains 2 bytes
   223  
   224  			listRes, err := providerClient.ListFileVersions(ctx, &storagep.ListFileVersionsRequest{Ref: vRef})
   225  			Expect(err).ToNot(HaveOccurred())
   226  			restoreRes, err := providerClient.RestoreFileVersion(ctx,
   227  				&storagep.RestoreFileVersionRequest{
   228  					Ref: vRef,
   229  					Key: listRes.Versions[0].Key,
   230  				})
   231  			Expect(err).ToNot(HaveOccurred())
   232  			Expect(restoreRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   233  
   234  			statRes, err = providerClient.Stat(ctx, &storagep.StatRequest{Ref: vRef})
   235  			Expect(err).ToNot(HaveOccurred())
   236  			Expect(statRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   237  			Expect(statRes.Info.Size).To(Equal(uint64(1))) // initial version contains 1 byte
   238  		})
   239  	}
   240  
   241  	assertDelete := func(provider string) {
   242  		It("deletes a directory", func() {
   243  			subdirRef := ref(provider, subdirPath)
   244  			statRes, err := providerClient.Stat(ctx, &storagep.StatRequest{Ref: subdirRef})
   245  			Expect(err).ToNot(HaveOccurred())
   246  			Expect(statRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   247  
   248  			res, err := providerClient.Delete(ctx, &storagep.DeleteRequest{Ref: subdirRef})
   249  			Expect(res.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   250  			Expect(err).ToNot(HaveOccurred())
   251  
   252  			statRes, err = providerClient.Stat(ctx, &storagep.StatRequest{Ref: subdirRef})
   253  			Expect(err).ToNot(HaveOccurred())
   254  			Expect(statRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_NOT_FOUND))
   255  		})
   256  	}
   257  
   258  	assertMove := func(provider string) {
   259  		It("moves a directory", func() {
   260  			subdirRef := ref(provider, subdirPath)
   261  			statRes, err := providerClient.Stat(ctx, &storagep.StatRequest{Ref: subdirRef})
   262  			Expect(err).ToNot(HaveOccurred())
   263  			Expect(statRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   264  
   265  			targetRef := &storagep.Reference{ResourceId: subdirRef.ResourceId, Path: "/new_subdir"}
   266  			res, err := providerClient.Move(ctx, &storagep.MoveRequest{Source: subdirRef, Destination: targetRef})
   267  
   268  			Expect(err).ToNot(HaveOccurred())
   269  			Expect(res.GetStatus().GetCode()).To(Equal(rpcv1beta1.Code_CODE_OK))
   270  
   271  			statRes, err = providerClient.Stat(ctx, &storagep.StatRequest{Ref: subdirRef})
   272  			Expect(err).ToNot(HaveOccurred())
   273  			Expect(statRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_NOT_FOUND))
   274  
   275  			statRes, err = providerClient.Stat(ctx, &storagep.StatRequest{Ref: targetRef})
   276  			Expect(err).ToNot(HaveOccurred())
   277  			Expect(statRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   278  		})
   279  	}
   280  
   281  	assertGetPath := func(provider string) {
   282  		It("gets the path to an ID", func() {
   283  			r := ref(provider, subdirPath)
   284  			statRes, err := providerClient.Stat(ctx, &storagep.StatRequest{Ref: r})
   285  			Expect(err).ToNot(HaveOccurred())
   286  			Expect(statRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   287  
   288  			res, err := providerClient.GetPath(ctx, &storagep.GetPathRequest{ResourceId: statRes.Info.Id})
   289  			Expect(err).ToNot(HaveOccurred())
   290  
   291  			// TODO: FIXME both cases should work for all providers
   292  
   293  			Expect(res.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   294  			if provider != "nextcloud" {
   295  				Expect(res.Path).To(Equal(subdirPath))
   296  			}
   297  		})
   298  	}
   299  
   300  	assertGrants := func(provider string) {
   301  		It("lists, adds and removes grants", func() {
   302  			By("there are no grants initially")
   303  			subdirRef := ref(provider, subdirPath)
   304  			listRes, err := providerClient.ListGrants(ctx, &storagep.ListGrantsRequest{Ref: subdirRef})
   305  			Expect(err).ToNot(HaveOccurred())
   306  			Expect(len(listRes.Grants)).To(Equal(0))
   307  
   308  			By("adding a grant")
   309  			grant := &storagep.Grant{
   310  				Grantee: &storagep.Grantee{
   311  					Type: storagep.GranteeType_GRANTEE_TYPE_USER,
   312  					Id: &storagep.Grantee_UserId{
   313  						UserId: &userpb.UserId{
   314  							OpaqueId: "4c510ada-c86b-4815-8820-42cdf82c3d51",
   315  						},
   316  					},
   317  				},
   318  				Permissions: &storagep.ResourcePermissions{
   319  					Stat:                 true,
   320  					Move:                 true,
   321  					Delete:               false,
   322  					InitiateFileDownload: true,
   323  				},
   324  			}
   325  			addRes, err := providerClient.AddGrant(ctx, &storagep.AddGrantRequest{Ref: subdirRef, Grant: grant})
   326  			Expect(err).ToNot(HaveOccurred())
   327  			Expect(addRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   328  
   329  			By("listing the new grant")
   330  			listRes, err = providerClient.ListGrants(ctx, &storagep.ListGrantsRequest{Ref: subdirRef})
   331  			Expect(err).ToNot(HaveOccurred())
   332  			Expect(len(listRes.Grants)).To(Equal(1))
   333  			readGrant := listRes.Grants[0]
   334  			Expect(readGrant.Permissions.Stat).To(BeTrue())
   335  			Expect(readGrant.Permissions.Move).To(BeTrue())
   336  			Expect(readGrant.Permissions.Delete).To(BeFalse())
   337  			Expect(readGrant.Permissions.InitiateFileDownload).To(BeTrue())
   338  
   339  			By("updating the grant")
   340  			grant.Permissions.Delete = true
   341  			updateRes, err := providerClient.UpdateGrant(ctx, &storagep.UpdateGrantRequest{Ref: subdirRef, Grant: grant})
   342  			Expect(err).ToNot(HaveOccurred())
   343  			Expect(updateRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   344  
   345  			By("listing the update grant")
   346  			listRes, err = providerClient.ListGrants(ctx, &storagep.ListGrantsRequest{Ref: subdirRef})
   347  			Expect(err).ToNot(HaveOccurred())
   348  			Expect(len(listRes.Grants)).To(Equal(1))
   349  			readGrant = listRes.Grants[0]
   350  			Expect(readGrant.Permissions.Stat).To(BeTrue())
   351  			Expect(readGrant.Permissions.Move).To(BeTrue())
   352  			Expect(readGrant.Permissions.Delete).To(BeTrue())
   353  			Expect(readGrant.Permissions.InitiateFileDownload).To(BeTrue())
   354  
   355  			By("deleting a grant")
   356  			delRes, err := providerClient.RemoveGrant(ctx, &storagep.RemoveGrantRequest{Ref: subdirRef, Grant: readGrant})
   357  			Expect(err).ToNot(HaveOccurred())
   358  			Expect(delRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   359  
   360  			By("the grant is gone")
   361  			listRes, err = providerClient.ListGrants(ctx, &storagep.ListGrantsRequest{Ref: subdirRef})
   362  			Expect(err).ToNot(HaveOccurred())
   363  			Expect(len(listRes.Grants)).To(Equal(0))
   364  		})
   365  	}
   366  
   367  	assertUploads := func(provider string) {
   368  		It("returns upload URLs for simple and tus", func() {
   369  			fileRef := ref(provider, filePath)
   370  			res, err := providerClient.InitiateFileUpload(ctx, &storagep.InitiateFileUploadRequest{Ref: fileRef})
   371  			Expect(err).ToNot(HaveOccurred())
   372  			Expect(res.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   373  			Expect(len(res.Protocols)).To(Equal(2))
   374  		})
   375  	}
   376  
   377  	assertDownloads := func(provider string) {
   378  		It("returns 'simple' download URLs", func() {
   379  			fileRef := ref(provider, filePath)
   380  			res, err := providerClient.InitiateFileDownload(ctx, &storagep.InitiateFileDownloadRequest{Ref: fileRef})
   381  			Expect(err).ToNot(HaveOccurred())
   382  			Expect(res.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   383  			Expect(len(res.Protocols)).To(Equal(1))
   384  		})
   385  	}
   386  
   387  	assertRecycle := func(provider string) {
   388  		It("lists and restores resources", func() {
   389  			By("deleting an item")
   390  			subdirRef := ref(provider, subdirPath)
   391  			res, err := providerClient.Delete(ctx, &storagep.DeleteRequest{Ref: subdirRef})
   392  			Expect(err).ToNot(HaveOccurred())
   393  			Expect(res.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   394  
   395  			By("listing the recycle items")
   396  			homeRef := ref(provider, homePath)
   397  			listRes, err := providerClient.ListRecycle(ctx, &storagep.ListRecycleRequest{Ref: homeRef})
   398  			Expect(err).ToNot(HaveOccurred())
   399  			Expect(listRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   400  
   401  			Expect(len(listRes.RecycleItems)).To(Equal(1))
   402  			item := listRes.RecycleItems[0]
   403  			Expect(item.Ref.Path).To(Equal(subdirPath))
   404  
   405  			By("restoring a recycle item")
   406  			statRes, err := providerClient.Stat(ctx, &storagep.StatRequest{Ref: subdirRef})
   407  			Expect(err).ToNot(HaveOccurred())
   408  			Expect(statRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_NOT_FOUND))
   409  
   410  			restoreRes, err := providerClient.RestoreRecycleItem(ctx,
   411  				&storagep.RestoreRecycleItemRequest{
   412  					Ref: homeRef,
   413  					Key: item.Key,
   414  				},
   415  			)
   416  			Expect(err).ToNot(HaveOccurred())
   417  			Expect(restoreRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   418  
   419  			statRes, err = providerClient.Stat(ctx, &storagep.StatRequest{Ref: subdirRef})
   420  			Expect(err).ToNot(HaveOccurred())
   421  			Expect(statRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   422  		})
   423  
   424  		It("restores resources to a different location", func() {
   425  			restoreRef := ref(provider, subdirRestoredPath)
   426  			subdirRef := ref(provider, subdirPath)
   427  			homeRef := ref(provider, homePath)
   428  
   429  			By("deleting an item")
   430  			res, err := providerClient.Delete(ctx, &storagep.DeleteRequest{Ref: subdirRef})
   431  			Expect(err).ToNot(HaveOccurred())
   432  			Expect(res.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   433  
   434  			By("listing the recycle items")
   435  			listRes, err := providerClient.ListRecycle(ctx, &storagep.ListRecycleRequest{Ref: homeRef})
   436  			Expect(err).ToNot(HaveOccurred())
   437  			Expect(listRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   438  
   439  			Expect(len(listRes.RecycleItems)).To(Equal(1))
   440  			item := listRes.RecycleItems[0]
   441  			Expect(item.Ref.Path).To(Equal(subdirPath))
   442  
   443  			By("restoring the item to a different location")
   444  			statRes, err := providerClient.Stat(ctx, &storagep.StatRequest{Ref: restoreRef})
   445  			Expect(err).ToNot(HaveOccurred())
   446  			Expect(statRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_NOT_FOUND))
   447  
   448  			restoreRes, err := providerClient.RestoreRecycleItem(ctx,
   449  				&storagep.RestoreRecycleItemRequest{
   450  					Ref:        homeRef,
   451  					Key:        item.Key,
   452  					RestoreRef: restoreRef,
   453  				},
   454  			)
   455  			Expect(err).ToNot(HaveOccurred())
   456  			Expect(restoreRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   457  
   458  			statRes, err = providerClient.Stat(ctx, &storagep.StatRequest{Ref: restoreRef})
   459  			Expect(err).ToNot(HaveOccurred())
   460  			Expect(statRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   461  		})
   462  
   463  		It("purges recycle items resources", func() {
   464  			subdirRef := ref(provider, subdirPath)
   465  			homeRef := ref(provider, homePath)
   466  
   467  			By("deleting an item")
   468  			res, err := providerClient.Delete(ctx, &storagep.DeleteRequest{Ref: subdirRef})
   469  			Expect(err).ToNot(HaveOccurred())
   470  			Expect(res.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   471  
   472  			By("listing recycle items")
   473  			listRes, err := providerClient.ListRecycle(ctx, &storagep.ListRecycleRequest{Ref: homeRef})
   474  			Expect(err).ToNot(HaveOccurred())
   475  			Expect(listRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   476  			Expect(len(listRes.RecycleItems)).To(Equal(1))
   477  
   478  			By("purging a recycle item")
   479  			ref := listRes.RecycleItems[0].Ref
   480  			ref.ResourceId = homeRef.ResourceId
   481  			purgeRes, err := providerClient.PurgeRecycle(ctx, &storagep.PurgeRecycleRequest{Ref: ref})
   482  			Expect(err).ToNot(HaveOccurred())
   483  			Expect(purgeRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   484  
   485  			listRes, err = providerClient.ListRecycle(ctx, &storagep.ListRecycleRequest{Ref: homeRef})
   486  			Expect(err).ToNot(HaveOccurred())
   487  			Expect(listRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   488  			Expect(len(listRes.RecycleItems)).To(Equal(0))
   489  		})
   490  	}
   491  
   492  	assertReferences := func(provider string) {
   493  		It("creates references", func() {
   494  			if provider == "ocis" {
   495  				// ocis can't create references like this
   496  				return
   497  			}
   498  
   499  			sharesRef := ref(provider, sharesPath)
   500  			listRes, err := providerClient.ListContainer(ctx, &storagep.ListContainerRequest{Ref: sharesRef})
   501  			Expect(err).ToNot(HaveOccurred())
   502  			Expect(listRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_NOT_FOUND))
   503  			Expect(len(listRes.Infos)).To(Equal(0))
   504  
   505  			res, err := providerClient.CreateReference(ctx, &storagep.CreateReferenceRequest{
   506  				Ref: &storagep.Reference{
   507  					Path: "/Shares/reference",
   508  				},
   509  				TargetUri: "scheme://target",
   510  			})
   511  			Expect(err).ToNot(HaveOccurred())
   512  			Expect(res.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   513  
   514  			listRes, err = providerClient.ListContainer(ctx, &storagep.ListContainerRequest{Ref: sharesRef})
   515  			Expect(err).ToNot(HaveOccurred())
   516  			Expect(listRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   517  			Expect(len(listRes.Infos)).To(Equal(1))
   518  		})
   519  	}
   520  
   521  	assertMetadata := func(provider string) {
   522  		It("sets and unsets metadata", func() {
   523  			subdirRef := ref(provider, subdirPath)
   524  			statRes, err := providerClient.Stat(ctx, &storagep.StatRequest{Ref: subdirRef})
   525  			Expect(err).ToNot(HaveOccurred())
   526  			Expect(statRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   527  			Expect(statRes.Info.ArbitraryMetadata.Metadata["foo"]).To(BeEmpty())
   528  
   529  			By("setting arbitrary metadata")
   530  			samRes, err := providerClient.SetArbitraryMetadata(ctx, &storagep.SetArbitraryMetadataRequest{
   531  				Ref:               subdirRef,
   532  				ArbitraryMetadata: &storagep.ArbitraryMetadata{Metadata: map[string]string{"foo": "bar"}},
   533  			})
   534  			Expect(err).ToNot(HaveOccurred())
   535  			Expect(samRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   536  
   537  			statRes, err = providerClient.Stat(ctx, &storagep.StatRequest{Ref: subdirRef})
   538  			Expect(err).ToNot(HaveOccurred())
   539  			Expect(statRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   540  			Expect(statRes.Info.ArbitraryMetadata.Metadata["foo"]).To(Equal("bar"))
   541  
   542  			By("unsetting arbitrary metadata")
   543  			uamRes, err := providerClient.UnsetArbitraryMetadata(ctx, &storagep.UnsetArbitraryMetadataRequest{
   544  				Ref:                   subdirRef,
   545  				ArbitraryMetadataKeys: []string{"foo"},
   546  			})
   547  			Expect(err).ToNot(HaveOccurred())
   548  			Expect(uamRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   549  
   550  			statRes, err = providerClient.Stat(ctx, &storagep.StatRequest{Ref: subdirRef})
   551  			Expect(err).ToNot(HaveOccurred())
   552  			Expect(statRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   553  			Expect(statRes.Info.ArbitraryMetadata.Metadata["foo"]).To(BeEmpty())
   554  		})
   555  	}
   556  
   557  	assertLocking := func(provider string) {
   558  		var (
   559  			subdirRef = ref(provider, subdirPath)
   560  			lock      = &storagep.Lock{
   561  				Type:   storagep.LockType_LOCK_TYPE_EXCL,
   562  				User:   user.Id,
   563  				LockId: uuid.New().String(),
   564  			}
   565  		)
   566  		It("locks, gets, refreshes and unlocks a lock", func() {
   567  			lockRes, err := providerClient.SetLock(ctx, &storagep.SetLockRequest{
   568  				Ref:  subdirRef,
   569  				Lock: lock,
   570  			})
   571  			Expect(err).ToNot(HaveOccurred())
   572  			Expect(lockRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   573  
   574  			getRes, err := providerClient.GetLock(ctx, &storagep.GetLockRequest{
   575  				Ref: subdirRef,
   576  			})
   577  			Expect(err).ToNot(HaveOccurred())
   578  			Expect(getRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   579  			Expect(getRes.Lock.Type).To(Equal(lock.Type))
   580  			Expect(getRes.Lock.User.Idp).To(Equal(lock.User.Idp))
   581  			Expect(getRes.Lock.User.OpaqueId).To(Equal(lock.User.OpaqueId))
   582  			Expect(getRes.Lock.User.Type).To(Equal(lock.User.Type))
   583  			Expect(getRes.Lock.LockId).To(Equal(lock.LockId))
   584  			Expect(getRes.Lock.AppName).To(Equal(lock.AppName))
   585  			Expect(getRes.Lock.Expiration).To(Equal(lock.Expiration))
   586  			Expect(getRes.Lock.Opaque).To(Equal(lock.Opaque))
   587  
   588  			refreshRes, err := providerClient.RefreshLock(ctx, &storagep.RefreshLockRequest{
   589  				Ref:  subdirRef,
   590  				Lock: lock,
   591  			})
   592  			Expect(err).ToNot(HaveOccurred())
   593  			Expect(refreshRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   594  
   595  			unlockRes, err := providerClient.Unlock(ctx, &storagep.UnlockRequest{
   596  				Ref:  subdirRef,
   597  				Lock: lock,
   598  			})
   599  			Expect(err).ToNot(HaveOccurred())
   600  			Expect(unlockRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   601  		})
   602  
   603  		Context("with a locked file", func() {
   604  			JustBeforeEach(func() {
   605  				lockRes, err := providerClient.SetLock(ctx, &storagep.SetLockRequest{
   606  					Ref:  subdirRef,
   607  					Lock: lock,
   608  				})
   609  				Expect(err).ToNot(HaveOccurred())
   610  				Expect(lockRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   611  			})
   612  
   613  			It("removes the lock when unlocking", func() {
   614  				delRes, err := providerClient.Delete(ctx, &storagep.DeleteRequest{
   615  					Ref: subdirRef,
   616  				})
   617  				Expect(err).ToNot(HaveOccurred())
   618  				Expect(delRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_LOCKED))
   619  
   620  				unlockRes, err := providerClient.Unlock(ctx, &storagep.UnlockRequest{
   621  					Ref:  subdirRef,
   622  					Lock: lock,
   623  				})
   624  				Expect(err).ToNot(HaveOccurred())
   625  				Expect(unlockRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   626  
   627  				delRes, err = providerClient.Delete(ctx, &storagep.DeleteRequest{
   628  					Ref: subdirRef,
   629  				})
   630  				Expect(err).ToNot(HaveOccurred())
   631  				Expect(delRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   632  
   633  			})
   634  
   635  			// FIXME these tests are all wrong as they use the reference of a directory, but try to lock and upload a file
   636  			Context("with the owner holding the lock", func() {
   637  				It("can not initiate an upload that would overwrite a folder", func() {
   638  					ulRes, err := providerClient.InitiateFileUpload(ctx, &storagep.InitiateFileUploadRequest{
   639  						Ref:    subdirRef,
   640  						LockId: lock.LockId,
   641  					})
   642  					Expect(err).ToNot(HaveOccurred())
   643  					Expect(ulRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_FAILED_PRECONDITION))
   644  				})
   645  
   646  				It("can delete the file", func() {
   647  					delRes, err := providerClient.Delete(ctx, &storagep.DeleteRequest{
   648  						Ref:    subdirRef,
   649  						LockId: lock.LockId,
   650  					})
   651  					Expect(err).ToNot(HaveOccurred())
   652  					Expect(delRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   653  
   654  				})
   655  			})
   656  			Context("with the owner not holding the lock", func() {
   657  				It("can only delete after unlocking the file", func() {
   658  					delRes, err := providerClient.Delete(ctx, &storagep.DeleteRequest{
   659  						Ref: subdirRef,
   660  					})
   661  					Expect(err).ToNot(HaveOccurred())
   662  					Expect(delRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_LOCKED))
   663  				})
   664  			})
   665  
   666  		})
   667  	}
   668  
   669  	suite := func(provider string, deps []RevadConfig) {
   670  		Describe(provider, func() {
   671  			BeforeEach(func() {
   672  				dependencies = deps
   673  				variables = map[string]string{
   674  					"enable_home": "true",
   675  				}
   676  			})
   677  
   678  			assertCreateHome(provider)
   679  
   680  			Context("with a home and a subdirectory", func() {
   681  				JustBeforeEach(func() {
   682  					res, err := spacesClient.CreateStorageSpace(ctx, &storagep.CreateStorageSpaceRequest{
   683  						Owner: user,
   684  						Type:  "personal",
   685  						Name:  user.Id.OpaqueId,
   686  					})
   687  					Expect(err).ToNot(HaveOccurred())
   688  					Expect(res.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   689  
   690  					subdirRes, err := providerClient.CreateContainer(ctx, &storagep.CreateContainerRequest{Ref: ref(provider, subdirPath)})
   691  					Expect(err).ToNot(HaveOccurred())
   692  					Expect(subdirRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
   693  				})
   694  
   695  				assertCreateContainer(provider)
   696  				assertListContainer(provider)
   697  				assertGetPath(provider)
   698  				assertDelete(provider)
   699  				assertMove(provider)
   700  				assertGrants(provider)
   701  				assertUploads(provider)
   702  				assertDownloads(provider)
   703  				assertRecycle(provider)
   704  				assertReferences(provider)
   705  				assertMetadata(provider)
   706  				if provider == "ocis" {
   707  					assertLocking(provider)
   708  				} else {
   709  					PIt("Locking implementation still pending for provider " + provider)
   710  				}
   711  			})
   712  
   713  			Context("with an existing file /versioned_file", func() {
   714  				JustBeforeEach(func() {
   715  					fs, err := createFS(provider, revads)
   716  					Expect(err).ToNot(HaveOccurred())
   717  
   718  					content1 := []byte("1")
   719  					content2 := []byte("22")
   720  
   721  					vRef := ref(provider, versionedFilePath)
   722  					if provider == "nextcloud" {
   723  						vRef.ResourceId = &storagep.ResourceId{StorageId: user.Id.OpaqueId}
   724  					}
   725  
   726  					_, err = fs.CreateStorageSpace(ctx, &storagep.CreateStorageSpaceRequest{
   727  						Owner: user,
   728  						Type:  "personal",
   729  					})
   730  					Expect(err).ToNot(HaveOccurred())
   731  					err = helpers.Upload(ctx, fs, vRef, content1)
   732  					Expect(err).ToNot(HaveOccurred())
   733  					err = helpers.Upload(ctx, fs, vRef, content2)
   734  					Expect(err).ToNot(HaveOccurred())
   735  				})
   736  
   737  				assertFileVersions(provider)
   738  			})
   739  		})
   740  
   741  	}
   742  
   743  	suite("nextcloud", []RevadConfig{
   744  		{
   745  			Name:   "storage",
   746  			Config: "storageprovider-nextcloud.toml",
   747  		},
   748  	})
   749  
   750  	suite("ocis", []RevadConfig{
   751  		{
   752  			Name: "storage", Config: "storageprovider-ocis.toml",
   753  		},
   754  		{
   755  			Name: "permissions", Config: "permissions-ocis-ci.toml",
   756  		},
   757  	})
   758  
   759  })