Skip to content

Commit 8237158

Browse files
committed
special prefix behaviour, does not cover workflows
1 parent 0d05950 commit 8237158

File tree

8 files changed

+175
-199
lines changed

8 files changed

+175
-199
lines changed

packages/test/src/test-integration-split-two.ts

Lines changed: 2 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,11 @@ import {
2121
defineUpdate,
2222
setDefaultQueryHandler,
2323
setDefaultSignalHandler,
24+
setDefaultUpdateHandler,
2425
setHandler,
2526
sleep,
2627
} from '@temporalio/workflow';
27-
import { reservedPrefixes } from '@temporalio/common/lib/reserved';
28+
import { ReservedPrefixError, reservedPrefixes } from '@temporalio/common/lib/reserved';
2829
import { configurableHelpers, createTestWorkflowBundle } from './helpers-integration';
2930
import * as activities from './activities';
3031
import * as workflows from './workflows';
@@ -772,159 +773,4 @@ test.serial('default query handler is not used if requested query exists', confi
772773
const result = await handle.query('query-handler-type', ...args);
773774
t.deepEqual(result, { name: definedQuery.name, args });
774775
});
775-
});
776-
777-
test('Cannot register activities using reserved prefixes', configMacro, async (t, config) => {
778-
const { createWorkerWithDefaults } = config;
779-
780-
for (const prefix of reservedPrefixes) {
781-
const activityName = prefix + '_test';
782-
await t.throwsAsync(
783-
createWorkerWithDefaults(t, {
784-
activities: { [activityName]: () => {} },
785-
}),
786-
{
787-
instanceOf: Error,
788-
message: `Cannot register activity name: '${activityName}', with reserved prefix: '${prefix}'`,
789-
}
790-
);
791-
}
792-
});
793-
794-
test('Cannot register task queues using reserved prefixes', configMacro, async (t, config) => {
795-
const { createWorkerWithDefaults } = config;
796-
797-
for (const prefix of reservedPrefixes) {
798-
const taskQueue = prefix + '_test';
799-
800-
await t.throwsAsync(
801-
createWorkerWithDefaults(t, {
802-
taskQueue,
803-
}),
804-
{
805-
instanceOf: Error,
806-
message: `Cannot register task queue name: '${taskQueue}', with reserved prefix: '${prefix}'`,
807-
}
808-
);
809-
}
810-
});
811-
812-
interface HandlerError {
813-
name: string;
814-
message: string;
815-
}
816-
817-
export async function workflowBadPrefixHandler(prefix: string): Promise<HandlerError[]> {
818-
// Re-package errors, default payload converter has trouble converting native errors (no 'data' field).
819-
const expectedErrors: HandlerError[] = [];
820-
try {
821-
setHandler(defineSignal(prefix + '_signal'), () => {});
822-
} catch (e) {
823-
if (e instanceof Error) {
824-
expectedErrors.push({ name: e.name, message: e.message });
825-
}
826-
}
827-
try {
828-
setHandler(defineUpdate(prefix + '_update'), () => {});
829-
} catch (e) {
830-
if (e instanceof Error) {
831-
expectedErrors.push({ name: e.name, message: e.message });
832-
}
833-
}
834-
try {
835-
setHandler(defineQuery(prefix + '_query'), () => {});
836-
} catch (e) {
837-
if (e instanceof Error) {
838-
expectedErrors.push({ name: e.name, message: e.message });
839-
}
840-
}
841-
return expectedErrors;
842-
}
843-
844-
test('Workflow failure if define signals/updates/queries with reserved prefixes', configMacro, async (t, config) => {
845-
const { env, createWorkerWithDefaults } = config;
846-
const { executeWorkflow } = configurableHelpers(t, t.context.workflowBundle, env);
847-
const worker = await createWorkerWithDefaults(t);
848-
await worker.runUntil(async () => {
849-
const prefix = reservedPrefixes[0];
850-
// for (const prefix of reservedPrefixes) {
851-
const result = await executeWorkflow(workflowBadPrefixHandler, {
852-
args: [prefix],
853-
});
854-
console.log('result', result);
855-
t.deepEqual(result, [
856-
{ name: 'Error', message: `Cannot register signal name: '${prefix}_signal', with reserved prefix: '${prefix}'` },
857-
{ name: 'Error', message: `Cannot register update name: '${prefix}_update', with reserved prefix: '${prefix}'` },
858-
{ name: 'Error', message: `Cannot register query name: '${prefix}_query', with reserved prefix: '${prefix}'` },
859-
]);
860-
// }
861-
});
862-
});
863-
864-
export async function workflowWithDefaultHandlers(): Promise<void> {
865-
let unblocked = false;
866-
setHandler(defineSignal('unblock'), () => {
867-
unblocked = true;
868-
});
869-
870-
setDefaultQueryHandler(() => {});
871-
setDefaultSignalHandler(() => {});
872-
setDefaultUpdateHandler({
873-
handler: () => {},
874-
});
875-
876-
await condition(() => unblocked);
877-
}
878-
879-
test('Default handlers fail WFT given reserved prefix', configMacro, async (t, config) => {
880-
const { env, createWorkerWithDefaults } = config;
881-
const { startWorkflow } = configurableHelpers(t, t.context.workflowBundle, env);
882-
const worker = await createWorkerWithDefaults(t);
883-
884-
const assertWftFailure = async (
885-
handle: WorkflowHandle,
886-
name: string,
887-
prefix: string,
888-
handlerType: 'query' | 'signal' | 'update'
889-
) => {
890-
await asyncRetry(
891-
async () => {
892-
const history = await handle.fetchHistory();
893-
const wftFailedEvent = history.events?.findLast((ev) => ev.workflowTaskFailedEventAttributes);
894-
if (wftFailedEvent === undefined) {
895-
throw new Error('No WFT failed event found');
896-
}
897-
const { failure } = wftFailedEvent.workflowTaskFailedEventAttributes ?? {};
898-
if (!failure) {
899-
return t.fail('Expected failure in workflowTaskFailedEventAttributes');
900-
}
901-
t.is(failure.message, `Cannot use ${handlerType} name: '${name}', with reserved prefix: '${prefix}'`);
902-
},
903-
{ minTimeout: 300, factor: 1, retries: 10 }
904-
);
905-
};
906-
907-
await worker.runUntil(async () => {
908-
for (const prefix of reservedPrefixes) {
909-
// Test Query
910-
let handle = await startWorkflow(workflowWithDefaultHandlers);
911-
const queryName = `${prefix}_query`;
912-
await t.throwsAsync(handle.query(queryName), undefined, `Query ${queryName} should fail`);
913-
await assertWftFailure(handle, queryName, prefix, 'query');
914-
await handle.terminate();
915-
// Test Signal
916-
handle = await startWorkflow(workflowWithDefaultHandlers);
917-
const signalName = `${prefix}_signal`;
918-
await handle.signal(signalName);
919-
await assertWftFailure(handle, signalName, prefix, 'signal');
920-
await handle.terminate();
921-
922-
// Test Update
923-
handle = await startWorkflow(workflowWithDefaultHandlers);
924-
const updateName = `${prefix}_update`;
925-
await t.throwsAsync(handle.executeUpdate(updateName), undefined, `Update ${updateName} should fail`);
926-
await assertWftFailure(handle, updateName, prefix, 'update');
927-
await handle.terminate();
928-
}
929-
});
930776
});

