Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DatastoreEmulatorContainer to gcloud module #782

Merged
merged 9 commits into from
Jul 26, 2024
22 changes: 16 additions & 6 deletions docs/modules/gcloud.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@ Testcontainers module for the Google Cloud Platform's [Cloud SDK](https://cloud.
npm install @testcontainers/gcloud --save-dev
```

Currently, the module supports `Firestore` emulators in Native mode and Datastore mode. In order to use them, you should use the following classes:

Currently, the module supports `Firestore` emulators. In order to use it, you should use the following classes:

Class | Container Image
-|-
FirestoreEmulatorContainer | [gcr.io/google.com/cloudsdktool/google-cloud-cli:emulators](https://gcr.io/google.com/cloudsdktool/google-cloud-cli)
Mode | Class | Container Image
-|-|-
Native mode | FirestoreEmulatorContainer | [gcr.io/google.com/cloudsdktool/google-cloud-cli:emulators](https://gcr.io/google.com/cloudsdktool/google-cloud-cli)
Datastore mode | DatastoreEmulatorContainer | [gcr.io/google.com/cloudsdktool/google-cloud-cli:emulators](https://gcr.io/google.com/cloudsdktool/google-cloud-cli)

## Examples

### Firestore
### Firestore Native mode

<!--codeinclude-->
[Starting a Firestore Emulator container with the default image](../../packages/modules/gcloud/src/firestore-emulator-container.test.ts) inside_block:firestore4
Expand All @@ -26,3 +26,13 @@ FirestoreEmulatorContainer | [gcr.io/google.com/cloudsdktool/google-cloud-cli:em
<!--codeinclude-->
[Starting a Firestore Emulator container with a custom emulator image](../../packages/modules/gcloud/src/firestore-emulator-container.test.ts) inside_block:firestore5
<!--/codeinclude-->

### Firestore Datastore mode

<!--codeinclude-->
[Starting a Datastore Emulator container with the default image](../../packages/modules/gcloud/src/datastore-emulator-container.test.ts) inside_block:datastore4
<!--/codeinclude-->

<!--codeinclude-->
[Starting a Datastore Emulator container with a custom emulator image](../../packages/modules/gcloud/src/datastore-emulator-container.test.ts) inside_block:datastore5
<!--/codeinclude-->
53 changes: 51 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/modules/gcloud/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"testcontainers": "^10.10.4"
},
"devDependencies": {
"@google-cloud/datastore": "^9.0.0",
"@google-cloud/firestore": "7.9.0",
"firebase-admin": "12.2.0"
}
Expand Down
45 changes: 45 additions & 0 deletions packages/modules/gcloud/src/datastore-emulator-container.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { DatastoreEmulatorContainer, StartedDatastoreEmulatorContainer } from "./datastore-emulator-container";
import { Datastore } from "@google-cloud/datastore";

describe("DatastoreEmulatorContainer", () => {
jest.setTimeout(240_000);

// datastore4 {
it("should work using default version", async () => {
const datastoreEmulatorContainer = await new DatastoreEmulatorContainer().start();

await checkDatastore(datastoreEmulatorContainer);

await datastoreEmulatorContainer.stop();
});
// }

// datastore5 {
it("should work using version 468.0.0", async () => {
const datastoreEmulatorContainer = await new DatastoreEmulatorContainer(
"gcr.io/google.com/cloudsdktool/google-cloud-cli:468.0.0-emulators"
).start();

await checkDatastore(datastoreEmulatorContainer);

await datastoreEmulatorContainer.stop();
});

// }

async function checkDatastore(datastoreEmulatorContainer: StartedDatastoreEmulatorContainer) {
expect(datastoreEmulatorContainer).toBeDefined();
const testProjectId = "test-project";
const testKind = "test-kind";
const testId = "123";
const databaseConfig = { projectId: testProjectId, apiEndpoint: datastoreEmulatorContainer.getEmulatorEndpoint() };
const datastore = new Datastore(databaseConfig);

const key = datastore.key([testKind, testId]);
const data = { message: "Hello, Datastore!" };
await datastore.save({ key, data });
const [entity] = await datastore.get(key);

expect(entity).toEqual({ message: "Hello, Datastore!", [Datastore.KEY]: key });
}
});
33 changes: 33 additions & 0 deletions packages/modules/gcloud/src/datastore-emulator-container.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { AbstractStartedContainer, GenericContainer, StartedTestContainer, Wait } from "testcontainers";

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

export class DatastoreEmulatorContainer extends GenericContainer {
oskarwidmark marked this conversation as resolved.
Show resolved Hide resolved
constructor(image = DEFAULT_IMAGE) {
super(image);
this.withExposedPorts(EMULATOR_PORT)
.withCommand(["/bin/sh", "-c", CMD])
.withWaitStrategy(Wait.forLogMessage(RegExp(".*running.*"), 1))
.withStartupTimeout(120_000);
}

public override async start(): Promise<StartedDatastoreEmulatorContainer> {
return new StartedDatastoreEmulatorContainer(await super.start());
}
}

export class StartedDatastoreEmulatorContainer extends AbstractStartedContainer {
constructor(startedTestContainer: StartedTestContainer) {
super(startedTestContainer);
}

/**
* @return a <code>host:port</code> pair corresponding to the address on which the emulator is
* reachable from the test host machine.
*/
public getEmulatorEndpoint(): string {
return `${this.getHost()}:${this.getMappedPort(EMULATOR_PORT)}`;
}
}
Loading