Skip to content

Commit c260c2a

Browse files
authored
Add startup lifecycle hook (#1531)
* checkpoint * Finish missing tests; remove redundant v1 tests * Fix linter error * Fix import error * Add changelog; fix exports of v2/core
1 parent 5a94583 commit c260c2a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+702
-59
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add onInit callback function for global variable initialization (#1531)

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@
110110
"v2": [
111111
"lib/v2"
112112
],
113+
"v2/core": [
114+
"lib/v2/core"
115+
],
113116
"v2/alerts": [
114117
"lib/v2/providers/alerts"
115118
],
@@ -250,4 +253,4 @@
250253
"engines": {
251254
"node": ">=14.10.0"
252255
}
253-
}
256+
}

spec/v1/cloud-functions.spec.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import { expect } from "chai";
2424

2525
import {
26+
onInit,
2627
Event,
2728
EventContext,
2829
makeCloudFunction,
@@ -41,6 +42,34 @@ describe("makeCloudFunction", () => {
4142
legacyEventType: "providers/provider/eventTypes/event",
4243
};
4344

45+
it("calls init function", async () => {
46+
const test: Event = {
47+
context: {
48+
eventId: "00000",
49+
timestamp: "2016-11-04T21:29:03.496Z",
50+
eventType: "provider.event",
51+
resource: {
52+
service: "provider",
53+
name: "resource",
54+
},
55+
},
56+
data: "data",
57+
};
58+
const cf = makeCloudFunction({
59+
provider: "mock.provider",
60+
eventType: "mock.event",
61+
service: "service",
62+
triggerResource: () => "resource",
63+
handler: () => null,
64+
});
65+
66+
let hello;
67+
onInit(() => (hello = "world"));
68+
expect(hello).is.undefined;
69+
await cf(test.data, test.context);
70+
expect(hello).equals("world");
71+
});
72+
4473
it("should put a __trigger/__endpoint on the returned CloudFunction", () => {
4574
const cf = makeCloudFunction({
4675
provider: "mock.provider",

spec/v1/providers/analytics.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ describe("Analytics Functions", () => {
8585
});
8686

8787
describe("#dataConstructor", () => {
88-
it("should handle an event with the appropriate fields", () => {
88+
it("should handle an event with the appropriate fields", async () => {
8989
const cloudFunction = analytics
9090
.event("first_open")
9191
.onLog((data: analytics.AnalyticsEvent) => data);
@@ -109,7 +109,7 @@ describe("Analytics Functions", () => {
109109
},
110110
};
111111

112-
return expect(cloudFunction(event.data, event.context)).to.eventually.deep.equal({
112+
await expect(cloudFunction(event.data, event.context)).to.eventually.deep.equal({
113113
params: {},
114114
user: {
115115
userId: "hi!",

spec/v1/providers/https.spec.ts

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import {
3535
import { runHandler } from "../../helper";
3636
import { MINIMAL_V1_ENDPOINT } from "../../fixtures";
3737
import { CALLABLE_AUTH_HEADER, ORIGINAL_AUTH_HEADER } from "../../../src/common/providers/https";
38+
import { onInit } from "../../../src/v1";
3839

3940
describe("CloudHttpsBuilder", () => {
4041
describe("#onRequest", () => {
@@ -70,6 +71,26 @@ describe("CloudHttpsBuilder", () => {
7071
expect(fn.__endpoint.timeoutSeconds).to.deep.equal(90);
7172
expect(fn.__endpoint.httpsTrigger.invoker).to.deep.equal(["private"]);
7273
});
74+
75+
it("calls init function", async () => {
76+
let hello;
77+
onInit(() => (hello = "world"));
78+
expect(hello).to.be.undefined;
79+
const fn = functions.https.onRequest((_req, res) => {
80+
res.send(200);
81+
});
82+
const req = new MockRequest(
83+
{
84+
data: { foo: "bar" },
85+
},
86+
{
87+
"content-type": "application/json",
88+
}
89+
);
90+
req.method = "POST";
91+
await runHandler(fn, req as any);
92+
expect(hello).to.equal("world");
93+
});
7394
});
7495
});
7596

@@ -114,7 +135,7 @@ describe("#onCall", () => {
114135
expect(fn.__endpoint.timeoutSeconds).to.deep.equal(90);
115136
});
116137

117-
it("has a .run method", () => {
138+
it("has a .run method", async () => {
118139
const cf = https.onCall((d, c) => {
119140
return { data: d, context: c };
120141
});
@@ -127,7 +148,8 @@ describe("#onCall", () => {
127148
token: "token",
128149
},
129150
};
130-
expect(cf.run(data, context)).to.deep.equal({ data, context });
151+
152+
await expect(cf.run(data, context)).to.eventually.deep.equal({ data, context });
131153
});
132154

133155
// Regression test for firebase-functions#947
@@ -152,6 +174,25 @@ describe("#onCall", () => {
152174
expect(gotData).to.deep.equal({ foo: "bar" });
153175
});
154176

177+
it("should call initializer", async () => {
178+
const func = https.onCall(() => null);
179+
const req = new MockRequest(
180+
{
181+
data: {},
182+
},
183+
{
184+
"content-type": "application/json",
185+
}
186+
);
187+
req.method = "POST";
188+
189+
let hello;
190+
onInit(() => (hello = "world"));
191+
expect(hello).to.be.undefined;
192+
await runHandler(func, req as any);
193+
expect(hello).to.equal("world");
194+
});
195+
155196
// Test for firebase-tools#5210
156197
it("should create context.auth for v1 emulated functions", async () => {
157198
sinon.stub(debug, "isDebugFeatureEnabled").withArgs("skipTokenVerification").returns(true);

spec/v1/providers/remoteConfig.spec.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,14 @@ describe("RemoteConfig Functions", () => {
122122
delete process.env.GCLOUD_PROJECT;
123123
});
124124

125-
it("should unwrap the version in the event", () => {
126-
return Promise.all([
127-
cloudFunctionUpdate(event.data, event.context).then((data: any) => {
128-
expect(data).to.deep.equal(constructVersion());
129-
}),
130-
]);
125+
it("should unwrap the version in the event", async () => {
126+
let hello;
127+
functions.onInit(() => (hello = "world"));
128+
expect(hello).to.be.undefined;
129+
await cloudFunctionUpdate(event.data, event.context).then((data: any) => {
130+
expect(data).to.deep.equal(constructVersion());
131+
});
132+
expect(hello).to.equal("world");
131133
});
132134
});
133135
});

spec/v2/providers/alerts/alerts.spec.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { expect } from "chai";
2-
import { CloudEvent } from "../../../../src/v2";
2+
import { CloudEvent, onInit } from "../../../../src/v2";
33
import * as options from "../../../../src/v2/options";
44
import * as alerts from "../../../../src/v2/providers/alerts";
55
import { FULL_OPTIONS } from "../fixtures";
@@ -211,4 +211,21 @@ describe("alerts", () => {
211211
});
212212
});
213213
});
214+
215+
it("calls init function", async () => {
216+
const event: CloudEvent<string> = {
217+
specversion: "1.0",
218+
id: "id",
219+
source: "source",
220+
type: "type",
221+
time: "now",
222+
data: "data",
223+
};
224+
225+
let hello;
226+
onInit(() => (hello = "world"));
227+
expect(hello).to.be.undefined;
228+
await alerts.onAlertPublished("alert", () => null)(event);
229+
expect(hello).to.equal("world");
230+
});
214231
});

spec/v2/providers/alerts/appDistribution.spec.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as alerts from "../../../../src/v2/providers/alerts";
33
import * as appDistribution from "../../../../src/v2/providers/alerts/appDistribution";
44
import { FULL_OPTIONS } from "../fixtures";
55
import { FULL_ENDPOINT, MINIMAL_V2_ENDPOINT } from "../../../fixtures";
6+
import { onInit } from "../../../../src/v2/core";
67

78
const APPID = "123456789";
89
const myHandler = () => 42;
@@ -91,6 +92,16 @@ describe("appDistribution", () => {
9192

9293
expect(res).to.equal("input");
9394
});
95+
96+
it("calls init function", async () => {
97+
const func = appDistribution.onNewTesterIosDevicePublished(APPID, (event) => event);
98+
99+
let hello;
100+
onInit(() => (hello = "world"));
101+
expect(hello).to.be.undefined;
102+
await func({ data: "test" } as any);
103+
expect(hello).to.equal("world");
104+
});
94105
});
95106

96107
describe("onInAppfeedbackPublished", () => {
@@ -172,6 +183,16 @@ describe("appDistribution", () => {
172183

173184
expect(res).to.equal("input");
174185
});
186+
187+
it("calls init function", async () => {
188+
const func = appDistribution.onInAppFeedbackPublished(APPID, (event) => event);
189+
190+
let hello;
191+
onInit(() => (hello = "world"));
192+
expect(hello).to.be.undefined;
193+
await func({ data: "test" } as any);
194+
expect(hello).to.equal("world");
195+
});
175196
});
176197

177198
describe("getOptsAndApp", () => {

spec/v2/providers/alerts/billing.spec.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as alerts from "../../../../src/v2/providers/alerts";
33
import * as billing from "../../../../src/v2/providers/alerts/billing";
44
import { FULL_OPTIONS } from "../fixtures";
55
import { FULL_ENDPOINT, MINIMAL_V2_ENDPOINT } from "../../../fixtures";
6+
import { onInit } from "../../../../src/v2/core";
67

78
const ALERT_TYPE = "new-alert-type";
89
const myHandler = () => 42;
@@ -41,6 +42,16 @@ describe("billing", () => {
4142
},
4243
});
4344
});
45+
46+
it("calls init function", async () => {
47+
const func = billing.onPlanAutomatedUpdatePublished((event) => event);
48+
49+
let hello;
50+
onInit(() => (hello = "world"));
51+
expect(hello).to.be.undefined;
52+
await func({ data: "test" } as any);
53+
expect(hello).to.equal("world");
54+
});
4455
});
4556

4657
describe("onPlanAutomatedUpdatePublished", () => {
@@ -76,6 +87,16 @@ describe("billing", () => {
7687
},
7788
});
7889
});
90+
91+
it("calls init function", async () => {
92+
const func = billing.onPlanAutomatedUpdatePublished((event) => event);
93+
94+
let hello;
95+
onInit(() => (hello = "world"));
96+
expect(hello).to.be.undefined;
97+
await func({ data: "test" } as any);
98+
expect(hello).to.equal("world");
99+
});
79100
});
80101

81102
describe("onOperation", () => {
@@ -119,5 +140,15 @@ describe("billing", () => {
119140

120141
expect(res).to.equal("input");
121142
});
143+
144+
it("calls init function", async () => {
145+
const func = billing.onOperation(ALERT_TYPE, (event) => event, undefined);
146+
147+
let hello;
148+
onInit(() => (hello = "world"));
149+
expect(hello).to.be.undefined;
150+
await func({ data: "test" } as any);
151+
expect(hello).to.equal("world");
152+
});
122153
});
123154
});

spec/v2/providers/alerts/crashlytics.spec.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as alerts from "../../../../src/v2/providers/alerts";
33
import * as crashlytics from "../../../../src/v2/providers/alerts/crashlytics";
44
import { FULL_OPTIONS } from "../fixtures";
55
import { FULL_ENDPOINT, MINIMAL_V2_ENDPOINT } from "../../../fixtures";
6+
import { onInit } from "../../../../src/v2/core";
67

78
const ALERT_TYPE = "new-alert-type";
89
const APPID = "123456789";
@@ -104,6 +105,16 @@ describe("crashlytics", () => {
104105
},
105106
});
106107
});
108+
109+
it("calls init function", async () => {
110+
const func = crashlytics[method](APPID, myHandler);
111+
112+
let hello;
113+
onInit(() => (hello = "world"));
114+
expect(hello).to.be.undefined;
115+
await func({ data: "crash" } as any);
116+
expect(hello).to.equal("world");
117+
});
107118
});
108119
}
109120

spec/v2/providers/alerts/performance.spec.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as alerts from "../../../../src/v2/providers/alerts";
33
import * as performance from "../../../../src/v2/providers/alerts/performance";
44
import { FULL_OPTIONS } from "../fixtures";
55
import { FULL_ENDPOINT, MINIMAL_V2_ENDPOINT } from "../../../fixtures";
6+
import { CloudEvent, onInit } from "../../../../src/v2/core";
67

78
const APPID = "123456789";
89
const myHandler = () => 42;
@@ -45,6 +46,23 @@ describe("performance", () => {
4546
retry: false,
4647
},
4748
});
49+
50+
it("calls init function", async () => {
51+
const event: CloudEvent<string> = {
52+
specversion: "1.0",
53+
id: "id",
54+
source: "source",
55+
type: "type",
56+
time: "now",
57+
data: "data",
58+
};
59+
60+
let hello: string;
61+
onInit(() => (hello = "world"));
62+
expect(hello).to.be.undefined;
63+
await performance.onThresholdAlertPublished(() => null)(event);
64+
expect(hello).to.equal("world");
65+
});
4866
});
4967

5068
it("should create a function with appid in opts", () => {

0 commit comments

Comments
 (0)