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,210 @@
|
||||
const assert = require('node:assert/strict');
|
||||
const { createHash } = require('node:crypto');
|
||||
const { test } = require('node:test');
|
||||
|
||||
const {
|
||||
InvalidPluginPackagePromptOutputKeyRetirementError,
|
||||
PluginPackagePromptOutputKeyRetirementConflictError,
|
||||
PluginPackagePromptOutputKeyRetirementCoordinator,
|
||||
PluginPackagePromptOutputKeyRetirementUnavailableError,
|
||||
createPluginPackagePromptOutputKeyRetirementCompletion,
|
||||
createPluginPackagePromptOutputKeyRetirementPreparation,
|
||||
normalizePluginPackagePromptOutputKeyRetirementCompletion,
|
||||
normalizePluginPackagePromptOutputKeyRetirementPreparation,
|
||||
pluginPackagePromptOutputKeyRetirementAbsenceProof,
|
||||
} = require('../dist/prompt-output/key-management/pluginPackagePromptOutputKeyRetirement.js');
|
||||
|
||||
const digest = (value) => createHash('sha256').update(value).digest('hex');
|
||||
|
||||
function request() {
|
||||
return {
|
||||
keyId: 'prompt-output-key-old',
|
||||
retirementId: 'retire-prompt-output-key-old',
|
||||
requestId: 'request-retire-prompt-output-key-old',
|
||||
mutationId: 'mutation-retire-prompt-output-key-old',
|
||||
};
|
||||
}
|
||||
|
||||
function harness(options = {}) {
|
||||
let record = null;
|
||||
let material = {
|
||||
state: options.materialState ?? 'inactive',
|
||||
keyId: request().keyId,
|
||||
catalogDigest: digest('catalog-before'),
|
||||
materialProof: digest('material-old'),
|
||||
};
|
||||
let retireCalls = 0;
|
||||
let failRetireResponse = options.failRetireResponse ?? false;
|
||||
let failCompleteResponse = options.failCompleteResponse ?? false;
|
||||
const repository = {
|
||||
async find() {
|
||||
return record;
|
||||
},
|
||||
async prepare(command) {
|
||||
if (options.liveArtifacts) {
|
||||
throw new PluginPackagePromptOutputKeyRetirementUnavailableError();
|
||||
}
|
||||
const preparation =
|
||||
createPluginPackagePromptOutputKeyRetirementPreparation({
|
||||
...command,
|
||||
preparedAtMs: 100,
|
||||
});
|
||||
if (record) {
|
||||
assert.deepEqual(record.preparation, preparation);
|
||||
return { status: 'existing', preparation: record.preparation };
|
||||
}
|
||||
record = { preparation, completion: null };
|
||||
return { status: 'created', preparation };
|
||||
},
|
||||
async complete(command) {
|
||||
const completion = createPluginPackagePromptOutputKeyRetirementCompletion(
|
||||
{
|
||||
...command,
|
||||
completedAtMs: 200,
|
||||
},
|
||||
);
|
||||
if (record.completion) {
|
||||
assert.deepEqual(record.completion, completion);
|
||||
return { status: 'existing', completion: record.completion };
|
||||
}
|
||||
record = { ...record, completion };
|
||||
if (failCompleteResponse) {
|
||||
failCompleteResponse = false;
|
||||
throw new Error('completion response lost');
|
||||
}
|
||||
return { status: 'created', completion };
|
||||
},
|
||||
};
|
||||
const materials = {
|
||||
async inspect() {
|
||||
return { ...material };
|
||||
},
|
||||
async retire(command) {
|
||||
retireCalls += 1;
|
||||
assert.equal(command.preparation.keyId, material.keyId);
|
||||
assert.equal(command.preparation.catalogDigest, material.catalogDigest);
|
||||
assert.equal(command.preparation.materialProof, material.materialProof);
|
||||
material = {
|
||||
state: 'absent',
|
||||
keyId: command.preparation.keyId,
|
||||
catalogDigest: digest('catalog-after'),
|
||||
absenceProof: pluginPackagePromptOutputKeyRetirementAbsenceProof(
|
||||
record.preparation,
|
||||
digest('catalog-after'),
|
||||
),
|
||||
};
|
||||
if (failRetireResponse) {
|
||||
failRetireResponse = false;
|
||||
throw new Error('retirement response lost');
|
||||
}
|
||||
return { ...material };
|
||||
},
|
||||
};
|
||||
return {
|
||||
coordinator: new PluginPackagePromptOutputKeyRetirementCoordinator({
|
||||
repository,
|
||||
materials,
|
||||
}),
|
||||
record: () => record,
|
||||
retireCalls: () => retireCalls,
|
||||
setMaterial(next) {
|
||||
material = next;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
test('normalizes exact content-free preparation and completion receipts', () => {
|
||||
const preparation = createPluginPackagePromptOutputKeyRetirementPreparation({
|
||||
...request(),
|
||||
catalogDigest: digest('catalog'),
|
||||
materialProof: digest('material'),
|
||||
preparedAtMs: 100,
|
||||
});
|
||||
const completion = createPluginPackagePromptOutputKeyRetirementCompletion({
|
||||
preparation,
|
||||
retiredCatalogDigest: digest('retired-catalog'),
|
||||
absenceProof: digest('absence'),
|
||||
completedAtMs: 200,
|
||||
});
|
||||
assert.deepEqual(
|
||||
normalizePluginPackagePromptOutputKeyRetirementPreparation(preparation),
|
||||
preparation,
|
||||
);
|
||||
assert.deepEqual(
|
||||
normalizePluginPackagePromptOutputKeyRetirementCompletion(completion),
|
||||
completion,
|
||||
);
|
||||
assert.throws(
|
||||
() =>
|
||||
normalizePluginPackagePromptOutputKeyRetirementPreparation({
|
||||
...preparation,
|
||||
widened: true,
|
||||
}),
|
||||
InvalidPluginPackagePromptOutputKeyRetirementError,
|
||||
);
|
||||
});
|
||||
|
||||
test('prepares a durable fence before retiring inactive material', async () => {
|
||||
const value = harness();
|
||||
const retired = await value.coordinator.retire(request());
|
||||
assert.equal(retired.status, 'completed');
|
||||
assert.equal(value.retireCalls(), 1);
|
||||
assert.deepEqual(value.record(), {
|
||||
preparation: retired.preparation,
|
||||
completion: retired.completion,
|
||||
});
|
||||
assert.equal((await value.coordinator.retire(request())).status, 'existing');
|
||||
assert.equal(value.retireCalls(), 1);
|
||||
});
|
||||
|
||||
test('rejects active material and live Artifact coverage', async () => {
|
||||
const active = harness({ materialState: 'active' });
|
||||
await assert.rejects(
|
||||
active.coordinator.retire(request()),
|
||||
PluginPackagePromptOutputKeyRetirementConflictError,
|
||||
);
|
||||
assert.equal(active.record(), null);
|
||||
const referenced = harness({ liveArtifacts: true });
|
||||
await assert.rejects(
|
||||
referenced.coordinator.retire(request()),
|
||||
PluginPackagePromptOutputKeyRetirementUnavailableError,
|
||||
);
|
||||
assert.equal(referenced.retireCalls(), 0);
|
||||
});
|
||||
|
||||
test('recovers when material retirement succeeded but its response was lost', async () => {
|
||||
const value = harness({ failRetireResponse: true });
|
||||
await assert.rejects(
|
||||
value.coordinator.retire(request()),
|
||||
PluginPackagePromptOutputKeyRetirementUnavailableError,
|
||||
);
|
||||
assert.equal(value.record().completion, null);
|
||||
const recovered = await value.coordinator.retire(request());
|
||||
assert.equal(recovered.status, 'completed');
|
||||
assert.equal(value.retireCalls(), 1);
|
||||
});
|
||||
|
||||
test('recovers completion response loss and rejects material drift', async () => {
|
||||
const responseLoss = harness({ failCompleteResponse: true });
|
||||
await assert.rejects(
|
||||
responseLoss.coordinator.retire(request()),
|
||||
PluginPackagePromptOutputKeyRetirementUnavailableError,
|
||||
);
|
||||
assert.equal(
|
||||
(await responseLoss.coordinator.retire(request())).status,
|
||||
'existing',
|
||||
);
|
||||
|
||||
const drift = harness({ failRetireResponse: true });
|
||||
await assert.rejects(drift.coordinator.retire(request()));
|
||||
drift.setMaterial({
|
||||
state: 'absent',
|
||||
keyId: request().keyId,
|
||||
catalogDigest: digest('drifted-catalog'),
|
||||
absenceProof: digest('drifted-absence'),
|
||||
});
|
||||
await assert.rejects(
|
||||
drift.coordinator.retire(request()),
|
||||
PluginPackagePromptOutputKeyRetirementConflictError,
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user