Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions src/eventarc/eventarc-client-internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const DEFAULT_CHANNEL_REGION = 'us-central1';
*/
export class EventarcApiClient {
private readonly httpClient: HttpClient;
private readonly eventarcHost: string;
private projectId?: string;
private readonly resolvedChannelName: Promise<string>;

Expand All @@ -53,6 +54,7 @@ export class EventarcApiClient {
});
}
this.httpClient = new AuthorizedHttpClient(app as FirebaseApp);
this.eventarcHost = process.env.CLOUD_EVENTARC_EMULATOR_HOST ?? EVENTARC_API;
this.resolvedChannelName = this.resolveChannelName(channel.name);
}

Expand Down Expand Up @@ -105,7 +107,7 @@ export class EventarcApiClient {
}
const request: HttpRequestConfig = {
method: 'POST',
url: `${this.getEventarcHost()}/${channel}:publishEvents`,
url: `${this.eventarcHost}/${channel}:publishEvents`,
data: JSON.stringify({ events }),
};
return this.sendRequest(request);
Expand Down Expand Up @@ -162,8 +164,4 @@ export class EventarcApiClient {
const projectId = await this.getProjectId();
return `projects/${projectId}/locations/${location}/channels/${channelId}`;
}

private getEventarcHost(): string {
return process.env.CLOUD_EVENTARC_EMULATOR_HOST ?? EVENTARC_API;
}
}
80 changes: 80 additions & 0 deletions test/unit/eventarc/eventarc.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ const TEST_EVENT2 : CloudEvent = {
};
const TEST_EVENT2_SERIALIZED = JSON.stringify(toCloudEventProtoFormat(TEST_EVENT2));

const EMULATOR_HOST = 'http://127.0.0.1:9299';

describe('eventarc', () => {
let mockApp: FirebaseApp;
let eventarc: Eventarc;
Expand Down Expand Up @@ -168,6 +170,84 @@ describe('eventarc', () => {
});
});

describe('emulator host', () => {
let mockAccessToken: string;
let httpStub: sinon.SinonStub;
let accessTokenStub: sinon.SinonStub;
let originalEmulatorHost: string | undefined;

before(() => {
mockAccessToken = utils.generateRandomAccessToken();
accessTokenStub = utils.stubGetAccessToken(mockAccessToken);
originalEmulatorHost = process.env.CLOUD_EVENTARC_EMULATOR_HOST;
});

after(() => {
accessTokenStub?.restore();
if (originalEmulatorHost === undefined) {
delete process.env.CLOUD_EVENTARC_EMULATOR_HOST;
} else {
process.env.CLOUD_EVENTARC_EMULATOR_HOST = originalEmulatorHost;
}
});
Comment on lines +174 to +192

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Modifying process.env in tests without restoring its original value can lead to test pollution and flaky tests if other test suites run in the same process. It is highly recommended to capture the original value of CLOUD_EVENTARC_EMULATOR_HOST in the before hook and restore it in the after hook.

    let mockAccessToken: string;
    let httpStub: sinon.SinonStub;
    let accessTokenStub: sinon.SinonStub;
    let originalEmulatorHost: string | undefined;

    before(() => {
      mockAccessToken = utils.generateRandomAccessToken();
      accessTokenStub = utils.stubGetAccessToken(mockAccessToken);
      originalEmulatorHost = process.env.CLOUD_EVENTARC_EMULATOR_HOST;
    });

    after(() => {
      accessTokenStub?.restore();
      if (originalEmulatorHost === undefined) {
        delete process.env.CLOUD_EVENTARC_EMULATOR_HOST;
      } else {
        process.env.CLOUD_EVENTARC_EMULATOR_HOST = originalEmulatorHost;
      }
    });


afterEach(() => {
httpStub?.restore();
delete process.env.CLOUD_EVENTARC_EMULATOR_HOST;
});

it('is resolved at construction time', async () => {
delete process.env.CLOUD_EVENTARC_EMULATOR_HOST;
const prodChannel = eventarc.channel();

process.env.CLOUD_EVENTARC_EMULATOR_HOST = EMULATOR_HOST;
const emulatorChannel = eventarc.channel();

delete process.env.CLOUD_EVENTARC_EMULATOR_HOST;

httpStub = sinon
.stub(HttpClient.prototype, 'send')
.resolves(utils.responseFrom({}));

await prodChannel.publish(TEST_EVENT1);
await emulatorChannel.publish(TEST_EVENT1);

expect(httpStub).to.have.been.calledTwice;
expect(httpStub.firstCall).to.have.been.calledWith({
method: 'POST',
url: 'https://eventarcpublishing.googleapis.com/v1/projects/project_id/locations/us-central1/channels/firebase:publishEvents',
data: `{"events":[${TEST_EVENT1_SERIALIZED}]}`,
headers: getExpectedHeaders(mockAccessToken)
});
expect(httpStub.secondCall).to.have.been.calledWith({
method: 'POST',
url: `${EMULATOR_HOST}/projects/project_id/locations/us-central1/channels/firebase:publishEvents`,
data: `{"events":[${TEST_EVENT1_SERIALIZED}]}`,
headers: getExpectedHeaders(mockAccessToken)
});
});

it('is not picked up by a channel created before it was set', async () => {
delete process.env.CLOUD_EVENTARC_EMULATOR_HOST;
const prodChannel = eventarc.channel();

process.env.CLOUD_EVENTARC_EMULATOR_HOST = EMULATOR_HOST;

httpStub = sinon
.stub(HttpClient.prototype, 'send')
.resolves(utils.responseFrom({}));

await prodChannel.publish(TEST_EVENT1);

expect(httpStub).to.have.been.calledOnce.and.calledWith({
method: 'POST',
url: 'https://eventarcpublishing.googleapis.com/v1/projects/project_id/locations/us-central1/channels/firebase:publishEvents',
data: `{"events":[${TEST_EVENT1_SERIALIZED}]}`,
headers: getExpectedHeaders(mockAccessToken)
});
});
});

describe('full resource name Channel', () => {
let channel : Channel;
let mockAccessToken: string;
Expand Down