Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

debug replay fork utility #122

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 15 additions & 6 deletions packages/transformer/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,35 @@
const itwinjsRecommended = require("@itwin/eslint-plugin/dist/configs/itwinjs-recommended");

/** @type {import("eslint").ESLint.ConfigData} */
module.exports = {
rules: {
"@itwin/no-internal": [
"warn",
{
tag: [
"internal"
]
}
"internal",
],
},
],
"@typescript-eslint/naming-convention": [
...itwinjsRecommended.rules["@typescript-eslint/naming-convention"],
{
selector: "objectLiteralProperty",
format: null,
leadingUnderscore: "allowSingleOrDouble"
leadingUnderscore: "allowSingleOrDouble",
},
]
],
},
"parserOptions": {
"project": "./tsconfig.json"
}
},
overrides: [
{
files: "",
rules: {
"@itwin/no-internal": ["off"],
},
},
],
};

Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@
*--------------------------------------------------------------------------------------------*/

import { assert, expect } from "chai";
import * as fs from "fs";
import * as path from "path";
import * as semver from "semver";
import {
BisCoreSchema, BriefcaseDb, BriefcaseManager, CategorySelector, DefinitionContainer, DefinitionModel, DefinitionPartition, deleteElementTree, DisplayStyle3d, Element, ElementOwnsChildElements, ElementOwnsExternalSourceAspects, ElementRefersToElements,
ExternalSourceAspect, GenericSchema, HubMock, IModelDb, IModelHost, IModelJsFs, IModelJsNative, ModelSelector, NativeLoggerCategory, PhysicalModel,
PhysicalObject, SnapshotDb, SpatialCategory, SpatialViewDefinition, Subject, SubjectOwnsPartitionElements,
PhysicalObject, SnapshotDb, SpatialCategory, SpatialViewDefinition, SQLiteDb, Subject, SubjectOwnsPartitionElements,
} from "@itwin/core-backend";

