Skip to content

Commit cddbffb

Browse files
authored
feat(testing): Use temporal CLI to power local test environment (#1077)
BREAKING CHANGE: the `TemporaliteConfig` interface was deleted but it likely was not directly referenced as only the deprecated `create` method accepted it. Closes #1055
1 parent 3eea2fb commit cddbffb

File tree

9 files changed

+62
-57
lines changed

9 files changed

+62
-57
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ jobs:
7070

7171
- run: npm test
7272
env:
73-
# TODO: Run integration tests on MacOS / Windows probably using temporalite
73+
# NOTE: Newer tests start their own server and are not subject to this env var.
7474
RUN_INTEGRATION_TESTS: ${{ startsWith(matrix.os, 'ubuntu') }}
7575
REUSE_V8_CONTEXT: ${{ matrix.reuse-v8-context }}
7676

packages/core-bridge/Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/core-bridge/src/conversions.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,15 @@ use temporal_sdk_core::{
1414
},
1515
api::worker::{WorkerConfig, WorkerConfigBuilder},
1616
ephemeral_server::{
17-
TemporaliteConfig, TemporaliteConfigBuilder, TestServerConfig, TestServerConfigBuilder,
17+
TemporalDevServerConfig, TemporalDevServerConfigBuilder, TestServerConfig,
18+
TestServerConfigBuilder,
1819
},
1920
ClientOptions, ClientOptionsBuilder, ClientTlsConfig, RetryConfig, TlsConfig, Url,
2021
};
2122

2223
pub enum EphemeralServerConfig {
2324
TestServer(TestServerConfig),
24-
Temporalite(TemporaliteConfig),
25+
DevServer(TemporalDevServerConfig),
2526
}
2627

2728
pub trait ArrayHandleConversionsExt {
@@ -403,8 +404,8 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
403404

404405
let server_type = js_value_getter!(cx, self, "type", JsString);
405406
match server_type.as_str() {
406-
"temporalite" => {
407-
let mut config = TemporaliteConfigBuilder::default();
407+
"dev-server" => {
408+
let mut config = TemporalDevServerConfigBuilder::default();
408409
config.exe(executable).port(port);
409410

410411
if let Some(extra_args) = js_optional_getter!(cx, self, "extraArgs", JsArray) {
@@ -427,9 +428,9 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
427428
}
428429

429430
match config.build() {
430-
Ok(config) => Ok(EphemeralServerConfig::Temporalite(config)),
431+
Ok(config) => Ok(EphemeralServerConfig::DevServer(config)),
431432
Err(err) => {
432-
cx.throw_type_error(format!("Invalid temporalite config: {:?}", err))
433+
cx.throw_type_error(format!("Invalid dev server config: {:?}", err))
433434
}
434435
}
435436
}
@@ -450,7 +451,7 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
450451
}
451452
}
452453
s => cx.throw_type_error(format!(
453-
"Invalid ephemeral server type: {}, expected 'temporalite' or 'time-skipping'",
454+
"Invalid ephemeral server type: {}, expected 'dev-server' or 'time-skipping'",
454455
s
455456
)),
456457
}

