UNPKG

@itwin/core-backend

Version:
233 lines • 12.9 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ import * as chai from "chai"; import * as chaiAsPromised from "chai-as-promised"; import { HubWrappers, IModelTestUtils, KnownTestLocations } from ".."; import { BriefcaseDb, BriefcaseManager, ChannelControl, Subject, SubjectOwnsSubjects } from "../../core-backend"; import { withEditTxn } from "../../EditTxn"; import { HubMock } from "../../internal/HubMock"; import { IModel, SchemaState } from "@itwin/core-common"; import { Guid } from "@itwin/core-bentley"; import { TestUtils } from "../TestUtils"; chai.use(chaiAsPromised); describe("apply changesets", function () { before(async () => { await TestUtils.startBackend(); }); it("Apply changeset with no local changes, should not create new local changes", async () => { HubMock.startup("PullMergeMethod", KnownTestLocations.outputDir); let b1; let b2; let b3; let iModelId; try { iModelId = await HubMock.createNewIModel({ accessToken: "user1", iTwinId: HubMock.iTwinId, iModelName: "Test", description: "TestSubject" }); b1 = await HubWrappers.downloadAndOpenBriefcase({ accessToken: "user1", iTwinId: HubMock.iTwinId, iModelId, noLock: true }); const b1Db = b1; withEditTxn(b1Db, "apply changeset b1", () => { b1Db.channels.addAllowedChannel(ChannelControl.sharedChannelName); }); b2 = await HubWrappers.downloadAndOpenBriefcase({ accessToken: "user2", iTwinId: HubMock.iTwinId, iModelId, noLock: true }); const b2Db = b2; withEditTxn(b2Db, "apply changeset b2", () => { b2Db.channels.addAllowedChannel(ChannelControl.sharedChannelName); }); b3 = await HubWrappers.downloadAndOpenBriefcase({ accessToken: "user2", iTwinId: HubMock.iTwinId, iModelId, noLock: true }); const b3Db = b3; withEditTxn(b3Db, "apply changeset b3", () => { b3Db.channels.addAllowedChannel(ChannelControl.sharedChannelName); }); const schema1 = `<?xml version="1.0" encoding="UTF-8"?> <ECSchema schemaName="TestDomain" alias="ts" version="01.00" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.1"> <ECSchemaReference name="BisCore" version="01.00" alias="bis"/> <ECEntityClass typeName="a1"> <BaseClass>bis:GraphicalElement2d</BaseClass> </ECEntityClass> <ECEntityClass typeName="b1"> <BaseClass>a1</BaseClass> </ECEntityClass> <ECEntityClass typeName="b2"> <BaseClass>a1</BaseClass> </ECEntityClass> <ECEntityClass typeName="c1"> <BaseClass>b1</BaseClass> </ECEntityClass> <ECEntityClass typeName="c2"> <BaseClass>b1</BaseClass> </ECEntityClass> <ECEntityClass typeName="d1"> <BaseClass>b2</BaseClass> </ECEntityClass> <ECEntityClass typeName="d2"> <BaseClass>b2</BaseClass> </ECEntityClass> <ECEntityClass typeName="f1"> <BaseClass>d1</BaseClass> </ECEntityClass> <ECEntityClass typeName="f2"> <BaseClass>d1</BaseClass> </ECEntityClass> <ECEntityClass typeName="e1"> <BaseClass>d2</BaseClass> </ECEntityClass> <ECEntityClass typeName="e2"> <BaseClass>d2</BaseClass> </ECEntityClass> </ECSchema>`; await b1.importSchemaStrings([schema1]); chai.expect(b1.txns.hasPendingTxns).to.be.true; await b1.pushChanges({ description: "schema1" }); chai.expect(b1.txns.hasPendingTxns).to.be.false; chai.expect(b2.txns.hasPendingTxns).to.be.false; await b2.pullChanges(); chai.expect(b2.txns.hasPendingTxns).to.be.false; const schema2 = `<?xml version="1.0" encoding="UTF-8"?> <ECSchema schemaName="TestDomain2" alias="ts1" version="01.00" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.1"> <ECSchemaReference name="BisCore" version="01.00" alias="bis"/> <ECEntityClass typeName="a1"> <BaseClass>bis:GraphicalElement2d</BaseClass> </ECEntityClass> <ECEntityClass typeName="b1"> <BaseClass>a1</BaseClass> </ECEntityClass> <ECEntityClass typeName="b2"> <BaseClass>a1</BaseClass> </ECEntityClass> <ECEntityClass typeName="c1"> <BaseClass>b1</BaseClass> </ECEntityClass> <ECEntityClass typeName="c2"> <BaseClass>b1</BaseClass> </ECEntityClass> <ECEntityClass typeName="d1"> <BaseClass>b2</BaseClass> </ECEntityClass> <ECEntityClass typeName="d2"> <BaseClass>b2</BaseClass> </ECEntityClass> <ECEntityClass typeName="f1"> <BaseClass>d1</BaseClass> </ECEntityClass> <ECEntityClass typeName="f2"> <BaseClass>d1</BaseClass> </ECEntityClass> <ECEntityClass typeName="e1"> <BaseClass>d2</BaseClass> </ECEntityClass> <ECEntityClass typeName="e2"> <BaseClass>d2</BaseClass> </ECEntityClass> </ECSchema>`; await b1.importSchemaStrings([schema2]); chai.expect(b1.txns.hasPendingTxns).to.be.true; await b1.pushChanges({ description: "schema2" }); chai.expect(b1.txns.hasPendingTxns).to.be.false; chai.expect(b2.txns.hasPendingTxns).to.be.false; await b2.pullChanges(); chai.expect(b2.txns.hasPendingTxns).to.be.false; chai.expect(b3.txns.hasPendingTxns).to.be.false; await b3.pullChanges(); chai.expect(b3.txns.hasPendingTxns).to.be.false; } finally { b1?.close(); b2?.close(); b3?.close(); if (iModelId) await HubMock.deleteIModel({ accessToken: "user1", iTwinId: HubMock.iTwinId, iModelId }).catch(() => { }); HubMock.shutdown(); } }); it("Pulling profile upgrade before inserting element should pass", async () => { // startup HubMock.startup("ProfileUpgradeBeforeInsertElement", KnownTestLocations.outputDir); let b1; let iModelId; try { const pathname = IModelTestUtils.resolveAssetFile("CompatibilityTestSeed.bim"); iModelId = await HubWrappers.pushIModel("user1", HubMock.iTwinId, pathname, "Test", true); // inserting and updating elements in one briefcase b1 = await HubWrappers.downloadAndOpenBriefcase({ accessToken: "user1", iTwinId: HubMock.iTwinId, iModelId }); const briefcase = b1; withEditTxn(briefcase, "profile upgrade before insert", () => { briefcase.channels.addAllowedChannel(ChannelControl.sharedChannelName); }); // upgrading schemas in second briefcase const props = await BriefcaseManager.downloadBriefcase({ accessToken: "user2", iTwinId: HubMock.iTwinId, iModelId }); const schemaState = BriefcaseDb.validateSchemas(props.fileName, true); chai.assert(schemaState === SchemaState.UpgradeRecommended); await BriefcaseDb.upgradeSchemas({ fileName: props.fileName }); await b1.pullChanges(); await b1.locks.acquireLocks({ shared: IModel.repositoryModelId, }); const subjectProps = { classFullName: Subject.classFullName, code: Subject.createCode(b1, IModel.rootSubjectId, "code value 1"), federationGuid: Guid.createValue(), model: IModel.repositoryModelId, parent: new SubjectOwnsSubjects(IModel.rootSubjectId), }; const subjectId = withEditTxn(b1, "Inserted Subject", (txn) => txn.insertElement(subjectProps)); await b1.pushChanges({ description: "Inserted Subject", retainLocks: true }); // FIXME: We should not need to reacquire this element lock, since we pushed with `retainLocks: true`. // See https://github.com/iTwin/itwinjs-core/issues/9302 await b1.locks.acquireLocks({ exclusive: subjectId, }); const existingCode = b1.elements.getElementProps(subjectId).code; withEditTxn(b1, "Updated Subject", (txn) => { txn.updateElement({ id: subjectId, code: { ...existingCode, value: "code value 2" }, }); }); await b1.pushChanges({ description: "Updated Subject" }); await b1.locks.releaseAllLocks(); } finally { if (b1) { await b1.locks.releaseAllLocks().catch(() => { }); b1.close(); } if (iModelId) await HubMock.deleteIModel({ accessToken: "user1", iTwinId: HubMock.iTwinId, iModelId }).catch(() => { }); HubMock.shutdown(); } }); it("Pulling profile upgrade after inserting element should pass", async () => { // startup HubMock.startup("ProfileUpgradeAfterInsertElement", KnownTestLocations.outputDir); let b1; let iModelId; try { const pathname = IModelTestUtils.resolveAssetFile("CompatibilityTestSeed.bim"); iModelId = await HubWrappers.pushIModel("user1", HubMock.iTwinId, pathname, "Test", true); // inserting and updating elements in one briefcase b1 = await HubWrappers.downloadAndOpenBriefcase({ accessToken: "user1", iTwinId: HubMock.iTwinId, iModelId }); const briefcase = b1; withEditTxn(briefcase, "profile upgrade after insert", () => { briefcase.channels.addAllowedChannel(ChannelControl.sharedChannelName); }); await b1.locks.acquireLocks({ shared: IModel.repositoryModelId, }); const subjectProps = { classFullName: Subject.classFullName, code: Subject.createCode(b1, IModel.rootSubjectId, "code value 1"), federationGuid: Guid.createValue(), model: IModel.repositoryModelId, parent: new SubjectOwnsSubjects(IModel.rootSubjectId), }; const subjectId = withEditTxn(b1, "Inserted Subject", (txn) => txn.insertElement(subjectProps)); await b1.pushChanges({ description: "Inserted Subject", retainLocks: true }); // FIXME: We should not need to reacquire this element lock, since we pushed with `retainLocks: true`. // See https://github.com/iTwin/itwinjs-core/issues/9302 await b1.locks.acquireLocks({ exclusive: subjectId, }); const existingCode = b1.elements.getElementProps(subjectId).code; withEditTxn(b1, "Updated Subject", (txn) => { txn.updateElement({ id: subjectId, code: { ...existingCode, value: "code value 2" }, }); }); await b1.pushChanges({ description: "Updated Subject" }); await b1.locks.releaseAllLocks(); // upgrading schemas in second briefcase const props = await BriefcaseManager.downloadBriefcase({ accessToken: "user2", iTwinId: HubMock.iTwinId, iModelId }); const schemaState = BriefcaseDb.validateSchemas(props.fileName, true); chai.assert(schemaState === SchemaState.UpgradeRecommended); await BriefcaseDb.upgradeSchemas({ fileName: props.fileName }); await b1.pullChanges(); await b1.locks.acquireLocks({ shared: IModel.repositoryModelId, }); const subjectProps2 = { classFullName: Subject.classFullName, code: Subject.createCode(b1, IModel.rootSubjectId, "code value 3"), federationGuid: Guid.createValue(), model: IModel.repositoryModelId, parent: new SubjectOwnsSubjects(IModel.rootSubjectId), }; withEditTxn(b1, "Inserted Subject 2", (txn) => { txn.insertElement(subjectProps2); }); await b1.pushChanges({ description: "Inserted Subject 2", retainLocks: true }); await b1.locks.releaseAllLocks(); } finally { if (b1) { await b1.locks.releaseAllLocks().catch(() => { }); b1.close(); } if (iModelId) await HubMock.deleteIModel({ accessToken: "user1", iTwinId: HubMock.iTwinId, iModelId }).catch(() => { }); HubMock.shutdown(); } }); }); //# sourceMappingURL=ApplyChangeset.test.js.map