@distrohelena/canton-typescript-sdk 0.1.5 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +333 -1
- package/dist/client/canton-client-options.d.ts +3 -0
- package/dist/client/canton-client-options.js +2 -0
- package/dist/client/service-registry.js +3 -2
- package/dist/core/errors/grpc-transport-error.d.ts +14 -0
- package/dist/core/errors/grpc-transport-error.js +76 -0
- package/dist/core/types/canton-hash-purpose.d.ts +2 -1
- package/dist/core/types/canton-hash-purpose.js +1 -0
- package/dist/core/types/daml-numeric.d.ts +6 -0
- package/dist/core/types/daml-numeric.js +14 -0
- package/dist/core/types/daml-party.d.ts +6 -0
- package/dist/core/types/daml-party.js +14 -0
- package/dist/core/types/requests/create-decentralized-party-request.d.ts +41 -0
- package/dist/core/types/requests/create-decentralized-party-request.js +82 -0
- package/dist/core/types/requests/create-external-party-request.d.ts +42 -0
- package/dist/core/types/requests/create-external-party-request.js +47 -0
- package/dist/core/types/requests/finalize-decentralized-party-request.d.ts +39 -0
- package/dist/core/types/requests/finalize-decentralized-party-request.js +42 -0
- package/dist/core/types/requests/get-active-contracts-page-request.d.ts +15 -2
- package/dist/core/types/requests/get-active-contracts-page-request.js +4 -0
- package/dist/core/types/topology/topology-signature-format.d.ts +2 -1
- package/dist/core/types/topology/topology-signature-format.js +1 -0
- package/dist/daml-lf/container/dar-archive-entry.d.ts +8 -0
- package/dist/daml-lf/container/dar-archive-entry.js +8 -0
- package/dist/daml-lf/container/dar-archive-loader.js +14 -0
- package/dist/daml-lf/container/dar-archive.d.ts +6 -0
- package/dist/daml-lf/container/dar-archive.js +4 -0
- package/dist/daml-lf/container/dar-source-bundle-loader.d.ts +5 -0
- package/dist/daml-lf/container/dar-source-bundle-loader.js +33 -0
- package/dist/daml-lf/container/dar-source-bundle.d.ts +45 -0
- package/dist/daml-lf/container/dar-source-bundle.js +11 -0
- package/dist/daml-lf/container/dar-source-file-entry.d.ts +8 -0
- package/dist/daml-lf/container/dar-source-file-entry.js +8 -0
- package/dist/daml-lf/daml-lf-compilation.d.ts +12 -0
- package/dist/daml-lf/daml-lf-compilation.js +35 -0
- package/dist/daml-lf/index.d.ts +11 -0
- package/dist/daml-lf/index.js +10 -0
- package/dist/daml-lf/interpreter/daml-lf-builtin-dispatch.d.ts +43 -0
- package/dist/daml-lf/interpreter/daml-lf-builtin-dispatch.js +933 -0
- package/dist/daml-lf/interpreter/daml-lf-evaluator.d.ts +95 -0
- package/dist/daml-lf/interpreter/daml-lf-evaluator.js +1131 -0
- package/dist/daml-lf/interpreter/daml-lf-interpreter-scaffold.d.ts +3 -0
- package/dist/daml-lf/interpreter/daml-lf-interpreter-scaffold.js +6 -1
- package/dist/daml-lf/interpreter/daml-lf-lexical-scope.d.ts +13 -0
- package/dist/daml-lf/interpreter/daml-lf-lexical-scope.js +46 -0
- package/dist/daml-lf/interpreter/daml-lf-runtime-frame.d.ts +16 -0
- package/dist/daml-lf/interpreter/daml-lf-runtime-frame.js +15 -0
- package/dist/daml-lf/interpreter/daml-lf-runtime-value.d.ts +21 -0
- package/dist/daml-lf/interpreter/daml-lf-runtime-value.js +4 -1
- package/dist/daml-lf/interpreter/daml-lf-step-kind.d.ts +7 -0
- package/dist/daml-lf/interpreter/daml-lf-step-kind.js +8 -0
- package/dist/daml-lf/interpreter/daml-lf-trace-sink.interface.d.ts +30 -0
- package/dist/daml-lf/interpreter/daml-lf-trace-sink.interface.js +1 -0
- package/dist/daml-lf/model/daml-lf-builtin-type.d.ts +3 -0
- package/dist/daml-lf/model/daml-lf-builtin-type.js +3 -0
- package/dist/daml-lf/model/daml-lf-choice.d.ts +5 -0
- package/dist/daml-lf/model/daml-lf-choice.js +4 -0
- package/dist/daml-lf/model/daml-lf-expression-path.d.ts +2 -0
- package/dist/daml-lf/model/daml-lf-expression-path.js +81 -0
- package/dist/daml-lf/model/daml-lf-expression.d.ts +146 -0
- package/dist/daml-lf/model/daml-lf-expression.js +71 -0
- package/dist/daml-lf/model/daml-lf-template.d.ts +2 -0
- package/dist/daml-lf/model/daml-lf-template.js +2 -0
- package/dist/daml-lf/model/daml-lf-type.d.ts +2 -0
- package/dist/daml-lf/model/daml-lf-type.js +4 -0
- package/dist/daml-lf/model/lf-2-model-mapper.d.ts +5 -0
- package/dist/daml-lf/model/lf-2-model-mapper.js +445 -12
- package/dist/debugger/errors/replay-determinism.exception.d.ts +3 -0
- package/dist/debugger/errors/replay-determinism.exception.js +3 -0
- package/dist/debugger/errors/replay-missing-package.exception.d.ts +3 -0
- package/dist/debugger/errors/replay-missing-package.exception.js +3 -0
- package/dist/debugger/errors/replay-missing-source.exception.d.ts +3 -0
- package/dist/debugger/errors/replay-missing-source.exception.js +3 -0
- package/dist/debugger/errors/replay-source-map.exception.d.ts +3 -0
- package/dist/debugger/errors/replay-source-map.exception.js +3 -0
- package/dist/debugger/errors/replay-state-hydration.exception.d.ts +3 -0
- package/dist/debugger/errors/replay-state-hydration.exception.js +3 -0
- package/dist/debugger/errors/replay-unsupported-lf-construct.exception.d.ts +3 -0
- package/dist/debugger/errors/replay-unsupported-lf-construct.exception.js +3 -0
- package/dist/debugger/errors/replay-unsupported-update.exception.d.ts +3 -0
- package/dist/debugger/errors/replay-unsupported-update.exception.js +3 -0
- package/dist/debugger/index.d.ts +31 -0
- package/dist/debugger/index.js +31 -0
- package/dist/debugger/ledger-replay-debugger-client.d.ts +31 -0
- package/dist/debugger/ledger-replay-debugger-client.js +53 -0
- package/dist/debugger/replay/ledger-replay-environment-builder.d.ts +95 -0
- package/dist/debugger/replay/ledger-replay-environment-builder.js +249 -0
- package/dist/debugger/replay/ledger-replay-session-loader.d.ts +78 -0
- package/dist/debugger/replay/ledger-replay-session-loader.js +565 -0
- package/dist/debugger/replay/replay-artifact-resolver.d.ts +30 -0
- package/dist/debugger/replay/replay-artifact-resolver.js +210 -0
- package/dist/debugger/replay/replay-determinism-validator.d.ts +12 -0
- package/dist/debugger/replay/replay-determinism-validator.js +161 -0
- package/dist/debugger/replay/replay-entrypoint-definition-resolver.d.ts +40 -0
- package/dist/debugger/replay/replay-entrypoint-definition-resolver.js +337 -0
- package/dist/debugger/replay/replay-entrypoint.d.ts +22 -0
- package/dist/debugger/replay/replay-entrypoint.js +14 -0
- package/dist/debugger/replay/replay-ledger-value-normalizer.d.ts +7 -0
- package/dist/debugger/replay/replay-ledger-value-normalizer.js +194 -0
- package/dist/debugger/replay/replay-update-loader.d.ts +24 -0
- package/dist/debugger/replay/replay-update-loader.js +94 -0
- package/dist/debugger/replay/replay-update-visibility-validator.d.ts +19 -0
- package/dist/debugger/replay/replay-update-visibility-validator.js +19 -0
- package/dist/debugger/session/in-memory-replay-session-store.d.ts +27 -0
- package/dist/debugger/session/in-memory-replay-session-store.js +109 -0
- package/dist/debugger/session/replay-phase.d.ts +7 -0
- package/dist/debugger/session/replay-phase.js +8 -0
- package/dist/debugger/session/replay-scope.d.ts +10 -0
- package/dist/debugger/session/replay-scope.js +10 -0
- package/dist/debugger/session/replay-session-metadata.d.ts +10 -0
- package/dist/debugger/session/replay-session-metadata.js +10 -0
- package/dist/debugger/session/replay-session-request.d.ts +6 -0
- package/dist/debugger/session/replay-session-request.js +10 -0
- package/dist/debugger/session/replay-session.d.ts +12 -0
- package/dist/debugger/session/replay-session.js +10 -0
- package/dist/debugger/session/replay-source-location.d.ts +17 -0
- package/dist/debugger/session/replay-source-location.js +16 -0
- package/dist/debugger/session/replay-stack-frame.d.ts +8 -0
- package/dist/debugger/session/replay-stack-frame.js +8 -0
- package/dist/debugger/session/replay-state-delta.d.ts +29 -0
- package/dist/debugger/session/replay-state-delta.js +24 -0
- package/dist/debugger/session/replay-step-advance-result.d.ts +24 -0
- package/dist/debugger/session/replay-step-advance-result.js +16 -0
- package/dist/debugger/session/replay-step.d.ts +30 -0
- package/dist/debugger/session/replay-step.js +24 -0
- package/dist/debugger/session/replay-value-preview.d.ts +8 -0
- package/dist/debugger/session/replay-value-preview.js +15 -0
- package/dist/debugger/source/daml-source-mapper.d.ts +12 -0
- package/dist/debugger/source/daml-source-mapper.js +21 -0
- package/dist/debugger/source/dar-source-map-metadata.d.ts +26 -0
- package/dist/debugger/source/dar-source-map-metadata.js +10 -0
- package/dist/debugger/source/source-coverage-validator.d.ts +8 -0
- package/dist/debugger/source/source-coverage-validator.js +16 -0
- package/dist/debugger/source/source-indexed-compilation.d.ts +45 -0
- package/dist/debugger/source/source-indexed-compilation.js +110 -0
- package/dist/debugger/source/source-mapping-precision.d.ts +5 -0
- package/dist/debugger/source/source-mapping-precision.js +4 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +12 -0
- package/dist/query/cache/memory-query-cache.d.ts +9 -0
- package/dist/query/cache/memory-query-cache.js +24 -0
- package/dist/query/cache/query-cache-store.d.ts +5 -0
- package/dist/query/cache/query-cache-store.js +1 -0
- package/dist/query/canton-manager-options.d.ts +17 -0
- package/dist/query/canton-manager-options.js +1 -0
- package/dist/query/canton-manager.d.ts +11 -0
- package/dist/query/canton-manager.js +42 -0
- package/dist/query/errors/pqs-query-error.d.ts +10 -0
- package/dist/query/errors/pqs-query-error.js +11 -0
- package/dist/query/errors/pqs-schema-profile-error.d.ts +3 -0
- package/dist/query/errors/pqs-schema-profile-error.js +3 -0
- package/dist/query/errors/query-capability-error.d.ts +7 -0
- package/dist/query/errors/query-capability-error.js +10 -0
- package/dist/query/grpc/grpc-contract-query-client.d.ts +32 -0
- package/dist/query/grpc/grpc-contract-query-client.js +126 -0
- package/dist/query/model-types.d.ts +258 -0
- package/dist/query/model-types.js +14 -0
- package/dist/query/pqs/pqs-pool.d.ts +13 -0
- package/dist/query/pqs/pqs-pool.js +18 -0
- package/dist/query/pqs/pqs-query-client.d.ts +49 -0
- package/dist/query/pqs/pqs-query-client.js +324 -0
- package/dist/query/pqs/pqs-schema-profile.d.ts +25 -0
- package/dist/query/pqs/pqs-schema-profile.js +120 -0
- package/dist/query/pqs/pqs-sql-compiler.d.ts +7 -0
- package/dist/query/pqs/pqs-sql-compiler.js +132 -0
- package/dist/query/pqs/read-only-sql.d.ts +1 -0
- package/dist/query/pqs/read-only-sql.js +35 -0
- package/dist/query/query-client.d.ts +61 -0
- package/dist/query/query-client.js +1 -0
- package/dist/query/query-source.d.ts +4 -0
- package/dist/query/query-source.js +5 -0
- package/dist/services/party-management/decentralized-party-lifecycle.d.ts +6 -0
- package/dist/services/party-management/decentralized-party-lifecycle.js +82 -0
- package/dist/services/party-management/party-management-service-client.d.ts +16 -1
- package/dist/services/party-management/party-management-service-client.js +142 -1
- package/dist/services/topology-manager-write/topology-signed-transaction-assembler.js +4 -0
- package/dist/testing/campaign/campaign-artifact.d.ts +20 -0
- package/dist/testing/campaign/campaign-artifact.js +147 -0
- package/dist/testing/campaign/campaign-definition.d.ts +9 -0
- package/dist/testing/campaign/campaign-definition.js +78 -0
- package/dist/testing/campaign/campaign-metrics.d.ts +32 -0
- package/dist/testing/campaign/campaign-metrics.js +26 -0
- package/dist/testing/campaign/campaign-model.d.ts +11 -0
- package/dist/testing/campaign/campaign-model.js +21 -0
- package/dist/testing/campaign/campaign-runner.d.ts +99 -0
- package/dist/testing/campaign/campaign-runner.js +194 -0
- package/dist/testing/campaign/campaign-scheduler.d.ts +40 -0
- package/dist/testing/campaign/campaign-scheduler.js +75 -0
- package/dist/testing/campaign/campaign-types.d.ts +52 -0
- package/dist/testing/campaign/campaign-types.js +11 -0
- package/dist/testing/daml/daml-action-arbitrary.d.ts +13 -0
- package/dist/testing/daml/daml-action-arbitrary.js +24 -0
- package/dist/testing/daml/daml-choice-action-arbitrary.d.ts +18 -0
- package/dist/testing/daml/daml-choice-action-arbitrary.js +27 -0
- package/dist/testing/daml/daml-create-action-arbitrary.d.ts +19 -0
- package/dist/testing/daml/daml-create-action-arbitrary.js +34 -0
- package/dist/testing/daml/daml-testing-catalog.d.ts +38 -0
- package/dist/testing/daml/daml-testing-catalog.js +40 -0
- package/dist/testing/daml/daml-value-arbitrary.d.ts +8 -0
- package/dist/testing/daml/daml-value-arbitrary.js +43 -0
- package/dist/testing/daml/declarative-campaign-arbitrary.d.ts +15 -0
- package/dist/testing/daml/declarative-campaign-arbitrary.js +30 -0
- package/dist/testing/errors/invariant-campaign-failure.d.ts +24 -0
- package/dist/testing/errors/invariant-campaign-failure.js +37 -0
- package/dist/testing/errors/testing-configuration-error.d.ts +3 -0
- package/dist/testing/errors/testing-configuration-error.js +6 -0
- package/dist/testing/handlers/handler.d.ts +19 -0
- package/dist/testing/handlers/handler.js +31 -0
- package/dist/testing/index.d.ts +22 -0
- package/dist/testing/index.js +22 -0
- package/dist/testing/runtime/campaign-isolation.d.ts +14 -0
- package/dist/testing/runtime/campaign-isolation.js +23 -0
- package/dist/testing/runtime/canton-test-runtime.d.ts +58 -0
- package/dist/testing/runtime/canton-test-runtime.js +138 -0
- package/dist/testing/runtime/declarative-action-executor.d.ts +16 -0
- package/dist/testing/runtime/declarative-action-executor.js +41 -0
- package/dist/testing/targets/target.d.ts +49 -0
- package/dist/testing/targets/target.js +121 -0
- package/dist/transports/grpc/grpc-channel-factory.js +31 -1
- package/dist/transports/grpc/grpc-transport.js +5 -3
- package/dist/transports/grpc/mappers/commands-mapper.js +18 -0
- package/dist/transports/grpc/mappers/contracts-mapper.d.ts +3 -1
- package/dist/transports/grpc/mappers/contracts-mapper.js +16 -3
- package/dist/transports/grpc/mappers/topology-manager-write-mapper.js +59 -1
- package/dist/transports/json/mappers/commands-mapper.js +20 -6
- package/node/.generated/start-local/additional-config.extra-participants.conf +37 -0
- package/node/.generated/start-local/additional-config.extra-validators.conf +35 -0
- package/node/.generated/start-local/compose-extra-participants.yaml +147 -0
- package/node/.generated/start-local/extra-participants.env +30 -0
- package/node/es256-jwt.mjs +177 -0
- package/node/start-local.sh +886 -0
- package/node/stop-local.sh +200 -0
- package/node/test-start-local.sh +354 -0
- package/node/test-stop-local.sh +112 -0
- package/package.json +21 -2
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as fc from "fast-check";
|
|
2
|
+
import { TestingConfigurationError } from "../errors/testing-configuration-error.js";
|
|
3
|
+
import { createDamlValueArbitrary } from "./daml-value-arbitrary.js";
|
|
4
|
+
/**
|
|
5
|
+
* Builds a well-typed, actor-routed automatic create input from declarative
|
|
6
|
+
* DAML template metadata. Ledger command construction stays in the runtime
|
|
7
|
+
* adapter.
|
|
8
|
+
*/
|
|
9
|
+
export function createDeclarativeCreateActionArbitrary(catalog, target, options = {}) {
|
|
10
|
+
const template = catalog.getTemplate(target.templateId);
|
|
11
|
+
if (template === undefined) {
|
|
12
|
+
throw new TestingConfigurationError(`Declarative target '${target.key}' does not exist in the DAML catalog.`);
|
|
13
|
+
}
|
|
14
|
+
else if (target.actors.length === 0) {
|
|
15
|
+
throw new TestingConfigurationError(`Declarative target '${target.key}' requires at least one actor.`);
|
|
16
|
+
}
|
|
17
|
+
const templateFieldNames = new Set(template.fields.map((field) => field.name));
|
|
18
|
+
const unknownField = Object.keys(options.fieldArbitraries ?? {})
|
|
19
|
+
.find((name) => !templateFieldNames.has(name));
|
|
20
|
+
if (unknownField !== undefined) {
|
|
21
|
+
throw new TestingConfigurationError(`Declarative target '${target.key}' has no field generator '${unknownField}'.`);
|
|
22
|
+
}
|
|
23
|
+
const payload = fc.record(Object.fromEntries(template.fields.map((field) => [
|
|
24
|
+
field.name,
|
|
25
|
+
options.fieldArbitraries?.[field.name]
|
|
26
|
+
?? createDamlValueArbitrary(field.type, options),
|
|
27
|
+
])));
|
|
28
|
+
return fc.tuple(fc.constantFrom(...target.actors), payload).map(([actor, value]) => Object.freeze({
|
|
29
|
+
actor,
|
|
30
|
+
payload: Object.freeze(value),
|
|
31
|
+
targetKey: target.key,
|
|
32
|
+
templateId: target.templateId,
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { DamlLfType } from "../../daml-lf/model/daml-lf-type.js";
|
|
2
|
+
export interface DamlTestingChoice {
|
|
3
|
+
readonly argumentType?: DamlLfType;
|
|
4
|
+
readonly choice: string;
|
|
5
|
+
readonly templateId: string;
|
|
6
|
+
}
|
|
7
|
+
export interface DamlTestingTemplate {
|
|
8
|
+
readonly choices: readonly string[];
|
|
9
|
+
readonly fields: readonly {
|
|
10
|
+
readonly name: string;
|
|
11
|
+
readonly type: DamlLfType;
|
|
12
|
+
}[];
|
|
13
|
+
readonly templateId: string;
|
|
14
|
+
}
|
|
15
|
+
export interface DamlTestingCatalog {
|
|
16
|
+
readonly templates: readonly DamlTestingTemplate[];
|
|
17
|
+
getChoice(templateId: string, choice: string): DamlTestingChoice | undefined;
|
|
18
|
+
getTemplate(templateId: string): DamlTestingTemplate | undefined;
|
|
19
|
+
}
|
|
20
|
+
export declare function createDamlTestingCatalog(init: {
|
|
21
|
+
readonly getTemplates: () => readonly {
|
|
22
|
+
readonly choices: readonly {
|
|
23
|
+
readonly name: string;
|
|
24
|
+
readonly parameter?: {
|
|
25
|
+
readonly type: DamlLfType;
|
|
26
|
+
};
|
|
27
|
+
}[];
|
|
28
|
+
readonly fields?: readonly {
|
|
29
|
+
readonly name: string;
|
|
30
|
+
readonly type: DamlLfType;
|
|
31
|
+
}[];
|
|
32
|
+
readonly templateId: {
|
|
33
|
+
readonly moduleName: string;
|
|
34
|
+
readonly packageId: string;
|
|
35
|
+
readonly templateName: string;
|
|
36
|
+
};
|
|
37
|
+
}[];
|
|
38
|
+
}): DamlTestingCatalog;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export function createDamlTestingCatalog(init) {
|
|
2
|
+
const choices = new Map();
|
|
3
|
+
const templates = init.getTemplates()
|
|
4
|
+
.map((template) => {
|
|
5
|
+
const templateId = formatTemplateId(template.templateId);
|
|
6
|
+
for (const choice of template.choices) {
|
|
7
|
+
choices.set(createChoiceKey(templateId, choice.name), Object.freeze({
|
|
8
|
+
templateId,
|
|
9
|
+
choice: choice.name,
|
|
10
|
+
...(choice.parameter === undefined
|
|
11
|
+
? {}
|
|
12
|
+
: { argumentType: choice.parameter.type }),
|
|
13
|
+
}));
|
|
14
|
+
}
|
|
15
|
+
return Object.freeze({
|
|
16
|
+
templateId,
|
|
17
|
+
choices: Object.freeze(template.choices.map(({ name }) => name)),
|
|
18
|
+
fields: Object.freeze((template.fields ?? []).map((field) => Object.freeze({
|
|
19
|
+
name: field.name,
|
|
20
|
+
type: field.type,
|
|
21
|
+
}))),
|
|
22
|
+
});
|
|
23
|
+
})
|
|
24
|
+
.sort((left, right) => left.templateId.localeCompare(right.templateId));
|
|
25
|
+
return Object.freeze({
|
|
26
|
+
templates: Object.freeze(templates),
|
|
27
|
+
getChoice(templateId, choice) {
|
|
28
|
+
return choices.get(createChoiceKey(templateId, choice));
|
|
29
|
+
},
|
|
30
|
+
getTemplate(templateId) {
|
|
31
|
+
return templates.find((template) => template.templateId === templateId);
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
function formatTemplateId(value) {
|
|
36
|
+
return `${value.packageId}:${value.moduleName}:${value.templateName}`;
|
|
37
|
+
}
|
|
38
|
+
function createChoiceKey(templateId, choice) {
|
|
39
|
+
return `${templateId}:${choice}`;
|
|
40
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as fc from "fast-check";
|
|
2
|
+
import { DamlNumeric } from "../../core/types/daml-numeric.js";
|
|
3
|
+
import { DamlParty } from "../../core/types/daml-party.js";
|
|
4
|
+
import { DamlLfType } from "../../daml-lf/model/daml-lf-type.js";
|
|
5
|
+
export type DamlTestingValue = string | bigint | DamlParty | DamlNumeric;
|
|
6
|
+
export declare function createDamlValueArbitrary(type: DamlLfType, options?: {
|
|
7
|
+
readonly valueParties?: readonly string[];
|
|
8
|
+
}): fc.Arbitrary<DamlTestingValue>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as fc from "fast-check";
|
|
2
|
+
import { DamlNumeric } from "../../core/types/daml-numeric.js";
|
|
3
|
+
import { DamlParty } from "../../core/types/daml-party.js";
|
|
4
|
+
import { DamlLfBuiltinType } from "../../daml-lf/model/daml-lf-builtin-type.js";
|
|
5
|
+
import { TestingConfigurationError } from "../errors/testing-configuration-error.js";
|
|
6
|
+
export function createDamlValueArbitrary(type, options = {}) {
|
|
7
|
+
if (type.typeConReference !== undefined) {
|
|
8
|
+
throw new TestingConfigurationError("Automatic DAML value generation does not yet support type constructors.");
|
|
9
|
+
}
|
|
10
|
+
switch (type.builtinType) {
|
|
11
|
+
case DamlLfBuiltinType.text:
|
|
12
|
+
return fc.string({ maxLength: 64 });
|
|
13
|
+
case DamlLfBuiltinType.int64:
|
|
14
|
+
return fc.bigInt({
|
|
15
|
+
min: -(2n ** 63n),
|
|
16
|
+
max: (2n ** 63n) - 1n,
|
|
17
|
+
});
|
|
18
|
+
case DamlLfBuiltinType.numeric:
|
|
19
|
+
return createNumericArbitrary(type.numericScale);
|
|
20
|
+
case DamlLfBuiltinType.party:
|
|
21
|
+
if (options.valueParties === undefined || options.valueParties.length === 0) {
|
|
22
|
+
throw new TestingConfigurationError("Automatic DAML party generation requires non-empty valueParties.");
|
|
23
|
+
}
|
|
24
|
+
return fc.constantFrom(...options.valueParties).map((party) => new DamlParty(party));
|
|
25
|
+
default:
|
|
26
|
+
throw new TestingConfigurationError(`Automatic DAML value generation does not support '${type.builtinType}'.`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function createNumericArbitrary(scale) {
|
|
30
|
+
const fractionScale = Math.min(scale ?? 6, 6);
|
|
31
|
+
if (fractionScale < 1) {
|
|
32
|
+
throw new TestingConfigurationError("Automatic DAML numeric generation requires a Numeric scale of at least one.");
|
|
33
|
+
}
|
|
34
|
+
const denominator = 10 ** fractionScale;
|
|
35
|
+
return fc.integer({ min: -1_000_000, max: 1_000_000 })
|
|
36
|
+
.filter((value) => value % denominator !== 0)
|
|
37
|
+
.map((value) => new DamlNumeric(formatNumeric(value, fractionScale)));
|
|
38
|
+
}
|
|
39
|
+
function formatNumeric(value, scale) {
|
|
40
|
+
const sign = value < 0 ? "-" : "";
|
|
41
|
+
const digits = Math.abs(value).toString().padStart(scale + 1, "0");
|
|
42
|
+
return `${sign}${digits.slice(0, -scale)}.${digits.slice(-scale)}`;
|
|
43
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as fc from "fast-check";
|
|
2
|
+
import { InvariantCampaign } from "../campaign/campaign-types.js";
|
|
3
|
+
import { ResolvedDeclarativeTarget } from "../targets/target.js";
|
|
4
|
+
import { DeclarativeAction, DeclarativeActionGenerationOptions } from "./daml-action-arbitrary.js";
|
|
5
|
+
import { DamlTestingCatalog } from "./daml-testing-catalog.js";
|
|
6
|
+
/**
|
|
7
|
+
* Produces exact-depth declarative action sequences for a campaign. Every
|
|
8
|
+
* resolved target must be declared by the campaign and every generated actor
|
|
9
|
+
* must be eligible for that target before execution starts.
|
|
10
|
+
*/
|
|
11
|
+
export declare function createDeclarativeCampaignArbitrary(init: {
|
|
12
|
+
readonly campaign: InvariantCampaign;
|
|
13
|
+
readonly catalog: DamlTestingCatalog;
|
|
14
|
+
readonly targets: readonly ResolvedDeclarativeTarget[];
|
|
15
|
+
} & DeclarativeActionGenerationOptions): fc.Arbitrary<readonly DeclarativeAction[]>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as fc from "fast-check";
|
|
2
|
+
import { TestingConfigurationError } from "../errors/testing-configuration-error.js";
|
|
3
|
+
import { createDeclarativeActionArbitrary, } from "./daml-action-arbitrary.js";
|
|
4
|
+
/**
|
|
5
|
+
* Produces exact-depth declarative action sequences for a campaign. Every
|
|
6
|
+
* resolved target must be declared by the campaign and every generated actor
|
|
7
|
+
* must be eligible for that target before execution starts.
|
|
8
|
+
*/
|
|
9
|
+
export function createDeclarativeCampaignArbitrary(init) {
|
|
10
|
+
validateTargets(init.campaign, init.targets);
|
|
11
|
+
return fc.array(createDeclarativeActionArbitrary(init.catalog, init.targets, init), {
|
|
12
|
+
minLength: init.campaign.config.depth,
|
|
13
|
+
maxLength: init.campaign.config.depth,
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
function validateTargets(campaign, targets) {
|
|
17
|
+
const declaredTargets = new Map(campaign.targets.map((target) => [target.key, target]));
|
|
18
|
+
const allActors = Object.keys(campaign.runtime.actors);
|
|
19
|
+
for (const target of targets) {
|
|
20
|
+
const declared = declaredTargets.get(target.key);
|
|
21
|
+
if (declared === undefined) {
|
|
22
|
+
throw new TestingConfigurationError(`Declarative target '${target.key}' is absent from the campaign definition.`);
|
|
23
|
+
}
|
|
24
|
+
const eligibleActors = new Set(declared.actors ?? allActors);
|
|
25
|
+
const invalidActor = target.actors.find((actor) => !eligibleActors.has(actor));
|
|
26
|
+
if (invalidActor !== undefined) {
|
|
27
|
+
throw new TestingConfigurationError(`Declarative target '${target.key}' assigns ineligible actor '${invalidActor}'.`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { CampaignInvariantFailure } from "../campaign/campaign-runner.js";
|
|
2
|
+
import { CampaignMetrics } from "../campaign/campaign-metrics.js";
|
|
3
|
+
export interface InvariantCampaignFailureInit<Trace = unknown> {
|
|
4
|
+
readonly artifactPath?: string;
|
|
5
|
+
readonly cause?: unknown;
|
|
6
|
+
readonly failures: readonly CampaignInvariantFailure[];
|
|
7
|
+
readonly message: string;
|
|
8
|
+
readonly metrics: CampaignMetrics;
|
|
9
|
+
readonly trace?: Trace;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* A safe public summary of a failed invariant campaign.
|
|
13
|
+
*
|
|
14
|
+
* The original cause is intentionally retained in a private field so that
|
|
15
|
+
* credentials or transport details cannot be serialized with this error.
|
|
16
|
+
*/
|
|
17
|
+
export declare class InvariantCampaignFailure<Trace = unknown> extends Error {
|
|
18
|
+
#private;
|
|
19
|
+
readonly artifactPath?: string;
|
|
20
|
+
readonly failures: readonly CampaignInvariantFailure[];
|
|
21
|
+
readonly metrics: CampaignMetrics;
|
|
22
|
+
readonly trace?: Trace;
|
|
23
|
+
constructor(init: InvariantCampaignFailureInit<Trace>);
|
|
24
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A safe public summary of a failed invariant campaign.
|
|
3
|
+
*
|
|
4
|
+
* The original cause is intentionally retained in a private field so that
|
|
5
|
+
* credentials or transport details cannot be serialized with this error.
|
|
6
|
+
*/
|
|
7
|
+
export class InvariantCampaignFailure extends Error {
|
|
8
|
+
artifactPath;
|
|
9
|
+
failures;
|
|
10
|
+
metrics;
|
|
11
|
+
trace;
|
|
12
|
+
#cause;
|
|
13
|
+
constructor(init) {
|
|
14
|
+
super(init.message);
|
|
15
|
+
this.name = "InvariantCampaignFailure";
|
|
16
|
+
this.artifactPath = init.artifactPath;
|
|
17
|
+
this.failures = Object.freeze(init.failures.map((failure) => Object.freeze({
|
|
18
|
+
...failure,
|
|
19
|
+
})));
|
|
20
|
+
this.metrics = snapshotMetrics(init.metrics);
|
|
21
|
+
this.trace = init.trace;
|
|
22
|
+
this.#cause = init.cause;
|
|
23
|
+
Object.freeze(this);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function snapshotMetrics(metrics) {
|
|
27
|
+
return Object.freeze({
|
|
28
|
+
byActor: snapshotMetricGroup(metrics.byActor),
|
|
29
|
+
byTarget: snapshotMetricGroup(metrics.byTarget),
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
function snapshotMetricGroup(group) {
|
|
33
|
+
return Object.freeze(Object.fromEntries(Object.entries(group).map(([key, values]) => [
|
|
34
|
+
key,
|
|
35
|
+
Object.freeze({ ...values }),
|
|
36
|
+
])));
|
|
37
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type CampaignHandlerCleanup = "none" | {
|
|
2
|
+
readonly archive: (contractId: string) => Promise<void>;
|
|
3
|
+
readonly discover: () => Promise<readonly string[]>;
|
|
4
|
+
readonly trackCreated?: (contractId: string) => void;
|
|
5
|
+
};
|
|
6
|
+
export interface CampaignHandler<Input = unknown, Context = unknown> {
|
|
7
|
+
readonly assume?: (context: Context, input: Input) => boolean | Promise<boolean>;
|
|
8
|
+
readonly cleanup: CampaignHandlerCleanup;
|
|
9
|
+
readonly name: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function handler<Input = unknown, Context = unknown>(name: string, init: Omit<CampaignHandler<Input, Context>, "name">): CampaignHandler<Input, Context>;
|
|
12
|
+
export declare function evaluateHandlerAssumptionAsync<Input, Context>(value: CampaignHandler<Input, Context>, context: Context, input: Input): Promise<{
|
|
13
|
+
readonly kind: "eligible";
|
|
14
|
+
} | {
|
|
15
|
+
readonly kind: "discarded";
|
|
16
|
+
readonly reason: string;
|
|
17
|
+
}>;
|
|
18
|
+
export declare function bound(value: number, minimum: number, maximum: number): number;
|
|
19
|
+
export declare function bound(value: bigint, minimum: bigint, maximum: bigint): bigint;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export function handler(name, init) {
|
|
2
|
+
if (name.length === 0) {
|
|
3
|
+
throw new Error("Invariant campaign handler names must not be empty.");
|
|
4
|
+
}
|
|
5
|
+
return Object.freeze({
|
|
6
|
+
name,
|
|
7
|
+
cleanup: init.cleanup,
|
|
8
|
+
...(init.assume === undefined ? {} : { assume: init.assume }),
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
export async function evaluateHandlerAssumptionAsync(value, context, input) {
|
|
12
|
+
if (value.assume === undefined || await value.assume(context, input)) {
|
|
13
|
+
return { kind: "eligible" };
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
kind: "discarded",
|
|
17
|
+
reason: "handler assumption returned false",
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export function bound(value, minimum, maximum) {
|
|
21
|
+
if (minimum > maximum) {
|
|
22
|
+
throw new Error("Invariant campaign bounds require minimum <= maximum.");
|
|
23
|
+
}
|
|
24
|
+
else if (value < minimum) {
|
|
25
|
+
return minimum;
|
|
26
|
+
}
|
|
27
|
+
else if (value > maximum) {
|
|
28
|
+
return maximum;
|
|
29
|
+
}
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export { defineInvariantCampaign } from "./campaign/campaign-definition.js";
|
|
2
|
+
export { CampaignReplayArtifact, createCampaignFingerprint, loadCampaignReplayArtifactAsync, selectCampaignCounterexampleTrace, serializeCampaignReplayArtifact, writeCampaignReplayArtifactAsync, } from "./campaign/campaign-artifact.js";
|
|
3
|
+
export { applyAcceptedGhostTransition, CampaignModel, createCampaignModel, reconcileCampaignModel, } from "./campaign/campaign-model.js";
|
|
4
|
+
export { CampaignInvariantFailure, CampaignExecutableAction, CampaignLifecyclePhase, CampaignLifecycleTrace, evaluateCampaignInvariantsAsync, runCampaignLifecycleCheckAsync, runInvariantCampaignCheckAsync, runCampaignCheckAsync, } from "./campaign/campaign-runner.js";
|
|
5
|
+
export { CampaignMetricOutcome, CampaignMetrics, createCampaignMetrics, recordCampaignAction, } from "./campaign/campaign-metrics.js";
|
|
6
|
+
export { CampaignSchedulingTarget, createCampaignScheduleArbitrary, createInvariantCampaignScheduleArbitrary, ScheduledCampaignSlot, scheduleCampaignSlots, } from "./campaign/campaign-scheduler.js";
|
|
7
|
+
export { createDamlTestingCatalog, DamlTestingCatalog, DamlTestingChoice, DamlTestingTemplate, } from "./daml/daml-testing-catalog.js";
|
|
8
|
+
export { createDamlValueArbitrary, DamlTestingValue, } from "./daml/daml-value-arbitrary.js";
|
|
9
|
+
export { DamlNumeric } from "../core/types/daml-numeric.js";
|
|
10
|
+
export { DamlParty } from "../core/types/daml-party.js";
|
|
11
|
+
export { createDeclarativeActionArbitrary, DeclarativeAction, DeclarativeActionGenerationOptions, } from "./daml/daml-action-arbitrary.js";
|
|
12
|
+
export { createDeclarativeCampaignArbitrary } from "./daml/declarative-campaign-arbitrary.js";
|
|
13
|
+
export { createDeclarativeChoiceActionArbitrary, DeclarativeChoiceAction, } from "./daml/daml-choice-action-arbitrary.js";
|
|
14
|
+
export { createDeclarativeCreateActionArbitrary, DeclarativeCreateAction, DeclarativeCreateActionGenerationOptions, } from "./daml/daml-create-action-arbitrary.js";
|
|
15
|
+
export { bound, CampaignHandler, CampaignHandlerCleanup, evaluateHandlerAssumptionAsync, handler, } from "./handlers/handler.js";
|
|
16
|
+
export { CantonCommandOutcome, CantonTestRoute, CantonTestRuntime, classifyCantonCommandOutcome, createCantonTestRuntime, pollUntilAsync, toCampaignMetricOutcome, } from "./runtime/canton-test-runtime.js";
|
|
17
|
+
export { executeDeclarativeActionAsync } from "./runtime/declarative-action-executor.js";
|
|
18
|
+
export { CampaignRunIsolation, runWithCampaignIsolationAsync, } from "./runtime/campaign-isolation.js";
|
|
19
|
+
export { excludeChoice, ExcludedChoiceTarget, excludeTemplate, ExcludedTemplateTarget, targetCreate, targetChoice, targetTemplate, resolveDeclarativeTargets, ResolvedDeclarativeChoiceTarget, ResolvedDeclarativeCreateTarget, ResolvedDeclarativeTarget, TemplateCreateTarget, TemplateTarget, TemplateTargetBuilder, } from "./targets/target.js";
|
|
20
|
+
export { CampaignInvariant, CampaignIsolation, CampaignRuntime, CampaignTarget, CantonTestActor, InvariantCampaign, InvariantCampaignConfig, invariant, ResolvedInvariantCampaignConfig, } from "./campaign/campaign-types.js";
|
|
21
|
+
export { TestingConfigurationError } from "./errors/testing-configuration-error.js";
|
|
22
|
+
export { InvariantCampaignFailure, InvariantCampaignFailureInit, } from "./errors/invariant-campaign-failure.js";
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export { defineInvariantCampaign } from "./campaign/campaign-definition.js";
|
|
2
|
+
export { createCampaignFingerprint, loadCampaignReplayArtifactAsync, selectCampaignCounterexampleTrace, serializeCampaignReplayArtifact, writeCampaignReplayArtifactAsync, } from "./campaign/campaign-artifact.js";
|
|
3
|
+
export { applyAcceptedGhostTransition, createCampaignModel, reconcileCampaignModel, } from "./campaign/campaign-model.js";
|
|
4
|
+
export { evaluateCampaignInvariantsAsync, runCampaignLifecycleCheckAsync, runInvariantCampaignCheckAsync, runCampaignCheckAsync, } from "./campaign/campaign-runner.js";
|
|
5
|
+
export { createCampaignMetrics, recordCampaignAction, } from "./campaign/campaign-metrics.js";
|
|
6
|
+
export { createCampaignScheduleArbitrary, createInvariantCampaignScheduleArbitrary, scheduleCampaignSlots, } from "./campaign/campaign-scheduler.js";
|
|
7
|
+
export { createDamlTestingCatalog, } from "./daml/daml-testing-catalog.js";
|
|
8
|
+
export { createDamlValueArbitrary, } from "./daml/daml-value-arbitrary.js";
|
|
9
|
+
export { DamlNumeric } from "../core/types/daml-numeric.js";
|
|
10
|
+
export { DamlParty } from "../core/types/daml-party.js";
|
|
11
|
+
export { createDeclarativeActionArbitrary, } from "./daml/daml-action-arbitrary.js";
|
|
12
|
+
export { createDeclarativeCampaignArbitrary } from "./daml/declarative-campaign-arbitrary.js";
|
|
13
|
+
export { createDeclarativeChoiceActionArbitrary, } from "./daml/daml-choice-action-arbitrary.js";
|
|
14
|
+
export { createDeclarativeCreateActionArbitrary, } from "./daml/daml-create-action-arbitrary.js";
|
|
15
|
+
export { bound, evaluateHandlerAssumptionAsync, handler, } from "./handlers/handler.js";
|
|
16
|
+
export { classifyCantonCommandOutcome, createCantonTestRuntime, pollUntilAsync, toCampaignMetricOutcome, } from "./runtime/canton-test-runtime.js";
|
|
17
|
+
export { executeDeclarativeActionAsync } from "./runtime/declarative-action-executor.js";
|
|
18
|
+
export { runWithCampaignIsolationAsync, } from "./runtime/campaign-isolation.js";
|
|
19
|
+
export { excludeChoice, excludeTemplate, targetCreate, targetChoice, targetTemplate, resolveDeclarativeTargets, } from "./targets/target.js";
|
|
20
|
+
export { invariant, } from "./campaign/campaign-types.js";
|
|
21
|
+
export { TestingConfigurationError } from "./errors/testing-configuration-error.js";
|
|
22
|
+
export { InvariantCampaignFailure, } from "./errors/invariant-campaign-failure.js";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type CampaignRunIsolation = {
|
|
2
|
+
readonly kind: "cleanup";
|
|
3
|
+
} | {
|
|
4
|
+
readonly kind: "external";
|
|
5
|
+
readonly reset: (phase: "before-run" | "after-run") => Promise<void>;
|
|
6
|
+
} | {
|
|
7
|
+
readonly create: () => Promise<string>;
|
|
8
|
+
readonly kind: "snapshot";
|
|
9
|
+
readonly restore: (snapshot: string) => Promise<void>;
|
|
10
|
+
};
|
|
11
|
+
export declare function runWithCampaignIsolationAsync(init: {
|
|
12
|
+
readonly isolation: CampaignRunIsolation;
|
|
13
|
+
readonly runAsync: () => Promise<void>;
|
|
14
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export async function runWithCampaignIsolationAsync(init) {
|
|
2
|
+
if (init.isolation.kind === "external") {
|
|
3
|
+
await init.isolation.reset("before-run");
|
|
4
|
+
try {
|
|
5
|
+
await init.runAsync();
|
|
6
|
+
}
|
|
7
|
+
finally {
|
|
8
|
+
await init.isolation.reset("after-run");
|
|
9
|
+
}
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
else if (init.isolation.kind === "snapshot") {
|
|
13
|
+
const snapshot = await init.isolation.create();
|
|
14
|
+
try {
|
|
15
|
+
await init.runAsync();
|
|
16
|
+
}
|
|
17
|
+
finally {
|
|
18
|
+
await init.isolation.restore(snapshot);
|
|
19
|
+
}
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
await init.runAsync();
|
|
23
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { CampaignIsolation, CantonTestActor } from "../campaign/campaign-types.js";
|
|
2
|
+
import { CampaignMetricOutcome } from "../campaign/campaign-metrics.js";
|
|
3
|
+
export interface CantonTestRoute {
|
|
4
|
+
readonly actAs: readonly string[];
|
|
5
|
+
readonly actor: string;
|
|
6
|
+
readonly participant: string;
|
|
7
|
+
readonly party: string;
|
|
8
|
+
readonly readAs: readonly string[];
|
|
9
|
+
}
|
|
10
|
+
export type CantonCommandOutcome = {
|
|
11
|
+
readonly commandId?: string;
|
|
12
|
+
readonly kind: "accepted";
|
|
13
|
+
readonly transactionId?: string;
|
|
14
|
+
} | {
|
|
15
|
+
readonly details: string;
|
|
16
|
+
readonly kind: "protocol-revert";
|
|
17
|
+
readonly statusCode: number;
|
|
18
|
+
} | {
|
|
19
|
+
readonly details: string;
|
|
20
|
+
readonly kind: "transport-error";
|
|
21
|
+
readonly statusCode?: number;
|
|
22
|
+
} | {
|
|
23
|
+
readonly details: string;
|
|
24
|
+
readonly kind: "timeout";
|
|
25
|
+
readonly statusCode?: number;
|
|
26
|
+
} | {
|
|
27
|
+
readonly details: string;
|
|
28
|
+
readonly kind: "malformed-response";
|
|
29
|
+
} | {
|
|
30
|
+
readonly details: string;
|
|
31
|
+
readonly kind: "unknown-commit-outcome";
|
|
32
|
+
readonly statusCode?: number;
|
|
33
|
+
};
|
|
34
|
+
export interface CantonTestRuntime<Participant = unknown> {
|
|
35
|
+
readonly actors: Readonly<Record<string, CantonTestActor>>;
|
|
36
|
+
readonly isolation: CampaignIsolation;
|
|
37
|
+
readonly participants: Readonly<Record<string, Participant>>;
|
|
38
|
+
readLedgerEndAsync(participant: string): Promise<string>;
|
|
39
|
+
resolveRoute(actor: string): CantonTestRoute;
|
|
40
|
+
submitAndWaitAsync(actor: string, request: unknown): Promise<CantonCommandOutcome>;
|
|
41
|
+
}
|
|
42
|
+
export declare function createCantonTestRuntime<Participant>(init: {
|
|
43
|
+
readonly actors: Readonly<Record<string, CantonTestActor>>;
|
|
44
|
+
readonly isolation: CampaignIsolation;
|
|
45
|
+
readonly participants: Readonly<Record<string, Participant>>;
|
|
46
|
+
}): CantonTestRuntime<Participant>;
|
|
47
|
+
export declare function classifyCantonCommandOutcome(input: {
|
|
48
|
+
readonly error?: unknown;
|
|
49
|
+
readonly response?: unknown;
|
|
50
|
+
}): CantonCommandOutcome;
|
|
51
|
+
/** Converts the runtime's transport-safe outcome into the campaign metric union. */
|
|
52
|
+
export declare function toCampaignMetricOutcome(outcome: CantonCommandOutcome): CampaignMetricOutcome;
|
|
53
|
+
export declare function pollUntilAsync<T>(init: {
|
|
54
|
+
readonly intervalMs: number;
|
|
55
|
+
readonly isReady: (value: T) => boolean;
|
|
56
|
+
readonly readAsync: () => Promise<T>;
|
|
57
|
+
readonly timeoutMs: number;
|
|
58
|
+
}): Promise<T>;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { TestingConfigurationError } from "../errors/testing-configuration-error.js";
|
|
2
|
+
export function createCantonTestRuntime(init) {
|
|
3
|
+
for (const [name, actor] of Object.entries(init.actors)) {
|
|
4
|
+
if (init.participants[actor.participant] === undefined) {
|
|
5
|
+
throw new TestingConfigurationError(`Canton test actor '${name}' references unknown participant '${actor.participant}'.`);
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
const actors = Object.freeze({ ...init.actors });
|
|
9
|
+
const participants = Object.freeze({ ...init.participants });
|
|
10
|
+
const resolveRoute = (actorName) => {
|
|
11
|
+
const actor = actors[actorName];
|
|
12
|
+
if (actor === undefined) {
|
|
13
|
+
throw new TestingConfigurationError(`Canton test runtime has no actor '${actorName}'.`);
|
|
14
|
+
}
|
|
15
|
+
return Object.freeze({
|
|
16
|
+
actor: actorName,
|
|
17
|
+
participant: actor.participant,
|
|
18
|
+
party: actor.party,
|
|
19
|
+
actAs: Object.freeze([...(actor.actAs ?? [actor.party])]),
|
|
20
|
+
readAs: Object.freeze([...(actor.readAs ?? [])]),
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
return Object.freeze({
|
|
24
|
+
actors,
|
|
25
|
+
participants,
|
|
26
|
+
isolation: init.isolation,
|
|
27
|
+
async readLedgerEndAsync(participantName) {
|
|
28
|
+
const participant = participants[participantName];
|
|
29
|
+
const stateService = readObjectProperty(participant, "stateService");
|
|
30
|
+
const getLedgerEndAsync = readFunctionProperty(stateService, "getLedgerEndAsync");
|
|
31
|
+
if (getLedgerEndAsync === undefined) {
|
|
32
|
+
throw new TestingConfigurationError(`Canton test participant '${participantName}' has no stateService.getLedgerEndAsync method.`);
|
|
33
|
+
}
|
|
34
|
+
const response = await getLedgerEndAsync.call(stateService);
|
|
35
|
+
const offset = readStringProperty(response, "offset");
|
|
36
|
+
if (offset === undefined) {
|
|
37
|
+
throw new TestingConfigurationError(`Canton test participant '${participantName}' returned no ledger end offset.`);
|
|
38
|
+
}
|
|
39
|
+
return offset;
|
|
40
|
+
},
|
|
41
|
+
resolveRoute,
|
|
42
|
+
async submitAndWaitAsync(actorName, request) {
|
|
43
|
+
const route = resolveRoute(actorName);
|
|
44
|
+
const participant = participants[route.participant];
|
|
45
|
+
const commandService = readObjectProperty(participant, "commandService");
|
|
46
|
+
const submitAndWaitAsync = readFunctionProperty(commandService, "submitAndWaitAsync");
|
|
47
|
+
if (submitAndWaitAsync === undefined) {
|
|
48
|
+
throw new TestingConfigurationError(`Canton test participant '${route.participant}' has no commandService.submitAndWaitAsync method.`);
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
return classifyCantonCommandOutcome({
|
|
52
|
+
response: await submitAndWaitAsync.call(commandService, request),
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
return classifyCantonCommandOutcome({ error });
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
export function classifyCantonCommandOutcome(input) {
|
|
62
|
+
if (input.error === undefined) {
|
|
63
|
+
const transactionId = readStringProperty(input.response, "transactionId");
|
|
64
|
+
const commandId = readStringProperty(input.response, "commandId");
|
|
65
|
+
return {
|
|
66
|
+
kind: "accepted",
|
|
67
|
+
...(transactionId === undefined ? {} : { transactionId }),
|
|
68
|
+
...(commandId === undefined ? {} : { commandId }),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
const statusCode = readNumberProperty(input.error, "code");
|
|
72
|
+
const details = readStringProperty(input.error, "details") ?? "Unknown command failure.";
|
|
73
|
+
if ((statusCode === 9 && details.startsWith("DAML_INTERPRETATION_ERROR("))
|
|
74
|
+
|| (statusCode === 3 && details.startsWith("DAML_AUTHORIZATION_ERROR("))) {
|
|
75
|
+
return { kind: "protocol-revert", statusCode, details };
|
|
76
|
+
}
|
|
77
|
+
else if (statusCode === 14 || statusCode === 13) {
|
|
78
|
+
return { kind: "transport-error", statusCode, details };
|
|
79
|
+
}
|
|
80
|
+
else if (statusCode === 4) {
|
|
81
|
+
return { kind: "timeout", statusCode, details };
|
|
82
|
+
}
|
|
83
|
+
return { kind: "unknown-commit-outcome", statusCode, details };
|
|
84
|
+
}
|
|
85
|
+
/** Converts the runtime's transport-safe outcome into the campaign metric union. */
|
|
86
|
+
export function toCampaignMetricOutcome(outcome) {
|
|
87
|
+
if (outcome.kind !== "accepted") {
|
|
88
|
+
return {
|
|
89
|
+
kind: outcome.kind,
|
|
90
|
+
reason: outcome.details,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
const updateId = outcome.transactionId ?? outcome.commandId;
|
|
94
|
+
return updateId === undefined
|
|
95
|
+
? {
|
|
96
|
+
kind: "malformed-response",
|
|
97
|
+
reason: "Canton command response has no transaction or command ID.",
|
|
98
|
+
}
|
|
99
|
+
: { kind: "accepted", updateId };
|
|
100
|
+
}
|
|
101
|
+
export async function pollUntilAsync(init) {
|
|
102
|
+
const deadline = Date.now() + init.timeoutMs;
|
|
103
|
+
while (true) {
|
|
104
|
+
const value = await init.readAsync();
|
|
105
|
+
if (init.isReady(value)) {
|
|
106
|
+
return value;
|
|
107
|
+
}
|
|
108
|
+
else if (Date.now() >= deadline) {
|
|
109
|
+
throw new Error("Canton test runtime polling timed out.");
|
|
110
|
+
}
|
|
111
|
+
await new Promise((resolveDelay) => {
|
|
112
|
+
setTimeout(resolveDelay, init.intervalMs);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function readNumberProperty(value, key) {
|
|
117
|
+
const candidate = value;
|
|
118
|
+
const property = candidate?.[key];
|
|
119
|
+
return typeof property === "number" ? property : undefined;
|
|
120
|
+
}
|
|
121
|
+
function readObjectProperty(value, key) {
|
|
122
|
+
const candidate = value;
|
|
123
|
+
const property = candidate?.[key];
|
|
124
|
+
return property !== null && typeof property === "object"
|
|
125
|
+
? property
|
|
126
|
+
: undefined;
|
|
127
|
+
}
|
|
128
|
+
function readFunctionProperty(value, key) {
|
|
129
|
+
const property = value?.[key];
|
|
130
|
+
return typeof property === "function"
|
|
131
|
+
? property
|
|
132
|
+
: undefined;
|
|
133
|
+
}
|
|
134
|
+
function readStringProperty(value, key) {
|
|
135
|
+
const candidate = value;
|
|
136
|
+
const property = candidate?.[key];
|
|
137
|
+
return typeof property === "string" ? property : undefined;
|
|
138
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { DeclarativeAction } from "../daml/daml-action-arbitrary.js";
|
|
2
|
+
import { DeclarativeChoiceAction } from "../daml/daml-choice-action-arbitrary.js";
|
|
3
|
+
import { CantonTestRuntime } from "./canton-test-runtime.js";
|
|
4
|
+
import { CampaignMetricOutcome } from "../campaign/campaign-metrics.js";
|
|
5
|
+
/**
|
|
6
|
+
* Converts a generated declarative action into SDK command types and submits
|
|
7
|
+
* it over the actor's configured Canton route. Choice actions deliberately
|
|
8
|
+
* require an explicit contract resolver: the testing SDK never guesses an
|
|
9
|
+
* active contract ID from stale local state.
|
|
10
|
+
*/
|
|
11
|
+
export declare function executeDeclarativeActionAsync(init: {
|
|
12
|
+
readonly action: DeclarativeAction;
|
|
13
|
+
readonly applicationId: string;
|
|
14
|
+
readonly resolveContractIdAsync?: (action: DeclarativeChoiceAction) => Promise<string>;
|
|
15
|
+
readonly runtime: CantonTestRuntime;
|
|
16
|
+
}): Promise<CampaignMetricOutcome>;
|