218 lines
16 KiB
TypeScript
218 lines
16 KiB
TypeScript
import { describe, expect, test } from 'bun:test';
|
|
import {
|
|
CAPABILITY_DEFINITIONS,
|
|
CAPABILITY_REQUIREMENTS,
|
|
ESI_ASSETS_SCOPE,
|
|
ESI_WALLET_SCOPE,
|
|
gateCapabilityWithAuthorization,
|
|
validateCapabilityScopes,
|
|
validateResourceCapabilityScopes,
|
|
validateConsentCallback,
|
|
validateDatasetJobFence,
|
|
validateCompleteReportPins,
|
|
validateInventoryCursorUse,
|
|
validateInventoryPageResult,
|
|
} from '../src/lib/domain/capabilities';
|
|
import { absentLocation, afterEndInventoryCursorState, afterEndInventoryResult, ambiguousType, appendDatasetState, authorization, borrowedInventoryCursorLookup, changedQueryInventoryCursorLookup, changedRevisionInventoryCursorLookup, consent, datasetState, inventoryCursor, inventoryCursorLookup, inventoryCursorState, inventoryQuery, inventoryResult, approvedMoneyPolicy, singletonRows, systemListedStationPlaceholder, syntheticResource, systemJob, verifiedNamelessStation, walletResult } from '../fixtures/contracts/t02';
|
|
|
|
describe('T02 typed contract fixtures', () => {
|
|
test('separates snapshot generations from append checkpoints and unknown upstream time', () => {
|
|
expect(datasetState.coverage).toEqual({ kind: 'snapshot', generation: 'assets-g7', complete: true });
|
|
expect(datasetState.fetchedAt).toBeGreaterThan(0);
|
|
expect(datasetState.upstreamEffectiveAt).toBeNull();
|
|
expect(appendDatasetState.coverage.kind).toBe('append');
|
|
if (appendDatasetState.coverage.kind === 'append') {
|
|
expect(appendDatasetState.coverage.checkpoint).toBe('journal-from-90000000000000001');
|
|
}
|
|
expect(typeof authorization.grantRevision).toBe('number');
|
|
expect(typeof authorization.credentialVersion).toBe('number');
|
|
});
|
|
|
|
test('binds consent to one session, capability, scopes and selected resources', () => {
|
|
expect(consent.state).toBe('pending');
|
|
expect(consent.sessionId).toBe('session-fixture-1');
|
|
expect(consent.resourceRequests[0]?.resource.authorizationRevision).toBe(7);
|
|
expect(consent.resourceRequests[0]?.requestedScopes).toEqual([ESI_ASSETS_SCOPE]);
|
|
});
|
|
|
|
test('keeps system job authority distinct from user resources', () => {
|
|
expect(systemJob.authority).toBe('system');
|
|
expect(systemJob.owner).toEqual({ kind: 'system', service: 'reference' });
|
|
expect(systemJob.publicationFence.resources).toHaveLength(0);
|
|
expect(validateDatasetJobFence(systemJob)).toEqual({ valid: true });
|
|
});
|
|
|
|
test('pins inventory cursors and reports to authorized resources and all matching rows', () => {
|
|
expect(inventoryQuery.cursor).toBe(inventoryCursor);
|
|
expect(inventoryCursorState.token).toBe(inventoryCursor.token);
|
|
expect(inventoryCursorState.status).toBe('active');
|
|
expect(inventoryCursorState.position).toEqual({ offset: 0, lastItemId: null });
|
|
expect(inventoryQuery.sort.tieBreaker).toBe('item_id');
|
|
expect(inventoryQuery.authorizationRevisions['character:90000000000000001']).toBe(7);
|
|
expect(inventoryCursorState.pin.callerUserId).toBe('fixture-user-a');
|
|
expect(validateInventoryCursorUse(inventoryCursorState, inventoryCursorLookup)).toEqual({ valid: true });
|
|
expect(validateInventoryCursorUse(inventoryCursorState, borrowedInventoryCursorLookup)).toEqual({ valid: false, reason: 'caller_mismatch' });
|
|
expect(validateInventoryCursorUse(inventoryCursorState, changedQueryInventoryCursorLookup)).toEqual({ valid: false, reason: 'query_mismatch' });
|
|
expect(validateInventoryCursorUse(inventoryCursorState, changedRevisionInventoryCursorLookup)).toEqual({ valid: false, reason: 'authorization_mismatch' });
|
|
expect(validateInventoryCursorUse(inventoryCursorState, { ...inventoryCursorLookup, selectedResources: [{ ...syntheticResource, principal: { kind: 'character', ownerUserId: 'fixture-user-b', id: syntheticResource.principal.id } }] })).toEqual({ valid: false, reason: 'resource_mismatch' });
|
|
expect(validateInventoryCursorUse(inventoryCursorState, { ...inventoryCursorLookup, selectedResources: [syntheticResource, syntheticResource] })).toEqual({ valid: false, reason: 'resource_mismatch' });
|
|
expect(validateInventoryCursorUse({ ...inventoryCursorState, position: { offset: -1, lastItemId: null } } as unknown as typeof inventoryCursorState, inventoryCursorLookup)).toEqual({ valid: false, reason: 'malformed_state' });
|
|
expect(validateInventoryCursorUse({ ...inventoryCursorState, position: { offset: 1, lastItemId: '01' } }, inventoryCursorLookup)).toEqual({ valid: false, reason: 'malformed_state' });
|
|
expect(validateInventoryCursorUse({ ...inventoryCursorState, position: { offset: 1, lastItemId: '1\n' } }, inventoryCursorLookup)).toEqual({ valid: false, reason: 'malformed_state' });
|
|
expect(validateInventoryCursorUse({ ...inventoryCursorState, status: 'unexpected' } as unknown as typeof inventoryCursorState, inventoryCursorLookup)).toEqual({ valid: false, reason: 'malformed_state' });
|
|
expect(inventoryCursorState.pin.authorizationEpochs['character:90000000000000001']).toBe(1);
|
|
expect(inventoryResult.status).toBe('ready');
|
|
if (inventoryResult.status === 'ready') {
|
|
expect(inventoryResult.summary.scope).toBe('all_matching_rows');
|
|
expect(inventoryResult.pageState).toBe('initial');
|
|
expect(inventoryResult.provenance.input.snapshotGenerations.assets).toBe('assets-g7');
|
|
expect(inventoryResult.provenance.input.referenceVersion).toBe('reference-g1');
|
|
expect(validateInventoryPageResult(inventoryResult)).toEqual({ valid: true });
|
|
expect(validateInventoryPageResult({ ...inventoryResult, pageState: 'unexpected' } as unknown as typeof inventoryResult)).toEqual({ valid: false, reason: 'invalid_page_state' });
|
|
expect(validateInventoryPageResult({ ...inventoryResult, status: 'unexpected' } as unknown as typeof inventoryResult)).toEqual({ valid: false, reason: 'invalid_page_state' });
|
|
expect(validateCompleteReportPins(inventoryResult.provenance.input)).toEqual({ valid: true });
|
|
expect(validateCompleteReportPins({ ...inventoryResult.provenance.input, selectedResources: [syntheticResource, syntheticResource] })).toEqual({ valid: false, reason: 'duplicate_resource' });
|
|
expect(validateCompleteReportPins({ ...inventoryResult.provenance.input, datasetPins: [inventoryResult.provenance.input.datasetPins[0]!, inventoryResult.provenance.input.datasetPins[0]!] })).toEqual({ valid: false, reason: 'duplicate_pin' });
|
|
expect(validateCompleteReportPins({ ...inventoryResult.provenance.input, datasetPins: [{ ...inventoryResult.provenance.input.datasetPins[0]!, authorizationRevision: 8 }] })).toEqual({ valid: false, reason: 'revision_mismatch' });
|
|
}
|
|
});
|
|
|
|
test('after-end pages keep all-matching summaries and terminate the cursor', () => {
|
|
expect(afterEndInventoryResult.status).toBe('ready');
|
|
if (afterEndInventoryResult.status === 'ready') {
|
|
expect(afterEndInventoryResult.pageState).toBe('after_end');
|
|
expect(afterEndInventoryResult.rows).toHaveLength(0);
|
|
expect(afterEndInventoryResult.summary.matchingRows).toBe(2);
|
|
expect(afterEndInventoryResult.nextCursor).toBeNull();
|
|
expect(afterEndInventoryCursorState.status).toBe('exhausted');
|
|
expect(afterEndInventoryCursorState.position.lastItemId).toBe('90000000000000042');
|
|
expect(validateInventoryPageResult(afterEndInventoryResult)).toEqual({ valid: true });
|
|
expect(validateInventoryPageResult({
|
|
status: 'ready', rows: [], summary: { matchingRows: 2, matchingQuantity: '0', estimatedValue: null, scope: 'all_matching_rows' },
|
|
nextCursor: null, pageState: 'initial', provenance: inventoryResult.provenance!,
|
|
} as unknown as Parameters<typeof validateInventoryPageResult>[0])).toEqual({ valid: false, reason: 'empty_page_summary' });
|
|
expect(validateInventoryPageResult({ ...afterEndInventoryResult, nextCursor: inventoryCursor } as unknown as typeof afterEndInventoryResult)).toEqual({ valid: false, reason: 'terminal_cursor' });
|
|
}
|
|
});
|
|
|
|
test('singleton facts preserve true, false and legacy unknown states', () => {
|
|
expect(singletonRows.map((row) => row.isSingleton)).toEqual([true, false, null]);
|
|
});
|
|
|
|
test('station evidence preserves verified, system-listed, and absent states', () => {
|
|
expect(verifiedNamelessStation.name).toBeNull();
|
|
expect(verifiedNamelessStation.evidence).toBe('verified');
|
|
expect(verifiedNamelessStation.sourceVerified).toBe(true);
|
|
expect(systemListedStationPlaceholder.evidence).toBe('system_listed');
|
|
expect(systemListedStationPlaceholder.sourceVerified).toBe(false);
|
|
expect(absentLocation.kind).toBe('unknown');
|
|
expect(absentLocation.sourceVerified).toBeNull();
|
|
expect(absentLocation.parentId).toBeNull();
|
|
});
|
|
|
|
test('ambiguous entity matches remain explicit instead of selecting by name', () => {
|
|
expect(ambiguousType.status).toBe('ambiguous');
|
|
if (ambiguousType.status === 'ambiguous') expect(ambiguousType.candidates).toHaveLength(2);
|
|
});
|
|
|
|
test('wallet is a separately labelled component and preserves signed cents', () => {
|
|
expect(walletResult.status).toBe('ready');
|
|
if (walletResult.status === 'ready') {
|
|
expect(walletResult.components[0]?.component).toBe('wallet_balance');
|
|
expect(walletResult.components[0]?.amount).toBe('-125');
|
|
expect(walletResult.components[0]?.credentialVersion).toBe(2);
|
|
expect(walletResult.provenance.input.datasetPins[0]?.dataset).toBe('wallet_balance');
|
|
}
|
|
});
|
|
|
|
test('capability metadata is allowlisted and wallet consent is opt-in', () => {
|
|
expect(CAPABILITY_REQUIREMENTS.wallet_balance).toEqual(['wallet_balance']);
|
|
expect(CAPABILITY_DEFINITIONS.wallet_balance.requiredScopes).toEqual([ESI_WALLET_SCOPE]);
|
|
expect(CAPABILITY_DEFINITIONS.inventory_query.requiredScopes).toEqual([ESI_ASSETS_SCOPE]);
|
|
expect(validateCapabilityScopes('wallet_balance', [ESI_WALLET_SCOPE]).valid).toBe(true);
|
|
expect(validateCapabilityScopes('wallet_balance', [ESI_WALLET_SCOPE, ESI_WALLET_SCOPE]).duplicateScopes).toEqual([ESI_WALLET_SCOPE]);
|
|
expect(validateCapabilityScopes('wallet_balance', []).missingScopes).toEqual([ESI_WALLET_SCOPE]);
|
|
expect(validateCapabilityScopes('wallet_balance', [ESI_WALLET_SCOPE, ESI_ASSETS_SCOPE], [ESI_ASSETS_SCOPE]).preservedScopes).toEqual([ESI_ASSETS_SCOPE]);
|
|
expect(validateResourceCapabilityScopes('wallet_balance', consent.resourceRequests[0]!).principal).toEqual(syntheticResource.principal);
|
|
expect(validateResourceCapabilityScopes('inventory_query', {
|
|
...consent.resourceRequests[0]!,
|
|
resource: { ...syntheticResource, requiredScopes: [ESI_WALLET_SCOPE] },
|
|
}).missingScopes).toEqual([ESI_WALLET_SCOPE]);
|
|
const accepted = {
|
|
status: 'accepted',
|
|
bindingId: consent.bindingId,
|
|
resourceGrants: [{
|
|
request: consent.resourceRequests[0]!,
|
|
grantedScopes: [ESI_ASSETS_SCOPE],
|
|
grantRevision: 7,
|
|
credentialVersion: 3,
|
|
authorizationEpoch: 1,
|
|
}],
|
|
} as const;
|
|
expect(validateConsentCallback(consent, accepted, 1_700_000_100_000)).toEqual({ valid: true });
|
|
expect(validateConsentCallback(consent, { ...accepted, resourceGrants: [{ ...accepted.resourceGrants[0]!, request: { ...accepted.resourceGrants[0]!.request, resource: { ...syntheticResource, principal: { ownerUserId: 'fixture-user-a', id: syntheticResource.principal.id, kind: 'character' } } } }] }, 1_700_000_100_000)).toEqual({ valid: true });
|
|
expect(validateConsentCallback(consent, {
|
|
...accepted,
|
|
resourceGrants: [{ ...accepted.resourceGrants[0]!, request: { ...accepted.resourceGrants[0]!.request, resource: { ...syntheticResource, principal: { kind: 'character', id: '90000000000000002', ownerUserId: 'fixture-user-a' } } } }],
|
|
}, 1_700_000_100_000)).toEqual({ valid: false, reason: 'resource_mismatch' });
|
|
expect(validateConsentCallback(consent, accepted, consent.expiresAt)).toEqual({ valid: false, reason: 'binding_mismatch' });
|
|
expect(validateConsentCallback(consent, { ...accepted, resourceGrants: [{ ...accepted.resourceGrants[0]!, grantRevision: Number.NaN }] }, 1_700_000_100_000)).toEqual({ valid: false, reason: 'revision_mismatch' });
|
|
expect(validateCapabilityScopes('wallet_balance', ['unallowlisted.scope']).valid).toBe(false);
|
|
expect(gateCapabilityWithAuthorization('wallet_balance', {
|
|
userId: 'fixture-user-a', resourceAuthorizations: [], selectedResources: [], datasets: [],
|
|
}).status).toBe('requirements_missing');
|
|
expect(gateCapabilityWithAuthorization('wallet_balance', {
|
|
userId: 'fixture-user-a', resourceAuthorizations: [{
|
|
...authorization, principal: { kind: 'corporation', id: '99000000000000001', ownerUserId: 'fixture-user-a' }, grantedScopes: [ESI_WALLET_SCOPE],
|
|
}], selectedResources: [{
|
|
principal: { kind: 'corporation', id: '99000000000000001', ownerUserId: 'fixture-user-a' },
|
|
requiredScopes: [ESI_WALLET_SCOPE], authorizationRevision: 1, authorizationEpoch: 1,
|
|
}], datasets: [],
|
|
}).status).toBe('requirements_missing');
|
|
expect(gateCapabilityWithAuthorization('inventory_query', {
|
|
userId: 'fixture-user-a', resourceAuthorizations: [authorization], selectedResources: [
|
|
{ principal: { kind: 'character', id: '90000000000000001', ownerUserId: 'fixture-user-a' }, requiredScopes: [ESI_ASSETS_SCOPE], authorizationRevision: 7, authorizationEpoch: 1 },
|
|
], datasets: [datasetState, { ...datasetState, principal: { kind: 'system', id: 'reference-public' }, dataset: 'reference_data' }],
|
|
}).status).toBe('available');
|
|
expect(gateCapabilityWithAuthorization('inventory_query', {
|
|
userId: 'fixture-user-a', resourceAuthorizations: [authorization], selectedResources: [syntheticResource], datasets: [
|
|
datasetState,
|
|
{ ...datasetState, dataset: 'reference_data' },
|
|
],
|
|
}).status).toBe('requirements_missing');
|
|
expect(gateCapabilityWithAuthorization('inventory_query', {
|
|
userId: 'fixture-user-a', resourceAuthorizations: [authorization], selectedResources: [syntheticResource], datasets: [
|
|
{ ...datasetState, authorizationEpoch: 2 },
|
|
{ ...datasetState, principal: { kind: 'system', id: 'reference-public' }, dataset: 'reference_data' },
|
|
],
|
|
}).status).toBe('requirements_missing');
|
|
expect(gateCapabilityWithAuthorization('inventory_query', {
|
|
userId: 'fixture-user-a', resourceAuthorizations: [authorization], selectedResources: [
|
|
syntheticResource,
|
|
{ principal: { kind: 'character', id: '90000000000000002', ownerUserId: 'fixture-user-a' }, requiredScopes: [ESI_ASSETS_SCOPE], authorizationRevision: 7, authorizationEpoch: 1 },
|
|
], datasets: [datasetState, { ...datasetState, principal: { kind: 'system', id: 'reference-public' }, dataset: 'reference_data' }],
|
|
}).status).toBe('requirements_missing');
|
|
expect(gateCapabilityWithAuthorization('inventory_query', {
|
|
userId: 'fixture-user-a', resourceAuthorizations: [
|
|
authorization,
|
|
{ ...authorization, principal: { kind: 'character', id: '90000000000000002', ownerUserId: 'fixture-user-a' }, grantedScopes: [] },
|
|
], selectedResources: [
|
|
syntheticResource,
|
|
{ principal: { kind: 'character', id: '90000000000000002', ownerUserId: 'fixture-user-a' }, requiredScopes: [ESI_ASSETS_SCOPE], authorizationRevision: 7, authorizationEpoch: 1 },
|
|
], datasets: [datasetState, { ...datasetState, principal: { kind: 'character', id: '90000000000000002', ownerUserId: 'fixture-user-a' }, dataset: 'assets' }, { ...datasetState, principal: { kind: 'system', id: 'reference-public' }, dataset: 'reference_data' }],
|
|
}).status).toBe('requirements_missing');
|
|
});
|
|
|
|
test('approved money policy fixes grammar, bounds and signed rounding', () => {
|
|
expect(approvedMoneyPolicy.input).toBe('decimal_text');
|
|
expect(approvedMoneyPolicy.rounding).toBe('half_away_from_zero');
|
|
expect(approvedMoneyPolicy.grammar).toBe('json_number_ascii_decimal');
|
|
expect(approvedMoneyPolicy.maxRawInputCharacters).toBe(8192);
|
|
expect(approvedMoneyPolicy.maxCoefficientDigits).toBe(4096);
|
|
expect(approvedMoneyPolicy.exponentRange).toEqual([-1000, 1000]);
|
|
expect(approvedMoneyPolicy.centsShiftRange).toEqual([-1000, 1000]);
|
|
expect(approvedMoneyPolicy.canonicalizeNegativeZero).toBe(true);
|
|
expect(authorization.staleAuthority.maximumWindowMs).toBeNull();
|
|
});
|
|
});
|