github.com/cs3org/reva/v2@v2.27.7/pkg/ocm/share/repository/nextcloud/nextcloud_test.go (about)

     1  // Copyright 2018-2023 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 nextcloud_test
    20  
    21  import (
    22  	"context"
    23  	"os"
    24  
    25  	userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
    26  	ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
    27  	provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
    28  	types "github.com/cs3org/go-cs3apis/cs3/types/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/ocm/share/repository/nextcloud"
    32  	jwt "github.com/cs3org/reva/v2/pkg/token/manager/jwt"
    33  	. "github.com/onsi/ginkgo"
    34  	. "github.com/onsi/gomega"
    35  	"google.golang.org/genproto/protobuf/field_mask"
    36  	"google.golang.org/grpc/metadata"
    37  	"google.golang.org/protobuf/testing/protocmp"
    38  )
    39  
    40  func setUpNextcloudServer() (*nextcloud.Manager, *[]string, func()) {
    41  	var conf *nextcloud.ShareManagerConfig
    42  
    43  	ncHost := os.Getenv("NEXTCLOUD")
    44  	if len(ncHost) == 0 {
    45  		conf = &nextcloud.ShareManagerConfig{
    46  			EndPoint: "http://mock.com/apps/sciencemesh/",
    47  			MockHTTP: true,
    48  		}
    49  		nc, _ := nextcloud.NewShareManager(conf)
    50  		called := make([]string, 0)
    51  		h := nextcloud.GetNextcloudServerMock(&called)
    52  		mock, teardown := nextcloud.TestingHTTPClient(h)
    53  		nc.SetHTTPClient(mock)
    54  		return nc, &called, teardown
    55  	}
    56  	conf = &nextcloud.ShareManagerConfig{
    57  		EndPoint: ncHost + "/apps/sciencemesh/",
    58  		MockHTTP: false,
    59  	}
    60  	nc, _ := nextcloud.NewShareManager(conf)
    61  	return nc, nil, func() {}
    62  }
    63  
    64  func checkCalled(called *[]string, expected string) {
    65  	if called == nil {
    66  		return
    67  	}
    68  	Expect(len(*called)).To(Equal(1))
    69  	Expect((*called)[0]).To(Equal(expected))
    70  }
    71  
    72  var _ = Describe("Nextcloud", func() {
    73  	var (
    74  		ctx     context.Context
    75  		options map[string]interface{}
    76  		tmpRoot string
    77  		user    = &userpb.User{
    78  			Id: &userpb.UserId{
    79  				Idp:      "0.0.0.0:19000",
    80  				OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
    81  				Type:     userpb.UserType_USER_TYPE_PRIMARY,
    82  			},
    83  			Username: "tester",
    84  		}
    85  	)
    86  
    87  	BeforeEach(func() {
    88  		var err error
    89  
    90  		options = map[string]interface{}{
    91  			"endpoint":  "http://mock.com/",
    92  			"mock_http": true,
    93  		}
    94  
    95  		ctx = context.Background()
    96  
    97  		// Add auth token
    98  		tokenManager, err := jwt.New(map[string]interface{}{"secret": "changemeplease"})
    99  		Expect(err).ToNot(HaveOccurred())
   100  		scope, err := scope.AddOwnerScope(nil)
   101  		Expect(err).ToNot(HaveOccurred())
   102  		t, err := tokenManager.MintToken(ctx, user, scope)
   103  		Expect(err).ToNot(HaveOccurred())
   104  		ctx = ctxpkg.ContextSetToken(ctx, t)
   105  		ctx = metadata.AppendToOutgoingContext(ctx, ctxpkg.TokenHeader, t)
   106  		ctx = ctxpkg.ContextSetUser(ctx, user)
   107  	})
   108  
   109  	AfterEach(func() {
   110  		if tmpRoot != "" {
   111  			os.RemoveAll(tmpRoot)
   112  		}
   113  	})
   114  
   115  	Describe("New", func() {
   116  		It("returns a new instance", func() {
   117  			_, err := nextcloud.New(options)
   118  			Expect(err).ToNot(HaveOccurred())
   119  		})
   120  	})
   121  
   122  	// Share(ctx context.Context, md *provider.ResourceInfo, g *ocm.ShareGrant) (*ocm.Share, error)
   123  	// FIXME: this triggers a call to the Send function from pkg/ocm/share/sender/sender.go
   124  	// which makes an outgoing network call. For the Nextcloud share manager itself we set the
   125  	// `mock_http` config variable, but not sure how to support the network call made by that
   126  	// other package.
   127  	// Describe("Share", func() {
   128  	// 	It("calls the addSentShare endpoint", func() {
   129  	// 		am, called, teardown := setUpNextcloudServer()
   130  	// 		defer teardown()
   131  	// 		var md = &provider.ResourceId{
   132  	// 			StorageId: "",
   133  	// 			OpaqueId:  "fileid-/some/path",
   134  	// 		}
   135  	// 		var g = &ocm.ShareGrant{
   136  	// 			Grantee: &provider.Grantee{
   137  	// 				Id: &provider.Grantee_UserId{
   138  	// 					UserId: &userpb.UserId{
   139  	// 						Idp:      "0.0.0.0:19000",
   140  	// 						OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
   141  	// 						Type:     userpb.UserType_USER_TYPE_PRIMARY,
   142  	// 					},
   143  	// 				},
   144  	// 			},
   145  	// 			Permissions: &ocm.SharePermissions{
   146  	// 				Permissions: &provider.ResourcePermissions{
   147  	// 					AddGrant:             false,
   148  	// 					CreateContainer:      false,
   149  	// 					Delete:               false,
   150  	// 					GetPath:              true,
   151  	// 					GetQuota:             false,
   152  	// 					InitiateFileDownload: false,
   153  	// 					InitiateFileUpload:   false,
   154  	// 					ListGrants:           false,
   155  	// 					ListContainer:        false,
   156  	// 					ListFileVersions:     false,
   157  	// 					ListRecycle:          false,
   158  	// 					Move:                 false,
   159  	// 					RemoveGrant:          false,
   160  	// 					PurgeRecycle:         false,
   161  	// 					RestoreFileVersion:   false,
   162  	// 					RestoreRecycleItem:   false,
   163  	// 					Stat:                 false,
   164  	// 					UpdateGrant:          false,
   165  	// 					DenyGrant:            false,
   166  	// 				},
   167  	// 			},
   168  	// 		}
   169  	// 		var name = "Some Name"
   170  	// 		var pi = &ocmprovider.ProviderInfo{}
   171  	// 		var pm = "some-permissions-string?"
   172  	// 		var owner = &userpb.UserId{
   173  	// 			Idp:      "0.0.0.0:19000",
   174  	// 			OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
   175  	// 			Type:     userpb.UserType_USER_TYPE_PRIMARY,
   176  	// 		}
   177  	// 		var token = "some-token"
   178  	// 		var st = ocm.Share_SHARE_TYPE_REGULAR
   179  	// 		share, err := am.Share(ctx, md, g, name, pi, pm, owner, token, st)
   180  
   181  	// 		Expect(err).ToNot(HaveOccurred())
   182  	// 		Expect(*share).To(Equal(ocm.Share{
   183  	// 			Id:         &ocm.ShareId{},
   184  	// 			ResourceId: &provider.ResourceId{},
   185  	// 			Permissions: &ocm.SharePermissions{
   186  	// 				Permissions: &provider.ResourcePermissions{
   187  	// 					AddGrant:             true,
   188  	// 					CreateContainer:      true,
   189  	// 					Delete:               true,
   190  	// 					GetPath:              true,
   191  	// 					GetQuota:             true,
   192  	// 					InitiateFileDownload: true,
   193  	// 					InitiateFileUpload:   true,
   194  	// 					ListGrants:           true,
   195  	// 					ListContainer:        true,
   196  	// 					ListFileVersions:     true,
   197  	// 					ListRecycle:          true,
   198  	// 					Move:                 true,
   199  	// 					RemoveGrant:          true,
   200  	// 					PurgeRecycle:         true,
   201  	// 					RestoreFileVersion:   true,
   202  	// 					RestoreRecycleItem:   true,
   203  	// 					Stat:                 true,
   204  	// 					UpdateGrant:          true,
   205  	// 					DenyGrant:            true,
   206  	// 				},
   207  	// 			},
   208  	// 			Grantee: &provider.Grantee{
   209  	// 				Id: &provider.Grantee_UserId{
   210  	// 					UserId: &userpb.UserId{
   211  	// 						Idp:      "0.0.0.0:19000",
   212  	// 						OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
   213  	// 						Type:     userpb.UserType_USER_TYPE_PRIMARY,
   214  	// 					},
   215  	// 				},
   216  	// 			},
   217  	// 			Owner: &userpb.UserId{
   218  	// 				Idp:      "0.0.0.0:19000",
   219  	// 				OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
   220  	// 				Type:     userpb.UserType_USER_TYPE_PRIMARY,
   221  	// 			},
   222  	// 			Creator: &userpb.UserId{
   223  	// 				Idp:      "0.0.0.0:19000",
   224  	// 				OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
   225  	// 				Type:     userpb.UserType_USER_TYPE_PRIMARY,
   226  	// 			},
   227  	// 			Ctime: &types.Timestamp{
   228  	// 				Seconds:              1234567890,
   229  	// 				Nanos:                0,
   230  	// 			},
   231  	// 			Mtime: &types.Timestamp{
   232  	// 				Seconds:              1234567890,
   233  	// 				Nanos:                0,
   234  	// 			},
   235  	// 		}))
   236  	// 		checkCalled(called, `POST /apps/sciencemesh/~tester/api/ocm/addReceivedShare {"md":{"opaque_id":"fileid-/some/path"},"g":{"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"permissions":{"permissions":{"get_path":true}}},"provider_domain":"cern.ch","resource_type":"file","provider_id":2,"owner_opaque_id":"einstein","owner_display_name":"Albert Einstein","protocol":{"name":"webdav","options":{"sharedSecret":"secret","permissions":"webdav-property"}}}`)
   237  	// 	})
   238  	// })
   239  
   240  	// GetShare(ctx context.Context, ref *ocm.ShareReference) (*ocm.Share, error)
   241  	Describe("GetShare", func() {
   242  		It("calls the GetShare endpoint", func() {
   243  			am, called, teardown := setUpNextcloudServer()
   244  			defer teardown()
   245  
   246  			share, err := am.GetShare(ctx, user, &ocm.ShareReference{
   247  				Spec: &ocm.ShareReference_Id{
   248  					Id: &ocm.ShareId{
   249  						OpaqueId: "some-share-id",
   250  					},
   251  				},
   252  			})
   253  			Expect(err).ToNot(HaveOccurred())
   254  			Expect(share).To(BeComparableTo(&ocm.Share{
   255  				Id: &ocm.ShareId{},
   256  				Grantee: &provider.Grantee{
   257  					Id: &provider.Grantee_UserId{
   258  						UserId: &userpb.UserId{
   259  							Idp:      "0.0.0.0:19000",
   260  							OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
   261  							Type:     userpb.UserType_USER_TYPE_PRIMARY,
   262  						},
   263  					},
   264  				},
   265  				Owner: &userpb.UserId{
   266  					Idp:      "0.0.0.0:19000",
   267  					OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
   268  					Type:     userpb.UserType_USER_TYPE_PRIMARY,
   269  				},
   270  				Creator: &userpb.UserId{
   271  					Idp:      "0.0.0.0:19000",
   272  					OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
   273  					Type:     userpb.UserType_USER_TYPE_PRIMARY,
   274  				},
   275  				Ctime: &types.Timestamp{
   276  					Seconds: 1234567890,
   277  					Nanos:   0,
   278  				},
   279  				Mtime: &types.Timestamp{
   280  					Seconds: 1234567890,
   281  					Nanos:   0,
   282  				},
   283  			}, protocmp.Transform()))
   284  			checkCalled(called, `POST /apps/sciencemesh/~tester/api/ocm/GetShare {"Spec":{"Id":{"opaque_id":"some-share-id"}}}`)
   285  		})
   286  	})
   287  
   288  	// Unshare(ctx context.Context, ref *ocm.ShareReference) error
   289  	Describe("Unshare", func() {
   290  		It("calls the Unshare endpoint", func() {
   291  			am, called, teardown := setUpNextcloudServer()
   292  			defer teardown()
   293  
   294  			err := am.DeleteShare(ctx, user, &ocm.ShareReference{
   295  				Spec: &ocm.ShareReference_Id{
   296  					Id: &ocm.ShareId{
   297  						OpaqueId: "some-share-id",
   298  					},
   299  				},
   300  			})
   301  			Expect(err).ToNot(HaveOccurred())
   302  			checkCalled(called, `POST /apps/sciencemesh/~tester/api/ocm/Unshare {"Spec":{"Id":{"opaque_id":"some-share-id"}}}`)
   303  		})
   304  	})
   305  
   306  	// UpdateShare(ctx context.Context, ref *ocm.ShareReference, p *ocm.SharePermissions) (*ocm.Share, error)
   307  	// Describe("UpdateShare", func() {
   308  	// 	It("calls the UpdateShare endpoint", func() {
   309  	// 		am, called, teardown := setUpNextcloudServer()
   310  	// 		defer teardown()
   311  
   312  	// 		share, err := am.UpdateShare(ctx, user, &ocm.ShareReference{
   313  	// 			Spec: &ocm.ShareReference_Id{
   314  	// 				Id: &ocm.ShareId{
   315  	// 					OpaqueId: "some-share-id",
   316  	// 				},
   317  	// 			},
   318  	// 		})
   319  	// 		Expect(err).ToNot(HaveOccurred())
   320  	// 		Expect(*share).To(Equal(ocm.Share{
   321  	// 			Id: &ocm.ShareId{},
   322  	// 			Grantee: &provider.Grantee{
   323  	// 				Id: &provider.Grantee_UserId{
   324  	// 					UserId: &userpb.UserId{
   325  	// 						Idp:      "0.0.0.0:19000",
   326  	// 						OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
   327  	// 						Type:     userpb.UserType_USER_TYPE_PRIMARY,
   328  	// 					},
   329  	// 				},
   330  	// 			},
   331  	// 			Owner: &userpb.UserId{
   332  	// 				Idp:      "0.0.0.0:19000",
   333  	// 				OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
   334  	// 				Type:     userpb.UserType_USER_TYPE_PRIMARY,
   335  	// 			},
   336  	// 			Creator: &userpb.UserId{
   337  	// 				Idp:      "0.0.0.0:19000",
   338  	// 				OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
   339  	// 				Type:     userpb.UserType_USER_TYPE_PRIMARY,
   340  	// 			},
   341  	// 			Ctime: &types.Timestamp{
   342  	// 				Seconds:              1234567890,
   343  	// 				Nanos:                0,
   344  	// 			},
   345  	// 			Mtime: &types.Timestamp{
   346  	// 				Seconds:              1234567890,
   347  	// 				Nanos:                0,
   348  	// 			},
   349  	// 		}))
   350  	// 		checkCalled(called, `POST /apps/sciencemesh/~tester/api/ocm/UpdateShare {"ref":{"Spec":{"Id":{"opaque_id":"some-share-id"}}},"p":{"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true,"deny_grant":true}}}`)
   351  	// 	})
   352  	// })
   353  
   354  	// ListShares(ctx context.Context, filters []*ocm.ListOCMSharesRequest_Filter) ([]*ocm.Share, error)
   355  	Describe("ListShares", func() {
   356  		It("calls the ListShares endpoint", func() {
   357  			am, called, teardown := setUpNextcloudServer()
   358  			defer teardown()
   359  
   360  			shares, err := am.ListShares(ctx, user, []*ocm.ListOCMSharesRequest_Filter{
   361  				{
   362  					Type: ocm.ListOCMSharesRequest_Filter_TYPE_CREATOR,
   363  					Term: &ocm.ListOCMSharesRequest_Filter_Creator{
   364  						Creator: &userpb.UserId{
   365  							Idp:      "0.0.0.0:19000",
   366  							OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
   367  							Type:     userpb.UserType_USER_TYPE_PRIMARY,
   368  						},
   369  					},
   370  				},
   371  			})
   372  			Expect(err).ToNot(HaveOccurred())
   373  			Expect(len(shares)).To(Equal(1))
   374  			Expect(shares[0]).To(BeComparableTo(&ocm.Share{
   375  				Id: &ocm.ShareId{},
   376  				Grantee: &provider.Grantee{
   377  					Id: &provider.Grantee_UserId{
   378  						UserId: &userpb.UserId{
   379  							Idp:      "0.0.0.0:19000",
   380  							OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
   381  							Type:     userpb.UserType_USER_TYPE_PRIMARY,
   382  						},
   383  					},
   384  				},
   385  				Owner: &userpb.UserId{
   386  					Idp:      "0.0.0.0:19000",
   387  					OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
   388  					Type:     userpb.UserType_USER_TYPE_PRIMARY,
   389  				},
   390  				Creator: &userpb.UserId{
   391  					Idp:      "0.0.0.0:19000",
   392  					OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
   393  					Type:     userpb.UserType_USER_TYPE_PRIMARY,
   394  				},
   395  				Ctime: &types.Timestamp{
   396  					Seconds: 1234567890,
   397  					Nanos:   0,
   398  				},
   399  				Mtime: &types.Timestamp{
   400  					Seconds: 1234567890,
   401  					Nanos:   0,
   402  				},
   403  			}, protocmp.Transform()))
   404  			checkCalled(called, `POST /apps/sciencemesh/~tester/api/ocm/ListShares [{"type":4,"Term":{"Creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}}]`)
   405  		})
   406  	})
   407  
   408  	// ListReceivedShares(ctx context.Context, filters []*ocm.ListOCMSharesRequest_Filter) ([]*ocm.ReceivedShare, error)
   409  	Describe("ListReceivedShares", func() {
   410  		It("calls the ListReceivedShares endpoint", func() {
   411  			am, called, teardown := setUpNextcloudServer()
   412  			defer teardown()
   413  
   414  			receivedShares, err := am.ListReceivedShares(ctx, user)
   415  			Expect(err).ToNot(HaveOccurred())
   416  			Expect(len(receivedShares)).To(Equal(1))
   417  			Expect(receivedShares[0]).To(BeComparableTo(&ocm.ReceivedShare{
   418  				Id:            &ocm.ShareId{},
   419  				RemoteShareId: "",
   420  				Grantee: &provider.Grantee{
   421  					Id: &provider.Grantee_UserId{
   422  						UserId: &userpb.UserId{
   423  							Idp:      "0.0.0.0:19000",
   424  							OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
   425  							Type:     userpb.UserType_USER_TYPE_PRIMARY,
   426  						},
   427  					},
   428  				},
   429  				Owner: &userpb.UserId{
   430  					Idp:      "0.0.0.0:19000",
   431  					OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
   432  					Type:     userpb.UserType_USER_TYPE_PRIMARY,
   433  				},
   434  				Creator: &userpb.UserId{
   435  					Idp:      "0.0.0.0:19000",
   436  					OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
   437  					Type:     userpb.UserType_USER_TYPE_PRIMARY,
   438  				},
   439  				Ctime: &types.Timestamp{
   440  					Seconds: 1234567890,
   441  					Nanos:   0,
   442  				},
   443  				Mtime: &types.Timestamp{
   444  					Seconds: 1234567890,
   445  					Nanos:   0,
   446  				},
   447  				State: ocm.ShareState_SHARE_STATE_ACCEPTED,
   448  			}, protocmp.Transform()))
   449  			checkCalled(called, `POST /apps/sciencemesh/~tester/api/ocm/ListReceivedShares `)
   450  		})
   451  	})
   452  
   453  	// GetReceivedShare(ctx context.Context, ref *ocm.ShareReference) (*ocm.ReceivedShare, error)
   454  	Describe("GetReceivedShare", func() {
   455  		It("calls the GetReceivedShare endpoint", func() {
   456  			am, called, teardown := setUpNextcloudServer()
   457  			defer teardown()
   458  
   459  			receivedShare, err := am.GetReceivedShare(ctx, user, &ocm.ShareReference{
   460  				Spec: &ocm.ShareReference_Id{
   461  					Id: &ocm.ShareId{
   462  						OpaqueId: "some-share-id",
   463  					},
   464  				},
   465  			})
   466  			Expect(err).ToNot(HaveOccurred())
   467  			Expect(receivedShare).To(BeComparableTo(ocm.ReceivedShare{
   468  				Id:            &ocm.ShareId{},
   469  				RemoteShareId: "",
   470  				Grantee: &provider.Grantee{
   471  					Id: &provider.Grantee_UserId{
   472  						UserId: &userpb.UserId{
   473  							Idp:      "0.0.0.0:19000",
   474  							OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
   475  							Type:     userpb.UserType_USER_TYPE_PRIMARY,
   476  						},
   477  					},
   478  				},
   479  				Owner: &userpb.UserId{
   480  					Idp:      "0.0.0.0:19000",
   481  					OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
   482  					Type:     userpb.UserType_USER_TYPE_PRIMARY,
   483  				},
   484  				Creator: &userpb.UserId{
   485  					Idp:      "0.0.0.0:19000",
   486  					OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
   487  					Type:     userpb.UserType_USER_TYPE_PRIMARY,
   488  				},
   489  				Ctime: &types.Timestamp{
   490  					Seconds: 1234567890,
   491  					Nanos:   0,
   492  				},
   493  				Mtime: &types.Timestamp{
   494  					Seconds: 1234567890,
   495  					Nanos:   0,
   496  				},
   497  				State: ocm.ShareState_SHARE_STATE_ACCEPTED,
   498  			}, protocmp.Transform()))
   499  			checkCalled(called, `POST /apps/sciencemesh/~tester/api/ocm/GetReceivedShare {"Spec":{"Id":{"opaque_id":"some-share-id"}}}`)
   500  		})
   501  	})
   502  
   503  	// UpdateReceivedShare(ctx context.Context, receivedShare *ocm.ReceivedShare, fieldMask *field_mask.FieldMask) (*ocm.ReceivedShare, error)
   504  	Describe("UpdateReceivedShare", func() {
   505  		It("calls the UpdateReceivedShare endpoint", func() {
   506  			am, called, teardown := setUpNextcloudServer()
   507  			defer teardown()
   508  
   509  			receivedShare, err := am.UpdateReceivedShare(ctx, user,
   510  				&ocm.ReceivedShare{
   511  					Id:            &ocm.ShareId{},
   512  					RemoteShareId: "",
   513  					Grantee: &provider.Grantee{
   514  						Id: &provider.Grantee_UserId{
   515  							UserId: &userpb.UserId{
   516  								Idp:      "0.0.0.0:19000",
   517  								OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
   518  								Type:     userpb.UserType_USER_TYPE_PRIMARY,
   519  							},
   520  						},
   521  					},
   522  					Owner: &userpb.UserId{
   523  						Idp:      "0.0.0.0:19000",
   524  						OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
   525  						Type:     userpb.UserType_USER_TYPE_PRIMARY,
   526  					},
   527  					Creator: &userpb.UserId{
   528  						Idp:      "0.0.0.0:19000",
   529  						OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
   530  						Type:     userpb.UserType_USER_TYPE_PRIMARY,
   531  					},
   532  					Ctime: &types.Timestamp{
   533  						Seconds: 1234567890,
   534  						Nanos:   0,
   535  					},
   536  					Mtime: &types.Timestamp{
   537  						Seconds: 1234567890,
   538  						Nanos:   0,
   539  					},
   540  					State: ocm.ShareState_SHARE_STATE_ACCEPTED,
   541  				},
   542  				&field_mask.FieldMask{
   543  					Paths: []string{"state"},
   544  				})
   545  			Expect(err).ToNot(HaveOccurred())
   546  			Expect(receivedShare).To(BeComparableTo(ocm.ReceivedShare{
   547  				Id:            &ocm.ShareId{},
   548  				RemoteShareId: "",
   549  				Grantee: &provider.Grantee{
   550  					Id: &provider.Grantee_UserId{
   551  						UserId: &userpb.UserId{
   552  							Idp:      "0.0.0.0:19000",
   553  							OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
   554  							Type:     userpb.UserType_USER_TYPE_PRIMARY,
   555  						},
   556  					},
   557  				},
   558  				Owner: &userpb.UserId{
   559  					Idp:      "0.0.0.0:19000",
   560  					OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
   561  					Type:     userpb.UserType_USER_TYPE_PRIMARY,
   562  				},
   563  				Creator: &userpb.UserId{
   564  					Idp:      "0.0.0.0:19000",
   565  					OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
   566  					Type:     userpb.UserType_USER_TYPE_PRIMARY,
   567  				},
   568  				Ctime: &types.Timestamp{
   569  					Seconds: 1234567890,
   570  					Nanos:   0,
   571  				},
   572  				Mtime: &types.Timestamp{
   573  					Seconds: 1234567890,
   574  					Nanos:   0,
   575  				},
   576  				State: ocm.ShareState_SHARE_STATE_ACCEPTED,
   577  			}, protocmp.Transform()))
   578  			checkCalled(called, `POST /apps/sciencemesh/~tester/api/ocm/UpdateReceivedShare {"received_share":{"id":{},"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890},"state":2},"field_mask":{"paths":["state"]}}`)
   579  		})
   580  	})
   581  
   582  })