mirror of
https://github.com/owncloud/ocis
synced 2026-04-25 17:25:21 +02:00
OnlyOffice sends a WOPI Lock request on document open regardless of whether the user has write access. The Lock handler was calling SetLock with a read-only CS3 token, which returned a permission error propagated as HTTP 500 to OnlyOffice, causing an error dialog on load. Return 200 OK immediately for READ_ONLY and VIEW_ONLY view modes without acquiring a CS3 lock. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Julian Koberg <julian.koberg@kiteworks.com>
2194 lines
81 KiB
Go
2194 lines
81 KiB
Go
package connector_test
|
|
|
|
import (
|
|
"context"
|
|
"encoding/hex"
|
|
"errors"
|
|
"net/url"
|
|
"path"
|
|
"regexp"
|
|
"strings"
|
|
"time"
|
|
|
|
appproviderv1beta1 "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1"
|
|
auth "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1"
|
|
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
|
|
userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
|
|
link "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1"
|
|
providerv1beta1 "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
|
typesv1beta1 "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
|
|
"github.com/golang-jwt/jwt/v5"
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
"github.com/owncloud/ocis/v2/ocis-pkg/shared"
|
|
collabmocks "github.com/owncloud/ocis/v2/services/collaboration/mocks"
|
|
"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/connector/fileinfo"
|
|
"github.com/owncloud/ocis/v2/services/collaboration/pkg/middleware"
|
|
"github.com/owncloud/ocis/v2/services/graph/mocks"
|
|
ctxpkg "github.com/owncloud/reva/v2/pkg/ctx"
|
|
"github.com/owncloud/reva/v2/pkg/rgrpc/status"
|
|
"github.com/owncloud/reva/v2/pkg/utils"
|
|
cs3mocks "github.com/owncloud/reva/v2/tests/cs3mocks/mocks"
|
|
"github.com/stretchr/testify/mock"
|
|
"google.golang.org/grpc"
|
|
)
|
|
|
|
var _ = Describe("FileConnector", func() {
|
|
var (
|
|
fc *connector.FileConnector
|
|
ccs *collabmocks.ContentConnectorService
|
|
gatewayClient *cs3mocks.GatewayAPIClient
|
|
gatewaySelector *mocks.Selectable[gateway.GatewayAPIClient]
|
|
cfg *config.Config
|
|
wopiCtx middleware.WopiContext
|
|
)
|
|
|
|
BeforeEach(func() {
|
|
cfg = &config.Config{
|
|
Commons: &shared.Commons{
|
|
OcisURL: "https://ocis.example.prv",
|
|
},
|
|
App: config.App{
|
|
Name: "test",
|
|
Product: "Microsoft",
|
|
},
|
|
Wopi: config.Wopi{
|
|
WopiSrc: "https://ocis.server.prv",
|
|
Secret: "topsecret",
|
|
},
|
|
TokenManager: &config.TokenManager{JWTSecret: "topsecret"},
|
|
}
|
|
ccs = &collabmocks.ContentConnectorService{}
|
|
|
|
gatewayClient = cs3mocks.NewGatewayAPIClient(GinkgoT())
|
|
|
|
gatewaySelector = mocks.NewSelectable[gateway.GatewayAPIClient](GinkgoT())
|
|
gatewaySelector.On("Next").Return(gatewayClient, nil)
|
|
fc = connector.NewFileConnector(gatewaySelector, cfg, nil)
|
|
|
|
// Generate a valid token for testing
|
|
now := time.Now()
|
|
claims := jwt.MapClaims{
|
|
"aud": "web",
|
|
"exp": now.Add(24 * time.Hour).Unix(),
|
|
"iat": now.Unix(),
|
|
"iss": "https://ocis.jp.solidgear.prv",
|
|
"jti": "fBWi7AXhQPUhah2CWEPTQKpCfgpFlAiL",
|
|
"lg.i": map[string]interface{}{
|
|
"dn": "bro",
|
|
"id": "ownCloudUUID=faf11647-7451-4b9a-bffe-3b5ddcc5972b",
|
|
"un": "brotato",
|
|
},
|
|
"lg.p": "identifier-ldap",
|
|
"lg.t": "1",
|
|
"scp": "openid profile email",
|
|
"sub": "cAvuzX8gXLZdiXx-@1NWTJtCPDqUJ44nt46FtD9p5L7tjePFdZMVJ9E30Nx2-dui7HKCLxAiaCTtbX511JcdHw",
|
|
}
|
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
|
accessToken, _ := token.SignedString([]byte(cfg.Wopi.Secret))
|
|
|
|
wopiCtx = middleware.WopiContext{
|
|
AccessToken: accessToken,
|
|
FileReference: &providerv1beta1.Reference{
|
|
ResourceId: &providerv1beta1.ResourceId{
|
|
StorageId: "abc",
|
|
OpaqueId: "12345",
|
|
SpaceId: "zzz",
|
|
},
|
|
Path: ".",
|
|
},
|
|
ViewMode: appproviderv1beta1.ViewMode_VIEW_MODE_READ_WRITE,
|
|
}
|
|
})
|
|
|
|
Describe("GetLock", func() {
|
|
It("No valid context", func() {
|
|
gatewaySelector.EXPECT().Next().Unset()
|
|
ctx := context.Background()
|
|
response, err := fc.GetLock(ctx)
|
|
Expect(err).To(HaveOccurred())
|
|
Expect(response).To(BeNil())
|
|
})
|
|
|
|
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)
|
|
|
|
response, err := fc.GetLock(ctx)
|
|
Expect(err).To(Equal(targetErr))
|
|
Expect(response).To(BeNil())
|
|
})
|
|
|
|
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)
|
|
|
|
response, err := fc.GetLock(ctx)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(404))
|
|
Expect(response.Headers[connector.HeaderWopiLock]).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)
|
|
|
|
response, err := fc.GetLock(ctx)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(200))
|
|
Expect(response.Headers[connector.HeaderWopiLock]).To(Equal("zzz999"))
|
|
})
|
|
})
|
|
|
|
Describe("Lock", func() {
|
|
Describe("Lock", func() {
|
|
It("No valid context", func() {
|
|
gatewaySelector.EXPECT().Next().Unset()
|
|
ctx := context.Background()
|
|
response, err := fc.Lock(ctx, "newLock", "")
|
|
Expect(err).To(HaveOccurred())
|
|
Expect(response).To(BeNil())
|
|
})
|
|
|
|
It("Empty lockId", func() {
|
|
gatewaySelector.EXPECT().Next().Unset()
|
|
ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
|
|
|
|
response, err := fc.Lock(ctx, "", "")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(400))
|
|
Expect(response.Headers).To(BeNil())
|
|
})
|
|
|
|
It("Read-only view mode returns 200 without locking", func() {
|
|
gatewaySelector.EXPECT().Next().Unset()
|
|
readOnlyCtx := wopiCtx
|
|
readOnlyCtx.ViewMode = appproviderv1beta1.ViewMode_VIEW_MODE_READ_ONLY
|
|
ctx := middleware.WopiContextToCtx(context.Background(), readOnlyCtx)
|
|
|
|
response, err := fc.Lock(ctx, "abcdef123", "")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(200))
|
|
})
|
|
|
|
It("View-only mode returns 200 without locking", func() {
|
|
gatewaySelector.EXPECT().Next().Unset()
|
|
viewOnlyCtx := wopiCtx
|
|
viewOnlyCtx.ViewMode = appproviderv1beta1.ViewMode_VIEW_MODE_VIEW_ONLY
|
|
ctx := middleware.WopiContextToCtx(context.Background(), viewOnlyCtx)
|
|
|
|
response, err := fc.Lock(ctx, "abcdef123", "")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(200))
|
|
})
|
|
|
|
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)
|
|
|
|
response, err := fc.Lock(ctx, "abcdef123", "")
|
|
Expect(err).To(HaveOccurred())
|
|
Expect(err).To(Equal(targetErr))
|
|
Expect(response).To(BeNil())
|
|
})
|
|
|
|
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)
|
|
|
|
gatewayClient.EXPECT().Stat(mock.Anything, mock.Anything).
|
|
Return(
|
|
&providerv1beta1.StatResponse{
|
|
Status: status.NewOK(ctx),
|
|
Info: &providerv1beta1.ResourceInfo{
|
|
Mtime: &typesv1beta1.Timestamp{
|
|
Seconds: 12345,
|
|
Nanos: 6789,
|
|
},
|
|
},
|
|
},
|
|
nil,
|
|
)
|
|
|
|
response, err := fc.Lock(ctx, "abcdef123", "")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(200))
|
|
Expect(response.Headers).To(HaveLen(1))
|
|
Expect(response.Headers[connector.HeaderWopiVersion]).To(Equal("v123456789"))
|
|
})
|
|
|
|
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)
|
|
|
|
gatewayClient.EXPECT().Stat(mock.Anything, mock.Anything).
|
|
Return(&providerv1beta1.StatResponse{Status: status.NewOK(ctx)}, nil)
|
|
|
|
response, err := fc.Lock(ctx, "abcdef123", "")
|
|
Expect(err).To(HaveOccurred())
|
|
Expect(err).To(Equal(targetErr))
|
|
Expect(response).To(BeNil())
|
|
})
|
|
|
|
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)
|
|
|
|
gatewayClient.EXPECT().Stat(mock.Anything, mock.Anything).
|
|
Return(&providerv1beta1.StatResponse{Status: status.NewOK(ctx)}, nil)
|
|
|
|
response, err := fc.Lock(ctx, "abcdef123", "")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(409))
|
|
Expect(response.Headers).To(HaveLen(2))
|
|
Expect(response.Headers[connector.HeaderWopiLock]).To(Equal("zzz999"))
|
|
Expect(response.Headers[connector.HeaderWopiLockFailureReason]).To(Equal("Conflicting LockID"))
|
|
})
|
|
|
|
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)
|
|
|
|
gatewayClient.EXPECT().Stat(mock.Anything, mock.Anything).
|
|
Return(&providerv1beta1.StatResponse{
|
|
Status: status.NewOK(ctx),
|
|
Info: &providerv1beta1.ResourceInfo{
|
|
Mtime: &typesv1beta1.Timestamp{Seconds: uint64(12345), Nanos: uint32(6789)},
|
|
},
|
|
}, nil)
|
|
|
|
response, err := fc.Lock(ctx, "abcdef123", "")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(200))
|
|
Expect(response.Headers).To(HaveLen(1))
|
|
Expect(response.Headers[connector.HeaderWopiVersion]).To(Equal("v123456789"))
|
|
})
|
|
|
|
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)
|
|
|
|
gatewayClient.EXPECT().Stat(mock.Anything, mock.Anything).
|
|
Return(&providerv1beta1.StatResponse{Status: status.NewOK(ctx)}, nil)
|
|
|
|
response, err := fc.Lock(ctx, "abcdef123", "")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(500))
|
|
Expect(response.Headers).To(BeNil())
|
|
})
|
|
|
|
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)
|
|
|
|
gatewayClient.EXPECT().Stat(mock.Anything, mock.Anything).
|
|
Return(&providerv1beta1.StatResponse{Status: status.NewOK(ctx)}, nil)
|
|
|
|
response, err := fc.Lock(ctx, "abcdef123", "")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(404))
|
|
Expect(response.Headers).To(BeNil())
|
|
})
|
|
|
|
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)
|
|
|
|
gatewayClient.EXPECT().Stat(mock.Anything, mock.Anything).
|
|
Return(&providerv1beta1.StatResponse{Status: status.NewOK(ctx)}, nil)
|
|
|
|
response, err := fc.Lock(ctx, "abcdef123", "")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(500))
|
|
Expect(response.Headers).To(BeNil())
|
|
})
|
|
})
|
|
|
|
Describe("Unlock and relock", func() {
|
|
It("No valid context", func() {
|
|
gatewaySelector.EXPECT().Next().Unset()
|
|
ctx := context.Background()
|
|
response, err := fc.Lock(ctx, "newLock", "oldLock")
|
|
Expect(err).To(HaveOccurred())
|
|
Expect(response).To(BeNil())
|
|
})
|
|
|
|
It("Empty lockId", func() {
|
|
gatewaySelector.EXPECT().Next().Unset()
|
|
ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
|
|
|
|
response, err := fc.Lock(ctx, "", "oldLock")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(400))
|
|
Expect(response.Headers).To(BeNil())
|
|
})
|
|
|
|
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)
|
|
|
|
response, err := fc.Lock(ctx, "abcdef123", "oldLock")
|
|
Expect(err).To(HaveOccurred())
|
|
Expect(err).To(Equal(targetErr))
|
|
Expect(response).To(BeNil())
|
|
})
|
|
|
|
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)
|
|
|
|
gatewayClient.EXPECT().Stat(mock.Anything, mock.Anything).
|
|
Return(&providerv1beta1.StatResponse{
|
|
Status: status.NewOK(ctx),
|
|
Info: &providerv1beta1.ResourceInfo{
|
|
Mtime: &typesv1beta1.Timestamp{Seconds: uint64(12345), Nanos: uint32(6789)},
|
|
},
|
|
}, nil)
|
|
|
|
response, err := fc.Lock(ctx, "abcdef123", "oldLock")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(200))
|
|
Expect(response.Headers).To(HaveLen(1))
|
|
Expect(response.Headers[connector.HeaderWopiVersion]).To(Equal("v123456789"))
|
|
})
|
|
|
|
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)
|
|
|
|
gatewayClient.EXPECT().Stat(mock.Anything, mock.Anything).
|
|
Return(&providerv1beta1.StatResponse{Status: status.NewOK(ctx)}, nil)
|
|
|
|
response, err := fc.Lock(ctx, "abcdef123", "112233")
|
|
Expect(err).To(HaveOccurred())
|
|
Expect(err).To(Equal(targetErr))
|
|
Expect(response).To(BeNil())
|
|
})
|
|
|
|
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)
|
|
|
|
gatewayClient.EXPECT().Stat(mock.Anything, mock.Anything).
|
|
Return(&providerv1beta1.StatResponse{Status: status.NewOK(ctx)}, nil)
|
|
|
|
response, err := fc.Lock(ctx, "abcdef123", "112233")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(409))
|
|
Expect(response.Headers[connector.HeaderWopiLock]).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)
|
|
|
|
gatewayClient.EXPECT().Stat(mock.Anything, mock.Anything).
|
|
Return(&providerv1beta1.StatResponse{
|
|
Status: status.NewOK(ctx),
|
|
Info: &providerv1beta1.ResourceInfo{
|
|
Mtime: &typesv1beta1.Timestamp{Seconds: uint64(12345), Nanos: uint32(6789)},
|
|
},
|
|
}, nil)
|
|
|
|
response, err := fc.Lock(ctx, "abcdef123", "112233")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(200))
|
|
Expect(response.Headers).To(HaveLen(1))
|
|
Expect(response.Headers[connector.HeaderWopiVersion]).To(Equal("v123456789"))
|
|
})
|
|
|
|
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)
|
|
|
|
gatewayClient.EXPECT().Stat(mock.Anything, mock.Anything).
|
|
Return(&providerv1beta1.StatResponse{Status: status.NewOK(ctx)}, nil)
|
|
|
|
response, err := fc.Lock(ctx, "abcdef123", "112233")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(500))
|
|
Expect(response.Headers).To(BeNil())
|
|
})
|
|
|
|
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)
|
|
|
|
gatewayClient.EXPECT().Stat(mock.Anything, mock.Anything).
|
|
Return(&providerv1beta1.StatResponse{Status: status.NewOK(ctx)}, nil)
|
|
|
|
response, err := fc.Lock(ctx, "abcdef123", "112233")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(404))
|
|
Expect(response.Headers).To(BeNil())
|
|
})
|
|
|
|
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)
|
|
|
|
gatewayClient.EXPECT().Stat(mock.Anything, mock.Anything).
|
|
Return(&providerv1beta1.StatResponse{Status: status.NewOK(ctx)}, nil)
|
|
|
|
response, err := fc.Lock(ctx, "abcdef123", "112233")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(500))
|
|
Expect(response.Headers).To(BeNil())
|
|
})
|
|
})
|
|
})
|
|
|
|
Describe("RefreshLock", func() {
|
|
It("No valid context", func() {
|
|
gatewaySelector.EXPECT().Next().Unset()
|
|
ctx := context.Background()
|
|
|
|
response, err := fc.RefreshLock(ctx, "")
|
|
Expect(err).To(HaveOccurred())
|
|
Expect(response).To(BeNil())
|
|
})
|
|
|
|
It("Empty lockId", func() {
|
|
gatewaySelector.EXPECT().Next().Unset()
|
|
ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
|
|
|
|
response, err := fc.RefreshLock(ctx, "")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(400))
|
|
Expect(response.Headers).To(BeNil())
|
|
})
|
|
|
|
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)
|
|
|
|
response, err := fc.RefreshLock(ctx, "abcdef123")
|
|
Expect(err).To(HaveOccurred())
|
|
Expect(err).To(Equal(targetErr))
|
|
Expect(response).To(BeNil())
|
|
})
|
|
|
|
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)
|
|
|
|
gatewayClient.EXPECT().Stat(mock.Anything, mock.Anything).
|
|
Return(&providerv1beta1.StatResponse{
|
|
Status: status.NewOK(ctx),
|
|
Info: &providerv1beta1.ResourceInfo{
|
|
Mtime: &typesv1beta1.Timestamp{Seconds: uint64(12345), Nanos: uint32(6789)},
|
|
},
|
|
}, nil)
|
|
|
|
response, err := fc.RefreshLock(ctx, "abcdef123")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(200))
|
|
Expect(response.Headers).To(HaveLen(1))
|
|
Expect(response.Headers[connector.HeaderWopiVersion]).To(Equal("v123456789"))
|
|
})
|
|
|
|
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)
|
|
|
|
gatewayClient.EXPECT().Stat(mock.Anything, mock.Anything).
|
|
Return(&providerv1beta1.StatResponse{Status: status.NewOK(ctx)}, nil)
|
|
|
|
response, err := fc.RefreshLock(ctx, "abcdef123")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(404))
|
|
Expect(response.Headers).To(BeNil())
|
|
})
|
|
|
|
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)
|
|
|
|
gatewayClient.EXPECT().Stat(mock.Anything, mock.Anything).
|
|
Return(&providerv1beta1.StatResponse{Status: status.NewOK(ctx)}, nil)
|
|
|
|
response, err := fc.RefreshLock(ctx, "abcdef123")
|
|
Expect(err).To(HaveOccurred())
|
|
Expect(err).To(Equal(targetErr))
|
|
Expect(response).To(BeNil())
|
|
})
|
|
|
|
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)
|
|
|
|
gatewayClient.EXPECT().Stat(mock.Anything, mock.Anything).
|
|
Return(&providerv1beta1.StatResponse{Status: status.NewOK(ctx)}, nil)
|
|
|
|
response, err := fc.RefreshLock(ctx, "abcdef123")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(500))
|
|
Expect(response.Headers).To(BeNil())
|
|
})
|
|
|
|
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)
|
|
|
|
gatewayClient.EXPECT().Stat(mock.Anything, mock.Anything).
|
|
Return(&providerv1beta1.StatResponse{Status: status.NewOK(ctx)}, nil)
|
|
|
|
response, err := fc.RefreshLock(ctx, "abcdef123")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(409))
|
|
Expect(response.Headers[connector.HeaderWopiLock]).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)
|
|
|
|
gatewayClient.EXPECT().Stat(mock.Anything, mock.Anything).
|
|
Return(&providerv1beta1.StatResponse{Status: status.NewOK(ctx)}, nil)
|
|
|
|
response, err := fc.RefreshLock(ctx, "abcdef123")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(409))
|
|
Expect(response.Headers[connector.HeaderWopiLock]).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)
|
|
|
|
gatewayClient.EXPECT().Stat(mock.Anything, mock.Anything).
|
|
Return(&providerv1beta1.StatResponse{Status: status.NewOK(ctx)}, nil)
|
|
|
|
response, err := fc.RefreshLock(ctx, "abcdef123")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(500))
|
|
Expect(response.Headers).To(BeNil())
|
|
})
|
|
})
|
|
|
|
Describe("Unlock", func() {
|
|
It("No valid context", func() {
|
|
gatewaySelector.EXPECT().Next().Unset()
|
|
ctx := context.Background()
|
|
|
|
response, err := fc.UnLock(ctx, "")
|
|
Expect(err).To(HaveOccurred())
|
|
Expect(response).To(BeNil())
|
|
})
|
|
|
|
It("Empty lockId", func() {
|
|
gatewaySelector.EXPECT().Next().Unset()
|
|
ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
|
|
|
|
response, err := fc.UnLock(ctx, "")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(400))
|
|
Expect(response.Headers).To(BeNil())
|
|
})
|
|
|
|
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)
|
|
|
|
response, err := fc.UnLock(ctx, "abcdef123")
|
|
Expect(err).To(HaveOccurred())
|
|
Expect(err).To(Equal(targetErr))
|
|
Expect(response).To(BeNil())
|
|
})
|
|
|
|
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)
|
|
|
|
gatewayClient.EXPECT().Stat(mock.Anything, mock.Anything).
|
|
Return(&providerv1beta1.StatResponse{
|
|
Status: status.NewOK(ctx),
|
|
Info: &providerv1beta1.ResourceInfo{
|
|
Mtime: &typesv1beta1.Timestamp{Seconds: uint64(12345), Nanos: uint32(6789)},
|
|
},
|
|
}, nil)
|
|
|
|
response, err := fc.UnLock(ctx, "abcdef123")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(200))
|
|
Expect(response.Headers).To(HaveLen(1))
|
|
Expect(response.Headers[connector.HeaderWopiVersion]).To(Equal("v123456789"))
|
|
})
|
|
|
|
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)
|
|
|
|
gatewayClient.EXPECT().Stat(mock.Anything, mock.Anything).
|
|
Return(&providerv1beta1.StatResponse{
|
|
Status: status.NewOK(ctx),
|
|
Info: &providerv1beta1.ResourceInfo{
|
|
Mtime: &typesv1beta1.Timestamp{Seconds: uint64(12345), Nanos: uint32(6789)},
|
|
},
|
|
}, nil)
|
|
|
|
response, err := fc.UnLock(ctx, "abcdef123")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(409))
|
|
Expect(response.Headers[connector.HeaderWopiLock]).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)
|
|
|
|
gatewayClient.EXPECT().Stat(mock.Anything, mock.Anything).
|
|
Return(&providerv1beta1.StatResponse{Status: status.NewOK(ctx)}, nil)
|
|
|
|
response, err := fc.UnLock(ctx, "abcdef123")
|
|
Expect(err).To(HaveOccurred())
|
|
Expect(err).To(Equal(targetErr))
|
|
Expect(response).To(BeNil())
|
|
})
|
|
|
|
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)
|
|
|
|
gatewayClient.EXPECT().Stat(mock.Anything, mock.Anything).
|
|
Return(&providerv1beta1.StatResponse{Status: status.NewOK(ctx)}, nil)
|
|
|
|
response, err := fc.UnLock(ctx, "abcdef123")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(500))
|
|
Expect(response.Headers).To(BeNil())
|
|
})
|
|
|
|
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)
|
|
|
|
gatewayClient.EXPECT().Stat(mock.Anything, mock.Anything).
|
|
Return(&providerv1beta1.StatResponse{Status: status.NewOK(ctx)}, nil)
|
|
|
|
response, err := fc.UnLock(ctx, "abcdef123")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(409))
|
|
Expect(response.Headers[connector.HeaderWopiLock]).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)
|
|
|
|
gatewayClient.EXPECT().Stat(mock.Anything, mock.Anything).
|
|
Return(&providerv1beta1.StatResponse{Status: status.NewOK(ctx)}, nil)
|
|
|
|
response, err := fc.UnLock(ctx, "abcdef123")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(409))
|
|
Expect(response.Headers[connector.HeaderWopiLock]).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)
|
|
|
|
gatewayClient.EXPECT().Stat(mock.Anything, mock.Anything).
|
|
Return(&providerv1beta1.StatResponse{Status: status.NewOK(ctx)}, nil)
|
|
|
|
response, err := fc.UnLock(ctx, "abcdef123")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(500))
|
|
Expect(response.Headers).To(BeNil())
|
|
})
|
|
})
|
|
|
|
Describe("PutRelativeFileSuggested", func() {
|
|
It("No valid context", func() {
|
|
gatewaySelector.EXPECT().Next().Unset()
|
|
ctx := context.Background()
|
|
stream := strings.NewReader("This is the content of a file")
|
|
response, err := fc.PutRelativeFileSuggested(ctx, ccs, stream, int64(stream.Len()), "newFile.txt")
|
|
Expect(err).To(HaveOccurred())
|
|
Expect(response).To(BeNil())
|
|
})
|
|
|
|
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)
|
|
|
|
stream := strings.NewReader("This is the content of a file")
|
|
response, err := fc.PutRelativeFileSuggested(ctx, ccs, stream, int64(stream.Len()), "newFile.txt")
|
|
Expect(err).To(HaveOccurred())
|
|
Expect(err).To(Equal(targetErr))
|
|
Expect(response).To(BeNil())
|
|
})
|
|
|
|
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)
|
|
|
|
stream := strings.NewReader("This is the content of a file")
|
|
response, err := fc.PutRelativeFileSuggested(ctx, ccs, stream, int64(stream.Len()), "newFile.txt")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(500))
|
|
Expect(response.Headers).To(BeNil())
|
|
Expect(response.Body).To(BeNil())
|
|
})
|
|
|
|
It("PutRelativeFileSuggested success", func() {
|
|
// requested filename is "newDocument.docx" so we'll write that
|
|
ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
|
|
|
|
stream := strings.NewReader("This is the content of a file")
|
|
|
|
stat1ParamMatcher := mock.MatchedBy(func(statReq *providerv1beta1.StatRequest) bool {
|
|
return statReq.Ref.ResourceId == wopiCtx.FileReference.ResourceId
|
|
})
|
|
gatewayClient.On("Stat", mock.Anything, stat1ParamMatcher).Times(1).Return(&providerv1beta1.StatResponse{
|
|
Status: status.NewOK(ctx),
|
|
Info: &providerv1beta1.ResourceInfo{
|
|
Path: "/personal/path/to/file.docx",
|
|
ParentId: &providerv1beta1.ResourceId{
|
|
StorageId: "storageid",
|
|
OpaqueId: "opaqueid",
|
|
SpaceId: "spaceid",
|
|
},
|
|
},
|
|
}, nil)
|
|
|
|
ccs.On("PutFile", mock.Anything, stream, int64(stream.Len()), "").Times(1).Return(connector.NewResponse(200), nil)
|
|
|
|
stat2ParamMatcher := mock.MatchedBy(func(statReq *providerv1beta1.StatRequest) bool {
|
|
if statReq.Ref.ResourceId.StorageId == "storageid" &&
|
|
statReq.Ref.ResourceId.OpaqueId == "opaqueid" &&
|
|
statReq.Ref.ResourceId.SpaceId == "spaceid" &&
|
|
statReq.Ref.Path == "./newDocument.docx" {
|
|
return true
|
|
}
|
|
return false
|
|
})
|
|
gatewayClient.On("Stat", mock.Anything, stat2ParamMatcher).Times(1).Return(&providerv1beta1.StatResponse{
|
|
Status: status.NewOK(ctx),
|
|
Info: &providerv1beta1.ResourceInfo{
|
|
Path: "/personal/path/to/newDocument.docx",
|
|
Id: &providerv1beta1.ResourceId{
|
|
StorageId: "storageid",
|
|
OpaqueId: "opaqueid_newDoc",
|
|
SpaceId: "spaceid",
|
|
},
|
|
},
|
|
}, nil)
|
|
|
|
response, err := fc.PutRelativeFileSuggested(ctx, ccs, stream, int64(stream.Len()), "newDocument.docx")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(200))
|
|
Expect(response.Headers).To(BeNil())
|
|
rBody := response.Body.(map[string]interface{})
|
|
Expect(rBody["Name"]).To(Equal("newDocument.docx"))
|
|
Expect(rBody["Url"]).To(HavePrefix("https://ocis.server.prv/wopi/files/")) // skip checking the actual reference
|
|
Expect(rBody["HostEditUrl"]).To(Equal("https://ocis.example.prv/external-test/personal/path/to/newDocument.docx?fileId=storageid%24spaceid%21opaqueid_newDoc&view_mode=write"))
|
|
Expect(rBody["HostViewUrl"]).To(Equal("https://ocis.example.prv/external-test/personal/path/to/newDocument.docx?fileId=storageid%24spaceid%21opaqueid_newDoc&view_mode=view"))
|
|
})
|
|
|
|
It("PutRelativeFileSuggested success only extension", func() {
|
|
// requested file is ".pdf" so we'll change the "file.docx" to "file.pdf"
|
|
ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
|
|
|
|
stream := strings.NewReader("This is the content of a file")
|
|
|
|
stat1ParamMatcher := mock.MatchedBy(func(statReq *providerv1beta1.StatRequest) bool {
|
|
return statReq.Ref.ResourceId == wopiCtx.FileReference.ResourceId
|
|
})
|
|
gatewayClient.On("Stat", mock.Anything, stat1ParamMatcher).Times(1).Return(&providerv1beta1.StatResponse{
|
|
Status: status.NewOK(ctx),
|
|
Info: &providerv1beta1.ResourceInfo{
|
|
Path: "/personal/path/to/file.docx",
|
|
ParentId: &providerv1beta1.ResourceId{
|
|
StorageId: "storageid",
|
|
OpaqueId: "opaqueid",
|
|
SpaceId: "spaceid",
|
|
},
|
|
},
|
|
}, nil)
|
|
|
|
ccs.On("PutFile", mock.Anything, stream, int64(stream.Len()), "").Times(1).Return(connector.NewResponse(200), nil)
|
|
|
|
stat2ParamMatcher := mock.MatchedBy(func(statReq *providerv1beta1.StatRequest) bool {
|
|
if statReq.Ref.ResourceId.StorageId == "storageid" &&
|
|
statReq.Ref.ResourceId.OpaqueId == "opaqueid" &&
|
|
statReq.Ref.ResourceId.SpaceId == "spaceid" &&
|
|
statReq.Ref.Path == "./file.pdf" {
|
|
return true
|
|
}
|
|
return false
|
|
})
|
|
gatewayClient.On("Stat", mock.Anything, stat2ParamMatcher).Times(1).Return(&providerv1beta1.StatResponse{
|
|
Status: status.NewOK(ctx),
|
|
Info: &providerv1beta1.ResourceInfo{
|
|
Path: "/personal/path/to/file.pdf",
|
|
Id: &providerv1beta1.ResourceId{
|
|
StorageId: "storageid",
|
|
OpaqueId: "opaqueid_newDoc",
|
|
SpaceId: "spaceid",
|
|
},
|
|
},
|
|
}, nil)
|
|
|
|
response, err := fc.PutRelativeFileSuggested(ctx, ccs, stream, int64(stream.Len()), ".pdf")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(200))
|
|
Expect(response.Headers).To(BeNil())
|
|
rBody := response.Body.(map[string]interface{})
|
|
Expect(rBody["Name"]).To(Equal("file.pdf"))
|
|
Expect(rBody["Url"]).To(HavePrefix("https://ocis.server.prv/wopi/files/")) // skip checking the actual reference
|
|
Expect(rBody["HostEditUrl"]).To(Equal("https://ocis.example.prv/external-test/personal/path/to/file.pdf?fileId=storageid%24spaceid%21opaqueid_newDoc&view_mode=write"))
|
|
Expect(rBody["HostViewUrl"]).To(Equal("https://ocis.example.prv/external-test/personal/path/to/file.pdf?fileId=storageid%24spaceid%21opaqueid_newDoc&view_mode=view"))
|
|
})
|
|
|
|
It("PutRelativeFileSuggested success conflict", func() {
|
|
// requested file is ".pdf", but "file.pdf" exists as target file (we get a conflict)
|
|
// so we change the "file.docx" to "<base64> file.pdf" file, where the <base64> is a
|
|
// sequence of base64 chars containing alphanumeric chars plus "-" and "_" (the char
|
|
// sequence is based on time, so we can't be too specific)
|
|
ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
|
|
|
|
stream := strings.NewReader("This is the content of a file")
|
|
|
|
stat1ParamMatcher := mock.MatchedBy(func(statReq *providerv1beta1.StatRequest) bool {
|
|
return statReq.Ref.ResourceId == wopiCtx.FileReference.ResourceId
|
|
})
|
|
gatewayClient.On("Stat", mock.Anything, stat1ParamMatcher).Times(1).Return(&providerv1beta1.StatResponse{
|
|
Status: status.NewOK(ctx),
|
|
Info: &providerv1beta1.ResourceInfo{
|
|
Path: "/personal/path/to/file.docx",
|
|
ParentId: &providerv1beta1.ResourceId{
|
|
StorageId: "storageid",
|
|
OpaqueId: "opaqueid",
|
|
SpaceId: "spaceid",
|
|
},
|
|
},
|
|
}, nil)
|
|
|
|
// first call will fail with conflict, second call succeeds.
|
|
// we're only interested on whether the file is locked or not, the actual lockID is irrelevant
|
|
ccs.On("PutFile", mock.Anything, stream, int64(stream.Len()), "").Times(1).Return(connector.NewResponse(409), nil).Once()
|
|
ccs.On("PutFile", mock.Anything, stream, int64(stream.Len()), "").Times(1).Return(connector.NewResponse(200), nil).Once()
|
|
|
|
newFilePath := new(string)
|
|
stat2ParamMatcher := mock.MatchedBy(func(statReq *providerv1beta1.StatRequest) bool {
|
|
r := regexp.MustCompile(`^\./[a-zA-Z0-9_-]+ file\.pdf$`)
|
|
if statReq.Ref.ResourceId.StorageId == "storageid" &&
|
|
statReq.Ref.ResourceId.OpaqueId == "opaqueid" &&
|
|
statReq.Ref.ResourceId.SpaceId == "spaceid" &&
|
|
r.MatchString(statReq.Ref.Path) {
|
|
*newFilePath = statReq.Ref.Path
|
|
return true
|
|
}
|
|
return false
|
|
})
|
|
|
|
gatewayClient.EXPECT().Stat(mock.Anything, stat2ParamMatcher).
|
|
RunAndReturn(func(ctx context.Context, req *providerv1beta1.StatRequest, opts ...grpc.CallOption) (*providerv1beta1.StatResponse, error) {
|
|
return &providerv1beta1.StatResponse{
|
|
Status: status.NewOK(ctx),
|
|
Info: &providerv1beta1.ResourceInfo{
|
|
Path: path.Join("/personal/path/to", path.Base(req.GetRef().GetPath())),
|
|
Id: &providerv1beta1.ResourceId{
|
|
StorageId: "storageid",
|
|
OpaqueId: "opaqueid_newDoc",
|
|
SpaceId: "spaceid",
|
|
},
|
|
Lock: &providerv1beta1.Lock{
|
|
LockId: "zzz999",
|
|
Type: providerv1beta1.LockType_LOCK_TYPE_WRITE,
|
|
},
|
|
},
|
|
}, nil
|
|
})
|
|
|
|
response, err := fc.PutRelativeFileSuggested(ctx, ccs, stream, int64(stream.Len()), ".pdf")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(200))
|
|
Expect(response.Headers).To(BeNil())
|
|
rBody := response.Body.(map[string]interface{})
|
|
Expect(rBody["Name"]).To(MatchRegexp(`[a-zA-Z0-9_-] file\.pdf`))
|
|
Expect(rBody["Url"]).To(HavePrefix("https://ocis.server.prv/wopi/files/")) // skip checking the actual reference
|
|
Expect(rBody["HostEditUrl"]).To(Equal("https://ocis.example.prv/external-test/personal/path/to/" + url.PathEscape(path.Base(*newFilePath)) + "?fileId=storageid%24spaceid%21opaqueid_newDoc&view_mode=write"))
|
|
Expect(rBody["HostViewUrl"]).To(Equal("https://ocis.example.prv/external-test/personal/path/to/" + url.PathEscape(path.Base(*newFilePath)) + "?fileId=storageid%24spaceid%21opaqueid_newDoc&view_mode=view"))
|
|
})
|
|
|
|
It("PutRelativeFileSuggested put file fails", func() {
|
|
ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
|
|
|
|
stream := strings.NewReader("This is the content of a file")
|
|
|
|
stat1ParamMatcher := mock.MatchedBy(func(statReq *providerv1beta1.StatRequest) bool {
|
|
return statReq.Ref.ResourceId == wopiCtx.FileReference.ResourceId
|
|
})
|
|
gatewayClient.On("Stat", mock.Anything, stat1ParamMatcher).Times(1).Return(&providerv1beta1.StatResponse{
|
|
Status: status.NewOK(ctx),
|
|
Info: &providerv1beta1.ResourceInfo{
|
|
Path: "/personal/path/to/file.docx",
|
|
ParentId: &providerv1beta1.ResourceId{
|
|
StorageId: "storageid",
|
|
OpaqueId: "opaqueid",
|
|
SpaceId: "spaceid",
|
|
},
|
|
},
|
|
}, nil)
|
|
|
|
ccs.On("PutFile", mock.Anything, stream, int64(stream.Len()), "").Times(1).Return(connector.NewResponse(500), nil)
|
|
|
|
response, err := fc.PutRelativeFileSuggested(ctx, ccs, stream, int64(stream.Len()), ".pdf")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(500))
|
|
Expect(response.Headers).To(BeNil())
|
|
Expect(response.Body).To(BeNil())
|
|
})
|
|
})
|
|
|
|
Describe("PutRelativeFileRelative", func() {
|
|
It("No valid context", func() {
|
|
gatewaySelector.EXPECT().Next().Unset()
|
|
ctx := context.Background()
|
|
stream := strings.NewReader("This is the content of a file")
|
|
response, err := fc.PutRelativeFileRelative(ctx, ccs, stream, int64(stream.Len()), "newFile.txt")
|
|
Expect(err).To(HaveOccurred())
|
|
Expect(response).To(BeNil())
|
|
})
|
|
|
|
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)
|
|
|
|
stream := strings.NewReader("This is the content of a file")
|
|
response, err := fc.PutRelativeFileRelative(ctx, ccs, stream, int64(stream.Len()), "newFile.txt")
|
|
Expect(err).To(HaveOccurred())
|
|
Expect(err).To(Equal(targetErr))
|
|
Expect(response).To(BeNil())
|
|
})
|
|
|
|
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)
|
|
|
|
stream := strings.NewReader("This is the content of a file")
|
|
response, err := fc.PutRelativeFileRelative(ctx, ccs, stream, int64(stream.Len()), "newFile.txt")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(500))
|
|
Expect(response.Headers).To(BeNil())
|
|
Expect(response.Body).To(BeNil())
|
|
})
|
|
|
|
It("PutRelativeFileRelative success", func() {
|
|
ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
|
|
|
|
stream := strings.NewReader("This is the content of a file")
|
|
|
|
stat1ParamMatcher := mock.MatchedBy(func(statReq *providerv1beta1.StatRequest) bool {
|
|
return statReq.Ref.ResourceId == wopiCtx.FileReference.ResourceId
|
|
})
|
|
gatewayClient.On("Stat", mock.Anything, stat1ParamMatcher).Times(1).Return(&providerv1beta1.StatResponse{
|
|
Status: status.NewOK(ctx),
|
|
Info: &providerv1beta1.ResourceInfo{
|
|
Path: "/personal/path/to/file.docx",
|
|
ParentId: &providerv1beta1.ResourceId{
|
|
StorageId: "storageid",
|
|
OpaqueId: "opaqueid",
|
|
SpaceId: "spaceid",
|
|
},
|
|
},
|
|
}, nil)
|
|
|
|
ccs.On("PutFile", mock.Anything, stream, int64(stream.Len()), "").Times(1).Return(connector.NewResponse(200), nil)
|
|
|
|
stat2ParamMatcher := mock.MatchedBy(func(statReq *providerv1beta1.StatRequest) bool {
|
|
if statReq.Ref.ResourceId.StorageId == "storageid" &&
|
|
statReq.Ref.ResourceId.OpaqueId == "opaqueid" &&
|
|
statReq.Ref.ResourceId.SpaceId == "spaceid" &&
|
|
statReq.Ref.Path == "./newDocument.docx" {
|
|
return true
|
|
}
|
|
return false
|
|
})
|
|
gatewayClient.On("Stat", mock.Anything, stat2ParamMatcher).Times(1).Return(&providerv1beta1.StatResponse{
|
|
Status: status.NewOK(ctx),
|
|
Info: &providerv1beta1.ResourceInfo{
|
|
Path: "/personal/path/to/newDocument.docx",
|
|
Id: &providerv1beta1.ResourceId{
|
|
StorageId: "storageid",
|
|
OpaqueId: "opaqueid_newDoc",
|
|
SpaceId: "spaceid",
|
|
},
|
|
},
|
|
}, nil)
|
|
|
|
response, err := fc.PutRelativeFileRelative(ctx, ccs, stream, int64(stream.Len()), "newDocument.docx")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(200))
|
|
Expect(response.Headers).To(BeNil())
|
|
rBody := response.Body.(map[string]interface{})
|
|
Expect(rBody["Name"]).To(Equal("newDocument.docx"))
|
|
Expect(rBody["Url"]).To(HavePrefix("https://ocis.server.prv/wopi/files/")) // skip checking the actual reference
|
|
Expect(rBody["HostEditUrl"]).To(Equal("https://ocis.example.prv/external-test/personal/path/to/newDocument.docx?fileId=storageid%24spaceid%21opaqueid_newDoc&view_mode=write"))
|
|
Expect(rBody["HostViewUrl"]).To(Equal("https://ocis.example.prv/external-test/personal/path/to/newDocument.docx?fileId=storageid%24spaceid%21opaqueid_newDoc&view_mode=view"))
|
|
})
|
|
|
|
It("PutRelativeFileRelative conflict", func() {
|
|
ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
|
|
|
|
stream := strings.NewReader("This is the content of a file")
|
|
|
|
stat1ParamMatcher := mock.MatchedBy(func(statReq *providerv1beta1.StatRequest) bool {
|
|
return statReq.Ref.ResourceId == wopiCtx.FileReference.ResourceId
|
|
})
|
|
gatewayClient.On("Stat", mock.Anything, stat1ParamMatcher).Times(1).Return(&providerv1beta1.StatResponse{
|
|
Status: status.NewOK(ctx),
|
|
Info: &providerv1beta1.ResourceInfo{
|
|
Path: "/personal/path/to/file.docx",
|
|
ParentId: &providerv1beta1.ResourceId{
|
|
StorageId: "storageid",
|
|
OpaqueId: "opaqueid",
|
|
SpaceId: "spaceid",
|
|
},
|
|
},
|
|
}, nil)
|
|
|
|
ccs.On("PutFile", mock.Anything, stream, int64(stream.Len()), "").Times(1).Return(connector.NewResponseWithLock(409, "zzz999"), nil)
|
|
|
|
stat2ParamMatcher := mock.MatchedBy(func(statReq *providerv1beta1.StatRequest) bool {
|
|
if statReq.Ref.ResourceId.StorageId == "storageid" &&
|
|
statReq.Ref.ResourceId.OpaqueId == "opaqueid" &&
|
|
statReq.Ref.ResourceId.SpaceId == "spaceid" &&
|
|
statReq.Ref.Path == "./convFile.pdf" {
|
|
return true
|
|
}
|
|
return false
|
|
})
|
|
gatewayClient.On("Stat", mock.Anything, stat2ParamMatcher).Times(1).Return(&providerv1beta1.StatResponse{
|
|
Status: status.NewOK(ctx),
|
|
Info: &providerv1beta1.ResourceInfo{
|
|
Path: "/personal/path/to/convFile.pdf",
|
|
Id: &providerv1beta1.ResourceId{
|
|
StorageId: "storageid",
|
|
OpaqueId: "opaqueid_newDoc",
|
|
SpaceId: "spaceid",
|
|
},
|
|
Lock: &providerv1beta1.Lock{
|
|
LockId: "zzz999",
|
|
Type: providerv1beta1.LockType_LOCK_TYPE_WRITE,
|
|
},
|
|
},
|
|
}, nil)
|
|
|
|
response, err := fc.PutRelativeFileRelative(ctx, ccs, stream, int64(stream.Len()), "convFile.pdf")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(409))
|
|
Expect(response.Headers[connector.HeaderWopiLock]).To(Equal("zzz999"))
|
|
Expect(response.Headers[connector.HeaderWopiValidRT]).To(MatchRegexp(`[a-zA-Z0-9_-] convFile\.pdf`))
|
|
rBody := response.Body.(map[string]interface{})
|
|
Expect(rBody["Name"]).To(Equal("convFile.pdf"))
|
|
Expect(rBody["Url"]).To(HavePrefix("https://ocis.server.prv/wopi/files/")) // skip checking the actual reference
|
|
Expect(rBody["HostEditUrl"]).To(Equal("https://ocis.example.prv/external-test/personal/path/to/convFile.pdf?fileId=storageid%24spaceid%21opaqueid_newDoc&view_mode=write"))
|
|
Expect(rBody["HostViewUrl"]).To(Equal("https://ocis.example.prv/external-test/personal/path/to/convFile.pdf?fileId=storageid%24spaceid%21opaqueid_newDoc&view_mode=view"))
|
|
})
|
|
|
|
It("PutRelativeFileRelative put file fails", func() {
|
|
ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
|
|
|
|
stream := strings.NewReader("This is the content of a file")
|
|
|
|
stat1ParamMatcher := mock.MatchedBy(func(statReq *providerv1beta1.StatRequest) bool {
|
|
return statReq.Ref.ResourceId == wopiCtx.FileReference.ResourceId
|
|
})
|
|
gatewayClient.On("Stat", mock.Anything, stat1ParamMatcher).Times(1).Return(&providerv1beta1.StatResponse{
|
|
Status: status.NewOK(ctx),
|
|
Info: &providerv1beta1.ResourceInfo{
|
|
Path: "/personal/path/to/file.docx",
|
|
ParentId: &providerv1beta1.ResourceId{
|
|
StorageId: "storageid",
|
|
OpaqueId: "opaqueid",
|
|
SpaceId: "spaceid",
|
|
},
|
|
},
|
|
}, nil)
|
|
|
|
ccs.On("PutFile", mock.Anything, stream, int64(stream.Len()), "").Times(1).Return(nil, connector.NewConnectorError(500, "Something happened"))
|
|
|
|
response, err := fc.PutRelativeFileRelative(ctx, ccs, stream, int64(stream.Len()), "convFile.pdf")
|
|
targetErr := connector.NewConnectorError(500, "Something happened")
|
|
Expect(err).To(Equal(targetErr))
|
|
Expect(response).To(BeNil())
|
|
})
|
|
})
|
|
|
|
Describe("DeleteFile", func() {
|
|
It("No valid context", func() {
|
|
gatewaySelector.EXPECT().Next().Unset()
|
|
ctx := context.Background()
|
|
response, err := fc.DeleteFile(ctx, "lock")
|
|
Expect(err).To(HaveOccurred())
|
|
Expect(response).To(BeNil())
|
|
})
|
|
|
|
It("Delete fails", func() {
|
|
ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
|
|
|
|
targetErr := errors.New("Something went wrong")
|
|
gatewayClient.On("Delete", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.DeleteResponse{
|
|
Status: status.NewInternal(ctx, "something failed"),
|
|
}, targetErr)
|
|
|
|
gatewayClient.EXPECT().Stat(mock.Anything, mock.Anything).Unset()
|
|
|
|
response, err := fc.DeleteFile(ctx, "newlock")
|
|
Expect(err).To(HaveOccurred())
|
|
Expect(err).To(Equal(targetErr))
|
|
Expect(response).To(BeNil())
|
|
})
|
|
|
|
It("Delete fails status not ok, get lock fails", func() {
|
|
ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
|
|
|
|
gatewayClient.On("Delete", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.DeleteResponse{
|
|
Status: status.NewInternal(ctx, "something failed"),
|
|
}, 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)
|
|
|
|
response, err := fc.DeleteFile(ctx, "newlock")
|
|
Expect(err).To(HaveOccurred())
|
|
Expect(err).To(Equal(targetErr))
|
|
Expect(response).To(BeNil())
|
|
})
|
|
|
|
It("Delete fails file missing", func() {
|
|
ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
|
|
|
|
gatewayClient.On("Delete", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.DeleteResponse{
|
|
Status: status.NewNotFound(ctx, "something failed"),
|
|
}, nil)
|
|
|
|
response, err := fc.DeleteFile(ctx, "newlock")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(404))
|
|
Expect(response.Headers).To(BeNil())
|
|
})
|
|
|
|
It("Delete fails status not ok, get lock not ok", func() {
|
|
ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
|
|
|
|
gatewayClient.On("Delete", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.DeleteResponse{
|
|
Status: status.NewInternal(ctx, "something failed"),
|
|
}, nil)
|
|
|
|
gatewayClient.On("GetLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.GetLockResponse{
|
|
Status: status.NewInternal(ctx, "something failed"),
|
|
}, nil)
|
|
|
|
response, err := fc.DeleteFile(ctx, "newlock")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(500))
|
|
Expect(response.Headers).To(BeNil())
|
|
})
|
|
|
|
It("Delete fails, file locked", func() {
|
|
ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
|
|
|
|
gatewayClient.On("Delete", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.DeleteResponse{
|
|
Status: status.NewInternal(ctx, "something failed"),
|
|
}, 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)
|
|
|
|
response, err := fc.DeleteFile(ctx, "newlock")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(409))
|
|
Expect(response.Headers[connector.HeaderWopiLock]).To(Equal("zzz999"))
|
|
})
|
|
|
|
It("Delete fails, file not locked", func() {
|
|
ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
|
|
|
|
gatewayClient.On("Delete", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.DeleteResponse{
|
|
Status: status.NewInternal(ctx, "something failed"),
|
|
}, nil)
|
|
|
|
gatewayClient.On("GetLock", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.GetLockResponse{
|
|
Status: status.NewOK(ctx),
|
|
}, nil)
|
|
|
|
response, err := fc.DeleteFile(ctx, "newlock")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(500))
|
|
Expect(response.Headers).To(BeNil())
|
|
})
|
|
|
|
It("Delete success", func() {
|
|
ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
|
|
|
|
gatewayClient.On("Delete", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.DeleteResponse{
|
|
Status: status.NewOK(ctx),
|
|
}, nil)
|
|
|
|
response, err := fc.DeleteFile(ctx, "newlock")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(200))
|
|
Expect(response.Headers).To(BeNil())
|
|
})
|
|
})
|
|
|
|
Describe("RenameFile", func() {
|
|
It("No valid context", func() {
|
|
gatewaySelector.EXPECT().Next().Unset()
|
|
ctx := context.Background()
|
|
response, err := fc.RenameFile(ctx, "lockid", "newFile.doc")
|
|
Expect(err).To(HaveOccurred())
|
|
Expect(response).To(BeNil())
|
|
})
|
|
|
|
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)
|
|
|
|
response, err := fc.RenameFile(ctx, "lockid", "newFile.doc")
|
|
Expect(err).To(HaveOccurred())
|
|
Expect(err).To(Equal(targetErr))
|
|
Expect(response).To(BeNil())
|
|
})
|
|
|
|
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)
|
|
|
|
response, err := fc.RenameFile(ctx, "lockid", "newFile.doc")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(500))
|
|
Expect(response.Headers).To(BeNil())
|
|
Expect(response.Body).To(BeNil())
|
|
})
|
|
|
|
It("Rename failed", 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{
|
|
Lock: &providerv1beta1.Lock{
|
|
LockId: "zzz999",
|
|
Type: providerv1beta1.LockType_LOCK_TYPE_WRITE,
|
|
},
|
|
},
|
|
}, nil)
|
|
|
|
targetErr := errors.New("Something went wrong")
|
|
gatewayClient.On("Move", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.MoveResponse{
|
|
Status: status.NewInternal(ctx, "something failed"),
|
|
}, targetErr)
|
|
|
|
response, err := fc.RenameFile(ctx, "lockid", "newFile.doc")
|
|
Expect(err).To(HaveOccurred())
|
|
Expect(err).To(Equal(targetErr))
|
|
Expect(response).To(BeNil())
|
|
})
|
|
|
|
It("Rename failed status not ok", 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{
|
|
Lock: &providerv1beta1.Lock{
|
|
LockId: "zzz999",
|
|
Type: providerv1beta1.LockType_LOCK_TYPE_WRITE,
|
|
},
|
|
},
|
|
}, nil)
|
|
|
|
gatewayClient.On("Move", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.MoveResponse{
|
|
Status: status.NewInternal(ctx, "something failed"),
|
|
}, nil)
|
|
|
|
response, err := fc.RenameFile(ctx, "lockid", "newFile.doc")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(500))
|
|
Expect(response.Headers).To(BeNil())
|
|
Expect(response.Body).To(BeNil())
|
|
})
|
|
|
|
It("Rename conflict", 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{
|
|
Lock: &providerv1beta1.Lock{
|
|
LockId: "zzz999",
|
|
Type: providerv1beta1.LockType_LOCK_TYPE_WRITE,
|
|
},
|
|
},
|
|
}, nil)
|
|
|
|
gatewayClient.On("Move", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.MoveResponse{
|
|
Status: status.NewLocked(ctx, "lock mismatch"),
|
|
}, nil)
|
|
|
|
response, err := fc.RenameFile(ctx, "lockid", "newFile.doc")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(409))
|
|
Expect(response.Headers[connector.HeaderWopiLock]).To(Equal("zzz999"))
|
|
Expect(response.Body).To(BeNil())
|
|
})
|
|
|
|
It("Rename already exists", 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{
|
|
Lock: &providerv1beta1.Lock{
|
|
LockId: "zzz999",
|
|
Type: providerv1beta1.LockType_LOCK_TYPE_WRITE,
|
|
},
|
|
},
|
|
}, nil)
|
|
|
|
moveParamMatcher := mock.MatchedBy(func(moveReq *providerv1beta1.MoveRequest) bool {
|
|
if moveReq.Destination.Path == "./newFile.doc" &&
|
|
moveReq.LockId == "zzz999" {
|
|
return true
|
|
}
|
|
return false
|
|
})
|
|
gatewayClient.On("Move", mock.Anything, moveParamMatcher).Times(1).Return(&providerv1beta1.MoveResponse{
|
|
Status: status.NewAlreadyExists(ctx, nil, "target already exists"),
|
|
}, nil).Once()
|
|
|
|
move2ParamMatcher := mock.MatchedBy(func(moveReq *providerv1beta1.MoveRequest) bool {
|
|
r := regexp.MustCompile(`^\./[a-zA-Z0-9_-]+ newFile\.doc$`)
|
|
if r.MatchString(moveReq.Destination.Path) &&
|
|
moveReq.LockId == "zzz999" {
|
|
return true
|
|
}
|
|
return false
|
|
})
|
|
gatewayClient.On("Move", mock.Anything, move2ParamMatcher).Times(1).Return(&providerv1beta1.MoveResponse{
|
|
Status: status.NewOK(ctx),
|
|
}, nil).Once()
|
|
|
|
response, err := fc.RenameFile(ctx, "zzz999", "newFile.doc")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(200))
|
|
Expect(response.Headers).To(BeNil())
|
|
rBody := response.Body.(map[string]interface{})
|
|
Expect(rBody["Name"]).To(MatchRegexp(`^[a-zA-Z0-9_-]+ newFile$`))
|
|
})
|
|
|
|
It("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{
|
|
Lock: &providerv1beta1.Lock{
|
|
LockId: "zzz999",
|
|
Type: providerv1beta1.LockType_LOCK_TYPE_WRITE,
|
|
},
|
|
},
|
|
}, nil)
|
|
|
|
moveParamMatcher := mock.MatchedBy(func(moveReq *providerv1beta1.MoveRequest) bool {
|
|
if moveReq.Destination.Path == "./newFile.doc" &&
|
|
moveReq.LockId == "zzz999" {
|
|
return true
|
|
}
|
|
return false
|
|
})
|
|
gatewayClient.On("Move", mock.Anything, moveParamMatcher).Times(1).Return(&providerv1beta1.MoveResponse{
|
|
Status: status.NewOK(ctx),
|
|
}, nil).Once()
|
|
|
|
response, err := fc.RenameFile(ctx, "zzz999", "newFile.doc")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(200))
|
|
Expect(response.Headers).To(BeNil())
|
|
rBody := response.Body.(map[string]interface{})
|
|
Expect(rBody["Name"]).To(Equal("newFile"))
|
|
})
|
|
})
|
|
|
|
Describe("CheckFileInfo", func() {
|
|
It("No valid context", func() {
|
|
gatewaySelector.EXPECT().Next().Unset()
|
|
ctx := context.Background()
|
|
response, err := fc.CheckFileInfo(ctx)
|
|
Expect(err).To(HaveOccurred())
|
|
Expect(response).To(BeNil())
|
|
})
|
|
|
|
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)
|
|
|
|
response, err := fc.CheckFileInfo(ctx)
|
|
Expect(err).To(HaveOccurred())
|
|
Expect(err).To(Equal(targetErr))
|
|
Expect(response).To(BeNil())
|
|
})
|
|
|
|
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)
|
|
|
|
response, err := fc.CheckFileInfo(ctx)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(500))
|
|
Expect(response.Body).To(BeNil())
|
|
})
|
|
|
|
It("Stat fails status not found", func() {
|
|
ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
|
|
|
|
gatewayClient.On("Stat", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.StatResponse{
|
|
Status: status.NewNotFound(ctx, "something not found"),
|
|
}, nil)
|
|
|
|
response, err := fc.CheckFileInfo(ctx)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(404))
|
|
Expect(response.Body).To(BeNil())
|
|
})
|
|
|
|
It("Stat success", func() {
|
|
ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
|
|
u := &userv1beta1.User{
|
|
Id: &userv1beta1.UserId{
|
|
Idp: "customIdp",
|
|
OpaqueId: "admin",
|
|
},
|
|
DisplayName: "Pet Shaft",
|
|
}
|
|
ctx = ctxpkg.ContextSetUser(ctx, u)
|
|
|
|
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),
|
|
Nanos: uint32(123456789),
|
|
},
|
|
Path: "/path/to/test.txt",
|
|
Id: &providerv1beta1.ResourceId{
|
|
StorageId: "storageid",
|
|
OpaqueId: "opaqueid",
|
|
SpaceId: "spaceid",
|
|
},
|
|
ParentId: &providerv1beta1.ResourceId{
|
|
StorageId: "storageid",
|
|
OpaqueId: "parentopaqueid",
|
|
SpaceId: "spaceid",
|
|
},
|
|
},
|
|
}, nil)
|
|
|
|
expectedFileInfo := &fileinfo.Microsoft{
|
|
OwnerID: "61616262636340637573746f6d496470", // hex of aabbcc@customIdp
|
|
Size: int64(998877),
|
|
Version: "v16273849123456789",
|
|
LastModifiedTime: "1970-07-08T08:30:49.1234567Z",
|
|
BaseFileName: "test.txt",
|
|
BreadcrumbDocName: "test.txt",
|
|
BreadcrumbFolderName: "/path/to",
|
|
BreadcrumbFolderURL: "https://ocis.example.prv/f/storageid$spaceid%21parentopaqueid",
|
|
UserCanNotWriteRelative: false,
|
|
SupportsExtendedLockLength: true,
|
|
SupportsGetLock: true,
|
|
SupportsLocks: true,
|
|
SupportsUpdate: true,
|
|
SupportsDeleteFile: true,
|
|
SupportsRename: true,
|
|
UserCanWrite: true,
|
|
UserCanRename: true,
|
|
UserID: "61646d696e40637573746f6d496470", // hex of admin@customIdp
|
|
UserFriendlyName: "Pet Shaft",
|
|
FileSharingURL: "https://ocis.example.prv/f/storageid$spaceid%21opaqueid?details=sharing",
|
|
FileVersionURL: "https://ocis.example.prv/f/storageid$spaceid%21opaqueid?details=versions",
|
|
HostEditURL: "https://ocis.example.prv/external-test/path/to/test.txt?fileId=storageid%24spaceid%21opaqueid&view_mode=write",
|
|
HostViewURL: "https://ocis.example.prv/external-test/path/to/test.txt?fileId=storageid%24spaceid%21opaqueid&view_mode=view",
|
|
}
|
|
|
|
response, err := fc.CheckFileInfo(ctx)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(200))
|
|
Expect(response.Body.(*fileinfo.Microsoft)).To(Equal(expectedFileInfo))
|
|
})
|
|
|
|
It("Stat success guests", func() {
|
|
// add user's opaque to include public-share-role
|
|
u := &userv1beta1.User{}
|
|
u.Opaque = &typesv1beta1.Opaque{
|
|
Map: map[string]*typesv1beta1.OpaqueEntry{
|
|
"public-share-role": {
|
|
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)
|
|
ctx = ctxpkg.ContextSetUser(ctx, u)
|
|
|
|
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 is intentionally nil for guest users
|
|
Mtime: &typesv1beta1.Timestamp{
|
|
Seconds: uint64(16273849),
|
|
Nanos: uint32(1234567),
|
|
},
|
|
Path: "/path/to/test.txt",
|
|
Id: &providerv1beta1.ResourceId{
|
|
StorageId: "storageid",
|
|
OpaqueId: "opaqueid",
|
|
SpaceId: "spaceid",
|
|
},
|
|
ParentId: &providerv1beta1.ResourceId{
|
|
StorageId: "storageid",
|
|
OpaqueId: "parentopaqueid",
|
|
SpaceId: "spaceid",
|
|
},
|
|
// Other properties aren't used for now.
|
|
},
|
|
}, nil)
|
|
|
|
// change wopi app provider
|
|
cfg.App.Name = "Collabora"
|
|
cfg.App.Product = "Collabora"
|
|
|
|
expectedFileInfo := &fileinfo.Collabora{
|
|
OwnerID: "61616262636340637573746f6d496470", // hex of aabbcc@customIdp
|
|
Size: 0,
|
|
BaseFileName: "test.txt",
|
|
UserCanNotWriteRelative: false,
|
|
DisableExport: true,
|
|
DisableCopy: true,
|
|
DisablePrint: true,
|
|
UserID: "guest-zzz000",
|
|
UserFriendlyName: "guest zzz000",
|
|
EnableOwnerTermination: true,
|
|
SupportsLocks: true,
|
|
SupportsRename: true,
|
|
UserCanRename: false,
|
|
BreadcrumbDocName: "test.txt",
|
|
PostMessageOrigin: "https://ocis.example.prv",
|
|
}
|
|
|
|
response, err := fc.CheckFileInfo(ctx)
|
|
|
|
// UserID and UserFriendlyName have random Ids generated which are impossible to guess
|
|
// Check both separately
|
|
Expect(response.Body.(*fileinfo.Collabora).UserID).To(HavePrefix(hex.EncodeToString([]byte("guest-"))))
|
|
Expect(response.Body.(*fileinfo.Collabora).UserFriendlyName).To(HavePrefix("Guest "))
|
|
// overwrite UserID and UserFriendlyName here for easier matching
|
|
response.Body.(*fileinfo.Collabora).UserID = "guest-zzz000"
|
|
response.Body.(*fileinfo.Collabora).UserFriendlyName = "guest zzz000"
|
|
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(200))
|
|
Expect(response.Body.(*fileinfo.Collabora)).To(Equal(expectedFileInfo))
|
|
})
|
|
|
|
It("Stat success guests", func() {
|
|
ResourceId := &providerv1beta1.ResourceId{
|
|
StorageId: "storageid",
|
|
OpaqueId: "opaqueid",
|
|
SpaceId: "spaceid",
|
|
}
|
|
|
|
// add user's opaque to include public-share-role
|
|
u := &userv1beta1.User{}
|
|
u.Opaque = &typesv1beta1.Opaque{
|
|
Map: map[string]*typesv1beta1.OpaqueEntry{
|
|
"public-share-role": {
|
|
Decoder: "plain",
|
|
Value: []byte("viewer"),
|
|
},
|
|
},
|
|
}
|
|
// Create a new "scope share" to only expose the required fields `ResourceId` and `Token` to the scope.
|
|
scopeShare := &link.PublicShare{ResourceId: ResourceId, Token: "ABC123"}
|
|
val, err := utils.MarshalProtoV1ToJSON(scopeShare)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
scopes := map[string]*auth.Scope{
|
|
"publicshare:ABC123": {
|
|
Resource: &typesv1beta1.OpaqueEntry{
|
|
Decoder: "json",
|
|
Value: val,
|
|
},
|
|
Role: auth.Role(appproviderv1beta1.ViewMode_VIEW_MODE_VIEW_ONLY),
|
|
},
|
|
}
|
|
// change view mode to view only
|
|
wopiCtx.ViewMode = appproviderv1beta1.ViewMode_VIEW_MODE_VIEW_ONLY
|
|
|
|
ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
|
|
ctx = ctxpkg.ContextSetUser(ctx, u)
|
|
ctx = ctxpkg.ContextSetScopes(ctx, scopes)
|
|
|
|
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 is intentionally nil for guest users
|
|
Mtime: &typesv1beta1.Timestamp{
|
|
Seconds: uint64(16273849),
|
|
Nanos: uint32(123456789),
|
|
},
|
|
Path: "/path/to/test.txt",
|
|
Id: ResourceId,
|
|
ParentId: &providerv1beta1.ResourceId{
|
|
StorageId: "storageid",
|
|
OpaqueId: "parentopaqueid",
|
|
SpaceId: "spaceid",
|
|
},
|
|
// Other properties aren't used for now.
|
|
},
|
|
}, nil)
|
|
|
|
// change wopi app provider
|
|
cfg.App.Name = "OnlyOffice"
|
|
cfg.App.Product = "OnlyOffice"
|
|
|
|
expectedFileInfo := &fileinfo.OnlyOffice{
|
|
Version: "v16273849123456789",
|
|
LastModifiedTime: "1970-07-08T08:30:49.1234567Z",
|
|
BaseFileName: "test.txt",
|
|
BreadcrumbDocName: "test.txt",
|
|
BreadcrumbFolderName: "/path/to",
|
|
BreadcrumbFolderURL: "https://ocis.example.prv/s/ABC123", // Match share token format
|
|
DisablePrint: true,
|
|
UserCanNotWriteRelative: false,
|
|
SupportsLocks: true,
|
|
SupportsUpdate: true,
|
|
SupportsRename: true,
|
|
IsAnonymousUser: true,
|
|
UserCanRename: false,
|
|
UserCanReview: false,
|
|
UserCanWrite: false,
|
|
UserID: "guest-zzz000",
|
|
UserFriendlyName: "guest zzz000",
|
|
FileSharingURL: "https://ocis.example.prv/f/storageid$spaceid%21opaqueid?details=sharing",
|
|
FileVersionURL: "https://ocis.example.prv/f/storageid$spaceid%21opaqueid?details=versions",
|
|
HostEditURL: "https://ocis.example.prv/external-onlyoffice/path/to/test.txt?fileId=storageid%24spaceid%21opaqueid&view_mode=write",
|
|
PostMessageOrigin: "https://ocis.example.prv",
|
|
}
|
|
|
|
response, err := fc.CheckFileInfo(ctx)
|
|
|
|
// UserID and UserFriendlyName have random Ids generated which are impossible to guess
|
|
// Check both separately
|
|
Expect(response.Body.(*fileinfo.OnlyOffice).UserID).To(HavePrefix(hex.EncodeToString([]byte("guest-"))))
|
|
Expect(response.Body.(*fileinfo.OnlyOffice).UserFriendlyName).To(HavePrefix("Guest "))
|
|
// overwrite UserID and UserFriendlyName here for easier matching
|
|
response.Body.(*fileinfo.OnlyOffice).UserID = "guest-zzz000"
|
|
response.Body.(*fileinfo.OnlyOffice).UserFriendlyName = "guest zzz000"
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(200))
|
|
Expect(response.Body.(*fileinfo.OnlyOffice)).To(Equal(expectedFileInfo))
|
|
})
|
|
|
|
It("Stat success authenticated user", func() {
|
|
// change view mode to view only
|
|
wopiCtx.ViewMode = appproviderv1beta1.ViewMode_VIEW_MODE_VIEW_ONLY
|
|
|
|
ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
|
|
u := &userv1beta1.User{
|
|
Id: &userv1beta1.UserId{
|
|
Idp: "example.com",
|
|
OpaqueId: "aabbcc",
|
|
Type: userv1beta1.UserType_USER_TYPE_PRIMARY,
|
|
},
|
|
DisplayName: "Pet Shaft",
|
|
Mail: "shaft@example.com",
|
|
}
|
|
ctx = ctxpkg.ContextSetUser(ctx, u)
|
|
|
|
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",
|
|
Id: &providerv1beta1.ResourceId{
|
|
StorageId: "storageid",
|
|
OpaqueId: "opaqueid",
|
|
SpaceId: "spaceid",
|
|
},
|
|
ParentId: &providerv1beta1.ResourceId{
|
|
StorageId: "storageid",
|
|
OpaqueId: "parentopaqueid",
|
|
SpaceId: "spaceid",
|
|
},
|
|
},
|
|
}, nil)
|
|
|
|
// change wopi app provider
|
|
cfg.App.Name = "Collabora"
|
|
cfg.App.Product = "Collabora"
|
|
|
|
expectedFileInfo := &fileinfo.Collabora{
|
|
OwnerID: "61616262636340637573746f6d496470", // hex of aabbcc@customIdp
|
|
Size: int64(998877),
|
|
BaseFileName: "test.txt",
|
|
UserCanNotWriteRelative: false,
|
|
DisableExport: true,
|
|
DisableCopy: true,
|
|
DisablePrint: true,
|
|
UserID: hex.EncodeToString([]byte("aabbcc@example.com")),
|
|
UserFriendlyName: "Pet Shaft",
|
|
EnableOwnerTermination: true,
|
|
WatermarkText: "",
|
|
SupportsLocks: true,
|
|
SupportsRename: true,
|
|
UserCanRename: false,
|
|
BreadcrumbDocName: "test.txt",
|
|
PostMessageOrigin: "https://ocis.example.prv",
|
|
}
|
|
|
|
response, err := fc.CheckFileInfo(ctx)
|
|
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(200))
|
|
Expect(response.Body.(*fileinfo.Collabora)).To(Equal(expectedFileInfo))
|
|
})
|
|
It("Stat success secure view authenticated user", func() {
|
|
// change view mode to view only
|
|
wopiCtx.ViewMode = appproviderv1beta1.ViewMode_VIEW_MODE_VIEW_ONLY
|
|
wopiCtx.ViewOnlyToken = "ABC123"
|
|
|
|
ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
|
|
u := &userv1beta1.User{
|
|
Id: &userv1beta1.UserId{
|
|
Idp: "example.com",
|
|
OpaqueId: "aabbcc",
|
|
Type: userv1beta1.UserType_USER_TYPE_PRIMARY,
|
|
},
|
|
DisplayName: "Pet Shaft",
|
|
Mail: "shaft@example.com",
|
|
}
|
|
ctx = ctxpkg.ContextSetUser(ctx, u)
|
|
|
|
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",
|
|
Id: &providerv1beta1.ResourceId{
|
|
StorageId: "storageid",
|
|
OpaqueId: "opaqueid",
|
|
SpaceId: "spaceid",
|
|
},
|
|
ParentId: &providerv1beta1.ResourceId{
|
|
StorageId: "storageid",
|
|
OpaqueId: "parentopaqueid",
|
|
SpaceId: "spaceid",
|
|
},
|
|
},
|
|
}, nil)
|
|
|
|
// change wopi app provider
|
|
cfg.App.Name = "Collabora"
|
|
cfg.App.Product = "Collabora"
|
|
|
|
expectedFileInfo := &fileinfo.Collabora{
|
|
OwnerID: "61616262636340637573746f6d496470", // hex of aabbcc@customIdp
|
|
Size: int64(998877),
|
|
BaseFileName: "test.txt",
|
|
UserCanNotWriteRelative: false,
|
|
DisableExport: true,
|
|
DisableCopy: true,
|
|
DisablePrint: true,
|
|
UserID: hex.EncodeToString([]byte("aabbcc@example.com")),
|
|
UserFriendlyName: "Pet Shaft",
|
|
EnableOwnerTermination: true,
|
|
WatermarkText: "Pet Shaft shaft@example.com",
|
|
SupportsLocks: true,
|
|
SupportsRename: true,
|
|
UserCanRename: false,
|
|
BreadcrumbDocName: "test.txt",
|
|
PostMessageOrigin: "https://ocis.example.prv",
|
|
}
|
|
|
|
response, err := fc.CheckFileInfo(ctx)
|
|
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(200))
|
|
Expect(response.Body.(*fileinfo.Collabora)).To(Equal(expectedFileInfo))
|
|
})
|
|
It("Stat success with template", func() {
|
|
wopiCtx.TemplateReference = &providerv1beta1.Reference{
|
|
ResourceId: &providerv1beta1.ResourceId{
|
|
StorageId: "storageid",
|
|
OpaqueId: "opaqueid2",
|
|
SpaceId: "spaceid",
|
|
},
|
|
}
|
|
ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
|
|
u := &userv1beta1.User{
|
|
Id: &userv1beta1.UserId{
|
|
Idp: "customIdp",
|
|
OpaqueId: "admin",
|
|
},
|
|
DisplayName: "Pet Shaft",
|
|
}
|
|
ctx = ctxpkg.ContextSetUser(ctx, u)
|
|
|
|
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(0),
|
|
Mtime: &typesv1beta1.Timestamp{
|
|
Seconds: uint64(16273849),
|
|
},
|
|
Path: "/path/to/test.txt",
|
|
Id: &providerv1beta1.ResourceId{
|
|
StorageId: "storageid",
|
|
OpaqueId: "opaqueid",
|
|
SpaceId: "spaceid",
|
|
},
|
|
ParentId: &providerv1beta1.ResourceId{
|
|
StorageId: "storageid",
|
|
OpaqueId: "parentopaqueid",
|
|
SpaceId: "spaceid",
|
|
},
|
|
},
|
|
}, nil)
|
|
|
|
expectedFileInfo := &fileinfo.OnlyOffice{
|
|
Version: "v162738490",
|
|
LastModifiedTime: "1970-07-08T08:30:49.0000000Z",
|
|
BaseFileName: "test.txt",
|
|
BreadcrumbDocName: "test.txt",
|
|
BreadcrumbFolderName: "/path/to",
|
|
BreadcrumbFolderURL: "https://ocis.example.prv/f/storageid$spaceid%21parentopaqueid",
|
|
UserCanNotWriteRelative: false,
|
|
SupportsLocks: true,
|
|
SupportsUpdate: true,
|
|
SupportsRename: true,
|
|
UserCanWrite: true,
|
|
UserCanRename: true,
|
|
UserID: "61646d696e40637573746f6d496470", // hex of admin@customIdp
|
|
UserFriendlyName: "Pet Shaft",
|
|
FileSharingURL: "https://ocis.example.prv/f/storageid$spaceid%21opaqueid?details=sharing",
|
|
FileVersionURL: "https://ocis.example.prv/f/storageid$spaceid%21opaqueid?details=versions",
|
|
HostEditURL: "https://ocis.example.prv/external-onlyoffice/path/to/test.txt?fileId=storageid%24spaceid%21opaqueid&view_mode=write",
|
|
PostMessageOrigin: "https://ocis.example.prv",
|
|
TemplateSource: "", // Remove the hardcoded token since it's dynamically generated
|
|
}
|
|
|
|
// change wopi app provider
|
|
cfg.App.Name = "OnlyOffice"
|
|
cfg.App.Product = "OnlyOffice"
|
|
|
|
response, err := fc.CheckFileInfo(ctx)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(response.Status).To(Equal(200))
|
|
|
|
returnedFileInfo := response.Body.(*fileinfo.OnlyOffice)
|
|
templateSource := returnedFileInfo.TemplateSource
|
|
expectedTemplateSource := "https://ocis.server.prv/wopi/templates/a340d017568d0d579ee061a9ac02109e32fb07082d35c40aa175864303bd9107?access_token="
|
|
|
|
// take TemplateSource out of the response for easier comparison
|
|
returnedFileInfo.TemplateSource = ""
|
|
Expect(returnedFileInfo).To(Equal(expectedFileInfo))
|
|
// check if the template source is correct
|
|
// the url is using a generated access token which always has a new ttl
|
|
// so we can't compare the whole url
|
|
Expect(templateSource).To(HavePrefix(expectedTemplateSource))
|
|
})
|
|
|
|
})
|
|
})
|