packages/core-bridge/src/runtime.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -273,9 +273,7 @@ pub fn start_bridge_loop(
273273
EphemeralServerConfig::TestServer(config) => {
274274
config.start_server().await
275275
}
276-
EphemeralServerConfig::Temporalite(config) => {
277-
config.start_server().await
278-
}
276+
EphemeralServerConfig::DevServer(config) => config.start_server().await,
279277
};
280278
match result {
281279
Err(err) => {

packages/core-bridge/ts/index.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -381,10 +381,10 @@ export interface TimeSkippingServerConfig {
381381
}
382382

383383
/**
384-
* Configuration for temporalite.
384+
* Configuration for the Temporal CLI dev server.
385385
*/
386-
export interface TemporaliteConfig {
387-
type: 'temporalite';
386+
export interface DevServerConfig {
387+
type: 'dev-server';
388388
executable?: EphemeralServerExecutable;
389389
/**
390390
* Namespace to use - created at startup.
@@ -399,11 +399,13 @@ export interface TemporaliteConfig {
399399
*/
400400
ip?: string;
401401
/**
402-
* Sqlite DB filename if persisting or non-persistent if none.
402+
* Sqlite DB filename if persisting or non-persistent if none (default).
403403
*/
404404
db_filename?: string;
405405
/**
406406
* Whether to enable the UI.
407+
*
408+
* @default false
407409
*/
408410
ui?: boolean;
409411
/**
@@ -424,9 +426,9 @@ export interface TemporaliteConfig {
424426
/**
425427
* Configuration for spawning an ephemeral Temporal server.
426428
*
427-
* Both the time-skipping test server and temporalite are supported.
429+
* Both the time-skipping test server and Temporal CLI dev server are supported.
428430
*/
429-
export type EphemeralServerConfig = TimeSkippingServerConfig | TemporaliteConfig;
431+
export type EphemeralServerConfig = TimeSkippingServerConfig | DevServerConfig;
430432

431433
export interface Worker {
432434
type: 'Worker';

packages/test/src/integration-tests.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,7 @@ export function runIntegrationTests(codec?: PayloadCodec): void {
115115
metaClient,
116116
};
117117

118-
// In case we're running with temporalite or other non default server.
119-
// NOTE: at the time this was added temporalite did not expose the grpc OperatorService.
118+
// In case we're running with a server that doesn't use the docker-compose setup.
120119
try {
121120
await connection.operatorService.addSearchAttributes({
122121
namespace: 'default',

packages/test/src/test-ephemeral-server.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ test('TestEnvironment sets up test server and is able to run a single workflow',
4141
await runSimpleWorkflow(t, testEnv);
4242
});
4343

44-
test('TestEnvironment sets up temporalite and is able to run a single workflow', async (t) => {
44+
test('TestEnvironment sets up dev server and is able to run a single workflow', async (t) => {
4545
const testEnv = await TestWorkflowEnvironment.createLocal();
4646
await runSimpleWorkflow(t, testEnv);
4747
});
@@ -51,8 +51,8 @@ test.todo('TestEnvironment sets up test server with specified port');
5151
test.todo('TestEnvironment sets up test server with latest version');
5252
test.todo('TestEnvironment sets up test server from executable path');
5353

54-
test.todo('TestEnvironment sets up temporalite with extra args');
55-
test.todo('TestEnvironment sets up temporalite with latest version');
56-
test.todo('TestEnvironment sets up temporalite from executable path');
57-
test.todo('TestEnvironment sets up temporalite with custom log level');
58-
test.todo('TestEnvironment sets up temporalite with custom namespace, IP, db filename, and UI');
54+
test.todo('TestEnvironment sets up dev server with extra args');
55+
test.todo('TestEnvironment sets up dev server with latest version');
56+
test.todo('TestEnvironment sets up dev server from executable path');
57+
test.todo('TestEnvironment sets up dev server with custom log level');
58+
test.todo('TestEnvironment sets up dev server with custom namespace, IP, db filename, and UI');

packages/testing/src/index.ts

Lines changed: 34 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,13 @@ import {
2929
EphemeralServer,
3030
EphemeralServerConfig,
3131
getEphemeralServerTarget,
32-
TemporaliteConfig,
32+
DevServerConfig,
3333
TimeSkippingServerConfig,
3434
} from '@temporalio/core-bridge';
3535
import { filterNullAndUndefined } from '@temporalio/common/lib/internal-non-workflow';
3636
import { Connection, TestService } from './connection';
3737

38-
export { TimeSkippingServerConfig, TemporaliteConfig, EphemeralServerExecutable } from '@temporalio/core-bridge';
38+
export { TimeSkippingServerConfig, DevServerConfig, EphemeralServerExecutable } from '@temporalio/core-bridge';
3939
export { EphemeralServerConfig };
4040

4141
export interface TimeSkippingWorkflowClientOptions extends WorkflowClientOptions {
@@ -121,8 +121,8 @@ export type ClientOptionsForTestEnv = Omit<ClientOptions, 'namespace' | 'connect
121121
/**
122122
* Options for {@link TestWorkflowEnvironment.create}
123123
*/
124-
type TestWorkflowEnvironmentOptions = {
125-
server?: EphemeralServerConfig;
124+
export type TestWorkflowEnvironmentOptions = {
125+
server: EphemeralServerConfig;
126126
client?: ClientOptionsForTestEnv;
127127
};
128128

@@ -138,17 +138,14 @@ export type TimeSkippingTestWorkflowEnvironmentOptions = {
138138
* Options for {@link TestWorkflowEnvironment.createLocal}
139139
*/
140140
export type LocalTestWorkflowEnvironmentOptions = {
141-
server?: Omit<TemporaliteConfig, 'type'>;
141+
server?: Omit<DevServerConfig, 'type'>;
142142
client?: ClientOptionsForTestEnv;
143143
};
144144

145145
export type TestWorkflowEnvironmentOptionsWithDefaults = Required<TestWorkflowEnvironmentOptions>;
146146

147147
function addDefaults(opts: TestWorkflowEnvironmentOptions): TestWorkflowEnvironmentOptionsWithDefaults {
148148
return {
149-
server: {
150-
type: 'time-skipping',
151-
},
152149
client: {},
153150
...opts,
154151
};
@@ -201,11 +198,12 @@ export class TestWorkflowEnvironment {
201198
public readonly supportsTimeSkipping: boolean,
202199
protected readonly server: EphemeralServer,
203200
connection: Connection,
204-
nativeConnection: NativeConnection
201+
nativeConnection: NativeConnection,
202+
namespace: string | undefined
205203
) {
206204
this.connection = connection;
207205
this.nativeConnection = nativeConnection;
208-
this.namespace = options.server.type === 'temporalite' ? options.server.namespace : undefined;
206+
this.namespace = namespace;
209207
this.client = new TestEnvClient({
210208
connection,
211209
namespace: this.namespace,
@@ -239,8 +237,11 @@ export class TestWorkflowEnvironment {
239237
* In the future, the test server implementation may be changed to another implementation.
240238
*/
241239
static async createTimeSkipping(opts?: TimeSkippingTestWorkflowEnvironmentOptions): Promise<TestWorkflowEnvironment> {
242-
// eslint-disable-next-line deprecation/deprecation
243-
return await this.create({ server: { type: 'time-skipping', ...opts?.server }, client: opts?.client });
240+
return await this.create({
241+
server: { type: 'time-skipping', ...opts?.server },
242+
client: opts?.client,
243+
supportsTimeSkipping: true,
244+
});
244245
}
245246

246247
/**
@@ -250,38 +251,42 @@ export class TestWorkflowEnvironment {
250251
* {@link createTimeSkipping} does. {@link supportsTimeSkipping} will always return `false` for this environment.
251252
* {@link sleep} will sleep the actual amount of time and {@link currentTimeMs} will return the current time.
252253
*
253-
* Internally, this uses [Temporalite](https://github.com/temporalio/temporalite). Which is a self-contained binary
254-
* for Temporal using Sqlite persistence. This will download Temporalite to a temporary directory by default if it
255-
* has not already been downloaded before and {@link LocalTestWorkflowEnvironmentOptions.server.executable.type} is
256-
* `'cached-download'`.
254+
* This local environment will be powered by [Temporal CLI](https://github.com/temporalio/cli), which is a
255+
* self-contained executable for Temporal. By default, Temporal's database will not be persisted to disk, and no UI
256+
* will be started.
257257
*
258-
* In the future, the Temporalite implementation may be changed to another implementation.
258+
* The CLI executable will be downloaded and cached to a temporary directory. See
259+
* {@link LocalTestWorkflowEnvironmentOptions.server.executable.type} if you'd prefer to provide the CLI executable
260+
* yourself.
259261
*/
260262
static async createLocal(opts?: LocalTestWorkflowEnvironmentOptions): Promise<TestWorkflowEnvironment> {
261263
// eslint-disable-next-line deprecation/deprecation
262-
return await this.create({ server: { type: 'temporalite', ...opts?.server }, client: opts?.client });
264+
return await this.create({
265+
server: { type: 'dev-server', ...opts?.server },
266+
client: opts?.client,
267+
namespace: opts?.server?.namespace,
268+
supportsTimeSkipping: false,
269+
});
263270
}
264271

265272
/**
266273
* Create a new test environment
267-
*
268-
* @deprecated - use {@link createTimeSkipping} or {@link createLocal}
269274
*/
270-
static async create(opts?: TestWorkflowEnvironmentOptions): Promise<TestWorkflowEnvironment> {
271-
const optsWithDefaults = addDefaults(filterNullAndUndefined(opts ?? {}));
275+
private static async create(
276+
opts: TestWorkflowEnvironmentOptions & {
277+
supportsTimeSkipping: boolean;
278+
namespace?: string;
279+
}
280+
): Promise<TestWorkflowEnvironment> {
281+
const { supportsTimeSkipping, namespace, ...rest } = opts;
282+
const optsWithDefaults = addDefaults(filterNullAndUndefined(rest));
272283
const server = await Runtime.instance().createEphemeralServer(optsWithDefaults.server);
273284
const address = getEphemeralServerTarget(server);
274285

275286
const nativeConnection = await NativeConnection.connect({ address });
276287
const connection = await Connection.connect({ address });
277288

278-
return new this(
279-
optsWithDefaults,
280-
optsWithDefaults.server.type === 'time-skipping',
281-
server,
282-
connection,
283-
nativeConnection
284-
);
289+
return new this(optsWithDefaults, supportsTimeSkipping, server, connection, nativeConnection, namespace);
285290
}
286291

287292
/**

0 commit comments

Comments
 (0)