From 5a6f3ae2a1c4886860585f67f7f0773ef7da8e85 Mon Sep 17 00:00:00 2001 From: hdphuong Date: Tue, 31 Jan 2023 13:46:53 +1100 Subject: [PATCH] go part cms-307 --- backend/editor/OT/operations/application.go | 2 +- .../editor/OT/operations/array_operation.go | 7 +++ .../editor/OT/operations/boolean_operation.go | 7 +++ .../editor/OT/operations/integer_operation.go | 7 +++ .../editor/OT/operations/noop_operation.go | 9 +++- .../editor/OT/operations/object_operation.go | 7 +++ .../editor/OT/operations/operation_model.go | 7 ++- .../editor/OT/operations/string_operation.go | 7 +++ backend/editor/OT/operations/transform.go | 4 +- backend/endpoints/tests/volume_test.go | 50 +++++++++++++++++++ 10 files changed, 99 insertions(+), 8 deletions(-) diff --git a/backend/editor/OT/operations/application.go b/backend/editor/OT/operations/application.go index abff6d84..4d06a82c 100644 --- a/backend/editor/OT/operations/application.go +++ b/backend/editor/OT/operations/application.go @@ -36,5 +36,5 @@ func (op Operation) ApplyTo(document cmsjson.AstNode) (cmsjson.AstNode, error) { } applicationIndex := op.Path[len(op.Path)-1] - return op.Operation.Apply(parent, applicationIndex, op.OperationType) + return op.Operation.Apply(parent, applicationIndex, op.Operation.GetEditType()) } diff --git a/backend/editor/OT/operations/array_operation.go b/backend/editor/OT/operations/array_operation.go index dcdb80a0..85271b9e 100644 --- a/backend/editor/OT/operations/array_operation.go +++ b/backend/editor/OT/operations/array_operation.go @@ -11,6 +11,7 @@ import ( // @implements OperationModel type ArrayOperation struct { NewValue float64 + operationType EditType } // TransformAgainst is the ArrayOperation implementation of the operationModel interface @@ -38,3 +39,9 @@ func (arrOp ArrayOperation) Apply(parentNode cmsjson.AstNode, applicationIndex i return nil, errors.New("invalid application of an array operation, expected parent node to be an array") } + +// getEditType is the ArrayOperation implementation of the OperationModel interface +func (arrOp ArrayOperation) GetEditType() EditType { + return arrOp.operationType +} + diff --git a/backend/editor/OT/operations/boolean_operation.go b/backend/editor/OT/operations/boolean_operation.go index 7224e0d0..b8040c3c 100644 --- a/backend/editor/OT/operations/boolean_operation.go +++ b/backend/editor/OT/operations/boolean_operation.go @@ -11,6 +11,7 @@ import ( // @implements OperationModel type BooleanOperation struct { NewValue bool + operationType EditType } // TransformAgainst is the BooleanOperation implementation of the operationModel interface @@ -31,3 +32,9 @@ func (boolOp BooleanOperation) Apply(parentNode cmsjson.AstNode, applicationInde } return nil, errors.New("invalid application of a primitive operation, expected parent node to be a primitive") } + +// getEditType is the BooleanOperation implementation of the OperationModel interface +func (boolOp BooleanOperation) GetEditType() EditType { + return boolOp.operationType +} + diff --git a/backend/editor/OT/operations/integer_operation.go b/backend/editor/OT/operations/integer_operation.go index 2699644a..7cdc03d4 100644 --- a/backend/editor/OT/operations/integer_operation.go +++ b/backend/editor/OT/operations/integer_operation.go @@ -11,6 +11,7 @@ import ( // @implementations of OperationModel type IntegerOperation struct { NewValue int + operationType EditType } // TransformAgainst is the IntegerOperation implementation of the operationModel interface @@ -31,3 +32,9 @@ func (intOp IntegerOperation) Apply(parentNode cmsjson.AstNode, applicationIndex } return nil, errors.New("invalid application of a primitive operation, expected parent node to be a primitive") } + +// getEditType is the IntegerOperation implementation of the OperationModel interface +func (intOp IntegerOperation) GetEditType() EditType { + return intOp.operationType +} + diff --git a/backend/editor/OT/operations/noop_operation.go b/backend/editor/OT/operations/noop_operation.go index 2a0cde82..ce49dace 100644 --- a/backend/editor/OT/operations/noop_operation.go +++ b/backend/editor/OT/operations/noop_operation.go @@ -4,7 +4,9 @@ import "cms.csesoc.unsw.edu.au/pkg/cmsjson" // Noop represents a non-existent operation // @implements OperationModel -type Noop struct{} +type Noop struct { + operationType EditType +} // TransformAgainst is the noop implementation of the operationModel interface func (noop Noop) TransformAgainst(operation OperationModel, applicationType EditType) (OperationModel, OperationModel) { @@ -15,3 +17,8 @@ func (noop Noop) TransformAgainst(operation OperationModel, applicationType Edit func (noop Noop) Apply(parentNode cmsjson.AstNode, applicationIndex int, applicationType EditType) (cmsjson.AstNode, error) { return parentNode, nil } + +// getEditType is the noop implementation of the OperationModel interface +func (noop Noop) GetEditType() EditType { + return noop.operationType +} diff --git a/backend/editor/OT/operations/object_operation.go b/backend/editor/OT/operations/object_operation.go index fd85c5c0..32bb683b 100644 --- a/backend/editor/OT/operations/object_operation.go +++ b/backend/editor/OT/operations/object_operation.go @@ -11,6 +11,7 @@ import ( // ObjectOperation represents an operation we perform on an object type ObjectOperation struct { NewValue datamodel.DataType + operationType EditType } // TransformAgainst is the ArrayOperation implementation of the operationModel interface @@ -37,3 +38,9 @@ func (objOp ObjectOperation) Apply(parentNode cmsjson.AstNode, applicationIndex } return nil, errors.New("invalid application of an object operation, expected parent node to be an object") } + +// getEditType is the ArrayOperation implementation of the OperationModel interface +func (objOp ObjectOperation) GetEditType() EditType { + return objOp.operationType +} + diff --git a/backend/editor/OT/operations/operation_model.go b/backend/editor/OT/operations/operation_model.go index 15d21090..f4b55eee 100644 --- a/backend/editor/OT/operations/operation_model.go +++ b/backend/editor/OT/operations/operation_model.go @@ -12,16 +12,15 @@ type ( OperationModel interface { TransformAgainst(op OperationModel, applicationType EditType) (OperationModel, OperationModel) Apply(parentNode cmsjson.AstNode, applicationIndex int, applicationType EditType) (cmsjson.AstNode, error) + GetEditType() EditType } // Operation is the fundamental incoming type from the frontend Operation struct { Path []int - OperationType EditType AcknowledgedServerOps int - - IsNoOp bool - Operation OperationModel + IsNoOp bool + Operation OperationModel } ) diff --git a/backend/editor/OT/operations/string_operation.go b/backend/editor/OT/operations/string_operation.go index 02997645..5bd07c52 100644 --- a/backend/editor/OT/operations/string_operation.go +++ b/backend/editor/OT/operations/string_operation.go @@ -12,6 +12,7 @@ import ( type StringOperation struct { RangeStart, RangeEnd int NewValue string + operationType EditType } // If NewValue == "", delete every character between RangeStart and RangeEnd @@ -139,3 +140,9 @@ func deleteDelete(o1 StringOperation, o2 StringOperation, isLast bool) StringOpe } return o1 } + +// getEditType is the ArrayOperation implementation of the OperationModel interface +func (arrOp StringOperation) GetEditType() EditType { + return arrOp.operationType +} + diff --git a/backend/editor/OT/operations/transform.go b/backend/editor/OT/operations/transform.go index 9c824384..624f265b 100644 --- a/backend/editor/OT/operations/transform.go +++ b/backend/editor/OT/operations/transform.go @@ -5,11 +5,11 @@ package operations func TransformPipeline(x Operation, y Operation) (Operation, Operation) { // Finally normalise the operations to account for no-op return values needsAppSpecific := false - x.Path, y.Path, needsAppSpecific = transformPaths(x.Path, y.Path, x.OperationType, y.OperationType) + x.Path, y.Path, needsAppSpecific = transformPaths(x.Path, y.Path, x.Operation.GetEditType(), y.Operation.GetEditType()) x, y = normaliseOperation(x), normaliseOperation(y) if needsAppSpecific { - x.Operation.TransformAgainst(y.Operation, x.OperationType) + x.Operation.TransformAgainst(y.Operation, x.Operation.GetEditType()) } return x, y diff --git a/backend/endpoints/tests/volume_test.go b/backend/endpoints/tests/volume_test.go index a2d86482..b3042155 100644 --- a/backend/endpoints/tests/volume_test.go +++ b/backend/endpoints/tests/volume_test.go @@ -16,6 +16,56 @@ import ( ) func TestUploadDocument(t *testing.T) { + controller := gomock.NewController(t) + assert := assert.New(t) + defer controller.Finish() + + // ==== test setup ===== + entityID := uuid.New() + parentID := uuid.New() + entityToCreate := repositories.FilesystemEntry{ + LogicalName: "file", + ParentFileID: parentID, + IsDocument: true, + OwnerUserId: 1, + } + + mockFileRepo := repMocks.NewMockIFilesystemRepository(controller) + mockFileRepo.EXPECT().CreateEntry(entityToCreate).Return(repositories.FilesystemEntry{ + EntityID: entityID, + LogicalName: "file", + ParentFileID: parentID, + IsDocument: true, + OwnerUserId: 1, + }, nil).Times(1) + + temp, _ := ioutil.TempFile(os.TempDir(), "expected") + defer os.Remove(temp.Name()) + + mockDockerFileSystemRepo := repMocks.NewMockIUnpublishedVolumeRepository(controller) + mockDockerFileSystemRepo.EXPECT().GetFromVolume(entityID.String()).Return(temp, nil).Times(1) + + mockDepFactory := createMockDependencyFactory(controller, mockFileRepo, true) + mockDepFactory.EXPECT().GetUnpublishedVolumeRepo().Return(mockDockerFileSystemRepo) + + const fileContent = "Hello World" + + form := models.ValidDocumentUploadRequest{ + Parent: parentID, + DocumentName: "file", + Content: fileContent, + } + + response := endpoints.UploadDocument(form, mockDepFactory) + assert.Equal(response.Status, http.StatusOK) + assert.Equal(response.Response, models.NewEntityResponse{ + NewID: entityID, + }) + + // check that the file was written to the docker volume + actual, _ := ioutil.ReadFile(temp.Name()) + assert.Equal(actual, []byte(fileContent)) + } func TestGetPublishedDocument(t *testing.T) {