Skip to content

Commit 1dc91a0

Browse files
committed
feat(gloud) add ability to set cmd flags
1 parent 5817d69 commit 1dc91a0

8 files changed

+113
-15
lines changed

packages/modules/gcloud/src/datastore-emulator-container.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ describe("DatastoreEmulatorContainer", { timeout: 240_000 }, () => {
2525

2626
// }
2727

28+
it("should have default host-port flag and database-mode flag", async (ctx) => {
29+
const datastoreEmulatorContainer = new DatastoreEmulatorContainer();
30+
31+
const flags = datastoreEmulatorContainer.expandFlags();
32+
33+
expect(flags.trim()).toEqual("--host-port=0.0.0.0:8080 --database-mode=datastore-mode");
34+
});
35+
2836
async function checkDatastore(datastoreEmulatorContainer: StartedDatastoreEmulatorContainer) {
2937
expect(datastoreEmulatorContainer).toBeDefined();
3038
const testProjectId = "test-project";

packages/modules/gcloud/src/datastore-emulator-container.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
1-
import { AbstractStartedContainer, GenericContainer, StartedTestContainer, Wait } from "testcontainers";
1+
import { AbstractStartedContainer, StartedTestContainer, Wait } from "testcontainers";
2+
import { GenericGCloudEmulatorContainer } from "./generic-emulator-container";
23

34
const EMULATOR_PORT = 8080;
4-
const CMD = `gcloud beta emulators firestore start --host-port 0.0.0.0:${EMULATOR_PORT} --database-mode=datastore-mode`;
5+
const CMD = `gcloud beta emulators firestore start`;
56
const DEFAULT_IMAGE = "gcr.io/google.com/cloudsdktool/cloud-sdk";
67

7-
export class DatastoreEmulatorContainer extends GenericContainer {
8+
export class DatastoreEmulatorContainer extends GenericGCloudEmulatorContainer {
89
constructor(image = DEFAULT_IMAGE) {
910
super(image);
1011
this.withExposedPorts(EMULATOR_PORT)
11-
.withCommand(["/bin/sh", "-c", CMD])
12+
.withFlag("host-port", `0.0.0.0:${EMULATOR_PORT}`)
13+
.withFlag("database-mode", `datastore-mode`)
14+
.withCommand(["/bin/sh", "-c", `${CMD} ${this.expandFlags()}`])
1215
.withWaitStrategy(Wait.forLogMessage(RegExp(".*running.*"), 1))
1316
.withStartupTimeout(120_000);
1417
}

packages/modules/gcloud/src/firestore-emulator-container.test.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import * as admin from "firebase-admin";
22
import { FirestoreEmulatorContainer, StartedFirestoreEmulatorContainer } from "./firestore-emulator-container";
33

44
describe("FirestoreEmulatorContainer", { timeout: 240_000 }, () => {
5-
afterEach(async () => {
5+
afterEach(async (ctx) => {
6+
if (ctx.task.name === "should have default host-port flag") return;
67
await admin.app().delete();
78
});
89

@@ -29,6 +30,14 @@ describe("FirestoreEmulatorContainer", { timeout: 240_000 }, () => {
2930

3031
// }
3132

33+
it("should have default host-port flag", async (ctx) => {
34+
const firestoreEmulatorContainer = new FirestoreEmulatorContainer();
35+
36+
const flags = firestoreEmulatorContainer.expandFlags();
37+
38+
expect(flags.trim()).toEqual("--host-port=0.0.0.0:8080");
39+
});
40+
3241
async function checkFirestore(firestoreEmulatorContainer: StartedFirestoreEmulatorContainer) {
3342
expect(firestoreEmulatorContainer).toBeDefined();
3443
const testProjectId = "test-project";

packages/modules/gcloud/src/firestore-emulator-container.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1-
import { AbstractStartedContainer, GenericContainer, StartedTestContainer, Wait } from "testcontainers";
1+
import { AbstractStartedContainer, StartedTestContainer, Wait } from "testcontainers";
2+
import { GenericGCloudEmulatorContainer } from "./generic-emulator-container";
23

34
const EMULATOR_PORT = 8080;
4-
const CMD = `gcloud beta emulators firestore start --host-port 0.0.0.0:${EMULATOR_PORT}`;
5+
const CMD = `gcloud beta emulators firestore start`;
56
const DEFAULT_IMAGE = "gcr.io/google.com/cloudsdktool/cloud-sdk";
67

7-
export class FirestoreEmulatorContainer extends GenericContainer {
8+
export class FirestoreEmulatorContainer extends GenericGCloudEmulatorContainer {
89
constructor(image = DEFAULT_IMAGE) {
910
super(image);
1011
this.withExposedPorts(EMULATOR_PORT)
11-
.withCommand(["/bin/sh", "-c", CMD])
12+
.withFlag("host-port", `0.0.0.0:${EMULATOR_PORT}`)
13+
.withCommand(["/bin/sh", "-c", `${CMD} ${this.expandFlags()}`])
1214
.withWaitStrategy(Wait.forLogMessage(RegExp(".*running.*"), 1))
1315
.withStartupTimeout(120_000);
1416
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
2+
import { GenericGCloudEmulatorContainer } from "./generic-emulator-container";
3+
4+
const IMAGE = "gcr.io/google.com/cloudsdktool/cloud-sdk"
5+
6+
describe("GenericGCloudEmulatorContainer", { timeout: 240_000 }, () => {
7+
it("should have all flags added", async () => {
8+
const genericGCloudEmulatorContainer = new GenericGCloudEmulatorContainer(IMAGE)
9+
.withFlag("database-mode", "firestore-native");
10+
11+
const flags = genericGCloudEmulatorContainer.expandFlags();
12+
13+
expect(flags.trim()).toEqual("--database-mode=firestore-native");
14+
});
15+
16+
it("should overwrite flag if added more than once", async () => {
17+
const genericGCloudEmulatorContainer = new GenericGCloudEmulatorContainer(IMAGE)
18+
.withFlag("database-mode", "firestore-native")
19+
.withFlag("database-mode", "datastore-mode")
20+
.withFlag("database-mode", "datastore-mode");
21+
22+
const flags = genericGCloudEmulatorContainer.expandFlags();
23+
24+
expect(flags.trim()).toEqual("--database-mode=datastore-mode");
25+
});
26+
});
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { GenericContainer } from "testcontainers";
2+
3+
export class GenericGCloudEmulatorContainer extends GenericContainer {
4+
private flags: { name: string, value: string }[] = []
5+
6+
constructor(image: string) {
7+
super(image);
8+
}
9+
10+
/**
11+
* Adds flag name and value as argument to emulator start command.
12+
* Adding same flag name twice replaces existing flag value.
13+
* Provided flag name may optionally contain -- prefix.
14+
*/
15+
public withFlag(name: string, value: string): this {
16+
if (!name) throw new Error("Flag name must be set.")
17+
// replace flag if it already exists
18+
const idx = this.flags.findIndex(f => f.name == this.trimFlagName(name))
19+
if (idx >= 0)
20+
this.flags = [...this.flags.slice(0, idx), ...this.flags.slice(idx + 1)]
21+
this.flags.push({ name, value });
22+
return this
23+
}
24+
25+
private trimFlagName(name: string): string {
26+
return name?.startsWith('--') ? name.slice(2) : name
27+
}
28+
29+
private flagToString(f: { name: string, value: string }): string {
30+
return `--${this.trimFlagName(f.name)}=${f.value}`
31+
}
32+
33+
/**
34+
* @return all flags provided to run this emulator instance, concatenated to string.
35+
*/
36+
public expandFlags(): string {
37+
return `${this.flags.reduce((p, c) => p + ' ' + this.flagToString(c), '')}`
38+
}
39+
}

packages/modules/gcloud/src/pubsub-emulator-container.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ describe("PubSubEmulatorContainer", { timeout: 240_000 }, () => {
1010
await pubsubEmulatorContainer.stop();
1111
});
1212

13+
it("should have default host-port flag", async () => {
14+
const pubsubEmulatorContainer = new PubSubEmulatorContainer();
15+
16+
const flags = pubsubEmulatorContainer.expandFlags();
17+
18+
expect(flags.trim()).toEqual("--host-port=0.0.0.0:8085");
19+
});
20+
1321
async function checkPubSub(pubsubEmulatorContainer: StartedPubSubEmulatorContainer) {
1422
expect(pubsubEmulatorContainer).toBeDefined();
1523

packages/modules/gcloud/src/pubsub-emulator-container.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,34 @@
11
import type { StartedTestContainer } from "testcontainers";
2-
import { AbstractStartedContainer, GenericContainer, Wait } from "testcontainers";
2+
import { AbstractStartedContainer, Wait } from "testcontainers";
3+
import { GenericGCloudEmulatorContainer } from "./generic-emulator-container";
34

45
const EMULATOR_PORT = 8085;
5-
const CMD = "gcloud beta emulators pubsub start --host-port 0.0.0.0:8085";
6+
const CMD = "gcloud beta emulators pubsub start";
67
const DEFAULT_IMAGE = "gcr.io/google.com/cloudsdktool/google-cloud-cli";
78

8-
export class PubSubEmulatorContainer extends GenericContainer {
9+
export class PubSubEmulatorContainer extends GenericGCloudEmulatorContainer {
910
private _projectId?: string;
1011

1112
constructor(image = DEFAULT_IMAGE) {
1213
super(image);
1314

1415
this.withExposedPorts(EMULATOR_PORT)
16+
.withFlag("host-port", `0.0.0.0:${EMULATOR_PORT}`)
1517
.withWaitStrategy(Wait.forLogMessage(/Server started/g, 1))
1618
.withStartupTimeout(120_000);
1719
}
1820

19-
public withProjectId(projectId: string): PubSubEmulatorContainer {
21+
public withProjectId(projectId: string): this {
2022
this._projectId = projectId;
2123
return this;
2224
}
2325

2426
public override async start(): Promise<StartedPubSubEmulatorContainer> {
2527
// Determine the valid command-line prompt when starting the Pub/Sub emulator
2628
const selectedProjectId = this._projectId ?? "test-project";
27-
const commandLine = `${CMD} --project=${selectedProjectId}`;
28-
this.withCommand(["/bin/sh", "-c", commandLine]);
29+
this
30+
.withFlag("project", selectedProjectId)
31+
.withCommand(["/bin/sh", "-c", `${CMD} ${this.expandFlags()}`]);
2932

3033
return new StartedPubSubEmulatorContainer(await super.start(), selectedProjectId);
3134
}

0 commit comments

Comments
 (0)