packages/test/src/test-integration-workflows.ts

Lines changed: 163 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1+
import asyncRetry from 'async-retry';
12
import { setTimeout as setTimeoutPromise } from 'timers/promises';
23
import { randomUUID } from 'crypto';
34
import { ExecutionContext } from 'ava';
45
import { firstValueFrom, Subject } from 'rxjs';
5-
import { WorkflowFailedError } from '@temporalio/client';
6+
import { WorkflowFailedError, WorkflowHandle } from '@temporalio/client';
67
import * as activity from '@temporalio/activity';
78
import { msToNumber, tsToMs } from '@temporalio/common/lib/time';
89
import { TestWorkflowEnvironment } from '@temporalio/testing';
910
import { CancelReason } from '@temporalio/worker/lib/activity';
1011
import * as workflow from '@temporalio/workflow';
11-
import { defineQuery, defineSignal } from '@temporalio/workflow';
12+
import { condition, defineQuery, defineSignal, defineUpdate, setDefaultQueryHandler, setDefaultSignalHandler, setDefaultUpdateHandler, setHandler } from '@temporalio/workflow';
1213
import { SdkFlags } from '@temporalio/workflow/lib/flags';
1314
import {
1415
ActivityCancellationType,
@@ -25,6 +26,7 @@ import * as workflows from './workflows';
2526
import { Context, createLocalTestEnvironment, helpers, makeTestFunction } from './helpers-integration';
2627
import { overrideSdkInternalFlag } from './mock-internal-flags';
2728
import { asSdkLoggerSink, loadHistory, RUN_TIME_SKIPPING_TESTS, waitUntil } from './helpers';
29+
import { reservedPrefixes } from '@temporalio/common/src/reserved';
2830

2931
const test = makeTestFunction({
3032
workflowsPath: __filename,
@@ -1414,3 +1416,162 @@ test('Workflow can return root workflow', async (t) => {
14141416
t.deepEqual(result, 'empty test-root-workflow-length');
14151417
});
14161418
});
1419+
1420+
test('Cannot register activities using reserved prefixes', async (t) => {
1421+
const { createWorker } = helpers(t);
1422+
1423+
for (const prefix of reservedPrefixes) {
1424+
const activityName = prefix + '_test';
1425+
await t.throwsAsync(
1426+
createWorker({
1427+
activities: { [activityName]: () => {} },
1428+
}),
1429+
{
1430+
name: 'ReservedPrefixError',
1431+
message: `Cannot use activity name: '${activityName}', with reserved prefix: '${prefix}'`,
1432+
}
1433+
);
1434+
}
1435+
});
1436+
1437+
test('Cannot register task queues using reserved prefixes', async (t) => {
1438+
const { createWorker } = helpers(t);
1439+
1440+
for (const prefix of reservedPrefixes) {
1441+
const taskQueue = prefix + '_test';
1442+
1443+
await t.throwsAsync(
1444+
createWorker({
1445+
taskQueue,
1446+
}),
1447+
{
1448+
name: 'ReservedPrefixError',
1449+
message: `Cannot use task queue name: '${taskQueue}', with reserved prefix: '${prefix}'`,
1450+
}
1451+
);
1452+
}
1453+
});
1454+
1455+
interface HandlerError {
1456+
name: string;
1457+
message: string;
1458+
}
1459+
1460+
export async function workflowBadPrefixHandler(prefix: string): Promise<HandlerError[]> {
1461+
// Re-package errors, default payload converter has trouble converting native errors (no 'data' field).
1462+
const expectedErrors: HandlerError[] = [];
1463+
try {
1464+
setHandler(defineSignal(prefix + '_signal'), () => {});
1465+
} catch (e) {
1466+
if (e instanceof Error) {
1467+
expectedErrors.push({ name: e.name, message: e.message });
1468+
}
1469+
}
1470+
try {
1471+
setHandler(defineUpdate(prefix + '_update'), () => {});
1472+
} catch (e) {
1473+
if (e instanceof Error) {
1474+
expectedErrors.push({ name: e.name, message: e.message });
1475+
}
1476+
}
1477+
try {
1478+
setHandler(defineQuery(prefix + '_query'), () => {});
1479+
} catch (e) {
1480+
if (e instanceof Error) {
1481+
expectedErrors.push({ name: e.name, message: e.message });
1482+
}
1483+
}
1484+
return expectedErrors;
1485+
}
1486+
1487+
test('Workflow failure if define signals/updates/queries with reserved prefixes', async (t) => {
1488+
const { createWorker, executeWorkflow } = helpers(t);
1489+
const worker = await createWorker();
1490+
await worker.runUntil(async () => {
1491+
for (const prefix of reservedPrefixes) {
1492+
const result = await executeWorkflow(workflowBadPrefixHandler, {
1493+
args: [prefix],
1494+
});
1495+
t.deepEqual(result, [
1496+
{ name: 'ReservedPrefixError', message: `Cannot use signal name: '${prefix}_signal', with reserved prefix: '${prefix}'` },
1497+
{ name: 'ReservedPrefixError', message: `Cannot use update name: '${prefix}_update', with reserved prefix: '${prefix}'` },
1498+
{ name: 'ReservedPrefixError', message: `Cannot use query name: '${prefix}_query', with reserved prefix: '${prefix}'` },
1499+
]);
1500+
}
1501+
});
1502+
});
1503+
1504+
export async function workflowWithDefaultHandlers(): Promise<void> {
1505+
let unblocked = false;
1506+
setHandler(defineSignal('unblock'), () => {
1507+
unblocked = true;
1508+
});
1509+
1510+
setDefaultQueryHandler(() => {});
1511+
setDefaultSignalHandler(() => {});
1512+
setDefaultUpdateHandler(() => {});
1513+
1514+
await condition(() => unblocked);
1515+
}
1516+
1517+
test('Default handlers fail given reserved prefix', async (t) => {
1518+
const { createWorker, startWorkflow } = helpers(t);
1519+
const worker = await createWorker();
1520+
1521+
const assertWftFailure = async (
1522+
handle: WorkflowHandle,
1523+
errMsg: string,
1524+
) => {
1525+
await asyncRetry(
1526+
async () => {
1527+
const history = await handle.fetchHistory();
1528+
const wftFailedEvent = history.events?.findLast((ev) => ev.workflowTaskFailedEventAttributes);
1529+
if (wftFailedEvent === undefined) {
1530+
throw new Error('No WFT failed event found');
1531+
}
1532+
const { failure } = wftFailedEvent.workflowTaskFailedEventAttributes ?? {};
1533+
if (!failure) {
1534+
return t.fail('Expected failure in workflowTaskFailedEventAttributes');
1535+
}
1536+
t.is(failure.message, errMsg);
1537+
},
1538+
{ minTimeout: 300, factor: 1, retries: 10 }
1539+
);
1540+
};
1541+
1542+
await worker.runUntil(async () => {
1543+
for (const prefix of reservedPrefixes) {
1544+
1545+
// Reserved query
1546+
let handle = await startWorkflow(workflowWithDefaultHandlers);
1547+
const queryName = `${prefix}_query`;
1548+
await t.throwsAsync(handle.query(queryName, { timeout: 1000 }), {
1549+
// ReservedPrefixError transforms to a QueryNotRegisteredError on the way back from server
1550+
name: 'QueryNotRegisteredError',
1551+
message: `Cannot use query name: '${queryName}', with reserved prefix: '${prefix}'`,
1552+
}, `Query ${queryName} should fail`);
1553+
await handle.terminate();
1554+
1555+
1556+
1557+
// Reserved signal
1558+
handle = await startWorkflow(workflowWithDefaultHandlers);
1559+
const signalName = `${prefix}_signal`;
1560+
await handle.signal(signalName);
1561+
await assertWftFailure(handle, `Cannot use signal name: '${signalName}', with reserved prefix: '${prefix}'`);
1562+
await handle.terminate();
1563+
1564+
1565+
// Reserved update
1566+
handle = await startWorkflow(workflowWithDefaultHandlers);
1567+
const updateName = `${prefix}_update`;
1568+
handle.executeUpdate(updateName).catch(() => {
1569+
// Expect failure. The error caught here is a WorkflowNotFound because
1570+
// the workflow will have already failed, so the update cannot go through.
1571+
// We assert on the expected failure below.
1572+
});
1573+
await assertWftFailure(handle, `Cannot use update name: '${updateName}', with reserved prefix: '${prefix}'`);
1574+
await handle.terminate();
1575+
}
1576+
});
1577+
});

packages/test/src/test-workflows.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,6 @@ import { VMWorkflow, VMWorkflowCreator } from '@temporalio/worker/lib/workflow/v
2121
import { SdkFlag, SdkFlags } from '@temporalio/workflow/lib/flags';
2222
import { ReusableVMWorkflow, ReusableVMWorkflowCreator } from '@temporalio/worker/lib/workflow/reusable-vm';
2323
import { parseWorkflowCode } from '@temporalio/worker/lib/worker';
24-
import {
25-
ENHANCED_STACK_TRACE_RESERVED_PREFIX,
26-
reservedPrefixes,
27-
STACK_TRACE_RESERVED_PREFIX,
28-
TEMPORAL_RESERVED_PREFIX,
29-
} from '@temporalio/common/lib/reserved';
3024
import * as activityFunctions from './activities';
3125
import { cleanStackTrace, REUSE_V8_CONTEXT, u8 } from './helpers';
3226
import { ProcessedSignal } from './workflows';

packages/test/src/workflows/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,4 +92,3 @@ export * from './workflow-cancellation-scenarios';
9292
export * from './upsert-and-read-memo';
9393
export * from './updates-ordering';
9494
export * from './wait-on-signal-then-activity';
95-
export * from './workflow-with-default-handlers';

packages/test/src/workflows/workflow-with-default-handlers.ts

Lines changed: 0 additions & 16 deletions
This file was deleted.

0 commit comments

Comments
 (0)