diff --git a/services/collaboration/pkg/connector/connector_suite_test.go b/services/collaboration/pkg/connector/connector_suite_test.go
new file mode 100644
index 000000000..0781160de
--- /dev/null
+++ b/services/collaboration/pkg/connector/connector_suite_test.go
@@ -0,0 +1,13 @@
+package connector_test
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+)
+
+func TestGraph(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Connector Suite")
+}
diff --git a/services/collaboration/pkg/connector/contentconnector_test.go b/services/collaboration/pkg/connector/contentconnector_test.go
new file mode 100644
index 000000000..a39a29d58
--- /dev/null
+++ b/services/collaboration/pkg/connector/contentconnector_test.go
@@ -0,0 +1,418 @@
+package connector_test
+
+import (
+ "context"
+ "errors"
+ "net/http"
+ "net/http/httptest"
+ "strings"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "github.com/stretchr/testify/mock"
+
+ appproviderv1beta1 "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1"
+ gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
+ userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
+ providerv1beta1 "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
+ "github.com/cs3org/reva/v2/pkg/rgrpc/status"
+ "github.com/owncloud/ocis/v2/services/collaboration/pkg/config"
+ "github.com/owncloud/ocis/v2/services/collaboration/pkg/connector"
+ "github.com/owncloud/ocis/v2/services/collaboration/pkg/middleware"
+
+ cs3mocks "github.com/cs3org/reva/v2/tests/cs3mocks/mocks"
+)
+
+var _ = Describe("ContentConnector", func() {
+ var (
+ cc *connector.ContentConnector
+ gatewayClient *cs3mocks.GatewayAPIClient
+ cfg *config.Config
+ wopiCtx middleware.WopiContext
+
+ srv *httptest.Server
+ srvReqHeader http.Header
+ randomContent string
+ )
+
+ BeforeEach(func() {
+ // contentConnector only uses "cfg.CS3Api.DataGateway.Insecure", which is irrelevant for the tests
+ cfg = &config.Config{}
+ gatewayClient = &cs3mocks.GatewayAPIClient{}
+ cc = connector.NewContentConnector(gatewayClient, cfg)
+
+ wopiCtx = middleware.WopiContext{
+ AccessToken: "abcdef123456",
+ FileReference: providerv1beta1.Reference{
+ ResourceId: &providerv1beta1.ResourceId{
+ StorageId: "abc",
+ OpaqueId: "12345",
+ SpaceId: "zzz",
+ },
+ Path: ".",
+ },
+ User: &userv1beta1.User{}, // Not used for now
+ ViewMode: appproviderv1beta1.ViewMode_VIEW_MODE_READ_WRITE,
+ EditAppUrl: "http://test.ex.prv/edit",
+ ViewAppUrl: "http://test.ex.prv/view",
+ }
+
+ randomContent = "This is the content of the test.txt file"
+ srv = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ srvReqHeader = req.Header // save the request header to check later
+ switch req.URL.Path {
+ case "/download/failed.png":
+ w.WriteHeader(404)
+ case "/download/test.txt":
+ w.Write([]byte(randomContent))
+ case "/upload/failed.png":
+ w.WriteHeader(404)
+ case "/upload/test.txt":
+ w.WriteHeader(200)
+ }
+ }))
+ })
+
+ AfterEach(func() {
+ srv.Close()
+ })
+
+ Describe("GetFile", func() {
+ It("No valid context", func() {
+ sb := &strings.Builder{}
+ ctx := context.Background()
+ err := cc.GetFile(ctx, sb)
+ Expect(err).To(HaveOccurred())
+ })
+
+ It("Initiate download failed", func() {
+ sb := &strings.Builder{}
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ targetErr := errors.New("Something went wrong")
+ gatewayClient.On("InitiateFileDownload", mock.Anything, mock.Anything).Times(1).Return(&gateway.InitiateFileDownloadResponse{
+ Status: status.NewInternal(ctx, "Something failed"),
+ }, targetErr)
+
+ err := cc.GetFile(ctx, sb)
+ Expect(err).To(Equal(targetErr))
+ })
+
+ It("Initiate download status not ok", func() {
+ sb := &strings.Builder{}
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("InitiateFileDownload", mock.Anything, mock.Anything).Times(1).Return(&gateway.InitiateFileDownloadResponse{
+ Status: status.NewInternal(ctx, "Something failed"),
+ }, nil)
+
+ err := cc.GetFile(ctx, sb)
+ Expect(err).To(HaveOccurred())
+ conErr := err.(*connector.ConnectorError)
+ Expect(conErr.HttpCodeOut).To(Equal(500))
+ })
+
+ It("Missing download endpoint", func() {
+ sb := &strings.Builder{}
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("InitiateFileDownload", mock.Anything, mock.Anything).Times(1).Return(&gateway.InitiateFileDownloadResponse{
+ Status: status.NewOK(ctx),
+ }, nil)
+
+ err := cc.GetFile(ctx, sb)
+ Expect(err).To(HaveOccurred())
+ conErr := err.(*connector.ConnectorError)
+ Expect(conErr.HttpCodeOut).To(Equal(500))
+ })
+
+ It("Download request failed", func() {
+ sb := &strings.Builder{}
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("InitiateFileDownload", mock.Anything, mock.Anything).Times(1).Return(&gateway.InitiateFileDownloadResponse{
+ Status: status.NewOK(ctx),
+ Protocols: []*gateway.FileDownloadProtocol{
+ &gateway.FileDownloadProtocol{
+ Protocol: "simple",
+ DownloadEndpoint: srv.URL + "/download/failed.png",
+ Token: "MyDownloadToken",
+ },
+ },
+ }, nil)
+
+ err := cc.GetFile(ctx, sb)
+ Expect(srvReqHeader.Get("X-Access-Token")).To(Equal(wopiCtx.AccessToken))
+ Expect(srvReqHeader.Get("X-Reva-Transfer")).To(Equal("MyDownloadToken"))
+ Expect(err).To(HaveOccurred())
+ conErr := err.(*connector.ConnectorError)
+ Expect(conErr.HttpCodeOut).To(Equal(500))
+ })
+
+ It("Download request success", func() {
+ sb := &strings.Builder{}
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("InitiateFileDownload", mock.Anything, mock.Anything).Times(1).Return(&gateway.InitiateFileDownloadResponse{
+ Status: status.NewOK(ctx),
+ Protocols: []*gateway.FileDownloadProtocol{
+ &gateway.FileDownloadProtocol{
+ Protocol: "simple",
+ DownloadEndpoint: srv.URL + "/download/test.txt",
+ Token: "MyDownloadToken",
+ },
+ },
+ }, nil)
+
+ err := cc.GetFile(ctx, sb)
+ Expect(srvReqHeader.Get("X-Access-Token")).To(Equal(wopiCtx.AccessToken))
+ Expect(srvReqHeader.Get("X-Reva-Transfer")).To(Equal("MyDownloadToken"))
+ Expect(err).To(Succeed())
+ Expect(sb.String()).To(Equal(randomContent))
+ })
+ })
+
+ Describe("PutFile", func() {
+ It("No valid context", func() {
+ reader := strings.NewReader("Content to upload is here!")
+ ctx := context.Background()
+ newLockId, err := cc.PutFile(ctx, reader, reader.Size(), "notARandomLockId")
+ Expect(err).To(HaveOccurred())
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Stat call failed", func() {
+ reader := strings.NewReader("Content to upload is here!")
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ targetErr := errors.New("Something went wrong")
+ gatewayClient.On("Stat", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.StatResponse{
+ Status: status.NewInternal(ctx, "Something failed"),
+ }, targetErr)
+
+ newLockId, err := cc.PutFile(ctx, reader, reader.Size(), "notARandomLockId")
+ Expect(err).To(Equal(targetErr))
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Stat call status not ok", func() {
+ reader := strings.NewReader("Content to upload is here!")
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("Stat", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.StatResponse{
+ Status: status.NewInternal(ctx, "Something failed"),
+ }, nil)
+
+ newLockId, err := cc.PutFile(ctx, reader, reader.Size(), "notARandomLockId")
+ Expect(err).To(HaveOccurred())
+ conErr := err.(*connector.ConnectorError)
+ Expect(conErr.HttpCodeOut).To(Equal(500))
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Mismatched lockId", func() {
+ reader := strings.NewReader("Content to upload is here!")
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("Stat", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.StatResponse{
+ Status: status.NewOK(ctx),
+ Info: &providerv1beta1.ResourceInfo{
+ Lock: &providerv1beta1.Lock{
+ LockId: "goodAndValidLock",
+ Type: providerv1beta1.LockType_LOCK_TYPE_WRITE,
+ },
+ },
+ }, nil)
+
+ newLockId, err := cc.PutFile(ctx, reader, reader.Size(), "notARandomLockId")
+ Expect(err).To(HaveOccurred())
+ conErr := err.(*connector.ConnectorError)
+ Expect(conErr.HttpCodeOut).To(Equal(409))
+ Expect(newLockId).To(Equal("goodAndValidLock"))
+ })
+
+ It("Upload without lockId but on a non empty file", func() {
+ reader := strings.NewReader("Content to upload is here!")
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("Stat", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.StatResponse{
+ Status: status.NewOK(ctx),
+ Info: &providerv1beta1.ResourceInfo{
+ Lock: nil,
+ Size: uint64(123456789),
+ },
+ }, nil)
+
+ newLockId, err := cc.PutFile(ctx, reader, reader.Size(), "")
+ Expect(err).To(HaveOccurred())
+ conErr := err.(*connector.ConnectorError)
+ Expect(conErr.HttpCodeOut).To(Equal(409))
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Initiate upload fails", func() {
+ reader := strings.NewReader("Content to upload is here!")
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("Stat", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.StatResponse{
+ Status: status.NewOK(ctx),
+ Info: &providerv1beta1.ResourceInfo{
+ Lock: &providerv1beta1.Lock{
+ LockId: "goodAndValidLock",
+ Type: providerv1beta1.LockType_LOCK_TYPE_WRITE,
+ },
+ Size: uint64(123456789),
+ },
+ }, nil)
+
+ targetErr := errors.New("Something went wrong")
+ gatewayClient.On("InitiateFileUpload", mock.Anything, mock.Anything).Times(1).Return(&gateway.InitiateFileUploadResponse{
+ Status: status.NewInternal(ctx, "Something failed"),
+ }, targetErr)
+
+ newLockId, err := cc.PutFile(ctx, reader, reader.Size(), "goodAndValidLock")
+ Expect(err).To(HaveOccurred())
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Initiate upload status not ok", func() {
+ reader := strings.NewReader("Content to upload is here!")
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("Stat", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.StatResponse{
+ Status: status.NewOK(ctx),
+ Info: &providerv1beta1.ResourceInfo{
+ Lock: &providerv1beta1.Lock{
+ LockId: "goodAndValidLock",
+ Type: providerv1beta1.LockType_LOCK_TYPE_WRITE,
+ },
+ Size: uint64(123456789),
+ },
+ }, nil)
+
+ gatewayClient.On("InitiateFileUpload", mock.Anything, mock.Anything).Times(1).Return(&gateway.InitiateFileUploadResponse{
+ Status: status.NewInternal(ctx, "Something failed"),
+ }, nil)
+
+ newLockId, err := cc.PutFile(ctx, reader, reader.Size(), "goodAndValidLock")
+ Expect(err).To(HaveOccurred())
+ conErr := err.(*connector.ConnectorError)
+ Expect(conErr.HttpCodeOut).To(Equal(500))
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Empty upload successful", func() {
+ reader := strings.NewReader("")
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("Stat", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.StatResponse{
+ Status: status.NewOK(ctx),
+ Info: &providerv1beta1.ResourceInfo{
+ Lock: &providerv1beta1.Lock{
+ LockId: "goodAndValidLock",
+ Type: providerv1beta1.LockType_LOCK_TYPE_WRITE,
+ },
+ Size: uint64(123456789),
+ },
+ }, nil)
+
+ gatewayClient.On("InitiateFileUpload", mock.Anything, mock.Anything).Times(1).Return(&gateway.InitiateFileUploadResponse{
+ Status: status.NewOK(ctx),
+ }, nil)
+
+ newLockId, err := cc.PutFile(ctx, reader, reader.Size(), "goodAndValidLock")
+ Expect(err).To(Succeed())
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Missing upload endpoint", func() {
+ reader := strings.NewReader("Content to upload is here!")
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("Stat", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.StatResponse{
+ Status: status.NewOK(ctx),
+ Info: &providerv1beta1.ResourceInfo{
+ Lock: &providerv1beta1.Lock{
+ LockId: "goodAndValidLock",
+ Type: providerv1beta1.LockType_LOCK_TYPE_WRITE,
+ },
+ Size: uint64(123456789),
+ },
+ }, nil)
+
+ gatewayClient.On("InitiateFileUpload", mock.Anything, mock.Anything).Times(1).Return(&gateway.InitiateFileUploadResponse{
+ Status: status.NewOK(ctx),
+ }, nil)
+
+ newLockId, err := cc.PutFile(ctx, reader, reader.Size(), "goodAndValidLock")
+ Expect(err).To(HaveOccurred())
+ conErr := err.(*connector.ConnectorError)
+ Expect(conErr.HttpCodeOut).To(Equal(500))
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("upload request failed", func() {
+ reader := strings.NewReader("Content to upload is here!")
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("Stat", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.StatResponse{
+ Status: status.NewOK(ctx),
+ Info: &providerv1beta1.ResourceInfo{
+ Lock: &providerv1beta1.Lock{
+ LockId: "goodAndValidLock",
+ Type: providerv1beta1.LockType_LOCK_TYPE_WRITE,
+ },
+ Size: uint64(123456789),
+ },
+ }, nil)
+
+ gatewayClient.On("InitiateFileUpload", mock.Anything, mock.Anything).Times(1).Return(&gateway.InitiateFileUploadResponse{
+ Status: status.NewOK(ctx),
+ Protocols: []*gateway.FileUploadProtocol{
+ &gateway.FileUploadProtocol{
+ Protocol: "simple",
+ UploadEndpoint: srv.URL + "/upload/failed.png",
+ },
+ },
+ }, nil)
+
+ newLockId, err := cc.PutFile(ctx, reader, reader.Size(), "goodAndValidLock")
+ Expect(srvReqHeader.Get("X-Access-Token")).To(Equal(wopiCtx.AccessToken))
+ Expect(err).To(HaveOccurred())
+ conErr := err.(*connector.ConnectorError)
+ Expect(conErr.HttpCodeOut).To(Equal(500))
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("upload request success", func() {
+ reader := strings.NewReader("Content to upload is here!")
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("Stat", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.StatResponse{
+ Status: status.NewOK(ctx),
+ Info: &providerv1beta1.ResourceInfo{
+ Lock: &providerv1beta1.Lock{
+ LockId: "goodAndValidLock",
+ Type: providerv1beta1.LockType_LOCK_TYPE_WRITE,
+ },
+ Size: uint64(123456789),
+ },
+ }, nil)
+
+ gatewayClient.On("InitiateFileUpload", mock.Anything, mock.Anything).Times(1).Return(&gateway.InitiateFileUploadResponse{
+ Status: status.NewOK(ctx),
+ Protocols: []*gateway.FileUploadProtocol{
+ &gateway.FileUploadProtocol{
+ Protocol: "simple",
+ UploadEndpoint: srv.URL + "/upload/test.txt",
+ },
+ },
+ }, nil)
+
+ newLockId, err := cc.PutFile(ctx, reader, reader.Size(), "goodAndValidLock")
+ Expect(srvReqHeader.Get("X-Access-Token")).To(Equal(wopiCtx.AccessToken))
+ Expect(err).To(Succeed())
+ Expect(newLockId).To(Equal(""))
+ })
+ })
+})
diff --git a/services/collaboration/pkg/connector/fileconnector.go b/services/collaboration/pkg/connector/fileconnector.go
index 2366c4a43..6945f3b91 100644
--- a/services/collaboration/pkg/connector/fileconnector.go
+++ b/services/collaboration/pkg/connector/fileconnector.go
@@ -4,6 +4,7 @@ import (
"context"
"encoding/hex"
"path"
+ "strconv"
"time"
appproviderv1beta1 "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1"
@@ -69,6 +70,7 @@ func (f *FileConnector) GetLock(ctx context.Context) (string, error) {
Str("StatusCode", resp.GetStatus().GetCode().String()).
Str("StatusMsg", resp.GetStatus().GetMessage()).
Msg("GetLock failed with unexpected status")
+ // TODO: Should we be more strict? There could be more causes for the failure
return "", NewConnectorError(404, resp.GetStatus().GetCode().String()+" "+resp.GetStatus().GetMessage())
}
@@ -469,7 +471,7 @@ func (f *FileConnector) CheckFileInfo(ctx context.Context) (FileInfo, error) {
// OwnerId must use only alphanumeric chars (https://learn.microsoft.com/en-us/microsoft-365/cloud-storage-partner-program/rest/files/checkfileinfo/checkfileinfo-response#requirements-for-user-identity-properties)
OwnerId: hex.EncodeToString([]byte(statRes.GetInfo().GetOwner().GetOpaqueId() + "@" + statRes.GetInfo().GetOwner().GetIdp())),
Size: int64(statRes.GetInfo().GetSize()),
- Version: statRes.GetInfo().GetMtime().String(),
+ Version: strconv.FormatUint(statRes.GetInfo().GetMtime().GetSeconds(), 10) + "." + strconv.FormatUint(uint64(statRes.GetInfo().GetMtime().GetNanos()), 10),
BaseFileName: path.Base(statRes.GetInfo().GetPath()),
BreadcrumbDocName: path.Base(statRes.GetInfo().GetPath()),
// to get the folder we actually need to do a GetPath() request
diff --git a/services/collaboration/pkg/connector/fileconnector_test.go b/services/collaboration/pkg/connector/fileconnector_test.go
new file mode 100644
index 000000000..4ed54e2da
--- /dev/null
+++ b/services/collaboration/pkg/connector/fileconnector_test.go
@@ -0,0 +1,875 @@
+package connector_test
+
+import (
+ "context"
+ "encoding/hex"
+ "errors"
+
+ appproviderv1beta1 "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1"
+ userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
+ providerv1beta1 "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
+ typesv1beta1 "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
+ "github.com/cs3org/reva/v2/pkg/rgrpc/status"
+ cs3mocks "github.com/cs3org/reva/v2/tests/cs3mocks/mocks"
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "github.com/owncloud/ocis/v2/services/collaboration/pkg/config"
+ "github.com/owncloud/ocis/v2/services/collaboration/pkg/connector"
+ "github.com/owncloud/ocis/v2/services/collaboration/pkg/middleware"
+ "github.com/stretchr/testify/mock"
+)
+
+var _ = Describe("FileConnector", func() {
+ var (
+ fc *connector.FileConnector
+ gatewayClient *cs3mocks.GatewayAPIClient
+ cfg *config.Config
+ wopiCtx middleware.WopiContext
+ )
+
+ BeforeEach(func() {
+ cfg = &config.Config{
+ App: config.App{
+ LockName: "testName_for_unittests", // Only the LockName is used
+ },
+ }
+ gatewayClient = &cs3mocks.GatewayAPIClient{}
+ fc = connector.NewFileConnector(gatewayClient, cfg)
+
+ wopiCtx = middleware.WopiContext{
+ AccessToken: "abcdef123456",
+ FileReference: providerv1beta1.Reference{
+ ResourceId: &providerv1beta1.ResourceId{
+ StorageId: "abc",
+ OpaqueId: "12345",
+ SpaceId: "zzz",
+ },
+ Path: ".",
+ },
+ User: &userv1beta1.User{
+ Id: &userv1beta1.UserId{
+ Idp: "inmemory",
+ OpaqueId: "opaqueId",
+ Type: userv1beta1.UserType_USER_TYPE_PRIMARY,
+ },
+ Username: "Pet Shaft",
+ // Opaque is here for reference, not used by default but might be needed for some tests
+ //Opaque: &typesv1beta1.Opaque{
+ // Map: map[string]*typesv1beta1.OpaqueEntry{
+ // "public-share-role": &typesv1beta1.OpaqueEntry{
+ // Decoder: "plain",
+ // Value: []byte("viewer"),
+ // },
+ // },
+ //},
+ },
+ ViewMode: appproviderv1beta1.ViewMode_VIEW_MODE_READ_WRITE,
+ EditAppUrl: "http://test.ex.prv/edit",
+ ViewAppUrl: "http://test.ex.prv/view",
+ }
+ })
+
+ Describe("GetLock", func() {
+ It("No valid context", func() {
+ ctx := context.Background()
+ newLockId, err := fc.GetLock(ctx)
+ Expect(err).To(HaveOccurred())
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Get lock failed", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ targetErr := errors.New("Something went wrong")
+ gatewayClient.On("GetLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.GetLockResponse{
+ Status: status.NewInternal(ctx, "Something failed"),
+ }, targetErr)
+
+ newLockId, err := fc.GetLock(ctx)
+ Expect(err).To(Equal(targetErr))
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Get lock failed status not ok", func() {
+ // assume failure happens because the target file doesn't exists
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("GetLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.GetLockResponse{
+ Status: status.NewNotFound(ctx, "File is missing"),
+ }, nil)
+
+ newLockId, err := fc.GetLock(ctx)
+ Expect(err).To(HaveOccurred())
+ conErr := err.(*connector.ConnectorError)
+ Expect(conErr.HttpCodeOut).To(Equal(404))
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Get lock success", func() {
+ // assume failure happens because the target file doesn't exists
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("GetLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.GetLockResponse{
+ Status: status.NewOK(ctx),
+ Lock: &providerv1beta1.Lock{
+ LockId: "zzz999",
+ Type: providerv1beta1.LockType_LOCK_TYPE_WRITE,
+ },
+ }, nil)
+
+ newLockId, err := fc.GetLock(ctx)
+ Expect(err).To(Succeed())
+ Expect(newLockId).To(Equal("zzz999"))
+ })
+ })
+
+ Describe("Lock", func() {
+ Describe("Lock", func() {
+ It("No valid context", func() {
+ ctx := context.Background()
+ newLockId, err := fc.Lock(ctx, "newLock", "")
+ Expect(err).To(HaveOccurred())
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Empty lockId", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ newLockId, err := fc.Lock(ctx, "", "")
+ Expect(err).To(HaveOccurred())
+ conErr := err.(*connector.ConnectorError)
+ Expect(conErr.HttpCodeOut).To(Equal(400))
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Set lock failed", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ targetErr := errors.New("Something went wrong")
+ gatewayClient.On("SetLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.SetLockResponse{
+ Status: status.NewInternal(ctx, "Something failed"),
+ }, targetErr)
+
+ newLockId, err := fc.Lock(ctx, "abcdef123", "")
+ Expect(err).To(HaveOccurred())
+ Expect(err).To(Equal(targetErr))
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Set lock success", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("SetLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.SetLockResponse{
+ Status: status.NewOK(ctx),
+ }, nil)
+
+ newLockId, err := fc.Lock(ctx, "abcdef123", "")
+ Expect(err).To(Succeed())
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Set lock mismatches error getting lock", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("SetLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.SetLockResponse{
+ Status: status.NewFailedPrecondition(ctx, nil, "lock mismatch"),
+ }, nil)
+
+ targetErr := errors.New("Something went wrong getting the lock")
+ gatewayClient.On("GetLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.GetLockResponse{
+ Status: status.NewInternal(ctx, "lock mismatch"),
+ }, targetErr)
+
+ newLockId, err := fc.Lock(ctx, "abcdef123", "")
+ Expect(err).To(HaveOccurred())
+ Expect(err).To(Equal(targetErr))
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Set lock mismatches", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("SetLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.SetLockResponse{
+ Status: status.NewFailedPrecondition(ctx, nil, "lock mismatch"),
+ }, nil)
+
+ gatewayClient.On("GetLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.GetLockResponse{
+ Status: status.NewOK(ctx),
+ Lock: &providerv1beta1.Lock{
+ LockId: "zzz999",
+ Type: providerv1beta1.LockType_LOCK_TYPE_WRITE,
+ },
+ }, nil)
+
+ newLockId, err := fc.Lock(ctx, "abcdef123", "")
+ Expect(err).To(HaveOccurred())
+ conErr := err.(*connector.ConnectorError)
+ Expect(conErr.HttpCodeOut).To(Equal(409))
+ Expect(newLockId).To(Equal("zzz999"))
+ })
+
+ It("Set lock mismatches but get lock matches", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("SetLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.SetLockResponse{
+ Status: status.NewFailedPrecondition(ctx, nil, "lock mismatch"),
+ }, nil)
+
+ gatewayClient.On("GetLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.GetLockResponse{
+ Status: status.NewOK(ctx),
+ Lock: &providerv1beta1.Lock{
+ LockId: "abcdef123",
+ Type: providerv1beta1.LockType_LOCK_TYPE_WRITE,
+ },
+ }, nil)
+
+ newLockId, err := fc.Lock(ctx, "abcdef123", "")
+ Expect(err).To(Succeed())
+ Expect(newLockId).To(Equal("abcdef123"))
+ })
+
+ It("Set lock mismatches but get lock doesn't return lockId", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("SetLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.SetLockResponse{
+ Status: status.NewFailedPrecondition(ctx, nil, "lock mismatch"),
+ }, nil)
+
+ gatewayClient.On("GetLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.GetLockResponse{
+ Status: status.NewOK(ctx),
+ }, nil)
+
+ newLockId, err := fc.Lock(ctx, "abcdef123", "")
+ Expect(err).To(HaveOccurred())
+ conErr := err.(*connector.ConnectorError)
+ Expect(conErr.HttpCodeOut).To(Equal(500))
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("File not found", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("SetLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.SetLockResponse{
+ Status: status.NewNotFound(ctx, "file not found"),
+ }, nil)
+
+ newLockId, err := fc.Lock(ctx, "abcdef123", "")
+ Expect(err).To(HaveOccurred())
+ conErr := err.(*connector.ConnectorError)
+ Expect(conErr.HttpCodeOut).To(Equal(404))
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Default error handling (insufficient storage)", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("SetLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.SetLockResponse{
+ Status: status.NewInsufficientStorage(ctx, nil, "file too big"),
+ }, nil)
+
+ newLockId, err := fc.Lock(ctx, "abcdef123", "")
+ Expect(err).To(HaveOccurred())
+ conErr := err.(*connector.ConnectorError)
+ Expect(conErr.HttpCodeOut).To(Equal(500))
+ Expect(newLockId).To(Equal(""))
+ })
+ })
+
+ Describe("Unlock and relock", func() {
+ It("No valid context", func() {
+ ctx := context.Background()
+ newLockId, err := fc.Lock(ctx, "newLock", "oldLock")
+ Expect(err).To(HaveOccurred())
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Empty lockId", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ newLockId, err := fc.Lock(ctx, "", "oldLock")
+ Expect(err).To(HaveOccurred())
+ conErr := err.(*connector.ConnectorError)
+ Expect(conErr.HttpCodeOut).To(Equal(400))
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Refresh lock failed", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ targetErr := errors.New("Something went wrong")
+ gatewayClient.On("RefreshLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.RefreshLockResponse{
+ Status: status.NewInternal(ctx, "Something failed"),
+ }, targetErr)
+
+ newLockId, err := fc.Lock(ctx, "abcdef123", "oldLock")
+ Expect(err).To(HaveOccurred())
+ Expect(err).To(Equal(targetErr))
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Refresh lock success", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("RefreshLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.RefreshLockResponse{
+ Status: status.NewOK(ctx),
+ }, nil)
+
+ newLockId, err := fc.Lock(ctx, "abcdef123", "oldLock")
+ Expect(err).To(Succeed())
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Refresh lock mismatches error getting lock", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("RefreshLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.RefreshLockResponse{
+ Status: status.NewConflict(ctx, nil, "lock mismatch"),
+ }, nil)
+
+ targetErr := errors.New("Something went wrong getting the lock")
+ gatewayClient.On("GetLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.GetLockResponse{
+ Status: status.NewInternal(ctx, "lock mismatch"),
+ }, targetErr)
+
+ newLockId, err := fc.Lock(ctx, "abcdef123", "112233")
+ Expect(err).To(HaveOccurred())
+ Expect(err).To(Equal(targetErr))
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Refresh lock mismatches", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("RefreshLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.RefreshLockResponse{
+ Status: status.NewConflict(ctx, nil, "lock mismatch"),
+ }, nil)
+
+ gatewayClient.On("GetLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.GetLockResponse{
+ Status: status.NewOK(ctx),
+ Lock: &providerv1beta1.Lock{
+ LockId: "zzz999",
+ Type: providerv1beta1.LockType_LOCK_TYPE_WRITE,
+ },
+ }, nil)
+
+ newLockId, err := fc.Lock(ctx, "abcdef123", "112233")
+ Expect(err).To(HaveOccurred())
+ conErr := err.(*connector.ConnectorError)
+ Expect(conErr.HttpCodeOut).To(Equal(409))
+ Expect(newLockId).To(Equal("zzz999"))
+ })
+
+ It("Refresh lock mismatches but get lock matches", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("RefreshLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.RefreshLockResponse{
+ Status: status.NewConflict(ctx, nil, "lock mismatch"),
+ }, nil)
+
+ gatewayClient.On("GetLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.GetLockResponse{
+ Status: status.NewOK(ctx),
+ Lock: &providerv1beta1.Lock{
+ LockId: "abcdef123",
+ Type: providerv1beta1.LockType_LOCK_TYPE_WRITE,
+ },
+ }, nil)
+
+ newLockId, err := fc.Lock(ctx, "abcdef123", "112233")
+ Expect(err).To(Succeed())
+ Expect(newLockId).To(Equal("abcdef123"))
+ })
+
+ It("Refresh lock mismatches but get lock doesn't return lockId", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("RefreshLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.RefreshLockResponse{
+ Status: status.NewConflict(ctx, nil, "lock mismatch"),
+ }, nil)
+
+ gatewayClient.On("GetLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.GetLockResponse{
+ Status: status.NewOK(ctx),
+ }, nil)
+
+ newLockId, err := fc.Lock(ctx, "abcdef123", "112233")
+ Expect(err).To(HaveOccurred())
+ conErr := err.(*connector.ConnectorError)
+ Expect(conErr.HttpCodeOut).To(Equal(500))
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("File not found", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("RefreshLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.RefreshLockResponse{
+ Status: status.NewNotFound(ctx, "file not found"),
+ }, nil)
+
+ newLockId, err := fc.Lock(ctx, "abcdef123", "112233")
+ Expect(err).To(HaveOccurred())
+ conErr := err.(*connector.ConnectorError)
+ Expect(conErr.HttpCodeOut).To(Equal(404))
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Default error handling (insufficient storage)", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("RefreshLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.RefreshLockResponse{
+ Status: status.NewInsufficientStorage(ctx, nil, "file too big"),
+ }, nil)
+
+ newLockId, err := fc.Lock(ctx, "abcdef123", "112233")
+ Expect(err).To(HaveOccurred())
+ conErr := err.(*connector.ConnectorError)
+ Expect(conErr.HttpCodeOut).To(Equal(500))
+ Expect(newLockId).To(Equal(""))
+ })
+ })
+ })
+
+ Describe("RefreshLock", func() {
+ It("No valid context", func() {
+ ctx := context.Background()
+ newLockId, err := fc.RefreshLock(ctx, "newLock")
+ Expect(err).To(HaveOccurred())
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Empty lockId", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ newLockId, err := fc.RefreshLock(ctx, "")
+ Expect(err).To(HaveOccurred())
+ conErr := err.(*connector.ConnectorError)
+ Expect(conErr.HttpCodeOut).To(Equal(400))
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Refresh lock fails", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ targetErr := errors.New("Something went wrong")
+ gatewayClient.On("RefreshLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.RefreshLockResponse{
+ Status: status.NewConflict(ctx, nil, "lock mismatch"),
+ }, targetErr)
+
+ newLockId, err := fc.RefreshLock(ctx, "abcdef123")
+ Expect(err).To(HaveOccurred())
+ Expect(err).To(Equal(targetErr))
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Refresh lock success", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("RefreshLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.RefreshLockResponse{
+ Status: status.NewOK(ctx),
+ }, nil)
+
+ newLockId, err := fc.RefreshLock(ctx, "abcdef123")
+ Expect(err).To(Succeed())
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Refresh lock file not found", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("RefreshLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.RefreshLockResponse{
+ Status: status.NewNotFound(ctx, "file not found"),
+ }, nil)
+
+ newLockId, err := fc.RefreshLock(ctx, "abcdef123")
+ Expect(err).To(HaveOccurred())
+ conErr := err.(*connector.ConnectorError)
+ Expect(conErr.HttpCodeOut).To(Equal(404))
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Refresh lock mismatch and get lock fails", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("RefreshLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.RefreshLockResponse{
+ Status: status.NewConflict(ctx, nil, "lock mismatch"),
+ }, nil)
+
+ targetErr := errors.New("Something went wrong")
+ gatewayClient.On("GetLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.GetLockResponse{
+ Status: status.NewConflict(ctx, nil, "lock mismatch"),
+ }, targetErr)
+
+ newLockId, err := fc.RefreshLock(ctx, "abcdef123")
+ Expect(err).To(HaveOccurred())
+ Expect(err).To(Equal(targetErr))
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Refresh lock mismatch and get lock status not ok", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("RefreshLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.RefreshLockResponse{
+ Status: status.NewConflict(ctx, nil, "lock mismatch"),
+ }, nil)
+
+ gatewayClient.On("GetLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.GetLockResponse{
+ Status: status.NewInternal(ctx, "lock mismatch"),
+ }, nil)
+
+ newLockId, err := fc.RefreshLock(ctx, "abcdef123")
+ Expect(err).To(HaveOccurred())
+ conErr := err.(*connector.ConnectorError)
+ Expect(conErr.HttpCodeOut).To(Equal(500))
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Refresh lock mismatch and no lock", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("RefreshLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.RefreshLockResponse{
+ Status: status.NewConflict(ctx, nil, "lock mismatch"),
+ }, nil)
+
+ gatewayClient.On("GetLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.GetLockResponse{
+ Status: status.NewOK(ctx),
+ }, nil)
+
+ newLockId, err := fc.RefreshLock(ctx, "abcdef123")
+ Expect(err).To(HaveOccurred())
+ conErr := err.(*connector.ConnectorError)
+ Expect(conErr.HttpCodeOut).To(Equal(409))
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Refresh lock mismatch", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("RefreshLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.RefreshLockResponse{
+ Status: status.NewConflict(ctx, nil, "lock mismatch"),
+ }, nil)
+
+ gatewayClient.On("GetLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.GetLockResponse{
+ Status: status.NewOK(ctx),
+ Lock: &providerv1beta1.Lock{
+ LockId: "zzz999",
+ Type: providerv1beta1.LockType_LOCK_TYPE_WRITE,
+ },
+ }, nil)
+
+ newLockId, err := fc.RefreshLock(ctx, "abcdef123")
+ Expect(err).To(HaveOccurred())
+ conErr := err.(*connector.ConnectorError)
+ Expect(conErr.HttpCodeOut).To(Equal(409))
+ Expect(newLockId).To(Equal("zzz999"))
+ })
+
+ It("Default error handling (insufficient storage)", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("RefreshLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.RefreshLockResponse{
+ Status: status.NewInsufficientStorage(ctx, nil, "file too big"),
+ }, nil)
+
+ newLockId, err := fc.RefreshLock(ctx, "abcdef123")
+ Expect(err).To(HaveOccurred())
+ conErr := err.(*connector.ConnectorError)
+ Expect(conErr.HttpCodeOut).To(Equal(500))
+ Expect(newLockId).To(Equal(""))
+ })
+ })
+
+ Describe("Unlock", func() {
+ It("No valid context", func() {
+ ctx := context.Background()
+ newLockId, err := fc.UnLock(ctx, "newLock")
+ Expect(err).To(HaveOccurred())
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Empty lockId", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ newLockId, err := fc.UnLock(ctx, "")
+ Expect(err).To(HaveOccurred())
+ conErr := err.(*connector.ConnectorError)
+ Expect(conErr.HttpCodeOut).To(Equal(400))
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Unlock fails", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ targetErr := errors.New("Something went wrong")
+ gatewayClient.On("Unlock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.UnlockResponse{
+ Status: status.NewInternal(ctx, "something failed"),
+ }, targetErr)
+
+ newLockId, err := fc.UnLock(ctx, "abcdef123")
+ Expect(err).To(HaveOccurred())
+ Expect(err).To(Equal(targetErr))
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Unlock success", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("Unlock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.UnlockResponse{
+ Status: status.NewOK(ctx),
+ }, nil)
+
+ newLockId, err := fc.UnLock(ctx, "abcdef123")
+ Expect(err).To(Succeed())
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Unlock file isn't locked", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("Unlock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.UnlockResponse{
+ Status: status.NewConflict(ctx, nil, "lock mismatch"),
+ }, nil)
+
+ newLockId, err := fc.UnLock(ctx, "abcdef123")
+ Expect(err).To(HaveOccurred())
+ conErr := err.(*connector.ConnectorError)
+ Expect(conErr.HttpCodeOut).To(Equal(409))
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Unlock mismatch get lock fails", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("Unlock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.UnlockResponse{
+ Status: status.NewLocked(ctx, "lock mismatch"),
+ }, nil)
+
+ targetErr := errors.New("Something went wrong")
+ gatewayClient.On("GetLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.GetLockResponse{
+ Status: status.NewInternal(ctx, "something failed"),
+ }, targetErr)
+
+ newLockId, err := fc.UnLock(ctx, "abcdef123")
+ Expect(err).To(HaveOccurred())
+ Expect(err).To(Equal(targetErr))
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Unlock mismatch get lock status not ok", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("Unlock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.UnlockResponse{
+ Status: status.NewLocked(ctx, "lock mismatch"),
+ }, nil)
+
+ gatewayClient.On("GetLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.GetLockResponse{
+ Status: status.NewInternal(ctx, "something failed"),
+ }, nil)
+
+ newLockId, err := fc.UnLock(ctx, "abcdef123")
+ Expect(err).To(HaveOccurred())
+ conErr := err.(*connector.ConnectorError)
+ Expect(conErr.HttpCodeOut).To(Equal(500))
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Unlock mismatch get lock doesn't return lock", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("Unlock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.UnlockResponse{
+ Status: status.NewLocked(ctx, "lock mismatch"),
+ }, nil)
+
+ gatewayClient.On("GetLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.GetLockResponse{
+ Status: status.NewOK(ctx),
+ }, nil)
+
+ newLockId, err := fc.UnLock(ctx, "abcdef123")
+ Expect(err).To(HaveOccurred())
+ conErr := err.(*connector.ConnectorError)
+ Expect(conErr.HttpCodeOut).To(Equal(409))
+ Expect(newLockId).To(Equal(""))
+ })
+
+ It("Unlock mismatch", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("Unlock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.UnlockResponse{
+ Status: status.NewLocked(ctx, "lock mismatch"),
+ }, nil)
+
+ gatewayClient.On("GetLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.GetLockResponse{
+ Status: status.NewOK(ctx),
+ Lock: &providerv1beta1.Lock{
+ LockId: "zzz999",
+ Type: providerv1beta1.LockType_LOCK_TYPE_WRITE,
+ },
+ }, nil)
+
+ newLockId, err := fc.UnLock(ctx, "abcdef123")
+ Expect(err).To(HaveOccurred())
+ conErr := err.(*connector.ConnectorError)
+ Expect(conErr.HttpCodeOut).To(Equal(409))
+ Expect(newLockId).To(Equal("zzz999"))
+ })
+
+ It("Default error handling (insufficient storage)", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("Unlock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.UnlockResponse{
+ Status: status.NewInsufficientStorage(ctx, nil, "file too big"),
+ }, nil)
+
+ newLockId, err := fc.UnLock(ctx, "abcdef123")
+ Expect(err).To(HaveOccurred())
+ conErr := err.(*connector.ConnectorError)
+ Expect(conErr.HttpCodeOut).To(Equal(500))
+ Expect(newLockId).To(Equal(""))
+ })
+ })
+
+ Describe("CheckFileInfo", func() {
+ It("No valid context", func() {
+ ctx := context.Background()
+ newFileInfo, err := fc.CheckFileInfo(ctx)
+ Expect(err).To(HaveOccurred())
+ Expect(newFileInfo).To(Equal(connector.FileInfo{}))
+ })
+
+ It("Stat fails", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ targetErr := errors.New("Something went wrong")
+ gatewayClient.On("Stat", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.StatResponse{
+ Status: status.NewInternal(ctx, "something failed"),
+ }, targetErr)
+
+ newFileInfo, err := fc.CheckFileInfo(ctx)
+ Expect(err).To(HaveOccurred())
+ Expect(err).To(Equal(targetErr))
+ Expect(newFileInfo).To(Equal(connector.FileInfo{}))
+ })
+
+ It("Stat fails status not ok", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("Stat", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.StatResponse{
+ Status: status.NewInternal(ctx, "something failed"),
+ }, nil)
+
+ newFileInfo, err := fc.CheckFileInfo(ctx)
+ Expect(err).To(HaveOccurred())
+ conErr := err.(*connector.ConnectorError)
+ Expect(conErr.HttpCodeOut).To(Equal(500))
+ Expect(newFileInfo).To(Equal(connector.FileInfo{}))
+ })
+
+ It("Stat success", func() {
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("Stat", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.StatResponse{
+ Status: status.NewOK(ctx),
+ Info: &providerv1beta1.ResourceInfo{
+ Owner: &userv1beta1.UserId{
+ Idp: "customIdp",
+ OpaqueId: "aabbcc",
+ Type: userv1beta1.UserType_USER_TYPE_PRIMARY,
+ },
+ Size: uint64(998877),
+ Mtime: &typesv1beta1.Timestamp{
+ Seconds: uint64(16273849),
+ },
+ Path: "/path/to/test.txt",
+ // Other properties aren't used for now.
+ },
+ }, nil)
+
+ expectedFileInfo := connector.FileInfo{
+ OwnerId: "61616262636340637573746f6d496470", // hex of aabbcc@customIdp
+ Size: int64(998877),
+ Version: "16273849.0",
+ BaseFileName: "test.txt",
+ BreadcrumbDocName: "test.txt",
+ UserCanNotWriteRelative: true,
+ HostViewUrl: "http://test.ex.prv/view",
+ HostEditUrl: "http://test.ex.prv/edit",
+ EnableOwnerTermination: false,
+ SupportsExtendedLockLength: true,
+ SupportsGetLock: true,
+ SupportsLocks: true,
+ SupportsUpdate: true,
+ UserCanWrite: true,
+ UserId: "6f7061717565496440696e6d656d6f7279", // hex of opaqueId@inmemory
+ UserFriendlyName: "Pet Shaft",
+ }
+
+ newFileInfo, err := fc.CheckFileInfo(ctx)
+ Expect(err).To(Succeed())
+ Expect(newFileInfo).To(Equal(expectedFileInfo))
+ })
+
+ It("Stat success guests", func() {
+ // add user's opaque to include public-share-role
+ wopiCtx.User.Opaque = &typesv1beta1.Opaque{
+ Map: map[string]*typesv1beta1.OpaqueEntry{
+ "public-share-role": &typesv1beta1.OpaqueEntry{
+ Decoder: "plain",
+ Value: []byte("viewer"),
+ },
+ },
+ }
+ // change view mode to view only
+ wopiCtx.ViewMode = appproviderv1beta1.ViewMode_VIEW_MODE_VIEW_ONLY
+
+ ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
+
+ gatewayClient.On("Stat", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.StatResponse{
+ Status: status.NewOK(ctx),
+ Info: &providerv1beta1.ResourceInfo{
+ Owner: &userv1beta1.UserId{
+ Idp: "customIdp",
+ OpaqueId: "aabbcc",
+ Type: userv1beta1.UserType_USER_TYPE_PRIMARY,
+ },
+ Size: uint64(998877),
+ Mtime: &typesv1beta1.Timestamp{
+ Seconds: uint64(16273849),
+ },
+ Path: "/path/to/test.txt",
+ // Other properties aren't used for now.
+ },
+ }, nil)
+
+ expectedFileInfo := connector.FileInfo{
+ OwnerId: "61616262636340637573746f6d496470", // hex of aabbcc@customIdp
+ Size: int64(998877),
+ Version: "16273849.0",
+ BaseFileName: "test.txt",
+ BreadcrumbDocName: "test.txt",
+ UserCanNotWriteRelative: true,
+ HostViewUrl: "http://test.ex.prv/view",
+ HostEditUrl: "http://test.ex.prv/edit",
+ EnableOwnerTermination: false,
+ SupportsExtendedLockLength: true,
+ SupportsGetLock: true,
+ SupportsLocks: true,
+ DisableExport: true,
+ DisableCopy: true,
+ DisablePrint: true,
+ IsAnonymousUser: true,
+ UserId: "guest-zzz000",
+ UserFriendlyName: "guest zzz000",
+ }
+
+ newFileInfo, err := fc.CheckFileInfo(ctx)
+
+ // UserId and UserFriendlyName have random Ids generated which are impossible to guess
+ // Check both separately
+ Expect(newFileInfo.UserId).To(HavePrefix(hex.EncodeToString([]byte("guest-"))))
+ Expect(newFileInfo.UserFriendlyName).To(HavePrefix("Guest "))
+ // overwrite UserId and UserFriendlyName here for easier matching
+ newFileInfo.UserId = "guest-zzz000"
+ newFileInfo.UserFriendlyName = "guest zzz000"
+
+ Expect(err).To(Succeed())
+ Expect(newFileInfo).To(Equal(expectedFileInfo))
+ })
+ })
+})
diff --git a/services/collaboration/pkg/helpers/discovery_test.go b/services/collaboration/pkg/helpers/discovery_test.go
new file mode 100644
index 000000000..cb1679045
--- /dev/null
+++ b/services/collaboration/pkg/helpers/discovery_test.go
@@ -0,0 +1,124 @@
+package helpers_test
+
+import (
+ "net/http"
+ "net/http/httptest"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+
+ "github.com/owncloud/ocis/v2/ocis-pkg/log"
+ "github.com/owncloud/ocis/v2/services/collaboration/pkg/config"
+ "github.com/owncloud/ocis/v2/services/collaboration/pkg/helpers"
+)
+
+var _ = Describe("Discovery", func() {
+ var (
+ discoveryContent1 string
+ srv *httptest.Server
+ )
+
+ BeforeEach(func() {
+ discoveryContent1 = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`
+ srv = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ switch req.URL.Path {
+ case "/bad/hosting/discovery":
+ w.WriteHeader(500)
+ case "/good/hosting/discovery":
+ w.Write([]byte(discoveryContent1))
+ case "/wrongformat/hosting/discovery":
+ w.Write([]byte("Text that be XML /form