import * as TestUtils from "../TestUtils";
import { AccessToken, Guid, GuidString, Id64, Id64String, Logger, LogLevel } from "@itwin/core-bentley";
import { Code, ColorDef, DefinitionElementProps, ElementProps, ExternalSourceAspectProps, IModel, IModelVersion, InformationPartitionElementProps, ModelProps, SpatialViewDefinitionProps, SubCategoryAppearance } from "@itwin/core-common";
import { AccessToken, DbResult, Guid, GuidString, Id64, Id64String, Logger, LogLevel } from "@itwin/core-bentley";
import { BriefcaseIdValue, ChangesetFileProps, Code, ColorDef, DefinitionElementProps, ElementProps, ExternalSourceAspectProps, IModel, IModelVersion, InformationPartitionElementProps, ModelProps, SpatialViewDefinitionProps, SubCategoryAppearance } from "@itwin/core-common";
import { Point3d, YawPitchRollAngles } from "@itwin/core-geometry";
import { IModelExporter, IModelImporter, IModelTransformer, TransformerLoggerCategory } from "../../transformer";
import {
Expand Down Expand Up @@ -1040,5 +1041,113 @@ describe("IModelTransformerHub", () => {
await tearDown();
sinon.restore();
});

// unskip this and set the env vars "REMOTE_IMODEL_DIR" to a path and "FORK_CHANGESET_ID" to a
// changeset id, to locally test synchronizing an remote iModel to a fork
// You must have used some kind of imodel-downloader tool to have all changesets stored locally
it.only("should test transforming a remote iModel to local", async () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to change this to .skip, just keeping it as is for someone else who is using this branch

const forkChangesetId = process.env.FORK_CHANGESET_ID;
assert(forkChangesetId, "FORK_CHANGESET_ID env var not set");

const remoteIModelDir = process.env.REMOTE_IMODEL_DIR;
assert(remoteIModelDir, "This test requires the REMOTE_IMODEL_DIR env variable to be set");
assert(fs.existsSync(remoteIModelDir), "REMOTE_IMODEL_DIR points to a non existent path");
const dirContents = await fs.promises.readdir(remoteIModelDir);
assert(dirContents);

const seedFileName = dirContents.find((f) => f.endsWith(".bim"));
assert(seedFileName, "no seed file (.bim) in REMOTE_IMODEL_DIR");
const seedPath = path.join(remoteIModelDir, seedFileName);

const changesetsPath = path.join(remoteIModelDir, "changeSets");
assert(fs.existsSync(remoteIModelDir), "no changeSets directory in REMOTE_IMODEL_DIR");

const changesetsDataPath = path.join(remoteIModelDir, "changeSets.json");
const changesetsDataText = await fs.promises.readFile(changesetsDataPath, { encoding: "utf8" });
const changesetsData = JSON.parse(changesetsDataText) as ChangesetFileProps[];

let remoteITwinId!: string;

const seedRawDb = new SQLiteDb();
seedRawDb.withOpenDb({ dbName: seedPath }, () => {
remoteITwinId = seedRawDb.withSqliteStatement(
"SELECT Data FROM be_Prop WHERE Namespace='be_Db' AND Name='ProjectGuid'",
(stmt) => {
assert(stmt.step() === DbResult.BE_SQLITE_ROW, seedRawDb.nativeDb.getLastError());
return stmt.getValueGuid(0);
},
);
});
seedRawDb.closeDb();

let sourceIModelId: string | undefined;
let targetIModelId: string | undefined;
try {
sourceIModelId = await HubMock.createNewIModel({
iTwinId: remoteITwinId,
version0: seedPath,
iModelName: "remoteIModelMaster",
noLocks: true,
});

const modelHub = HubMock.findLocalHub(sourceIModelId);

changesetsData.forEach((changeset) => {
const pathname = path.resolve(changesetsPath, `${changeset.id}.cs`);
const briefcases = modelHub.getBriefcases();
const briefcaseExists = briefcases.some((b) => b.id === changeset.briefcaseId);
if (!briefcaseExists) {
const MAX_BRIEFCASES = Number(process.env.MAX_REMOTE_IMODEL_BRIEFCASES) || 1000;
for (let i = 0; i < MAX_BRIEFCASES; ++i) {
const newBriefcase = modelHub.acquireNewBriefcaseId("test");
if (newBriefcase >= changeset.briefcaseId)
break;
}
}
// NOTE: local download seems to be missing the "size" property
modelHub.addChangeset({ ...changeset, pathname });
});

// FIXME: technically don't need to open it at all, just download it
const forkPointDb = await HubWrappers.downloadAndOpenBriefcase({
accessToken,
iTwinId: remoteITwinId,
iModelId: sourceIModelId,
// FIXME: I want _exact_
asOf: { afterChangeSetId: forkChangesetId },
briefcaseId: BriefcaseIdValue.Unassigned,
});

targetIModelId = await IModelHost.hubAccess.createNewIModel({
iTwinId: remoteITwinId,
version0: forkPointDb.pathName,
iModelName: "amalgam-model",
noLocks: true,
});

const branchDb = await HubWrappers.downloadAndOpenBriefcase({ accessToken, iTwinId: remoteITwinId, iModelId: targetIModelId });

const forkInitializer = new IModelTransformer(forkPointDb, branchDb, { wasSourceIModelCopiedToTarget: true });
await forkInitializer.processAll();
forkInitializer.dispose();

const masterDb = await HubWrappers.downloadAndOpenBriefcase({
accessToken,
iTwinId: remoteITwinId,
iModelId: sourceIModelId,
//briefcaseId: BriefcaseIdValue.Unassigned,
});

const forwardSyncer = new IModelTransformer(masterDb, branchDb,);
await forwardSyncer.processChanges({ accessToken, startChangeset: { id: forkChangesetId } });

forkPointDb.close();
masterDb.close();
branchDb.close();
} finally {
sourceIModelId && await IModelHost.hubAccess.deleteIModel({ iTwinId: remoteITwinId, iModelId: sourceIModelId });
targetIModelId && await IModelHost.hubAccess.deleteIModel({ iTwinId: remoteITwinId, iModelId: targetIModelId });
}
});
});