Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import { exampleStorage } from "../src/utils";
import fs from "fs";
import path from "path";
import { LocalDurableTestRunner } from "@aws/durable-execution-sdk-js-testing";
import { ArgumentParser, BooleanOptionalAction } from "argparse";

async function main() {
const parser = new ArgumentParser({
description: "Generate history files for durable execution examples",
});

parser.add_argument("--pattern", {
type: "str",
help: "String pattern to generate history for a specific example that matches the pattern (default: generate all examples)",
});

parser.add_argument("--log", {
action: "store_true",
help: "Log the history events to the console",
});

parser.add_argument("--skip-time", {
action: BooleanOptionalAction,
help: "Enable skip time in test environment",
default: true,
});

parser.add_argument("--suffix", {
help: "Optional suffix for test case",
type: "str",
});

parser.add_argument("--payload", {
help: "Optional payload for test case",
type: "str",
});

parser.add_argument("--only-missing", {
action: BooleanOptionalAction,
help: "Only add missing history files for the examples specified",
default: true,
});

const args = parser.parse_args();

const pattern = args.pattern;
const logEvents = args.log;
const skipTime = args.skip_time;
const suffix = args.suffix;
const onlyMissing = args.only_missing;

const examples = await exampleStorage.getExamples();

const filteredExamples = pattern
? examples.filter((example) => example.path.includes(pattern))
: examples;

if (pattern && filteredExamples.length === 0) {
console.log(`No examples found matching pattern: ${pattern}`);
return;
}

if (pattern) {
console.log(
`Found ${filteredExamples.length} example(s) matching pattern "${pattern}":`,
);
filteredExamples.forEach((example) => console.log(` - ${example.name}`));
} else {
console.log(
`Generating history for all ${filteredExamples.length} examples`,
);
}

try {
await LocalDurableTestRunner.setupTestEnvironment({
skipTime: skipTime,
});

const generated: string[] = [];
for (const example of filteredExamples) {
if (
example.path.includes("callback") ||
example.path.includes("invoke") ||
!example.durableConfig
) {
console.log("Skipping example", example.name);
continue;
}

const exampleDir = path.dirname(example.path);
const exampleBaseName = path.basename(
example.path,
path.extname(example.path),
);
if (
// If any .history.json file exists in this directory, don't generate a new one
fs
.readdirSync(exampleDir)
.some(
(file) =>
file.startsWith(exampleBaseName) &&
file.endsWith(".history.json"),
) &&
onlyMissing
) {
console.log(`History file already exists for ${example.name}`);
continue;
}

try {
console.log(`Generating history for ${example.name}`);

const runner = new LocalDurableTestRunner({
handlerFunction: (await import(example.path)).handler,
});
const result = await runner.run({
payload: args.payload ? JSON.parse(args.payload) : undefined,
});

const historyEvents = result.getHistoryEvents();

const outputPath = `${exampleDir}/${exampleBaseName + (suffix ? `-${suffix}` : "")}.history.json`;
console.log(`Output: ${outputPath}`);
fs.writeFileSync(outputPath, JSON.stringify(historyEvents, null, 2));
generated.push(example.name);

if (logEvents) {
console.log(
`History events for ${example.name}:`,
JSON.stringify(historyEvents, null, 2),
);
}
} catch (err) {
console.log(`Error generating history for ${example.name}`, err);
}
}
console.log(
`Generated ${generated.length} history files: ${JSON.stringify(generated)}`,
);
} finally {
await LocalDurableTestRunner.teardownTestEnvironment();
}
}

