Skip to content

Commit

Permalink
Dynamically invoke correct trigger when running functions emulator wi…
Browse files Browse the repository at this point in the history
…th --inspect-functions flag (#4232)

In #4149, we made large refactor of the Functions Runtime. Namely:

1) We no longer relied on Functions Runtime to parse triggers. Instead, we use [`RuntimeDelegate`](https://github.com/firebase/firebase-tools/blob/2a56d9520241ab9897a59aac22c9fd016251a7cd/src/deploy/functions/runtimes/index.ts#L114), the same procedure used to parse trigger in `firebase deploy` command.

2) Each process running the Functions Runtime was bound to a specific trigger.

Unfortunately, this change broke support for `--inspect-function` where users can attach Node Debugger to step through their function when triggered.

The debugging experience supported w/ `--inspect-function` relies on the fact that a single process executes all function triggers. This is drastically different to how functions run in Production environment, but it is a very useful feature that makes it easy to step through all functions in a single debug session.

I wasn't aware of the debugging capabilities when making the refactor. Unfortunately, the debug feature cuts across a strong assumption I've made for the future of Functions Emulator. This is a rather hasty rollback - I'm going to have to think more deeply about how we want the evolve this feature.

Fixes #4189, #4166
  • Loading branch information
taeold committed Mar 2, 2022
1 parent d7d8dc7 commit b1099a2
Show file tree
Hide file tree
Showing 7 changed files with 172 additions and 122 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@
- Fixes Storage Emulator rules resource evaluation (#4214).
- Fixes bug where securityLevel is overwritten on https function re-deploys (#4208).
- Fixes bug where functions emulator ignored functions.runtime option in firebase.json (#4207).
- Fixes bug where functions emulator triggered wrong functions when started with --inspect-functions flag (#4232).
- Updates functions init template to use latest versions of dependencies of functions init (#4177).
6 changes: 3 additions & 3 deletions scripts/emulator-tests/functionsEmulator.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,18 +123,18 @@ functionsEmulator.setTriggersForTesting(
);

// TODO(samstern): This is an ugly way to just override the InvokeRuntimeOpts on each call
const startFunctionRuntime = functionsEmulator.startFunctionRuntime.bind(functionsEmulator);
const invokeTrigger = functionsEmulator.invokeTrigger.bind(functionsEmulator);
function useFunctions(triggers: () => {}): void {
const serializedTriggers = triggers.toString();

// eslint-disable-next-line @typescript-eslint/unbound-method
functionsEmulator.startFunctionRuntime = (
functionsEmulator.invokeTrigger = (
backend: EmulatableBackend,
trigger: EmulatedTriggerDefinition,
proto?: any,
runtimeOpts?: InvokeRuntimeOpts
): Promise<RuntimeWorker> => {
return startFunctionRuntime(testBackend, trigger, proto, {
return invokeTrigger(testBackend, trigger, proto, {
nodeBinary: process.execPath,
serializedTriggers,
});
Expand Down
64 changes: 32 additions & 32 deletions scripts/emulator-tests/functionsEmulatorRuntime.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ async function countLogEntries(worker: RuntimeWorker): Promise<{ [key: string]:
return counts;
}

async function startRuntimeWithFunctions(
async function invokeFunction(
frb: FunctionsRuntimeBundle,
triggers: () => {},
signatureType: SignatureType,
Expand All @@ -67,7 +67,7 @@ async function startRuntimeWithFunctions(
entryPoint: "function_id",
platform: "gcfv1" as const,
};
return functionsEmulator.startFunctionRuntime(
return functionsEmulator.invokeTrigger(
testBackend,
{
...dummyTriggerDef,
Expand Down Expand Up @@ -129,7 +129,7 @@ describe("FunctionsEmulator-Runtime", () => {
describe("Stubs, Mocks, and Helpers (aka Magic, Glee, and Awesomeness)", () => {
describe("_InitializeNetworkFiltering(...)", () => {
it("should log outgoing unknown HTTP requests via 'http'", async () => {
const worker = await startRuntimeWithFunctions(
const worker = await invokeFunction(
FunctionRuntimeBundles.onCreate,
() => {
require("firebase-admin").initializeApp();
Expand All @@ -152,7 +152,7 @@ describe("FunctionsEmulator-Runtime", () => {
}).timeout(TIMEOUT_LONG);

it("should log outgoing unknown HTTP requests via 'https'", async () => {
const worker = await startRuntimeWithFunctions(
const worker = await invokeFunction(
FunctionRuntimeBundles.onCreate,
() => {
require("firebase-admin").initializeApp();
Expand All @@ -175,7 +175,7 @@ describe("FunctionsEmulator-Runtime", () => {
}).timeout(TIMEOUT_LONG);

it("should log outgoing Google API requests", async () => {
const worker = await startRuntimeWithFunctions(
const worker = await invokeFunction(
FunctionRuntimeBundles.onCreate,
() => {
require("firebase-admin").initializeApp();
Expand Down Expand Up @@ -210,7 +210,7 @@ describe("FunctionsEmulator-Runtime", () => {
});

it("should provide stubbed default app from initializeApp", async () => {
const worker = await startRuntimeWithFunctions(
const worker = await invokeFunction(
FunctionRuntimeBundles.onCreate,
() => {
require("firebase-admin").initializeApp();
Expand All @@ -228,7 +228,7 @@ describe("FunctionsEmulator-Runtime", () => {
}).timeout(TIMEOUT_MED);

it("should provide a stubbed app with custom options", async () => {
const worker = await startRuntimeWithFunctions(
const worker = await invokeFunction(
FunctionRuntimeBundles.onCreate,
() => {
require("firebase-admin").initializeApp({
Expand Down Expand Up @@ -258,7 +258,7 @@ describe("FunctionsEmulator-Runtime", () => {
}).timeout(TIMEOUT_MED);

it("should provide non-stubbed non-default app from initializeApp", async () => {
const worker = await startRuntimeWithFunctions(
const worker = await invokeFunction(
FunctionRuntimeBundles.onCreate,
() => {
require("firebase-admin").initializeApp(); // We still need to initialize default for snapshots
Expand All @@ -276,7 +276,7 @@ describe("FunctionsEmulator-Runtime", () => {
}).timeout(TIMEOUT_MED);

it("should route all sub-fields accordingly", async () => {
const worker = await startRuntimeWithFunctions(
const worker = await invokeFunction(
FunctionRuntimeBundles.onCreate,
() => {
require("firebase-admin").initializeApp();
Expand Down Expand Up @@ -308,7 +308,7 @@ describe("FunctionsEmulator-Runtime", () => {

it("should expose Firestore prod when the emulator is not running", async () => {
const frb = FunctionRuntimeBundles.onRequest;
const worker = await startRuntimeWithFunctions(
const worker = await invokeFunction(
frb,
() => {
const admin = require("firebase-admin");
Expand Down Expand Up @@ -340,7 +340,7 @@ describe("FunctionsEmulator-Runtime", () => {
port: 9090,
});

const worker = await startRuntimeWithFunctions(
const worker = await invokeFunction(
frb,
() => {
const admin = require("firebase-admin");
Expand All @@ -367,7 +367,7 @@ describe("FunctionsEmulator-Runtime", () => {
it("should expose RTDB prod when the emulator is not running", async () => {
const frb = FunctionRuntimeBundles.onRequest;

const worker = await startRuntimeWithFunctions(
const worker = await invokeFunction(
frb,
() => {
const admin = require("firebase-admin");
Expand Down Expand Up @@ -397,7 +397,7 @@ describe("FunctionsEmulator-Runtime", () => {
port: 9090,
});

const worker = await startRuntimeWithFunctions(
const worker = await invokeFunction(
frb,
() => {
const admin = require("firebase-admin");
Expand Down Expand Up @@ -427,7 +427,7 @@ describe("FunctionsEmulator-Runtime", () => {
port: 9090,
});

const worker = await startRuntimeWithFunctions(
const worker = await invokeFunction(
frb,
() => {
const admin = require("firebase-admin");
Expand All @@ -449,7 +449,7 @@ describe("FunctionsEmulator-Runtime", () => {

it("should return a real databaseURL when RTDB emulator is not running", async () => {
const frb = _.cloneDeep(FunctionRuntimeBundles.onRequest);
const worker = await startRuntimeWithFunctions(
const worker = await invokeFunction(
frb,
() => {
const admin = require("firebase-admin");
Expand Down Expand Up @@ -484,7 +484,7 @@ describe("FunctionsEmulator-Runtime", () => {
});

it("should tell the user if they've accessed a non-existent function field", async () => {
const worker = await startRuntimeWithFunctions(
const worker = await invokeFunction(
FunctionRuntimeBundles.onCreate,
() => {
require("firebase-admin").initializeApp();
Expand Down Expand Up @@ -513,7 +513,7 @@ describe("FunctionsEmulator-Runtime", () => {
describe("HTTPS", () => {
it("should handle a GET request", async () => {
const frb = FunctionRuntimeBundles.onRequest;
const worker = await startRuntimeWithFunctions(
const worker = await invokeFunction(
frb,
() => {
require("firebase-admin").initializeApp();
Expand All @@ -533,7 +533,7 @@ describe("FunctionsEmulator-Runtime", () => {

it("should handle a POST request with form data", async () => {
const frb = FunctionRuntimeBundles.onRequest;
const worker = await startRuntimeWithFunctions(
const worker = await invokeFunction(
frb,
() => {
require("firebase-admin").initializeApp();
Expand Down Expand Up @@ -564,7 +564,7 @@ describe("FunctionsEmulator-Runtime", () => {

it("should handle a POST request with JSON data", async () => {
const frb = FunctionRuntimeBundles.onRequest;
const worker = await startRuntimeWithFunctions(
const worker = await invokeFunction(
frb,
() => {
require("firebase-admin").initializeApp();
Expand Down Expand Up @@ -595,7 +595,7 @@ describe("FunctionsEmulator-Runtime", () => {

it("should handle a POST request with text data", async () => {
const frb = FunctionRuntimeBundles.onRequest;
const worker = await startRuntimeWithFunctions(
const worker = await invokeFunction(
frb,
() => {
require("firebase-admin").initializeApp();
Expand Down Expand Up @@ -626,7 +626,7 @@ describe("FunctionsEmulator-Runtime", () => {

it("should handle a POST request with any other type", async () => {
const frb = FunctionRuntimeBundles.onRequest;
const worker = await startRuntimeWithFunctions(
const worker = await invokeFunction(
frb,
() => {
require("firebase-admin").initializeApp();
Expand Down Expand Up @@ -658,7 +658,7 @@ describe("FunctionsEmulator-Runtime", () => {

it("should handle a POST request and store rawBody", async () => {
const frb = FunctionRuntimeBundles.onRequest;
const worker = await startRuntimeWithFunctions(
const worker = await invokeFunction(
frb,
() => {
require("firebase-admin").initializeApp();
Expand Down Expand Up @@ -689,7 +689,7 @@ describe("FunctionsEmulator-Runtime", () => {

it("should forward request to Express app", async () => {
const frb = FunctionRuntimeBundles.onRequest;
const worker = await startRuntimeWithFunctions(
const worker = await invokeFunction(
frb,
() => {
require("firebase-admin").initializeApp();
Expand Down Expand Up @@ -717,7 +717,7 @@ describe("FunctionsEmulator-Runtime", () => {

it("should handle `x-forwarded-host`", async () => {
const frb = FunctionRuntimeBundles.onRequest;
const worker = await startRuntimeWithFunctions(
const worker = await invokeFunction(
frb,
() => {
require("firebase-admin").initializeApp();
Expand All @@ -741,7 +741,7 @@ describe("FunctionsEmulator-Runtime", () => {

it("should report GMT time zone", async () => {
const frb = FunctionRuntimeBundles.onRequest;
const worker = await startRuntimeWithFunctions(
const worker = await invokeFunction(
frb,
() => {
return {
Expand All @@ -761,7 +761,7 @@ describe("FunctionsEmulator-Runtime", () => {

describe("Cloud Firestore", () => {
it("should provide Change for firestore.onWrite()", async () => {
const worker = await startRuntimeWithFunctions(
const worker = await invokeFunction(
FunctionRuntimeBundles.onWrite,
() => {
require("firebase-admin").initializeApp();
Expand Down Expand Up @@ -795,7 +795,7 @@ describe("FunctionsEmulator-Runtime", () => {
}).timeout(TIMEOUT_MED);

it("should provide Change for firestore.onUpdate()", async () => {
const worker = await startRuntimeWithFunctions(
const worker = await invokeFunction(
FunctionRuntimeBundles.onUpdate,
() => {
require("firebase-admin").initializeApp();
Expand Down Expand Up @@ -828,7 +828,7 @@ describe("FunctionsEmulator-Runtime", () => {
}).timeout(TIMEOUT_MED);

it("should provide DocumentSnapshot for firestore.onDelete()", async () => {
const worker = await startRuntimeWithFunctions(
const worker = await invokeFunction(
FunctionRuntimeBundles.onDelete,
() => {
require("firebase-admin").initializeApp();
Expand Down Expand Up @@ -860,7 +860,7 @@ describe("FunctionsEmulator-Runtime", () => {
}).timeout(TIMEOUT_MED);

it("should provide DocumentSnapshot for firestore.onCreate()", async () => {
const worker = await startRuntimeWithFunctions(
const worker = await invokeFunction(
FunctionRuntimeBundles.onWrite,
() => {
require("firebase-admin").initializeApp();
Expand Down Expand Up @@ -895,7 +895,7 @@ describe("FunctionsEmulator-Runtime", () => {
describe("Error handling", () => {
it("Should handle regular functions for Express handlers", async () => {
const frb = FunctionRuntimeBundles.onRequest;
const worker = await startRuntimeWithFunctions(
const worker = await invokeFunction(
frb,
() => {
require("firebase-admin").initializeApp();
Expand All @@ -921,7 +921,7 @@ describe("FunctionsEmulator-Runtime", () => {

it("Should handle async functions for Express handlers", async () => {
const frb = FunctionRuntimeBundles.onRequest;
const worker = await startRuntimeWithFunctions(
const worker = await invokeFunction(
frb,
() => {
require("firebase-admin").initializeApp();
Expand Down Expand Up @@ -950,7 +950,7 @@ describe("FunctionsEmulator-Runtime", () => {

it("Should handle async/runWith functions for Express handlers", async () => {
const frb = FunctionRuntimeBundles.onRequest;
const worker = await startRuntimeWithFunctions(
const worker = await invokeFunction(
frb,
() => {
require("firebase-admin").initializeApp();
Expand Down

0 comments on commit b1099a2

Please sign in to comment.