diff --git a/spec/v1/cloud-functions.spec.ts b/spec/v1/cloud-functions.spec.ts index ae145fb8a..d85afbe2f 100644 --- a/spec/v1/cloud-functions.spec.ts +++ b/spec/v1/cloud-functions.spec.ts @@ -42,7 +42,7 @@ describe("makeCloudFunction", () => { legacyEventType: "providers/provider/eventTypes/event", }; - it("should call the onInit callback", async () => { + it("calls init function", async () => { const test: Event = { context: { eventId: "00000", diff --git a/spec/v1/providers/analytics.spec.ts b/spec/v1/providers/analytics.spec.ts index 9b12eb7ff..98db1702f 100644 --- a/spec/v1/providers/analytics.spec.ts +++ b/spec/v1/providers/analytics.spec.ts @@ -109,8 +109,6 @@ describe("Analytics Functions", () => { }, }; - let hello; - functions.onInit(() => hello = "world"); await expect(cloudFunction(event.data, event.context)).to.eventually.deep.equal({ params: {}, user: { @@ -118,7 +116,6 @@ describe("Analytics Functions", () => { userProperties: {}, }, }); - expect(hello).equals("world"); }); it("should remove xValues", () => { diff --git a/spec/v1/providers/auth.spec.ts b/spec/v1/providers/auth.spec.ts index 90087e82c..f5f6a806d 100644 --- a/spec/v1/providers/auth.spec.ts +++ b/spec/v1/providers/auth.spec.ts @@ -339,30 +339,4 @@ describe("Auth Functions", () => { expect(cf.run).to.not.throw(Error); }); }); - - describe("onInit", () => { - beforeEach(() => { - functions.onInit(() => {}); - process.env.GCLOUD_PROJECT = "project"; - }); - - after(() => { - functions.onInit(null); - delete process.env.GCLOUD_PROJECT; - }) - - it("initailizes before onCreate", async () => { - let hello; - functions.onInit(() => hello = "world"); - await auth.user().onCreate(() => null)(event.data, event.context); - expect(hello).equals("world"); - }); - - it("initailizes before onDelete", async () => { - let hello; - functions.onInit(() => hello = "world"); - await auth.user().onDelete(() => null)(event.data, event.context); - expect(hello).equals("world"); - }); - }); }); diff --git a/spec/v1/providers/database.spec.ts b/spec/v1/providers/database.spec.ts index e33a3e2e2..18d973b1d 100644 --- a/spec/v1/providers/database.spec.ts +++ b/spec/v1/providers/database.spec.ts @@ -116,7 +116,7 @@ describe("Database Functions", () => { ); }); - it("should return a handler that emits events with a proper DataSnapshot", async () => { + it("should return a handler that emits events with a proper DataSnapshot", () => { const event = { data: { data: null, @@ -133,11 +133,7 @@ describe("Database Functions", () => { expect(change.after.val()).to.deep.equal({ foo: "bar" }); }); - let hello; - functions.onInit(() => (hello = "world")); - expect(hello).is.undefined; - await handler(event.data, event.context); - expect(hello).equals("world"); + return handler(event.data, event.context); }); it("Should have params of the correct type", () => { @@ -181,7 +177,7 @@ describe("Database Functions", () => { ); }); - it("should return a handler that emits events with a proper DataSnapshot", async () => { + it("should return a handler that emits events with a proper DataSnapshot", () => { const event = { data: { data: null, @@ -199,11 +195,7 @@ describe("Database Functions", () => { expect(data.val()).to.deep.equal({ foo: "bar" }); }); - let hello; - functions.onInit(() => (hello = "world")); - expect(hello).to.be.undefined; - await handler(event.data, event.context); - expect(hello).equals("world"); + return handler(event.data, event.context); }); it("Should have params of the correct type", () => { @@ -247,7 +239,7 @@ describe("Database Functions", () => { ); }); - it("should return a handler that emits events with a proper DataSnapshot", async () => { + it("should return a handler that emits events with a proper DataSnapshot", () => { const event = { data: { data: null, @@ -265,11 +257,7 @@ describe("Database Functions", () => { expect(change.after.val()).to.deep.equal({ foo: "bar" }); }); - let hello; - functions.onInit(() => (hello = "world")); - expect(hello).is.undefined; - await handler(event.data, event.context); - expect(hello).equals("world"); + return handler(event.data, event.context); }); it("Should have params of the correct type", () => { @@ -313,7 +301,7 @@ describe("Database Functions", () => { ); }); - it("should return a handler that emits events with a proper DataSnapshot", async () => { + it("should return a handler that emits events with a proper DataSnapshot", () => { const event = { data: { data: { foo: "bar" }, @@ -331,11 +319,7 @@ describe("Database Functions", () => { expect(data.val()).to.deep.equal({ foo: "bar" }); }); - let hello; - functions.onInit(() => (hello = "world")); - expect(hello).is.undefined; - await handler(event.data, event.context); - expect(hello).equals("world"); + return handler(event.data, event.context); }); it("Should have params of the correct type", () => { diff --git a/spec/v1/providers/firestore.spec.ts b/spec/v1/providers/firestore.spec.ts index 5c7fb3746..f8f4288db 100644 --- a/spec/v1/providers/firestore.spec.ts +++ b/spec/v1/providers/firestore.spec.ts @@ -234,7 +234,7 @@ describe("Firestore Functions", () => { delete process.env.GCLOUD_PROJECT; }); - it('constructs appropriate fields and getters for event.data on "document.write" events', async () => { + it('constructs appropriate fields and getters for event.data on "document.write" events', () => { const testFunction = firestore.document("path").onWrite((change) => { expect(change.before.data()).to.deep.equal({ key1: false, @@ -246,30 +246,20 @@ describe("Firestore Functions", () => { return true; // otherwise will get warning about returning undefined }); const event = constructEvent(createOldValue(), createValue()); - - let hello; - functions.onInit(() => (hello = "world")); - expect(hello).is.undefined; - await testFunction(event.data, event.context); - expect(hello).equals("world"); + return testFunction(event.data, event.context); }).timeout(5000); - it('constructs appropriate fields and getters for event.data on "document.create" events', async () => { + it('constructs appropriate fields and getters for event.data on "document.create" events', () => { const testFunction = firestore.document("path").onCreate((data) => { expect(data.data()).to.deep.equal({ key1: true, key2: 123 }); expect(data.get("key1")).to.equal(true); return true; // otherwise will get warning about returning undefined }); const event = constructEvent({}, createValue()); - - let hello; - functions.onInit(() => (hello = "world")); - expect(hello).is.undefined; - await testFunction(event.data, event.context); - expect(hello).equals("world"); + return testFunction(event.data, event.context); }).timeout(5000); - it('constructs appropriate fields and getters for event.data on "document.update" events', async () => { + it('constructs appropriate fields and getters for event.data on "document.update" events', () => { const testFunction = firestore.document("path").onUpdate((change) => { expect(change.before.data()).to.deep.equal({ key1: false, @@ -281,27 +271,17 @@ describe("Firestore Functions", () => { return true; // otherwise will get warning about returning undefined }); const event = constructEvent(createOldValue(), createValue()); - - let hello; - functions.onInit(() => (hello = "world")); - expect(hello).is.undefined; - await testFunction(event.data, event.context); - expect(hello).equals("world"); + return testFunction(event.data, event.context); }).timeout(5000); - it('constructs appropriate fields and getters for event.data on "document.delete" events', async () => { + it('constructs appropriate fields and getters for event.data on "document.delete" events', () => { const testFunction = firestore.document("path").onDelete((data) => { expect(data.data()).to.deep.equal({ key1: false, key2: 111 }); expect(data.get("key1")).to.equal(false); return true; // otherwise will get warning about returning undefined }); const event = constructEvent(createOldValue(), {}); - - let hello; - functions.onInit(() => (hello = "world")); - expect(hello).is.undefined; - await testFunction(event.data, event.context); - expect(hello).equals("world"); + return testFunction(event.data, event.context); }).timeout(5000); }); diff --git a/spec/v1/providers/https.spec.ts b/spec/v1/providers/https.spec.ts index 1f983709b..c3a7671c0 100644 --- a/spec/v1/providers/https.spec.ts +++ b/spec/v1/providers/https.spec.ts @@ -72,11 +72,13 @@ describe("CloudHttpsBuilder", () => { expect(fn.__endpoint.httpsTrigger.invoker).to.deep.equal(["private"]); }); - it("should call initializer", async () => { + it("calls init function", async () => { let hello; onInit(() => (hello = "world")); expect(hello).to.be.undefined; - const fn = functions.https.onRequest(() => null); + const fn = functions.https.onRequest((_req, res) => { + res.send(200); + }); const req = new MockRequest( { data: { foo: "bar" }, @@ -86,9 +88,7 @@ describe("CloudHttpsBuilder", () => { } ); req.method = "POST"; - // We don't really have test infrastructure to fake requests. Luckily we - // don't touch much of the request in boilerplate, just trace context. - await fn({headers: []} as any, null as any); + await runHandler(fn, req as any); expect(hello).to.equal("world"); }); }); diff --git a/spec/v1/providers/pubsub.spec.ts b/spec/v1/providers/pubsub.spec.ts index bd3394ef4..0a7b89ad6 100644 --- a/spec/v1/providers/pubsub.spec.ts +++ b/spec/v1/providers/pubsub.spec.ts @@ -123,7 +123,7 @@ describe("Pubsub Functions", () => { expect(() => pubsub.topic("bad/topic/format")).to.throw(Error); }); - it("should properly handle a new-style event", async () => { + it("should properly handle a new-style event", () => { const raw = new Buffer('{"hello":"world"}', "utf8").toString("base64"); const event: Event = { data: { @@ -151,15 +151,11 @@ describe("Pubsub Functions", () => { }; }); - let hello; - functions.onInit(() => (hello = "world")); - expect(hello).is.undefined; - await expect(result(event.data, event.context)).to.eventually.deep.equal({ + return expect(result(event.data, event.context)).to.eventually.deep.equal({ raw, json: { hello: "world" }, attributes: { foo: "bar" }, }); - expect(hello).equals("world"); }); }); diff --git a/spec/v2/providers/alerts/appDistribution.spec.ts b/spec/v2/providers/alerts/appDistribution.spec.ts index 739cb0ae2..045b84448 100644 --- a/spec/v2/providers/alerts/appDistribution.spec.ts +++ b/spec/v2/providers/alerts/appDistribution.spec.ts @@ -93,7 +93,7 @@ describe("appDistribution", () => { expect(res).to.equal("input"); }); - it("should call the initializer", async () => { + it("calls init function", async () => { const func = appDistribution.onNewTesterIosDevicePublished(APPID, (event) => event); let hello; @@ -184,7 +184,7 @@ describe("appDistribution", () => { expect(res).to.equal("input"); }); - it("should call the initializer", async () => { + it("calls init function", async () => { const func = appDistribution.onInAppFeedbackPublished(APPID, (event) => event); let hello; diff --git a/spec/v2/providers/alerts/billing.spec.ts b/spec/v2/providers/alerts/billing.spec.ts index bf75d019e..a0020f83b 100644 --- a/spec/v2/providers/alerts/billing.spec.ts +++ b/spec/v2/providers/alerts/billing.spec.ts @@ -43,7 +43,7 @@ describe("billing", () => { }); }); - it("should call the initializer", async () => { + it("calls init function", async () => { const func = billing.onPlanAutomatedUpdatePublished((event) => event); let hello; @@ -88,7 +88,7 @@ describe("billing", () => { }); }); - it("should call the initializer", async () => { + it("calls init function", async () => { const func = billing.onPlanAutomatedUpdatePublished((event) => event); let hello; @@ -141,7 +141,7 @@ describe("billing", () => { expect(res).to.equal("input"); }); - it("should call the initializer", async () => { + it("calls init function", async () => { const func = billing.onOperation(ALERT_TYPE, (event) => event, undefined); let hello; diff --git a/spec/v2/providers/alerts/crashlytics.spec.ts b/spec/v2/providers/alerts/crashlytics.spec.ts index 7a8da3df9..b70ed0644 100644 --- a/spec/v2/providers/alerts/crashlytics.spec.ts +++ b/spec/v2/providers/alerts/crashlytics.spec.ts @@ -106,7 +106,7 @@ describe("crashlytics", () => { }); }); - it("should call initializer", async () => { + it("calls init function", async () => { const func = crashlytics[method](APPID, myHandler); let hello; diff --git a/spec/v2/providers/alerts/performance.spec.ts b/spec/v2/providers/alerts/performance.spec.ts index 667aa7ba5..01004e3f6 100644 --- a/spec/v2/providers/alerts/performance.spec.ts +++ b/spec/v2/providers/alerts/performance.spec.ts @@ -3,6 +3,7 @@ import * as alerts from "../../../../src/v2/providers/alerts"; import * as performance from "../../../../src/v2/providers/alerts/performance"; import { FULL_OPTIONS } from "../fixtures"; import { FULL_ENDPOINT, MINIMAL_V2_ENDPOINT } from "../../../fixtures"; +import { CloudEvent, onInit } from "../../../../src/v2/core"; const APPID = "123456789"; const myHandler = () => 42; @@ -45,6 +46,23 @@ describe("performance", () => { retry: false, }, }); + + it("calls init function", async () => { + const event: CloudEvent = { + specversion: "1.0", + id: "id", + source: "source", + type: "type", + time: "now", + data: "data", + }; + + let hello: string; + onInit(() => (hello = "world")); + expect(hello).to.be.undefined; + await performance.onThresholdAlertPublished(() => null)(event); + expect(hello).to.equal("world"); + }); }); it("should create a function with appid in opts", () => { diff --git a/spec/v2/providers/database.spec.ts b/spec/v2/providers/database.spec.ts index acd87644d..c5e16f747 100644 --- a/spec/v2/providers/database.spec.ts +++ b/spec/v2/providers/database.spec.ts @@ -25,6 +25,7 @@ import { PathPattern } from "../../../src/common/utilities/path-pattern"; import * as database from "../../../src/v2/providers/database"; import { expectType } from "../../common/metaprogramming"; import { MINIMAL_V2_ENDPOINT } from "../../fixtures"; +import { CloudEvent, onInit } from "../../../src/v2/core"; const RAW_RTDB_EVENT: database.RawRTDBCloudEvent = { data: { @@ -409,6 +410,23 @@ describe("database", () => { }, }); }); + + it("calls init function", async () => { + const event: CloudEvent = { + specversion: "1.0", + id: "id", + source: "source", + type: "type", + time: "now", + data: "data", + }; + + let hello; + onInit(() => (hello = "world")); + expect(hello).to.be.undefined; + await database.onValueWritten("path", () => null)(event); + expect(hello).to.equal("world"); + }); }); describe("onValueCreated", () => { @@ -469,6 +487,23 @@ describe("database", () => { }, }); }); + + it("calls init function", async () => { + const event: CloudEvent = { + specversion: "1.0", + id: "id", + source: "source", + type: "type", + time: "now", + data: "data", + }; + + let hello; + onInit(() => (hello = "world")); + expect(hello).to.be.undefined; + await database.onValueCreated("path", () => null)(event); + expect(hello).to.equal("world"); + }); }); describe("onValueUpdated", () => { @@ -526,6 +561,23 @@ describe("database", () => { }, }); }); + + it("calls init function", async () => { + const event: CloudEvent = { + specversion: "1.0", + id: "id", + source: "source", + type: "type", + time: "now", + data: "data", + }; + + let hello; + onInit(() => (hello = "world")); + expect(hello).to.be.undefined; + await database.onValueUpdated("path", () => null)(event); + expect(hello).to.equal("world"); + }); }); describe("onValueDeleted", () => { @@ -583,5 +635,22 @@ describe("database", () => { }, }); }); + + it("calls init function", async () => { + const event: CloudEvent = { + specversion: "1.0", + id: "id", + source: "source", + type: "type", + time: "now", + data: "data", + }; + + let hello; + onInit(() => (hello = "world")); + expect(hello).to.be.undefined; + await database.onValueDeleted("path", () => null)(event); + expect(hello).to.equal("world"); + }); }); }); diff --git a/spec/v2/providers/eventarc.spec.ts b/spec/v2/providers/eventarc.spec.ts index feb42b458..28696319a 100644 --- a/spec/v2/providers/eventarc.spec.ts +++ b/spec/v2/providers/eventarc.spec.ts @@ -25,6 +25,7 @@ import * as options from "../../../src/v2/options"; import * as eventarc from "../../../src/v2/providers/eventarc"; import { FULL_OPTIONS } from "./fixtures"; import { FULL_ENDPOINT, MINIMAL_V2_ENDPOINT } from "../../fixtures"; +import { CloudEvent, onInit } from "../../../src/v2/core"; const ENDPOINT_EVENT_TRIGGER = { eventType: "event-type", @@ -149,5 +150,22 @@ describe("v2/eventarc", () => { }, }); }); + + it("calls init function", async () => { + const event: CloudEvent = { + specversion: "1.0", + id: "id", + source: "source", + type: "type", + time: "now", + data: "data", + }; + + let hello; + onInit(() => (hello = "world")); + expect(hello).to.be.undefined; + await eventarc.onCustomEventPublished("type", () => null)(event); + expect(hello).to.equal("world"); + }); }); }); diff --git a/spec/v2/providers/firestore.spec.ts b/spec/v2/providers/firestore.spec.ts index 555b2fd3b..4a5e40163 100644 --- a/spec/v2/providers/firestore.spec.ts +++ b/spec/v2/providers/firestore.spec.ts @@ -25,6 +25,7 @@ import { google } from "../../../protos/compiledFirestore"; import { Timestamp } from "firebase-admin/firestore"; import * as firestore from "../../../src/v2/providers/firestore"; import { PathPattern } from "../../../src/common/utilities/path-pattern"; +import { onInit } from "../../../src/v2/core"; /** static-complied protobuf */ const DocumentEventData = google.events.cloud.firestore.v1.DocumentEventData; @@ -39,9 +40,9 @@ const eventBase = { dataschema: "https://github.com/googleapis/google-cloudevents/blob/main/proto/google/events/cloud/firestore/v1/data.proto", id: "379ad868-5ef9-4c84-a8ba-f75f1b056663", - source: "//firestore.googleapis.com/projects/my-project/databases/my-db", + source: "projects/my-project/databases/my-db/documents/d", subject: "documents/foo/fGRodw71mHutZ4wGDuT8", - specversion: "1.0", + specversion: "1.0" as const, time: "2023-03-10T18:20:43.677647Z", type: "google.cloud.firestore.document.v1.created", }; @@ -192,6 +193,23 @@ describe("firestore", () => { expect(func.run(true as any)).to.eq(2); expect(func.__endpoint).to.deep.eq(expectedEp); }); + + it("calls init function", async () => { + const event: firestore.RawFirestoreEvent = { + ...eventBase, + datacontenttype: "application/json", + data: { + oldValue: null, + value: null, + }, + }; + + let hello; + onInit(() => (hello = "world")); + expect(hello).to.be.undefined; + await firestore.onDocumentWritten("path", () => null)(event); + expect(hello).to.equal("world"); + }); }); describe("onDocumentCreated", () => { @@ -239,6 +257,23 @@ describe("firestore", () => { expect(func.run(true as any)).to.eq(2); expect(func.__endpoint).to.deep.eq(expectedEp); }); + + it("calls init function", async () => { + const event: firestore.RawFirestoreEvent = { + ...eventBase, + datacontenttype: "application/json", + data: { + oldValue: null, + value: null, + }, + }; + + let hello; + onInit(() => (hello = "world")); + expect(hello).to.be.undefined; + await firestore.onDocumentCreated("type", () => null)(event); + expect(hello).to.equal("world"); + }); }); describe("onDocumentUpdated", () => { @@ -286,6 +321,24 @@ describe("firestore", () => { expect(func.run(true as any)).to.eq(2); expect(func.__endpoint).to.deep.eq(expectedEp); }); + + it("calls init function", async () => { + const event: firestore.RawFirestoreEvent = { + ...eventBase, + datacontenttype: "application/json", + data: { + oldValue: null, + value: null, + }, + }; + + + let hello; + onInit(() => (hello = "world")); + expect(hello).to.be.undefined; + await firestore.onDocumentUpdated("path", () => null)(event); + expect(hello).to.equal("world"); + }); }); describe("onDocumentDeleted", () => { @@ -333,6 +386,23 @@ describe("firestore", () => { expect(func.run(true as any)).to.eq(2); expect(func.__endpoint).to.deep.eq(expectedEp); }); + + it("calls init function", async () => { + const event: firestore.RawFirestoreEvent = { + ...eventBase, + datacontenttype: "application/json", + data: { + oldValue: null, + value: null, + }, + }; + + let hello; + onInit(() => (hello = "world")); + expect(hello).to.be.undefined; + await firestore.onDocumentDeleted("path", () => null)(event); + expect(hello).to.equal("world"); + }); }); describe("getOpts", () => { diff --git a/spec/v2/providers/https.spec.ts b/spec/v2/providers/https.spec.ts index 64a37c7eb..643044338 100644 --- a/spec/v2/providers/https.spec.ts +++ b/spec/v2/providers/https.spec.ts @@ -29,6 +29,7 @@ import * as https from "../../../src/v2/providers/https"; import { expectedResponseHeaders, MockRequest } from "../../fixtures/mockrequest"; import { runHandler } from "../../helper"; import { FULL_ENDPOINT, MINIMAL_V2_ENDPOINT, FULL_OPTIONS, FULL_TRIGGER } from "./fixtures"; +import { onInit } from "../../../src/v2/core"; describe("onRequest", () => { beforeEach(() => { @@ -270,6 +271,28 @@ describe("onRequest", () => { sinon.restore(); }); + + it("calls init function", async () => { + const func = https.onRequest((req, res) => { + res.status(200).send("Good"); + }); + const req = new MockRequest( + { + data: {}, + }, + { + "Access-Control-Request-Method": "POST", + "Access-Control-Request-Headers": "origin", + origin: "example.com", + } + ); + req.method = "OPTIONS"; + let hello; + onInit(() => (hello = "world")); + expect(hello).to.be.undefined; + await runHandler(func, req as any); + expect(hello).to.equal("world"); + }); }); describe("onCall", () => { @@ -363,7 +386,7 @@ describe("onCall", () => { }); }); - it("has a .run method", () => { + it("has a .run method", async () => { const cf = https.onCall((request) => { return request; }); @@ -376,7 +399,7 @@ describe("onCall", () => { token: "token", }, }; - expect(cf.run(request)).to.deep.equal(request); + await expect(cf.run(request)).to.eventually.deep.equal(request); }); it("should be an express handler", async () => { @@ -487,4 +510,25 @@ describe("onCall", () => { https.onCall((request: https.CallableRequest) => `Hello, ${request.data}`); https.onCall((request: https.CallableRequest) => `Hello, ${request.data}`); }); + + it("calls init function", async () => { + const func = https.onCall(() => 42); + + const req = new MockRequest( + { + data: {}, + }, + { + "content-type": "application/json", + origin: "example.com", + } + ); + req.method = "POST"; + + let hello; + onInit(() => (hello = "world")); + expect(hello).to.be.undefined; + await runHandler(func, req as any); + expect(hello).to.equal("world"); + }); }); diff --git a/spec/v2/providers/identity.spec.ts b/spec/v2/providers/identity.spec.ts index 7559a4133..bcd416d29 100644 --- a/spec/v2/providers/identity.spec.ts +++ b/spec/v2/providers/identity.spec.ts @@ -22,6 +22,9 @@ import { expect } from "chai"; import * as identity from "../../../src/v2/providers/identity"; import { MINIMAL_V2_ENDPOINT } from "../../fixtures"; +import { onInit } from "../../../src/v2/core"; +import { MockRequest } from "../../fixtures/mockrequest"; +import { runHandler } from "../../helper"; const BEFORE_CREATE_TRIGGER = { eventType: "providers/cloud.auth/eventTypes/user.beforeCreate", @@ -91,6 +94,27 @@ describe("identity", () => { }, ]); }); + + it("calls init function", async () => { + const func = identity.beforeUserCreated(() => null); + + const req = new MockRequest( + { + data: {}, + }, + { + "content-type": "application/json", + origin: "example.com", + } + ); + req.method = "POST"; + + let hello; + onInit(() => (hello = "world")); + expect(hello).to.be.undefined; + await runHandler(func, req as any); + expect(hello).to.equal("world"); + }); }); describe("beforeUserSignedIn", () => { @@ -135,6 +159,27 @@ describe("identity", () => { }, ]); }); + + it("calls init function", async () => { + const func = identity.beforeUserSignedIn(() => null); + + const req = new MockRequest( + { + data: {}, + }, + { + "content-type": "application/json", + origin: "example.com", + } + ); + req.method = "POST"; + + let hello; + onInit(() => (hello = "world")); + expect(hello).to.be.undefined; + await runHandler(func, req as any); + expect(hello).to.equal("world"); + }); }); describe("beforeOperation", () => { diff --git a/spec/v2/providers/remoteConfig.spec.ts b/spec/v2/providers/remoteConfig.spec.ts index ae29ecbc7..ce9a7da48 100644 --- a/spec/v2/providers/remoteConfig.spec.ts +++ b/spec/v2/providers/remoteConfig.spec.ts @@ -24,6 +24,8 @@ import { expect } from "chai"; import * as remoteConfig from "../../../src/v2/providers/remoteConfig"; import * as options from "../../../src/v2/options"; import { MINIMAL_V2_ENDPOINT } from "../../fixtures"; +import { CloudEvent } from "../../../lib/v2/core"; +import { onInit } from "../../../src/v2/core"; describe("onConfigUpdated", () => { afterEach(() => { @@ -43,7 +45,7 @@ describe("onConfigUpdated", () => { retry: false, }, }); - await expect(fn.run(1 as any)).to.eventually.eq(2); + await expect(fn(1 as any)).to.eventually.eq(2); }); it("should create a function with opts and a handler", async () => { @@ -72,6 +74,23 @@ describe("onConfigUpdated", () => { retry: true, }, }); - await expect(fn.run(1 as any)).to.eventually.eq(2); + await expect(fn(1 as any)).to.eventually.eq(2); + }); + + it("calls init function", async () => { + const event: CloudEvent = { + specversion: "1.0", + id: "id", + source: "source", + type: "type", + time: "now", + data: "data", + }; + + let hello; + onInit(() => (hello = "world")); + expect(hello).to.be.undefined; + await remoteConfig.onConfigUpdated(() => null)(event); + expect(hello).to.equal("world"); }); }); diff --git a/spec/v2/providers/scheduler.spec.ts b/spec/v2/providers/scheduler.spec.ts index 4f3e6f984..fcd03cf1f 100644 --- a/spec/v2/providers/scheduler.spec.ts +++ b/spec/v2/providers/scheduler.spec.ts @@ -25,6 +25,9 @@ import { ManifestEndpoint } from "../../../src/runtime/manifest"; import * as options from "../../../src/v2/options"; import * as schedule from "../../../src/v2/providers/scheduler"; import { MINIMAL_V2_ENDPOINT } from "../../fixtures"; +import { onInit } from "../../../src/v2/core"; +import { MockRequest } from "../../fixtures/mockrequest"; +import { runHandler } from "../../helper"; const MINIMAL_SCHEDULE_TRIGGER: ManifestEndpoint["scheduleTrigger"] = { schedule: "", @@ -187,5 +190,26 @@ describe("schedule", () => { foo: "newBar", }); }); + + it("calls init function", async () => { + const func = schedule.onSchedule("* * * * *", () => null); + + const req = new MockRequest( + { + data: {}, + }, + { + "content-type": "application/json", + origin: "example.com", + } + ); + req.method = "POST"; + + let hello; + onInit(() => (hello = "world")); + expect(hello).to.be.undefined; + await runHandler(func, req as any); + expect(hello).to.equal("world"); + }); }); }); diff --git a/spec/v2/providers/storage.spec.ts b/spec/v2/providers/storage.spec.ts index d5a699d70..06324e9ab 100644 --- a/spec/v2/providers/storage.spec.ts +++ b/spec/v2/providers/storage.spec.ts @@ -3,6 +3,7 @@ import * as config from "../../../src/common/config"; import * as options from "../../../src/v2/options"; import * as storage from "../../../src/v2/providers/storage"; import { FULL_ENDPOINT, MINIMAL_V2_ENDPOINT, FULL_OPTIONS, FULL_TRIGGER } from "./fixtures"; +import { CloudEvent, onInit } from "../../../src/v2/core"; const EVENT_TRIGGER = { eventType: "event-type", @@ -312,6 +313,23 @@ describe("v2/storage", () => { region: ["us-west1"], }); }); + + it("calls init function", async () => { + const event: CloudEvent = { + specversion: "1.0", + id: "id", + source: "source", + type: "type", + time: "now", + data: "data", + }; + + let hello; + onInit(() => (hello = "world")); + expect(hello).to.be.undefined; + await storage.onObjectArchived("bucket", () => null)(event); + expect(hello).to.equal("world"); + }); }); describe("onObjectFinalized", () => { @@ -429,6 +447,23 @@ describe("v2/storage", () => { region: ["us-west1"], }); }); + + it("calls init function", async () => { + const event: CloudEvent = { + specversion: "1.0", + id: "id", + source: "source", + type: "type", + time: "now", + data: "data", + }; + + let hello; + onInit(() => (hello = "world")); + expect(hello).to.be.undefined; + await storage.onObjectFinalized("bucket", () => null)(event); + expect(hello).to.equal("world"); + }); }); describe("onObjectDeleted", () => { @@ -543,6 +578,23 @@ describe("v2/storage", () => { region: ["us-west1"], }); }); + + it("calls init function", async () => { + const event: CloudEvent = { + specversion: "1.0", + id: "id", + source: "source", + type: "type", + time: "now", + data: "data", + }; + + let hello; + onInit(() => (hello = "world")); + expect(hello).to.be.undefined; + await storage.onObjectDeleted("bucket", () => null)(event); + expect(hello).to.equal("world"); + }); }); describe("onObjectMetadataUpdated", () => { @@ -661,5 +713,22 @@ describe("v2/storage", () => { region: ["us-west1"], }); }); + + it("calls init function", async () => { + const event: CloudEvent = { + specversion: "1.0", + id: "id", + source: "source", + type: "type", + time: "now", + data: "data", + }; + + let hello; + onInit(() => (hello = "world")); + expect(hello).to.be.undefined; + await storage.onObjectMetadataUpdated("bucket", () => null)(event); + expect(hello).to.equal("world"); + }); }); }); diff --git a/spec/v2/providers/tasks.spec.ts b/spec/v2/providers/tasks.spec.ts index 1597a1947..46ffd7a0a 100644 --- a/spec/v2/providers/tasks.spec.ts +++ b/spec/v2/providers/tasks.spec.ts @@ -28,6 +28,7 @@ import { onTaskDispatched, Request } from "../../../src/v2/providers/tasks"; import { MockRequest } from "../../fixtures/mockrequest"; import { runHandler } from "../../helper"; import { FULL_ENDPOINT, MINIMAL_V2_ENDPOINT, FULL_OPTIONS, FULL_TRIGGER } from "./fixtures"; +import { onInit } from "../../../src/v2/core"; const MINIMIAL_TASK_QUEUE_TRIGGER: ManifestEndpoint["taskQueueTrigger"] = { rateLimits: { @@ -299,4 +300,25 @@ describe("onTaskDispatched", () => { console.log(`Hello, ${request.data}`); }); }); + + it("calls init function", async () => { + const func = onTaskDispatched(() => null); + + const req = new MockRequest( + { + data: {}, + }, + { + "content-type": "application/json", + origin: "example.com", + } + ); + req.method = "POST"; + + let hello; + onInit(() => (hello = "world")); + expect(hello).to.be.undefined; + await runHandler(func, req as any); + expect(hello).to.equal("world"); + }); }); diff --git a/spec/v2/providers/testLab.spec.ts b/spec/v2/providers/testLab.spec.ts index 15ff77248..15d649d44 100644 --- a/spec/v2/providers/testLab.spec.ts +++ b/spec/v2/providers/testLab.spec.ts @@ -24,6 +24,7 @@ import { expect } from "chai"; import * as testLab from "../../../src/v2/providers/testLab"; import * as options from "../../../src/v2/options"; import { MINIMAL_V2_ENDPOINT } from "../../fixtures"; +import { CloudEvent, onInit } from "../../../src/v2/core"; describe("onTestMatrixCompleted", () => { afterEach(() => { @@ -74,4 +75,21 @@ describe("onTestMatrixCompleted", () => { }); expect(fn.run(1 as any)).to.eq(2); }); + + it("calls init function", async () => { + const event: CloudEvent = { + specversion: "1.0", + id: "id", + source: "source", + type: "type", + time: "now", + data: "data", + }; + + let hello; + onInit(() => (hello = "world")); + expect(hello).to.be.undefined; + await testLab.onTestMatrixCompleted(() => null)(event); + expect(hello).to.equal("world"); + }); }); diff --git a/src/common/onInit.ts b/src/common/onInit.ts index cf87ecbf4..bfd147193 100644 --- a/src/common/onInit.ts +++ b/src/common/onInit.ts @@ -10,7 +10,7 @@ let didInit = false; * Calling this function more than once leads to undefined behavior. * @param callback initialization callback to be run before any function executes. */ -export function onInit(callback: () => any) { +export function onInit(callback: () => unknown) { if (initCallback) { logger.warn( "Setting onInit callback more than once. Only the most recent callback will be called" @@ -23,7 +23,7 @@ export function onInit(callback: () => any) { type Resolved = T extends Promise ? V : T; /** @internal */ -export function withInit any>(func: T) { +export function withInit unknown>(func: T) { return async (...args: Parameters): Promise>> => { if (!didInit) { if (initCallback) { @@ -31,6 +31,10 @@ export function withInit any>(func: T) { } didInit = true; } - return func(...args); + + // Note: This cast is actually inaccurate because it may be a promise, but + // it doesn't actually matter because the async function will promisify + // non-promises and forward promises. + return func(...args) as Resolved>; }; } diff --git a/src/v2/providers/remoteConfig.ts b/src/v2/providers/remoteConfig.ts index 3018113a7..23707dea2 100644 --- a/src/v2/providers/remoteConfig.ts +++ b/src/v2/providers/remoteConfig.ts @@ -130,10 +130,12 @@ export function onConfigUpdated( const baseOpts = optionsToEndpoint(getGlobalOptions()); const specificOpts = optionsToEndpoint(optsOrHandler); - const func: any = (raw: CloudEvent) => { - return handler(raw as CloudEvent); - }; - func.run = wrapTraceContext(withInit(handler)); + const func: any = wrapTraceContext( + withInit((raw: CloudEvent) => { + return handler(raw as CloudEvent); + }) + ); + func.run = handler; const ep: ManifestEndpoint = { ...initV2Endpoint(getGlobalOptions(), optsOrHandler),