Skip to content

Commit 283ef61

Browse files
authored
chore: Improve integration test for failure converter (#947)
1 parent 9a690dc commit 283ef61

File tree

3 files changed

+42
-19
lines changed

3 files changed

+42
-19
lines changed

packages/common/src/converter/failure-converter.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ export class DefaultFailureConverter implements FailureConverter {
169169
throw new TypeError('Missing activityType?.name on activityFailureInfo');
170170
}
171171
return new ActivityFailure(
172+
failure.message ?? undefined,
172173
failure.activityFailureInfo.activityType.name,
173174
failure.activityFailureInfo.activityId ?? undefined,
174175
failure.activityFailureInfo.retryState ?? RetryState.RETRY_STATE_UNSPECIFIED,

packages/common/src/failure.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,13 +232,14 @@ export class ActivityFailure extends TemporalFailure {
232232
public readonly name: string = 'ActivityFailure';
233233

234234
public constructor(
235+
message: string | undefined,
235236
public readonly activityType: string,
236237
public readonly activityId: string | undefined,
237238
public readonly retryState: RetryState,
238239
public readonly identity: string | undefined,
239240
cause?: Error
240241
) {
241-
super('Activity execution failed', cause);
242+
super(message, cause);
242243
}
243244
}
244245

packages/test/src/test-failure-converter.ts

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,22 @@ import {
66
DataConverter,
77
DefaultEncodedFailureAttributes,
88
} from '@temporalio/common';
9+
import { proxyActivities } from '@temporalio/workflow';
910
import { WorkflowFailedError } from '@temporalio/client';
1011
import { decodeFromPayloadsAtIndex } from '@temporalio/common/lib/internal-non-workflow';
1112
import { test, bundlerOptions, ByteSkewerPayloadCodec, Worker } from './helpers';
1213

1314
export const failureConverter = new DefaultFailureConverter({ encodeCommonAttributes: true });
1415

15-
export async function workflow(): Promise<never> {
16-
throw ApplicationFailure.create({ message: 'error message' });
16+
class Activities {
17+
public raise = async () => {
18+
throw ApplicationFailure.nonRetryable('error message');
19+
};
20+
}
21+
22+
export async function workflow(): Promise<void> {
23+
const activities = proxyActivities<Activities>({ startToCloseTimeout: '1m' });
24+
await activities.raise();
1725
}
1826

1927
test('Client and Worker use provided failureConverter', async (t) => {
@@ -24,15 +32,10 @@ test('Client and Worker use provided failureConverter', async (t) => {
2432
};
2533
const env = await TestWorkflowEnvironment.createLocal({ client: { dataConverter } });
2634
try {
27-
const info = await env.connection.workflowService.getSystemInfo({});
28-
if (!info.capabilities?.encodedFailureAttributes) {
29-
t.pass('Skipped test for lack of encodedFailureAttributes capability');
30-
return;
31-
}
32-
3335
const taskQueue = 'test';
3436
const worker = await Worker.create({
3537
connection: env.nativeConnection,
38+
activities: new Activities(),
3639
workflowsPath: __filename,
3740
taskQueue,
3841
dataConverter,
@@ -42,19 +45,37 @@ test('Client and Worker use provided failureConverter', async (t) => {
4245
// Run the workflow, expect error with message and stack trace
4346
const handle = await env.client.workflow.start(workflow, { taskQueue, workflowId: randomUUID() });
4447
const err = (await worker.runUntil(t.throwsAsync(handle.result()))) as WorkflowFailedError;
45-
t.is(err.cause?.message, 'error message');
46-
t.true(err.cause?.stack?.startsWith('ApplicationFailure: error message\n'));
48+
t.is(err.cause?.message, 'Activity task failed');
49+
t.is(err.cause?.cause?.message, 'error message');
50+
t.true(err.cause?.cause?.stack?.includes('ApplicationFailure: error message\n'));
4751

4852
// Verify failure was indeed encoded
4953
const { events } = await handle.fetchHistory();
50-
const payload = events?.[events.length - 1].workflowExecutionFailedEventAttributes?.failure?.encodedAttributes;
51-
const attrs = await decodeFromPayloadsAtIndex<DefaultEncodedFailureAttributes>(
52-
env.client.options.loadedDataConverter,
53-
0,
54-
payload ? [payload] : undefined
55-
);
56-
t.is(attrs.message, 'error message');
57-
t.true(attrs.stack_trace.startsWith('ApplicationFailure: error message\n'));
54+
const { failure } = events?.[events.length - 1].workflowExecutionFailedEventAttributes ?? {};
55+
{
56+
const payload = failure?.encodedAttributes;
57+
const attrs = await decodeFromPayloadsAtIndex<DefaultEncodedFailureAttributes>(
58+
env.client.options.loadedDataConverter,
59+
0,
60+
payload ? [payload] : undefined
61+
);
62+
t.is(failure?.message, 'Encoded failure');
63+
t.is(failure?.stackTrace, '');
64+
t.is(attrs.message, 'Activity task failed');
65+
t.is(attrs.stack_trace, '');
66+
}
67+
{
68+
const payload = failure?.cause?.encodedAttributes;
69+
const attrs = await decodeFromPayloadsAtIndex<DefaultEncodedFailureAttributes>(
70+
env.client.options.loadedDataConverter,
71+
0,
72+
payload ? [payload] : undefined
73+
);
74+
t.is(failure?.cause?.message, 'Encoded failure');
75+
t.is(failure?.stackTrace, '');
76+
t.is(attrs.message, 'error message');
77+
t.true(attrs.stack_trace.includes('ApplicationFailure: error message\n'));
78+
}
5879
} finally {
5980
await env.teardown();
6081
}

0 commit comments

Comments
 (0)