@temporalio/testing 1.2.0 → 1.4.0
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/lib/{test-service-client.d.ts → connection.d.ts} +1 -1
- package/lib/{test-service-client.js → connection.js} +3 -3
- package/lib/connection.js.map +1 -0
- package/lib/index.d.ts +110 -66
- package/lib/index.js +141 -69
- package/lib/index.js.map +1 -1
- package/lib/utils.js +2 -2
- package/lib/utils.js.map +1 -1
- package/package.json +8 -21
- package/src/{test-service-client.ts → connection.ts} +1 -1
- package/src/index.ts +210 -135
- package/src/utils.ts +1 -1
- package/generated-protos/index.d.ts +0 -4206
- package/generated-protos/index.js +0 -11034
- package/lib/child-process.d.ts +0 -16
- package/lib/child-process.js +0 -57
- package/lib/child-process.js.map +0 -1
- package/lib/index-for-docs.d.ts +0 -1
- package/lib/index-for-docs.js +0 -29
- package/lib/index-for-docs.js.map +0 -1
- package/lib/test-service-client.js.map +0 -1
- package/scripts/common.mjs +0 -18
- package/scripts/compile-proto.mjs +0 -91
- package/scripts/download-test-server.mjs +0 -91
- package/src/child-process.ts +0 -60
- package/src/index-for-docs.ts +0 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@temporalio/testing",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Temporal.io SDK Testing sub-package",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "./lib/index.d.ts",
|
|
@@ -9,27 +9,16 @@
|
|
|
9
9
|
"workflow",
|
|
10
10
|
"testing"
|
|
11
11
|
],
|
|
12
|
-
"scripts": {
|
|
13
|
-
"install": "node ./scripts/download-test-server.mjs",
|
|
14
|
-
"build": "npm-run-all build:protos install",
|
|
15
|
-
"build:protos": "node ./scripts/compile-proto.mjs"
|
|
16
|
-
},
|
|
17
12
|
"author": "Temporal Technologies Inc. <sdk@temporal.io>",
|
|
18
13
|
"license": "MIT",
|
|
19
14
|
"dependencies": {
|
|
20
15
|
"@grpc/grpc-js": "^1.6.7",
|
|
21
|
-
"@temporalio/activity": "^1.
|
|
22
|
-
"@temporalio/client": "^1.
|
|
23
|
-
"@temporalio/common": "^1.
|
|
24
|
-
"@temporalio/worker": "^1.
|
|
25
|
-
"@types/long": "^4.0.2",
|
|
16
|
+
"@temporalio/activity": "^1.4.0",
|
|
17
|
+
"@temporalio/client": "^1.4.0",
|
|
18
|
+
"@temporalio/common": "^1.4.0",
|
|
19
|
+
"@temporalio/worker": "^1.4.0",
|
|
26
20
|
"abort-controller": "^3.0.0",
|
|
27
|
-
"
|
|
28
|
-
"got": "^12.1.0",
|
|
29
|
-
"long": "^5.2.0",
|
|
30
|
-
"protobufjs": "^7.0.0",
|
|
31
|
-
"tar-stream": "^2.2.0",
|
|
32
|
-
"unzipper": "^0.10.11"
|
|
21
|
+
"ms": "^2.1.3"
|
|
33
22
|
},
|
|
34
23
|
"bugs": {
|
|
35
24
|
"url": "https://github.com/temporalio/sdk-typescript/issues"
|
|
@@ -37,12 +26,10 @@
|
|
|
37
26
|
"homepage": "https://github.com/temporalio/sdk-typescript/tree/main/packages/testing",
|
|
38
27
|
"files": [
|
|
39
28
|
"lib",
|
|
40
|
-
"src"
|
|
41
|
-
"generated-protos",
|
|
42
|
-
"scripts"
|
|
29
|
+
"src"
|
|
43
30
|
],
|
|
44
31
|
"publishConfig": {
|
|
45
32
|
"access": "public"
|
|
46
33
|
},
|
|
47
|
-
"gitHead": "
|
|
34
|
+
"gitHead": "4b757ebbc052f327cc37e5693f46c8127c156b0c"
|
|
48
35
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as grpc from '@grpc/grpc-js';
|
|
2
2
|
import { Connection as BaseConnection, ConnectionOptions } from '@temporalio/client';
|
|
3
3
|
import { ConnectionCtorOptions as BaseConnectionCtorOptions } from '@temporalio/client/lib/connection';
|
|
4
|
-
import { temporal } from '
|
|
4
|
+
import { temporal } from '@temporalio/proto';
|
|
5
5
|
|
|
6
6
|
export type TestService = temporal.api.testservice.v1.TestService;
|
|
7
7
|
export const { TestService } = temporal.api.testservice.v1;
|
package/src/index.ts
CHANGED
|
@@ -11,54 +11,41 @@
|
|
|
11
11
|
import * as activity from '@temporalio/activity';
|
|
12
12
|
import {
|
|
13
13
|
AsyncCompletionClient,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
Client,
|
|
15
|
+
ClientOptions,
|
|
16
|
+
ConnectionLike,
|
|
17
|
+
WorkflowClient,
|
|
18
|
+
WorkflowClientOptions,
|
|
19
|
+
WorkflowResultOptions,
|
|
18
20
|
} from '@temporalio/client';
|
|
19
|
-
import { ActivityFunction, CancelledFailure
|
|
20
|
-
import {
|
|
21
|
+
import { ActivityFunction, CancelledFailure } from '@temporalio/common';
|
|
22
|
+
import { msToTs, tsToMs } from '@temporalio/common/lib/time';
|
|
23
|
+
import { NativeConnection, Runtime } from '@temporalio/worker';
|
|
24
|
+
import {
|
|
25
|
+
EphemeralServer,
|
|
26
|
+
EphemeralServerConfig,
|
|
27
|
+
getEphemeralServerTarget,
|
|
28
|
+
TemporaliteConfig,
|
|
29
|
+
TimeSkippingServerConfig,
|
|
30
|
+
} from '@temporalio/core-bridge';
|
|
21
31
|
import path from 'path';
|
|
22
|
-
import os from 'os';
|
|
23
32
|
import { AbortController } from 'abort-controller';
|
|
24
|
-
import { ChildProcess, spawn, StdioOptions } from 'child_process';
|
|
25
33
|
import events from 'events';
|
|
26
|
-
import {
|
|
27
|
-
import
|
|
28
|
-
import
|
|
29
|
-
|
|
30
|
-
const TEST_SERVER_EXECUTABLE_NAME = os.platform() === 'win32' ? 'test-server.exe' : 'test-server';
|
|
34
|
+
import { Connection, TestService } from './connection';
|
|
35
|
+
import { filterNullAndUndefined } from '@temporalio/common/lib/internal-non-workflow';
|
|
36
|
+
import ms from 'ms';
|
|
31
37
|
|
|
32
|
-
export
|
|
38
|
+
export { TimeSkippingServerConfig, TemporaliteConfig, EphemeralServerExecutable } from '@temporalio/core-bridge';
|
|
39
|
+
export { EphemeralServerConfig };
|
|
33
40
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
* whether to toggle time skipping in the Test server while waiting on a
|
|
38
|
-
* Workflow's result.
|
|
39
|
-
*/
|
|
40
|
-
export interface WorkflowResultOptions extends BaseWorkflowResultOptions {
|
|
41
|
-
/**
|
|
42
|
-
* If set to `true`, waiting for the result does not enable time skipping
|
|
43
|
-
*/
|
|
44
|
-
runInNormalTime?: boolean;
|
|
41
|
+
export interface TimeSkippingWorkflowClientOptions extends WorkflowClientOptions {
|
|
42
|
+
connection: Connection;
|
|
43
|
+
enableTimeSkipping: boolean;
|
|
45
44
|
}
|
|
46
45
|
|
|
47
|
-
|
|
48
|
-
* Options passed to {@link WorkflowClient.execute}, these are the same as the
|
|
49
|
-
* {@link BaseWorkflowStartOptions} with an additional option that controls
|
|
50
|
-
* whether to toggle time skipping in the Test server while waiting on a
|
|
51
|
-
* Workflow's result.
|
|
52
|
-
*/
|
|
53
|
-
export type WorkflowStartOptions<T extends Workflow> = BaseWorkflowStartOptions<T> & {
|
|
54
|
-
/**
|
|
55
|
-
* If set to `true`, waiting for the result does not enable time skipping
|
|
56
|
-
*/
|
|
57
|
-
runInNormalTime?: boolean;
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
export interface WorkflowClientOptions extends BaseWorkflowClientOptions {
|
|
46
|
+
export interface TestEnvClientOptions extends ClientOptions {
|
|
61
47
|
connection: Connection;
|
|
48
|
+
enableTimeSkipping: boolean;
|
|
62
49
|
}
|
|
63
50
|
|
|
64
51
|
/**
|
|
@@ -66,48 +53,63 @@ export interface WorkflowClientOptions extends BaseWorkflowClientOptions {
|
|
|
66
53
|
* When this client waits on a Workflow's result, it will enable time skipping
|
|
67
54
|
* in the test server.
|
|
68
55
|
*/
|
|
69
|
-
export class
|
|
56
|
+
export class TimeSkippingWorkflowClient extends WorkflowClient {
|
|
70
57
|
protected readonly testService: TestService;
|
|
58
|
+
protected readonly enableTimeSkipping: boolean;
|
|
71
59
|
|
|
72
|
-
constructor(options:
|
|
60
|
+
constructor(options: TimeSkippingWorkflowClientOptions) {
|
|
73
61
|
super(options);
|
|
62
|
+
this.enableTimeSkipping = options.enableTimeSkipping;
|
|
74
63
|
this.testService = options.connection.testService;
|
|
75
64
|
}
|
|
76
65
|
|
|
77
|
-
/**
|
|
78
|
-
* Execute a Workflow and wait for completion.
|
|
79
|
-
*
|
|
80
|
-
* @see {@link BaseWorkflowClient.execute}
|
|
81
|
-
*/
|
|
82
|
-
public async execute<T extends Workflow>(
|
|
83
|
-
workflowTypeOrFunc: string | T,
|
|
84
|
-
options: WorkflowStartOptions<T>
|
|
85
|
-
): Promise<WorkflowResultType<T>> {
|
|
86
|
-
return super.execute(workflowTypeOrFunc, options);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
66
|
/**
|
|
90
67
|
* Gets the result of a Workflow execution.
|
|
91
68
|
*
|
|
92
|
-
* @see {@link
|
|
69
|
+
* @see {@link WorkflowClient.result}
|
|
93
70
|
*/
|
|
94
71
|
override async result<T>(
|
|
95
72
|
workflowId: string,
|
|
96
73
|
runId?: string | undefined,
|
|
97
74
|
opts?: WorkflowResultOptions | undefined
|
|
98
75
|
): Promise<T> {
|
|
99
|
-
if (
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
76
|
+
if (this.enableTimeSkipping) {
|
|
77
|
+
await this.testService.unlockTimeSkipping({});
|
|
78
|
+
try {
|
|
79
|
+
return await super.result(workflowId, runId, opts);
|
|
80
|
+
} finally {
|
|
81
|
+
await this.testService.lockTimeSkipping({});
|
|
82
|
+
}
|
|
83
|
+
} else {
|
|
104
84
|
return await super.result(workflowId, runId, opts);
|
|
105
|
-
} finally {
|
|
106
|
-
await this.testService.lockTimeSkipping({});
|
|
107
85
|
}
|
|
108
86
|
}
|
|
109
87
|
}
|
|
110
88
|
|
|
89
|
+
/**
|
|
90
|
+
* A client with the exact same API as the "normal" client with one exception:
|
|
91
|
+
* when `TestEnvClient.workflow` (an instance of {@link TimeSkippingWorkflowClient}) waits on a Workflow's result, it will enable time skipping
|
|
92
|
+
* in the Test Server.
|
|
93
|
+
*/
|
|
94
|
+
class TestEnvClient extends Client {
|
|
95
|
+
constructor(options: TestEnvClientOptions) {
|
|
96
|
+
super(options);
|
|
97
|
+
|
|
98
|
+
const { workflow, loadedDataConverter, interceptors, ...base } = this.options;
|
|
99
|
+
|
|
100
|
+
// Recreate the client (this isn't optimal but it's better than adding public methods just for testing).
|
|
101
|
+
// NOTE: we cast to "any" to work around `workflow` being a readonly attribute.
|
|
102
|
+
(this as any).workflow = new TimeSkippingWorkflowClient({
|
|
103
|
+
...base,
|
|
104
|
+
...workflow,
|
|
105
|
+
connection: options.connection,
|
|
106
|
+
dataConverter: loadedDataConverter,
|
|
107
|
+
interceptors: interceptors.workflow,
|
|
108
|
+
enableTimeSkipping: options.enableTimeSkipping,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
111
113
|
/**
|
|
112
114
|
* Convenience workflow interceptors
|
|
113
115
|
*
|
|
@@ -116,48 +118,44 @@ export class WorkflowClient extends BaseWorkflowClient {
|
|
|
116
118
|
*/
|
|
117
119
|
export const workflowInterceptorModules = [path.join(__dirname, 'assert-to-failure-interceptor')];
|
|
118
120
|
|
|
119
|
-
export interface TestServerSpawnerOptions {
|
|
120
|
-
/**
|
|
121
|
-
* @default {@link DEFAULT_TEST_SERVER_PATH}
|
|
122
|
-
*/
|
|
123
|
-
path?: string;
|
|
124
|
-
/**
|
|
125
|
-
* @default ignore
|
|
126
|
-
*/
|
|
127
|
-
stdio?: StdioOptions;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
121
|
/**
|
|
131
|
-
*
|
|
122
|
+
* Subset of the "normal" client options that are used to create a client for the test environment.
|
|
132
123
|
*/
|
|
133
|
-
export type
|
|
124
|
+
export type ClientOptionsForTestEnv = Omit<ClientOptions, 'namespace' | 'connection'>;
|
|
134
125
|
|
|
135
126
|
/**
|
|
136
127
|
* Options for {@link TestWorkflowEnvironment.create}
|
|
137
128
|
*/
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
}
|
|
129
|
+
type TestWorkflowEnvironmentOptions = {
|
|
130
|
+
server?: EphemeralServerConfig;
|
|
131
|
+
client?: ClientOptionsForTestEnv;
|
|
132
|
+
};
|
|
142
133
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
134
|
+
/**
|
|
135
|
+
* Options for {@link TestWorkflowEnvironment.createTimeSkipping}
|
|
136
|
+
*/
|
|
137
|
+
export type TimeSkippingTestWorkflowEnvironmentOptions = {
|
|
138
|
+
server?: Omit<TimeSkippingServerConfig, 'type'>;
|
|
139
|
+
client?: ClientOptionsForTestEnv;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Options for {@link TestWorkflowEnvironment.createLocal}
|
|
144
|
+
*/
|
|
145
|
+
export type LocalTestWorkflowEnvironmentOptions = {
|
|
146
|
+
server?: Omit<TemporaliteConfig, 'type'>;
|
|
147
|
+
client?: ClientOptionsForTestEnv;
|
|
148
|
+
};
|
|
147
149
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}: TestWorkflowEnvironmentOptions): TestWorkflowEnvironmentOptionsWithDefaults {
|
|
150
|
+
export type TestWorkflowEnvironmentOptionsWithDefaults = Required<TestWorkflowEnvironmentOptions>;
|
|
151
|
+
|
|
152
|
+
function addDefaults(opts: TestWorkflowEnvironmentOptions): TestWorkflowEnvironmentOptionsWithDefaults {
|
|
152
153
|
return {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
stdio: testServer?.stdio || 'ignore',
|
|
159
|
-
}),
|
|
160
|
-
logger: logger ?? new DefaultLogger('INFO'),
|
|
154
|
+
server: {
|
|
155
|
+
type: 'time-skipping',
|
|
156
|
+
},
|
|
157
|
+
client: {},
|
|
158
|
+
...opts,
|
|
161
159
|
};
|
|
162
160
|
}
|
|
163
161
|
|
|
@@ -169,17 +167,30 @@ function addDefaults({
|
|
|
169
167
|
*/
|
|
170
168
|
export class TestWorkflowEnvironment {
|
|
171
169
|
/**
|
|
172
|
-
*
|
|
170
|
+
* Namespace used in this environment (taken from {@link TestWorkflowEnvironmentOptions})
|
|
171
|
+
*/
|
|
172
|
+
public readonly namespace?: string;
|
|
173
|
+
/**
|
|
174
|
+
* Get an established {@link Connection} to the ephemeral server
|
|
175
|
+
*/
|
|
176
|
+
public readonly connection: ConnectionLike;
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* A {@link TestEnvClient} for interacting with the ephemeral server
|
|
173
180
|
*/
|
|
174
|
-
public readonly
|
|
181
|
+
public readonly client: Client;
|
|
175
182
|
|
|
176
183
|
/**
|
|
177
184
|
* An {@link AsyncCompletionClient} for interacting with the test server
|
|
185
|
+
*
|
|
186
|
+
* @deprecated - use `client.activity` instead
|
|
178
187
|
*/
|
|
179
188
|
public readonly asyncCompletionClient: AsyncCompletionClient;
|
|
180
189
|
|
|
181
190
|
/**
|
|
182
|
-
* A {@link
|
|
191
|
+
* A {@link TimeSkippingWorkflowClient} for interacting with the test server
|
|
192
|
+
*
|
|
193
|
+
* @deprecated - use `client.workflow` instead
|
|
183
194
|
*/
|
|
184
195
|
public readonly workflowClient: WorkflowClient;
|
|
185
196
|
|
|
@@ -191,49 +202,91 @@ export class TestWorkflowEnvironment {
|
|
|
191
202
|
public readonly nativeConnection: NativeConnection;
|
|
192
203
|
|
|
193
204
|
protected constructor(
|
|
194
|
-
|
|
205
|
+
public readonly options: TestWorkflowEnvironmentOptionsWithDefaults,
|
|
206
|
+
public readonly supportsTimeSkipping: boolean,
|
|
207
|
+
protected readonly server: EphemeralServer,
|
|
195
208
|
connection: Connection,
|
|
196
209
|
nativeConnection: NativeConnection
|
|
197
210
|
) {
|
|
198
211
|
this.connection = connection;
|
|
199
212
|
this.nativeConnection = nativeConnection;
|
|
200
|
-
this.
|
|
201
|
-
this.
|
|
213
|
+
this.namespace = options.server.type === 'temporalite' ? options.server.namespace : undefined;
|
|
214
|
+
this.client = new TestEnvClient({
|
|
215
|
+
connection,
|
|
216
|
+
namespace: this.namespace,
|
|
217
|
+
enableTimeSkipping: options.server.type === 'time-skipping',
|
|
218
|
+
...options.client,
|
|
219
|
+
});
|
|
220
|
+
// eslint-disable-next-line deprecation/deprecation
|
|
221
|
+
this.asyncCompletionClient = this.client.activity;
|
|
222
|
+
// eslint-disable-next-line deprecation/deprecation
|
|
223
|
+
this.workflowClient = this.client.workflow;
|
|
202
224
|
}
|
|
203
225
|
|
|
204
226
|
/**
|
|
205
|
-
*
|
|
227
|
+
* Start a time skipping workflow environment.
|
|
228
|
+
*
|
|
229
|
+
* By default, this environment will automatically skip to the next events in time when a workflow handle's `result`
|
|
230
|
+
* is awaited on (which includes {@link WorkflowClient.execute}). Before the result is awaited on, time can be
|
|
231
|
+
* manually skipped forward using {@link sleep}. The currently known time can be obtained via {@link currentTimeMs}.
|
|
232
|
+
*
|
|
233
|
+
* Internally, this environment lazily downloads a test-server binary for the current OS/arch from the [Java SDK
|
|
234
|
+
* releases](https://github.com/temporalio/sdk-java/releases) into the temp directory if it is not already there.
|
|
235
|
+
* Then the executable is started and will be killed when {@link teardown} is called.
|
|
236
|
+
*
|
|
237
|
+
* Users can reuse this environment for testing multiple independent workflows, but not concurrently. Time skipping,
|
|
238
|
+
* which is automatically done when awaiting a workflow result and manually done on sleep, is global to the
|
|
239
|
+
* environment, not to the workflow under test.
|
|
240
|
+
*
|
|
241
|
+
* We highly recommend, running tests serially when using a single environment or creating a separate environment per
|
|
242
|
+
* test.
|
|
243
|
+
*
|
|
244
|
+
* In the future, the test server implementation may be changed to another implementation.
|
|
206
245
|
*/
|
|
207
|
-
static async
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
const child = testServerSpawner(port);
|
|
246
|
+
static async createTimeSkipping(opts?: TimeSkippingTestWorkflowEnvironmentOptions): Promise<TestWorkflowEnvironment> {
|
|
247
|
+
// eslint-disable-next-line deprecation/deprecation
|
|
248
|
+
return await this.create({ server: { type: 'time-skipping', ...opts?.server }, client: opts?.client });
|
|
249
|
+
}
|
|
213
250
|
|
|
214
|
-
|
|
215
|
-
|
|
251
|
+
/**
|
|
252
|
+
* Start a full Temporal server locally, downloading if necessary.
|
|
253
|
+
*
|
|
254
|
+
* This environment is good for testing full server capabilities, but does not support time skipping like
|
|
255
|
+
* {@link createTimeSkipping} does. {@link supportsTimeSkipping} will always return `false` for this environment.
|
|
256
|
+
* {@link sleep} will sleep the actual amount of time and {@link currentTimeMs} will return the current time.
|
|
257
|
+
*
|
|
258
|
+
* Internally, this uses [Temporalite](https://github.com/temporalio/temporalite). Which is a self-contained binary
|
|
259
|
+
* for Temporal using Sqlite persistence. This will download Temporalite to a temporary directory by default if it
|
|
260
|
+
* has not already been downloaded before and {@link LocalTestWorkflowEnvironmentOptions.server.executable.type} is
|
|
261
|
+
* `'cached-download'`.
|
|
262
|
+
*
|
|
263
|
+
* In the future, the Temporalite implementation may be changed to another implementation.
|
|
264
|
+
*/
|
|
265
|
+
static async createLocal(opts?: LocalTestWorkflowEnvironmentOptions): Promise<TestWorkflowEnvironment> {
|
|
266
|
+
// eslint-disable-next-line deprecation/deprecation
|
|
267
|
+
return await this.create({ server: { type: 'temporalite', ...opts?.server }, client: opts?.client });
|
|
268
|
+
}
|
|
216
269
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
await kill(child);
|
|
227
|
-
} catch (error) {
|
|
228
|
-
logger.error('Failed to kill test server child process', { error });
|
|
229
|
-
}
|
|
230
|
-
throw err;
|
|
231
|
-
}
|
|
270
|
+
/**
|
|
271
|
+
* Create a new test environment
|
|
272
|
+
*
|
|
273
|
+
* @deprecated - use {@link createTimeSkipping} or {@link createLocal}
|
|
274
|
+
*/
|
|
275
|
+
static async create(opts?: TestWorkflowEnvironmentOptions): Promise<TestWorkflowEnvironment> {
|
|
276
|
+
const optsWithDefaults = addDefaults(filterNullAndUndefined(opts ?? {}));
|
|
277
|
+
const server = await Runtime.instance().createEphemeralServer(optsWithDefaults.server);
|
|
278
|
+
const address = getEphemeralServerTarget(server);
|
|
232
279
|
|
|
233
|
-
const conn = await connPromise;
|
|
234
280
|
const nativeConnection = await NativeConnection.connect({ address });
|
|
235
|
-
|
|
236
|
-
|
|
281
|
+
const connection = await Connection.connect({ address });
|
|
282
|
+
|
|
283
|
+
return new this(
|
|
284
|
+
optsWithDefaults,
|
|
285
|
+
optsWithDefaults.server.type === 'time-skipping',
|
|
286
|
+
server,
|
|
287
|
+
connection,
|
|
288
|
+
nativeConnection
|
|
289
|
+
);
|
|
237
290
|
}
|
|
238
291
|
|
|
239
292
|
/**
|
|
@@ -242,20 +295,23 @@ export class TestWorkflowEnvironment {
|
|
|
242
295
|
async teardown(): Promise<void> {
|
|
243
296
|
await this.connection.close();
|
|
244
297
|
await this.nativeConnection.close();
|
|
245
|
-
|
|
246
|
-
await kill(this.serverProc, 'SIGINT', { validReturnCodes: [0, 130] });
|
|
298
|
+
await Runtime.instance().shutdownEphemeralServer(this.server);
|
|
247
299
|
}
|
|
248
300
|
|
|
249
301
|
/**
|
|
250
|
-
* Wait for `durationMs` in "
|
|
302
|
+
* Wait for `durationMs` in "server time".
|
|
251
303
|
*
|
|
252
|
-
*
|
|
253
|
-
*
|
|
254
|
-
* This method is likely to resolve in less than `durationMs` of "real time".
|
|
304
|
+
* This awaits using regular setTimeout in regular environments, or manually skips time in time-skipping environments.
|
|
255
305
|
*
|
|
256
306
|
* Useful for simulating events far into the future like completion of long running activities.
|
|
257
307
|
*
|
|
258
|
-
*
|
|
308
|
+
* **Time skippping**:
|
|
309
|
+
*
|
|
310
|
+
* The time skippping server toggles between skipped time and normal time depending on what it needs to execute.
|
|
311
|
+
*
|
|
312
|
+
* This method is _likely_ to resolve in less than `durationMs` of "real time".
|
|
313
|
+
*
|
|
314
|
+
* @param durationMs number of milliseconds or {@link https://www.npmjs.com/package/ms | ms-formatted string}
|
|
259
315
|
*
|
|
260
316
|
* @example
|
|
261
317
|
*
|
|
@@ -287,8 +343,27 @@ export class TestWorkflowEnvironment {
|
|
|
287
343
|
* ```
|
|
288
344
|
*/
|
|
289
345
|
sleep = async (durationMs: number | string): Promise<void> => {
|
|
290
|
-
|
|
346
|
+
if (this.supportsTimeSkipping) {
|
|
347
|
+
await (this.connection as Connection).testService.unlockTimeSkippingWithSleep({ duration: msToTs(durationMs) });
|
|
348
|
+
} else {
|
|
349
|
+
await new Promise((resolve) => setTimeout(resolve, typeof durationMs === 'string' ? ms(durationMs) : durationMs));
|
|
350
|
+
}
|
|
291
351
|
};
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Get the current time known to this environment.
|
|
355
|
+
*
|
|
356
|
+
* For non-time-skipping environments this is simply the system time. For time-skipping environments this is whatever
|
|
357
|
+
* time has been skipped to.
|
|
358
|
+
*/
|
|
359
|
+
async currentTimeMs(): Promise<number> {
|
|
360
|
+
if (this.supportsTimeSkipping) {
|
|
361
|
+
const { time } = await (this.connection as Connection).testService.getCurrentTime({});
|
|
362
|
+
return tsToMs(time);
|
|
363
|
+
} else {
|
|
364
|
+
return Date.now();
|
|
365
|
+
}
|
|
366
|
+
}
|
|
292
367
|
}
|
|
293
368
|
|
|
294
369
|
/**
|
package/src/utils.ts
CHANGED