UNPKG

@eclipse-emfcloud/modelserver-client

Version:

Typescript rest client to interact with an EMF.cloud modelserver

339 lines 19.9 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); /******************************************************************************** * Copyright (c) 2022 STMicroelectronics and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at * https://www.eclipse.org/legal/epl-2.0, or the MIT License which is * available at https://opensource.org/licenses/MIT. * * SPDX-License-Identifier: EPL-2.0 OR MIT *******************************************************************************/ const chai_1 = require("chai"); const fast_json_patch_1 = __importStar(require("fast-json-patch")); const urijs_1 = __importDefault(require("urijs")); const _1 = require("."); const model_server_client_api_v2_1 = require("./model-server-client-api-v2"); describe('Integration tests for ModelServerClientV2', () => { let client; const baseUrl = new urijs_1.default({ protocol: 'http', hostname: 'localhost', port: '8081', path: model_server_client_api_v2_1.ModelServerClientApiV2.API_ENDPOINT }); const testUndoRedo = async (modeluri, originalModel, patchedModel) => { // Expected: originalModel === undoModel === patchedUndoModel // Expected: patchedModel === redoModel === patchedRedoModel const undoPatch = await client.undo(modeluri); const undoModel = await client.get(modeluri, _1.ModelServerObjectV2.is); (0, chai_1.expect)(undoModel).to.deep.equal(originalModel); const patchedUndoModel = undoPatch.patchModel(patchedModel, true); (0, chai_1.expect)(patchedUndoModel).to.deep.equal(originalModel); const redoPatch = await client.redo(modeluri); const redoModel = await client.get(modeluri, _1.ModelServerObjectV2.is); (0, chai_1.expect)(redoModel).to.deep.equal(patchedModel); const patchedRedoModel = redoPatch.patchModel(patchedUndoModel, true); (0, chai_1.expect)(patchedRedoModel).to.deep.equal(patchedModel); // Restore initial state await client.undo(modeluri); }; beforeEach(() => { client = new _1.ModelServerClientV2(); client.initialize(baseUrl, 'json-v2'); }); describe('test requests', () => { it('edit with patch', async () => { const modeluri = new urijs_1.default('SuperBrewer3000.coffee'); const newName = 'Super Brewer 6000'; const machine = await client.get(modeluri, _1.ModelServerObjectV2.is); const patch = (0, _1.replace)(modeluri, machine, 'name', newName); await client.edit(modeluri, patch); const model = await client.get(modeluri); (0, chai_1.expect)(model.name).to.be.equal(newName); await testUndoRedo(modeluri, machine, model); }); it('create with patch', async () => { const modeluri = new urijs_1.default('SuperBrewer3000.coffee'); const originalModel = await client.get(modeluri, _1.ModelServerObjectV2.is); const newWorkflowName = 'New Test Workflow'; const initialWorkflowsCount = originalModel.workflows.length; const patch = (0, _1.create)(modeluri, originalModel, 'workflows', 'http://www.eclipsesource.com/modelserver/example/coffeemodel#//Workflow', { name: newWorkflowName }); await client.edit(modeluri, patch); const patchedModel = await client.get(modeluri); const workflows = patchedModel.workflows; (0, chai_1.expect)(workflows.length).to.be.equal(initialWorkflowsCount + 1); const newWorkflow = patchedModel.workflows[initialWorkflowsCount]; (0, chai_1.expect)(newWorkflow.name).to.be.equal(newWorkflowName); (0, chai_1.expect)(newWorkflow).to.have.property('$id'); (0, chai_1.expect)(newWorkflow.$id).to.be.a('string'); await testUndoRedo(modeluri, originalModel, patchedModel); }); it('add with patch', async () => { const modeluri = new urijs_1.default('SuperBrewer3000.coffee'); const initialModel = await client.get(modeluri, _1.ModelServerObjectV2.is); // Add a second workflow to the model; we'll use it to move a Task from a workflow to the other const createWorkflow = (0, _1.create)(modeluri, initialModel, 'workflows', 'http://www.eclipsesource.com/modelserver/example/coffeemodel#//Workflow', { name: 'New Workflow' }); await client.edit(modeluri, createWorkflow); const originalModel = await client.get(modeluri, _1.ModelServerObjectV2.is); const sourceWF = originalModel.workflows[0]; const targetWF = originalModel.workflows[1]; const patch = (0, _1.add)(modeluri, targetWF, 'nodes', sourceWF.nodes[0]); await client.edit(modeluri, patch); const patchedModel = await client.get(modeluri); const patchedSourceWF = patchedModel.workflows[0]; const patchedTargetWF = patchedModel.workflows[1]; (0, chai_1.expect)(patchedSourceWF.nodes).to.be.undefined; (0, chai_1.expect)(patchedTargetWF.nodes).to.be.an('array').of.length(1); (0, chai_1.expect)(patchedTargetWF.nodes[0].name).to.be.equal(sourceWF.nodes[0].name); // Node was moved await testUndoRedo(modeluri, originalModel, patchedModel); }); it('delete with patch - index based', async () => { const modeluri = new urijs_1.default('SuperBrewer3000.coffee'); const originalModel = await client.get(modeluri, _1.ModelServerObjectV2.is); const parentWorkflow = originalModel.workflows[0]; (0, chai_1.expect)(parentWorkflow.nodes).to.be.an('array').that.is.not.empty; const patch = (0, _1.removeValueAt)(modeluri, parentWorkflow, 'nodes', 0); await client.edit(modeluri, patch); const patchedModel = await client.get(modeluri); const patchedParentWorkflow = patchedModel.workflows[0]; (0, chai_1.expect)(patchedParentWorkflow.nodes).to.be.undefined; await testUndoRedo(modeluri, originalModel, patchedModel); }); it('delete with patch - object', async () => { const modeluri = new urijs_1.default('SuperBrewer3000.coffee'); const originalModel = await client.get(modeluri, _1.ModelServerObjectV2.is); const parentWorkflow = originalModel.workflows[0]; (0, chai_1.expect)(parentWorkflow.nodes).to.be.an('array').that.is.not.empty; const valueToRemove = parentWorkflow.nodes[0]; const patch = (0, _1.removeObject)(modeluri, valueToRemove); await client.edit(modeluri, patch); const patchedModel = await client.get(modeluri); const patchedParentWorkflow = patchedModel.workflows[0]; (0, chai_1.expect)(patchedParentWorkflow.nodes).to.be.undefined; await testUndoRedo(modeluri, originalModel, patchedModel); }); it('edit with command', async () => { const modeluri = new urijs_1.default('SuperBrewer3000.coffee'); const newName = 'Super Brewer 6000'; const originalModel = await client.get(modeluri, _1.ModelServerObjectV2.is); const owner = { eClass: originalModel.$type, $ref: urijs_1.default.build({ path: 'SuperBrewer3000.coffee', fragment: originalModel.$id }) }; const command = new _1.SetCommand(owner, 'name', [newName]); await client.edit(modeluri, command); const model = await client.get(modeluri); (0, chai_1.expect)(model.name).to.be.equal(newName); await testUndoRedo(modeluri, originalModel, model); }); it('incremental patch update', async () => { const modeluri = new urijs_1.default('SuperBrewer3000.coffee'); const newName = 'Super Brewer 6000'; const machine = await client.get(modeluri, _1.ModelServerObjectV2.is); const patch = (0, _1.replace)(modeluri, machine, 'name', newName); const updateResult = await client.edit(modeluri, patch); (0, chai_1.expect)(updateResult.success).to.be.true; (0, chai_1.expect)(updateResult.patchModel).to.not.be.undefined; (0, chai_1.expect)(updateResult.patch).to.not.be.undefined; // Patch a copy of the model (machine), to make sure the original model is // unchanged. We'll need it later to check undo/redo behavior. const patchedMachine = updateResult.patchModel(machine, true); (0, chai_1.expect)(patchedMachine.name).to.be.equal(newName); // Check that the incremental update is consistent with the server version of the model const newMachine = await client.get(modeluri, _1.ModelServerObjectV2.is); (0, chai_1.expect)(newMachine).to.deep.equal(patchedMachine); await testUndoRedo(modeluri, machine, patchedMachine); }); it('subscribe to changes', async () => { const modeluri = new urijs_1.default('SuperBrewer3000.coffee'); const newName = 'Super Brewer 6000'; const machine = await client.get(modeluri, _1.ModelServerObjectV2.is); const owner = { eClass: machine.$type, $ref: urijs_1.default.build({ path: 'SuperBrewer3000.coffee', fragment: machine.$id }) }; const command = new _1.SetCommand(owner, 'name', [newName]); const listener = {}; const patchNotification = new Promise((resolve, _rej) => { listener.onIncrementalUpdateV2 = resolve; }); const subscription = new Promise((resolve, _rej) => { listener.onSuccess = resolve; }); client.subscribe(modeluri, new _1.NotificationSubscriptionListenerV2(listener)); // Make sure the subscription is initialized before editing the model, // so that we don't miss the notification await subscription; await client.edit(modeluri, command); const notification = await patchNotification; const patch = notification.patch; (0, chai_1.expect)(notification.modeluri.toString()).to.be.equal(modeluri.toString()); (0, chai_1.expect)(patch.length).to.be.equal(1); const operation = patch[0]; (0, chai_1.expect)(_1.Operations.isReplace(operation, 'string')).to.be.equal(true); (0, chai_1.expect)(operation.path).to.be.equal('/name'); if (_1.Operations.isReplace(operation, 'string')) { (0, chai_1.expect)(operation.value).to.be.equal(newName); } await client.undo(modeluri); client.unsubscribe(modeluri); }); it('subscribe to incremental updates', async () => { const modeluri = new urijs_1.default('SuperBrewer3000.coffee'); const newName = 'Super Brewer 6000'; const machine = await client.get(modeluri, _1.ModelServerObjectV2.is); const owner = { eClass: machine.$type, $ref: urijs_1.default.build({ path: 'SuperBrewer3000.coffee', fragment: machine.$id }) }; const command = new _1.SetCommand(owner, 'name', [newName]); const listener = {}; const patchNotification = new Promise((resolve, _rej) => { listener.onIncrementalUpdateV2 = resolve; }); const subscription = new Promise((resolve, _rej) => { listener.onSuccess = resolve; }); client.subscribe(modeluri, new _1.NotificationSubscriptionListenerV2(listener)); // Make sure the subscription is initialized before editing the model, // so that we don't miss the notification await subscription; await client.edit(modeluri, command); const notification = await patchNotification; // Apply the incremental patch on the original model const incrementalPatchedModel = notification.patchModel(machine, true); // Retrieve the current model from the model server const patchedModel = await client.get(modeluri, _1.ModelServerObjectV2.is); // Check that the incrementally-patched model to be identical to the version // from the model server. (0, chai_1.expect)(incrementalPatchedModel).to.deep.equal(patchedModel); await client.undo(modeluri); client.unsubscribe(modeluri); }); it('pure Json Patch changes', async () => { const modeluri = new urijs_1.default('SuperBrewer3000.coffee'); const newName = 'Super Brewer 6000'; const machine = await client.get(modeluri, _1.ModelServerObjectV2.is); const patchedMachine = (0, fast_json_patch_1.deepClone)(machine); // Directly change the model patchedMachine.name = newName; patchedMachine.children[1].processor.clockSpeed = 6; // Generate patch by diffing the original model and the patched one const patch = fast_json_patch_1.default.compare(machine, patchedMachine); await client.edit(modeluri, patch); const model = await client.get(modeluri); (0, chai_1.expect)(model.name).to.be.equal(newName); (0, chai_1.expect)(model.children[1].processor.clockSpeed).to.be.equal(6); await testUndoRedo(modeluri, machine, model); }); it('clear list with "remove" patch operation', async () => { const modeluri = new urijs_1.default('SuperBrewer3000.coffee'); const machine = await client.get(modeluri, _1.ModelServerObjectV2.is); const initialWorkflowsSize = machine.workflows.length; (0, chai_1.expect)(initialWorkflowsSize).to.not.be.equal(0); const patch = [ { op: 'remove', path: '/workflows' } ]; await client.edit(modeluri, patch); const model = await client.get(modeluri); const newWorkflows = model.workflows; (0, chai_1.expect)(newWorkflows).to.be.undefined; await testUndoRedo(modeluri, machine, model); }); it('unset value with "remove" patch operation', async () => { const modeluri = new urijs_1.default('SuperBrewer3000.coffee'); const machine = await client.get(modeluri, _1.ModelServerObjectV2.is); const initialValue = machine.children[1].processor.thermalDesignPower; (0, chai_1.expect)(initialValue).to.not.be.oneOf([undefined, 0]); const patch = [ { op: 'remove', path: '/children/1/processor/thermalDesignPower' } ]; await client.edit(modeluri, patch); const model = await client.get(modeluri); const newValue = model.children[1].processor.thermalDesignPower; (0, chai_1.expect)(newValue).to.be.oneOf([undefined, 0]); // Should be === 0, but default values are not converted to Json at the moment; so we also expect 'undefined' await testUndoRedo(modeluri, machine, model); }); it('check all patch replies', async () => { const modeluri = new urijs_1.default('SuperBrewer3000.coffee'); const newName = 'Super Brewer 6000'; const machine = await client.get(modeluri, _1.ModelServerObjectV2.is); const patchedMachine = (0, fast_json_patch_1.deepClone)(machine); // Directly change the model patchedMachine.name = newName; patchedMachine.children[1].processor.clockSpeed = 6; // Generate patch by diffing the original model and the patched one const patch = fast_json_patch_1.default.compare(machine, patchedMachine); const result = await client.edit(modeluri, patch); (0, chai_1.expect)(result.success).to.be.true; (0, chai_1.expect)(result.patch).to.not.be.undefined; (0, chai_1.expect)(result.allPatches).to.not.be.undefined; (0, chai_1.expect)(result.allPatches).to.be.an('array').of.length(1); // Patch the main resource const updatedMachineMainPatch = result.patchModel(machine, true); (0, chai_1.expect)(patchedMachine).to.deep.equal(updatedMachineMainPatch); // Patch the first resource const updatedMachineFirstPatch = result.patchModel(machine, true, new urijs_1.default(result.allPatches[0].modelUri)); (0, chai_1.expect)(patchedMachine).to.deep.equal(updatedMachineFirstPatch); await testUndoRedo(modeluri, machine, updatedMachineFirstPatch); }); it('test model patches', async () => { const modeluri = new urijs_1.default('SuperBrewer3000.coffee'); const newName = 'Super Brewer 6000'; const machine = await client.get(modeluri, _1.ModelServerObjectV2.is); const patchedMachine = (0, fast_json_patch_1.deepClone)(machine); // Directly change the model patchedMachine.name = newName; patchedMachine.children[1].processor.clockSpeed = 6; // Generate patches by diffing the original model and the patched one const patch = fast_json_patch_1.default.compare(machine, patchedMachine); const result = await client.edit(modeluri, patch); (0, chai_1.expect)(result.success).to.be.true; (0, chai_1.expect)(result.patch).to.not.be.undefined; (0, chai_1.expect)(result.allPatches).to.not.be.undefined; (0, chai_1.expect)(result.allPatches).to.be.an('array').of.length(1); // Patch the main resource const updatedMachineMainPatch = result.patchModel(machine, true); (0, chai_1.expect)(patchedMachine).to.deep.equal(updatedMachineMainPatch); // Patch the first resource const updatedMachineFirstPatch = result.patchModel(machine, true, new urijs_1.default(result.allPatches[0].modelUri)); (0, chai_1.expect)(patchedMachine).to.deep.equal(updatedMachineFirstPatch); await testUndoRedo(modeluri, machine, updatedMachineFirstPatch); }); }); }); //# sourceMappingURL=model-server-client-v2-integration.spec.js.map