UNPKG

@itwin/core-backend

Version:
343 lines • 19.4 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ import { assert, expect } from "chai"; import { join } from "path"; import { Guid } from "@itwin/core-bentley"; import { ChangesetType, LockState } from "@itwin/core-common"; import { BriefcaseManager } from "../../BriefcaseManager"; import { IModelHost } from "../../IModelHost"; import { IModelJsFs } from "../../IModelJsFs"; import { HubMock } from "../../internal/HubMock"; import { IModelTestUtils } from "../IModelTestUtils"; import { KnownTestLocations } from "../KnownTestLocations"; import { ProgressStatus } from "../../CheckpointManager"; import { _hubAccess } from "../../internal/Symbols"; describe("HubMock", () => { const tmpDir = join(KnownTestLocations.outputDir, "HubMockTest"); const iTwinId = Guid.createValue(); const version0 = IModelTestUtils.resolveAssetFile("test.bim"); const accessToken = "fake token"; before(() => { HubMock.startup("HubMockTest", KnownTestLocations.outputDir); }); after(() => { HubMock.shutdown(); }); it("should be able to create HubMock", async () => { const iModelId = await IModelHost[_hubAccess].createNewIModel({ iTwinId, iModelName: "test imodel", version0 }); const localHub = HubMock.findLocalHub(iModelId); let checkpoints = localHub.getCheckpoints(); assert.equal(checkpoints.length, 1); assert.equal(checkpoints[0], 0); const cp1 = join(tmpDir, "cp-1.bim"); localHub.downloadCheckpoint({ changeset: { index: 0 }, targetFile: cp1 }); const stat1 = IModelJsFs.lstatSync(cp1); const statRev0 = IModelJsFs.lstatSync(version0); assert.equal(stat1?.size, statRev0?.size); assert.equal(2, localHub.acquireNewBriefcaseId("user1", "user1 briefcase 1")); assert.equal(3, localHub.acquireNewBriefcaseId("user2", "user2 briefcase 1")); assert.equal(4, localHub.acquireNewBriefcaseId("user3", "user3 briefcase 1")); let briefcases = localHub.getBriefcases(); assert.equal(briefcases.length, 3); assert.deepEqual(briefcases[0], { id: 2, user: "user1", alias: "user1 briefcase 1", assigned: true }); assert.deepEqual(briefcases[1], { id: 3, user: "user2", alias: "user2 briefcase 1", assigned: true }); assert.deepEqual(briefcases[2], { id: 4, user: "user3", alias: "user3 briefcase 1", assigned: true }); // releasing a briefcaseId should mark it as unassigned localHub.releaseBriefcaseId(2); briefcases = localHub.getBriefcases(false); assert.equal(briefcases.length, 3); assert.deepEqual(briefcases[0], { id: 2, user: "user1", alias: "user1 briefcase 1", assigned: false }); assert.deepEqual(briefcases[1], { id: 3, user: "user2", alias: "user2 briefcase 1", assigned: true }); assert.deepEqual(briefcases[2], { id: 4, user: "user3", alias: "user3 briefcase 1", assigned: true }); localHub.releaseBriefcaseId(4); briefcases = localHub.getBriefcases(); assert.equal(briefcases.length, 1); assert.deepEqual(briefcases[0], { id: 3, user: "user2", alias: "user2 briefcase 1", assigned: true }); assert.equal(5, localHub.acquireNewBriefcaseId("user4")); briefcases = localHub.getBriefcases(); assert.equal(briefcases.length, 2); assert.deepEqual(briefcases[0], { id: 3, user: "user2", alias: "user2 briefcase 1", assigned: true }); assert.deepEqual(briefcases[1], { id: 5, user: "user4", alias: "user4 (5)", assigned: true }); let pathname = IModelTestUtils.resolveAssetFile("CloneTest.01.00.00.ecschema.xml"); let fileSize = IModelJsFs.lstatSync(pathname).size; // try pushing changesets const cs1 = { id: "changeset0", description: "first changeset", changesType: ChangesetType.Regular, parentId: "", briefcaseId: 5, pushDate: "", index: 0, userCreated: "user1", pathname, size: fileSize, }; cs1.index = localHub.addChangeset(cs1); // first changeset const changesets1 = localHub.queryChangesets(); assert.equal(changesets1.length, 1); assert.equal(changesets1[0].id, cs1.id); assert.equal(changesets1[0].description, cs1.description); assert.equal(changesets1[0].changesType, cs1.changesType); assert.equal(changesets1[0].index, 1); assert.equal(changesets1[0].briefcaseId, 5); assert.isAtLeast(changesets1[0].size, 1); assert.equal(changesets1[0].parentId, ""); assert.isDefined(changesets1[0].pushDate); assert.equal(cs1.id, localHub.getLatestChangeset().id); pathname = IModelTestUtils.resolveAssetFile("CloneTest.01.00.01.ecschema.xml"); fileSize = IModelJsFs.lstatSync(pathname).size; const cs2 = { id: "changeset1", parentId: cs1.id, description: "second changeset", changesType: ChangesetType.Schema, briefcaseId: 5, pushDate: "", index: 0, userCreated: "user2", pathname: IModelTestUtils.resolveAssetFile("CloneTest.01.00.01.ecschema.xml"), size: fileSize, }; cs2.index = localHub.addChangeset(cs2); // second changeset, parent = cs1 const changesets2 = localHub.queryChangesets(); assert.equal(changesets2.length, 2); assert.deepEqual(changesets1[0], changesets2[0]); assert.equal(changesets2[1].id, cs2.id); assert.equal(changesets2[1].parentId, cs2.parentId); assert.equal(changesets2[1].description, cs2.description); assert.equal(changesets2[1].changesType, cs2.changesType); assert.equal(changesets2[1].index, 2); assert.equal(changesets2[1].briefcaseId, 5); assert.isAtLeast(changesets2[1].size, 1); assert.isDefined(changesets2[1].pushDate); assert.equal(cs2.id, localHub.getLatestChangeset().id); localHub.uploadCheckpoint({ changesetIndex: cs2.index, localFile: version0 }); checkpoints = localHub.getCheckpoints(); assert.equal(checkpoints.length, 2); assert.equal(checkpoints[1], 2); // test named versions const version1 = "release 1"; const version2 = "release 2"; localHub.addNamedVersion({ versionName: version1, csIndex: cs1.index }); localHub.addNamedVersion({ versionName: version2, csIndex: cs2.index }); assert.equal(localHub.findNamedVersion(version1).index, cs1.index); expect(() => localHub.findNamedVersion("not there")).throws("not found"); expect(() => localHub.addNamedVersion({ versionName: version2, csIndex: cs2.index })).throws("insert"); localHub.deleteNamedVersion(version1); expect(() => localHub.findNamedVersion(version1)).throws("not found"); // test for duplicate changeset id fails const cs3 = { id: "changeset0", parentId: "changeset1", description: "third changeset", changesType: ChangesetType.Regular, pathname: cs1.pathname, briefcaseId: 500, userCreated: "", pushDate: "", index: 0, size: fileSize, }; expect(() => localHub.addChangeset(cs3)).throws("no briefcase with that id"); cs3.briefcaseId = 5; expect(() => localHub.addChangeset(cs3)).throws("can't insert"); // now test for valid changeset id, but bad parentId const cs4 = { ...cs3, id: "changeset4", parentId: "bad", description: "fourth changeset" }; expect(() => localHub.addChangeset(cs4)).throws("bad not found"); cs3.id = "changeset3"; cs3.parentId = cs2.id; cs3.index = localHub.addChangeset(cs3); assert.equal(0, localHub.queryPreviousCheckpoint(0)); assert.equal(0, localHub.queryPreviousCheckpoint(cs1.index)); assert.equal(cs2.index, localHub.queryPreviousCheckpoint(cs2.index)); assert.equal(cs2.index, localHub.queryPreviousCheckpoint(cs3.index)); // downloading changesets const cSets = localHub.downloadChangesets({ range: { first: cs1.index, end: cs2.index }, targetDir: tmpDir }); assert.equal(cSets.length, 2); assert.equal(cSets[0].id, cs1.id); assert.equal(cSets[0].changesType, cs1.changesType); assert.equal(cSets[0].userCreated, cs1.userCreated); assert.equal(cSets[0].parentId, cs1.parentId); assert.equal(cSets[0].description, cs1.description); assert.equal(cSets[1].id, cs2.id); assert.equal(cSets[1].changesType, cs2.changesType); assert.equal(cSets[1].userCreated, cs2.userCreated); assert.equal(cSets[1].parentId, cs2.parentId); assert.equal(cSets[1].description, cs2.description); const orig1 = IModelJsFs.readFileSync(cs1.pathname); const downloaded1 = IModelJsFs.readFileSync(cSets[0].pathname); assert.deepEqual(orig1, downloaded1); const orig2 = IModelJsFs.readFileSync(cs2.pathname); const downloaded2 = IModelJsFs.readFileSync(cSets[1].pathname); assert.deepEqual(orig2, downloaded2); assert.notDeepEqual(orig1, orig2); const latest = await BriefcaseManager.getLatestChangeset({ iModelId }); expect(latest.index).to.equal(cs3.index); expect(latest.id).to.equal(cs3.id); expect(latest.parentId).to.equal(cs3.parentId); const cs1q = await BriefcaseManager.queryChangeset({ changeset: { index: cs1.index }, iModelId }); expect(cs1q.description).to.equal(cs1.description); const changes = await BriefcaseManager.queryChangesets({ range: { first: cs1.index }, iModelId }); expect(changes.length).to.equal(3); // test locks const lock1 = { state: LockState.Shared, id: "0x12", }; // get a new briefcaseId for some locks assert.equal(6, localHub.acquireNewBriefcaseId("user5", "alias for 5")); localHub.acquireLock(lock1, { briefcaseId: 3, changeset: cs1 }); assert.equal(localHub.countSharedLocks(), 1); assert.equal(localHub.countLocks(), 1); let lockStat = localHub.queryLockStatus(lock1.id); assert.equal(lockStat.state, LockState.Shared); assert.equal(lockStat.sharedBy.size, 1); assert.isTrue(lockStat.sharedBy.has(3)); assert.isUndefined(lockStat.lastCsIndex); localHub.acquireLock(lock1, { briefcaseId: 5, changeset: cs1 }); assert.equal(localHub.countSharedLocks(), 2); assert.equal(localHub.countLocks(), 1); lockStat = localHub.queryLockStatus(lock1.id); assert.equal(lockStat.sharedBy.size, 2); assert.isTrue(lockStat.sharedBy.has(3)); assert.isTrue(lockStat.sharedBy.has(5)); expect(() => localHub.acquireLock({ ...lock1, state: LockState.Exclusive }, { briefcaseId: 6, changeset: { id: "cs1" } })).to.throw("shared lock is held").include({ briefcaseId: 3, briefcaseAlias: "user2 briefcase 1" }); expect(() => localHub.releaseLocks([lock1], { briefcaseId: 9, changesetIndex: cs1.index })).to.throw("shared lock not held"); localHub.releaseLocks([lock1], { briefcaseId: 3, changesetIndex: cs1.index }); assert.equal(localHub.countSharedLocks(), 1); assert.equal(localHub.countLocks(), 1); lockStat = localHub.queryLockStatus(lock1.id); assert.equal(lockStat.sharedBy.size, 1); localHub.releaseLocks([lock1], { briefcaseId: 5, changesetIndex: cs1.index }); assert.equal(localHub.countSharedLocks(), 0); assert.equal(localHub.countLocks(), 1); lockStat = localHub.queryLockStatus(lock1.id); assert.equal(lockStat.state, LockState.None); lock1.state = LockState.Exclusive; localHub.acquireLock(lock1, { briefcaseId: 6, changeset: cs1 }); lockStat = localHub.queryLockStatus(lock1.id); assert.equal(lockStat.state, LockState.Exclusive); localHub.acquireLock(lock1, { briefcaseId: 6, changeset: cs1 }); assert.equal(localHub.countSharedLocks(), 0); assert.equal(localHub.countLocks(), 1); expect(() => localHub.acquireLock(lock1, { briefcaseId: 5, changeset: cs1 })).to.throw("exclusive lock is already held").include({ briefcaseId: 6, briefcaseAlias: "alias for 5" }); expect(() => localHub.acquireLock({ ...lock1, state: LockState.Shared }, { briefcaseId: 5, changeset: cs1 })).to.throw("exclusive lock is already held").include({ briefcaseId: 6, briefcaseAlias: "alias for 5" }); localHub.releaseLocks([lock1], { briefcaseId: 6, changesetIndex: cs2.index }); assert.equal(localHub.countLocks(), 1); lockStat = localHub.queryLockStatus(lock1.id); assert.equal(lockStat.state, LockState.None); assert.equal(lockStat.lastCsIndex, cs2.index); expect(() => localHub.acquireLock(lock1, { briefcaseId: 5, changeset: cs1 })).to.throw("pull is required"); localHub.acquireLock(lock1, { briefcaseId: 5, changeset: cs2 }); lockStat = localHub.queryLockStatus(lock1.id); assert.equal(lockStat.state, LockState.Exclusive); assert.equal(lockStat.briefcaseId, 5); assert.equal(lockStat.lastCsIndex, cs2.index); localHub.acquireLock({ state: LockState.Exclusive, id: "0x22" }, { briefcaseId: 5, changeset: cs1 }); lockStat = localHub.queryLockStatus("0x22"); assert.equal(lockStat.state, LockState.Exclusive); assert.equal(lockStat.briefcaseId, 5); assert.isUndefined(lockStat.lastCsIndex); localHub.acquireLock({ state: LockState.Exclusive, id: "0x23" }, { briefcaseId: 6, changeset: cs1 }); localHub.acquireLock({ state: LockState.Shared, id: "0x24" }, { briefcaseId: 6, changeset: cs1 }); localHub.acquireLock({ state: LockState.Shared, id: "0x24" }, { briefcaseId: 5, changeset: cs1 }); let locks = localHub.queryAllLocks(5); assert.equal(locks.length, 3); localHub.releaseBriefcaseId(5); // releasing a briefcaseId with held locks should release them lockStat = localHub.queryLockStatus("0x22"); locks = localHub.queryAllLocks(5); assert.equal(locks.length, 0); assert.equal(localHub.countSharedLocks(), 1); localHub.releaseAllLocks({ briefcaseId: 6, changesetIndex: 3 }); assert.equal(localHub.countSharedLocks(), 0); assert.equal(localHub.countLocks(), 4); lockStat = localHub.queryLockStatus("0x23"); assert.equal(lockStat.lastCsIndex, 3); assert.equal(lockStat.state, 0); lockStat = localHub.queryLockStatus("0x24"); assert.equal(lockStat.lastCsIndex, undefined); assert.equal(lockStat.state, 0); await IModelHost[_hubAccess].deleteIModel({ iTwinId, iModelId }); }); it("HubMock report progress of changesets 'downloads'", async () => { const iModelId = await IModelHost[_hubAccess].createNewIModel({ iTwinId, iModelName: "test imodel", version0 }); const localHub = HubMock.findLocalHub(iModelId); const briefcaseId = await HubMock.acquireNewBriefcaseId({ iModelId }); const pathname = IModelTestUtils.resolveAssetFile("CloneTest.01.00.00.ecschema.xml"); const fileSize = IModelJsFs.lstatSync(pathname).size; const cs1 = { id: "changeset0", description: "first changeset", changesType: ChangesetType.Regular, parentId: "", briefcaseId, pushDate: "", index: 0, size: fileSize, userCreated: "user1", pathname, }; const cs2 = { id: "changeset1", parentId: cs1.id, description: "second changeset", changesType: ChangesetType.Schema, briefcaseId, pushDate: "", index: 0, size: fileSize, userCreated: "user2", pathname: IModelTestUtils.resolveAssetFile("CloneTest.01.00.01.ecschema.xml"), }; cs1.index = localHub.addChangeset(cs1); cs2.index = localHub.addChangeset(cs2); // Progress reporting of single changeset "download" let progressReports = []; let progressCallback = (downloaded, total) => { progressReports.push({ downloaded, total }); return ProgressStatus.Continue; }; let cProps = await HubMock.downloadChangeset({ iModelId, changeset: { index: cs1.index, }, targetDir: tmpDir, progressCallback, }); let previousReport = { downloaded: 0, total: 0 }; for (const report of progressReports) { assert.isTrue(report.downloaded > previousReport.downloaded); assert.equal(report.total, cProps.size); } // Progress reporting of multiple changesets "download" progressReports = []; let cPropsSet = await HubMock.downloadChangesets({ iModelId, targetDir: tmpDir, progressCallback, }); previousReport = { downloaded: 0, total: 0 }; const totalSize = cPropsSet.reduce((sum, props) => sum + (props.size ?? 0), 0); for (const report of progressReports) { assert.isTrue(report.downloaded > previousReport.downloaded); assert.equal(report.total, totalSize); } // Cancel single changeset "download" progressReports = []; progressCallback = (downloaded, total) => { progressReports.push({ downloaded, total }); return downloaded > total / 2 ? ProgressStatus.Abort : ProgressStatus.Continue; }; let errorThrown = false; try { cProps = await HubMock.downloadChangeset({ iModelId, changeset: { index: cs1.index, }, targetDir: tmpDir, progressCallback, }); } catch { errorThrown = true; } assert.isTrue(errorThrown); let lastReport = progressReports[progressReports.length - 1]; assert.isBelow(lastReport.downloaded, lastReport.total); // Cancel multiple changesets "download" progressReports = []; errorThrown = false; try { cPropsSet = await HubMock.downloadChangesets({ iModelId, targetDir: tmpDir, progressCallback, }); } catch { errorThrown = true; } assert.isTrue(errorThrown); lastReport = progressReports[progressReports.length - 1]; assert.isBelow(lastReport.downloaded, lastReport.total); }); it("use HubMock with BriefcaseManager", async () => { const iModelId = await IModelHost[_hubAccess].createNewIModel({ iTwinId, iModelName: "test imodel", version0 }); const briefcase = await BriefcaseManager.downloadBriefcase({ accessToken, iTwinId, iModelId }); assert.equal(briefcase.briefcaseId, 2); assert.equal(briefcase.changeset.id, ""); assert.equal(briefcase.iModelId, iModelId); assert.equal(briefcase.iTwinId, iTwinId); await IModelHost[_hubAccess].deleteIModel({ iTwinId, iModelId }); }); }); //# sourceMappingURL=HubMock.test.js.map