main().catch((err) => {
console.error(err);
process.exit(1);
});
Original file line number Diff line number Diff line change
@@ -1,102 +1,140 @@
{
"expectedHistory": {
"events": [
{
"EventType": "ExecutionStarted",
"EventId": 1,
"Name": "block-example-typescript-acceptance-test",
"ExecutionStartedDetails": {
"Input": {
"Truncated": true
},
"ExecutionTimeout": 300
}
},
{
"EventType": "ContextStarted",
"SubType": "RunInChildContext",
"EventId": 2,
"Name": "parent_block",
"ContextStartedDetails": {}
},
{
"EventType": "StepStarted",
"SubType": "Step",
"EventId": 3,
"Name": "nested_step",
"ParentId": "c4ca4238a0b92382",
"StepStartedDetails": {}
},
{
"EventType": "StepSucceeded",
"SubType": "Step",
"EventId": 4,
"Name": "nested_step",
"ParentId": "c4ca4238a0b92382",
"StepSucceededDetails": {
"Result": {
"Truncated": true
},
"RetryDetails": {
"CurrentAttempt": 0
}
}
},
{
"EventType": "ContextStarted",
"SubType": "RunInChildContext",
"EventId": 5,
"Name": "nested_block",
"ParentId": "c4ca4238a0b92382",
"ContextStartedDetails": {}
},
{
"EventType": "WaitStarted",
"SubType": "Wait",
"EventId": 6,
"ParentId": "98c6f2c2287f4c73",
"WaitStartedDetails": {
"Duration": 1
}
},
{
"EventType": "WaitSucceeded",
"EventId": 7,
"WaitSucceededDetails": {}
},
{
"EventType": "ContextSucceeded",
"SubType": "RunInChildContext",
"EventId": 8,
"Name": "nested_block",
"ParentId": "c4ca4238a0b92382",
"ContextSucceededDetails": {
"Result": {
"Truncated": true
}
}
},
{
"EventType": "ContextSucceeded",
"SubType": "RunInChildContext",
"EventId": 9,
"Name": "parent_block",
"ContextSucceededDetails": {
"Result": {
"Truncated": true
}
}
[
{
"EventType": "ExecutionStarted",
"EventId": 1,
"Id": "ec1e8feb-0e24-4870-a740-cdb91b06501c",
"EventTimestamp": "2025-12-03T22:57:07.710Z",
"ExecutionStartedDetails": {
"Input": {
"Payload": "{}"
}
}
},
{
"EventType": "ContextStarted",
"SubType": "RunInChildContext",
"EventId": 2,
"Id": "c4ca4238a0b92382",
"Name": "parent_block",
"EventTimestamp": "2025-12-03T22:57:07.716Z",
"ContextStartedDetails": {}
},
{
"EventType": "StepStarted",
"SubType": "Step",
"EventId": 3,
"Id": "ea66c06c1e1c05fa",
"Name": "nested_step",
"EventTimestamp": "2025-12-03T22:57:07.716Z",
"ParentId": "c4ca4238a0b92382",
"StepStartedDetails": {}
},
{
"EventType": "StepSucceeded",
"SubType": "Step",
"EventId": 4,
"Id": "ea66c06c1e1c05fa",
"Name": "nested_step",
"EventTimestamp": "2025-12-03T22:57:07.716Z",
"ParentId": "c4ca4238a0b92382",
"StepSucceededDetails": {
"Result": {
"Payload": "\"nested step result\""
},
{
"EventType": "ExecutionSucceeded",
"EventId": 10,
"Name": "history-generation-1757540244",
"ExecutionSucceededDetails": {
"Result": {
"Truncated": true
}
}
"RetryDetails": {}
}
},
{
"EventType": "ContextStarted",
"SubType": "RunInChildContext",
"EventId": 5,
"Id": "98c6f2c2287f4c73",
"Name": "nested_block",
"EventTimestamp": "2025-12-03T22:57:07.717Z",
"ParentId": "c4ca4238a0b92382",
"ContextStartedDetails": {}
},
{
"EventType": "WaitStarted",
"SubType": "Wait",
"EventId": 6,
"Id": "6151f5ab282d90e4",
"EventTimestamp": "2025-12-03T22:57:07.719Z",
"ParentId": "98c6f2c2287f4c73",
"WaitStartedDetails": {
"Duration": 1,
"ScheduledEndTimestamp": "2025-12-03T22:57:08.719Z"
}
},
{
"EventType": "InvocationCompleted",
"EventId": 7,
"EventTimestamp": "2025-12-03T22:57:07.771Z",
"InvocationCompletedDetails": {
"StartTimestamp": "2025-12-03T22:57:07.710Z",
"EndTimestamp": "2025-12-03T22:57:07.771Z",
"Error": {},
"RequestId": "41787b19-d7ee-4aea-b701-7b3007bf5d64"
}
},
{
"EventType": "WaitSucceeded",
"SubType": "Wait",
"EventId": 8,
"Id": "6151f5ab282d90e4",
"EventTimestamp": "2025-12-03T22:57:08.721Z",
"ParentId": "98c6f2c2287f4c73",
"WaitSucceededDetails": {
"Duration": 1
}
},
{
"EventType": "ContextSucceeded",
"SubType": "RunInChildContext",
"EventId": 9,
"Id": "98c6f2c2287f4c73",
"Name": "nested_block",
"EventTimestamp": "2025-12-03T22:57:08.723Z",
"ParentId": "c4ca4238a0b92382",
"ContextSucceededDetails": {
"Result": {
"Payload": "\"nested block result\""
}
}
},
{
"EventType": "ContextSucceeded",
"SubType": "RunInChildContext",
"EventId": 10,
"Id": "c4ca4238a0b92382",
"Name": "parent_block",
"EventTimestamp": "2025-12-03T22:57:08.724Z",
"ContextSucceededDetails": {
"Result": {
"Payload": "{\"nestedStep\":\"nested step result\",\"nestedBlock\":\"nested block result\"}"
}
}
},
{
"EventType": "InvocationCompleted",
"EventId": 11,
"EventTimestamp": "2025-12-03T22:57:08.724Z",
"InvocationCompletedDetails": {
"StartTimestamp": "2025-12-03T22:57:08.722Z",
"EndTimestamp": "2025-12-03T22:57:08.724Z",
"Error": {},
"RequestId": "21a2b7fc-9b58-4957-ab15-eb555118008d"
}
},
{
"EventType": "ExecutionSucceeded",
"EventId": 12,
"Id": "ec1e8feb-0e24-4870-a740-cdb91b06501c",
"EventTimestamp": "2025-12-03T22:57:08.724Z",
"ExecutionSucceededDetails": {
"Result": {
"Payload": "{\"nestedStep\":\"nested step result\",\"nestedBlock\":\"nested block result\"}"
}
]
}
}
}
]
Loading