mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-20 16:07:11 +08:00
feat(ql3): establish 3.0 incubation baseline
This commit is contained in:
@@ -0,0 +1,226 @@
|
||||
const assert = require('node:assert/strict');
|
||||
const { test } = require('node:test');
|
||||
|
||||
const {
|
||||
createProjectToolDefinitionSnapshot,
|
||||
projectToolDefinitionSnapshotContribution,
|
||||
InvalidProjectToolDefinitionSnapshotError,
|
||||
ProjectToolDefinitionSnapshotConflictError,
|
||||
} = require('../../packages/ql3-runtime-core/dist/tool-execution/tool-registry/projectToolDefinitionSnapshot');
|
||||
const {
|
||||
createBuiltInTaskSpecSemanticRegistry,
|
||||
} = require('../../packages/ql3-runtime-core/dist/task-definition/taskSpecSemantic');
|
||||
const {
|
||||
activateInstall,
|
||||
pluginPackageTaskReconciliationFixture,
|
||||
} = require('./pluginPackageTaskReconciliationRepositoryContract.cjs');
|
||||
|
||||
function snapshotFor(value) {
|
||||
return createProjectToolDefinitionSnapshot({
|
||||
projectId: value.projectId,
|
||||
contributions: [
|
||||
projectToolDefinitionSnapshotContribution(value.revision, value.registry),
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
async function pendingProjectIds(repository) {
|
||||
const projects = [];
|
||||
let after;
|
||||
for (let pageNumber = 0; pageNumber < 8; pageNumber += 1) {
|
||||
const page = await repository.listPendingProjectPage({
|
||||
limit: 64,
|
||||
...(after ? { after } : {}),
|
||||
});
|
||||
projects.push(...page.projectIds);
|
||||
if (!page.truncated) return projects;
|
||||
after = page.next;
|
||||
}
|
||||
throw new Error('snapshot pending Project contract did not converge');
|
||||
}
|
||||
|
||||
function registerProjectToolDefinitionSnapshotRepositoryContract(options) {
|
||||
test(`${options.name}: publishes and exactly replays an empty active vector`, async (t) => {
|
||||
const projectId = `${options.namespace}-empty`;
|
||||
const registry = createBuiltInTaskSpecSemanticRegistry();
|
||||
const harness = await options.createRepository(t, { projectId, registry });
|
||||
t.after(() => harness.close?.());
|
||||
const snapshot = createProjectToolDefinitionSnapshot({
|
||||
projectId,
|
||||
contributions: [],
|
||||
});
|
||||
|
||||
assert.deepEqual(
|
||||
await harness.repository.listActiveSourcePage({
|
||||
projectId,
|
||||
limit: 1,
|
||||
}),
|
||||
{ sources: [], truncated: false },
|
||||
);
|
||||
assert.equal(
|
||||
(await pendingProjectIds(harness.repository)).includes(projectId),
|
||||
true,
|
||||
);
|
||||
assert.equal(await harness.repository.findCurrent(projectId), null);
|
||||
const created = await harness.repository.publish(snapshot);
|
||||
assert.equal(created.status, 'created');
|
||||
assert.deepEqual(created.record.snapshot, snapshot);
|
||||
assert.ok(Number.isSafeInteger(created.record.committedAtMs));
|
||||
const replay = await harness.repository.publish(snapshot);
|
||||
assert.equal(replay.status, 'existing');
|
||||
assert.deepEqual(replay.record, created.record);
|
||||
assert.deepEqual(
|
||||
await harness.repository.findCurrent(projectId),
|
||||
created.record,
|
||||
);
|
||||
assert.equal(
|
||||
(await pendingProjectIds(harness.repository)).includes(projectId),
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
test(`${options.name}: binds one active Package to its immutable revision`, async (t) => {
|
||||
const value = pluginPackageTaskReconciliationFixture(
|
||||
`${options.namespace}-active`,
|
||||
{ profile: options.profile },
|
||||
);
|
||||
const harness = await options.createRepository(t, value);
|
||||
t.after(() => harness.close?.());
|
||||
await activateInstall(harness.installRepository, value);
|
||||
await harness.materializedRepository.publish(value.revision);
|
||||
const snapshot = snapshotFor(value);
|
||||
|
||||
const sourcePage = await harness.repository.listActiveSourcePage({
|
||||
projectId: value.projectId,
|
||||
limit: 1,
|
||||
});
|
||||
assert.deepEqual(sourcePage, {
|
||||
sources: snapshot.sources,
|
||||
truncated: false,
|
||||
});
|
||||
assert.equal(
|
||||
(await pendingProjectIds(harness.repository)).includes(value.projectId),
|
||||
true,
|
||||
);
|
||||
const created = await harness.repository.publish(snapshot);
|
||||
assert.equal(created.status, 'created');
|
||||
assert.deepEqual(
|
||||
await harness.repository.findCurrent(value.projectId),
|
||||
created.record,
|
||||
);
|
||||
assert.deepEqual(created.record.snapshot.sources, [
|
||||
{
|
||||
installationId: value.install.active.installationId,
|
||||
packageName: value.packageName,
|
||||
generation: value.generation,
|
||||
generationDigest: value.revision.generation.generationDigest,
|
||||
lockDigest: value.lock.lockDigest,
|
||||
revisionDigest: value.revision.revisionDigest,
|
||||
},
|
||||
]);
|
||||
assert.equal(
|
||||
(await pendingProjectIds(harness.repository)).includes(value.projectId),
|
||||
false,
|
||||
);
|
||||
await options.assertDurableSource?.(harness, value, created.record);
|
||||
});
|
||||
|
||||
test(`${options.name}: keeps the old snapshot during staging and fails closed after activation`, async (t) => {
|
||||
const first = pluginPackageTaskReconciliationFixture(
|
||||
`${options.namespace}-upgrade`,
|
||||
{ profile: options.profile },
|
||||
);
|
||||
const harness = await options.createRepository(t, first);
|
||||
t.after(() => harness.close?.());
|
||||
await activateInstall(harness.installRepository, first);
|
||||
await harness.materializedRepository.publish(first.revision);
|
||||
const firstSnapshot = snapshotFor(first);
|
||||
const firstRecord = (await harness.repository.publish(firstSnapshot))
|
||||
.record;
|
||||
|
||||
const second = pluginPackageTaskReconciliationFixture(first.namespace, {
|
||||
profile: options.profile,
|
||||
previous: first,
|
||||
tasks: [['alpha', 'next']],
|
||||
});
|
||||
await harness.materializedRepository.publish(second.revision);
|
||||
await harness.installRepository.create(second.install.create);
|
||||
assert.deepEqual(
|
||||
await harness.repository.findCurrent(first.projectId),
|
||||
firstRecord,
|
||||
);
|
||||
await harness.installRepository.commit(second.install.commits[0]);
|
||||
await harness.installRepository.commit(second.install.commits[1]);
|
||||
assert.deepEqual(
|
||||
await harness.repository.findCurrent(first.projectId),
|
||||
firstRecord,
|
||||
);
|
||||
assert.deepEqual(
|
||||
(
|
||||
await harness.repository.listActiveSourcePage({
|
||||
projectId: first.projectId,
|
||||
limit: 1,
|
||||
})
|
||||
).sources,
|
||||
firstRecord.snapshot.sources,
|
||||
);
|
||||
await harness.installRepository.commit(second.install.commits[2]);
|
||||
|
||||
assert.equal(await harness.repository.findCurrent(first.projectId), null);
|
||||
assert.deepEqual(
|
||||
(
|
||||
await harness.repository.listActiveSourcePage({
|
||||
projectId: first.projectId,
|
||||
limit: 1,
|
||||
})
|
||||
).sources,
|
||||
secondSnapshotSources(second),
|
||||
);
|
||||
assert.equal(
|
||||
(await pendingProjectIds(harness.repository)).includes(first.projectId),
|
||||
true,
|
||||
);
|
||||
await assert.rejects(
|
||||
harness.repository.publish(firstSnapshot),
|
||||
ProjectToolDefinitionSnapshotConflictError,
|
||||
);
|
||||
|
||||
const secondSnapshot = snapshotFor(second);
|
||||
const secondRecord = (await harness.repository.publish(secondSnapshot))
|
||||
.record;
|
||||
assert.deepEqual(
|
||||
await harness.repository.findCurrent(first.projectId),
|
||||
secondRecord,
|
||||
);
|
||||
assert.notEqual(
|
||||
firstRecord.snapshot.activeVectorDigest,
|
||||
secondRecord.snapshot.activeVectorDigest,
|
||||
);
|
||||
assert.equal(
|
||||
(await pendingProjectIds(harness.repository)).includes(first.projectId),
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
test(`${options.name}: rejects invalid Project identity`, async (t) => {
|
||||
const projectId = `${options.namespace}-invalid`;
|
||||
const registry = createBuiltInTaskSpecSemanticRegistry();
|
||||
const harness = await options.createRepository(t, { projectId, registry });
|
||||
t.after(() => harness.close?.());
|
||||
await assert.rejects(
|
||||
Promise.resolve().then(() =>
|
||||
harness.repository.findCurrent('project\0invalid'),
|
||||
),
|
||||
InvalidProjectToolDefinitionSnapshotError,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function secondSnapshotSources(value) {
|
||||
return snapshotFor(value).sources;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
registerProjectToolDefinitionSnapshotRepositoryContract,
|
||||
projectToolDefinitionSnapshotForFixture: snapshotFor,
|
||||
};
|
||||
Reference in New Issue
Block a user