Disclaimer: This is not an official Google product.
This is a simple emulator that allows you to test your Cloud Functions on your local machine.
@google-cloud/functions-emulator is currently in pre-1.0.0 development. Before the 1.0.0 release backwards compatible changes and bug fixes will bump the patch version number and breaking changes will bump the minor version number.
- Installation
- [Authentication] (#authentication)
- Using the CLI
npm install -g @google-cloud/functions-emulator
If you're using Cloud Functions to access other Google Cloud Platform APIs (e.g. Google Cloud Storage or the Google Cloud Vision API), you can use the same Application Default Credential as you would when running your function in the cloud.
For example, when using the google-cloud Node.js module for Cloud Storage, the following:
const Storage = require('@google-cloud/storage');
const storage = Storage({
projectId: 'grape-spaceship-123',
keyFilename: '/path/to/keyfile.json'
});
can be abbreviated to:
const Storage = require('@google-cloud/storage');
const storage = Storage();
This abbreviated version will use the Application Default Credential as the
authentication principal, and in the emulator will use the GCLOUD_PROJECT
environment variable or the projectId
property of your config.json
file as
the projectId.
In order for this credential to be correctly injected into the emulator, you
need to have already authenticated the
Cloud SDK, via either init
:
gcloud init
or by manually invoking auth
:
gcloud auth login
To activate the Application Default Credentials run:
gcloud beta auth application-default login
To verify that the Application Default Credential is present, you can request the current access token using:
gcloud beta auth application-default print-access-token
Note: The current project defined in gcloud config
must match the projectId
set in config.json
for the Application Default Credential to work. If you want
to authenticate your Cloud Function against a different project you will need to
also include a keyfile as described in the google-cloud-node
authentication guide.
Print the available commands:
functions --help
Commands:
call <functionName> Invokes a function. You must specify either the "data" or the "file" option.
clear Resets the emulator to its default state and clears and deployed functions.
config <command> Manages emulator configuration.
delete <functionName> Undeploys a previously deployed function (does NOT delete the function source
code).
deploy <functionName> <modulePath> Deploys a function with the given module path and function name (entry point).
describe <functionName> Describes the details of a single deployed function.
kill Force kills the emulator process if it stops responding.
list Lists deployed functions.
logs <command> Manages emulator logs access.
prune Removes any functions known to the emulator but which no longer exist in their
corresponding module.
restart Restarts the emulator.
start Starts the emulator.
status Reports the current status of the emulator.
stop Stops the emulator gracefully.
Options:
--host, -h The emulator's host. [string]
--port, -p The emulator's port. [number]
--help Show help [boolean]
--version Show version number [boolean]
Examples:
functions deploy ~/myModule helloWorld --trigger-http Deploy helloWorld as an HTTP function from the module
located in ~/myModule
functions call helloWorld Invoke the helloWorld function with no data argument
functions call helloWorld --data '{"foo": "bar"}' Invoke the helloWorld function with a JSON document
argument
functions call helloWorld --file ~/myData/datafile.json Invoke the helloWorld function with a file argument
functions logs read --limit 10 Display the most recent 10 lines from the logs
Get help on a specific command passing --help
to the command, for example:
functions call --help
which would print:
functions call <functionName>
Options:
--host, -h The emulator's host. [string]
--port, -p The emulator's port. [number]
--help Show help [boolean]
--version Show version number [boolean]
--data, -d Specify inline the JSON data to send to the function. [string]
--file, -f A path to a JSON file to send to the function. [string]
The emulator can host both BACKGROUND and HTTP (foreground) Cloud Functions. By
default the emulator will consider functions deployed to be BACKGROUND
functions. To deploy an HTTP function, use the --trigger-http
argument:
functions deploy <functionName> <modulePath> --trigger-http
For example:
functions deploy helloWorld ~/myModule --trigger-http
This would deploy the helloWorld
function in the Node.js module contained in
the ~/myModule
path.
Note: The module path should be a directory containing the Node.js module you want to deploy.
Start the Emulator:
functions start
Deploy a BACKGROUND function (the first argument is the path to your module, the second argument is the name of the function):
functions deploy helloWorld ../myModule
Invoke the function:
functions call helloWorld
Stop the Emulator:
functions stop
For HTTP functions, just use the --trigger-http
argument.
Deploy an HTTP function:
functions deploy helloHttp ../myModule --trigger-http
Invoke the function (default port is 8008):
curl http://localhost:8008/helloHttp
When using the call
command, you can optionally provide a --data
argument to
send data to your function. This should be expressed as a JSON document, for
example:
functions call helloWorld --data '{"foo":"bar"}'
When calling HTTP functions in this way, your function will receive an HTTP POST with the JSON document as the request body.
Crafting lengthy JSON documents at the command line can be cumbersome, so you
can specify a path to a JSON file with the --file
option:
functions call helloWorld --file /usr/local/somedata.json
This example will load /usr/local/somedata.json
and pass its contents as the
argument to the function.
Note: file arguments are assumed to be utf-8
encoded text files.
A config.json
file in your home directory allows you to customize default
settings for the emulator:
Property | Type | Description |
---|---|---|
host | string | Host the emulator should listen on. Default: localhost . |
logFile | string | Path to the logs file. Default: logs/cloud-functions-emulator.log . |
port | integer | The TCP port on which the emulator will listen. Default: 8008 . |
projectId | string | Your Cloud Platform project ID. Default: process.env.GCLOUD_PROJECT . |
timeout | integer | Timeout (ms) to wait for the emulator to start. Default: 3000 . |
useMocks | boolean | Whether mocks.js should be loaded when the emulator starts. Default: false . |
verbose | boolean | Whether the emulator should write additional logs during operation. Default: false . |
View table of current configuration:
functions config list
or as JSON:
functions config list --json
Update a particular setting:
functions config set verbose true
Functions running in the emulator run in their own (detached) process, so
console logs from your function (e.g. console.log()
calls) will not be piped to
the stdout stream of the emulator. Instead a log file can be found in logs/cloud-functions-emulator.log
You can view the logs from your functions using the logs read
command:
functions logs read
By default this will return the most recent 20 log lines. You can alter this
with the --limit
flag.
functions logs read --limit 100
Alternatively, you can simply tail the log file itself.
Mac/Linux:
tail -f logs/cloud-functions-emulator.log
(Note this log will automatically roll when it reaches 1MB.)
To start the emulator in debug mode, use the --inspect
flag:
functions start --inspect
While running in debug mode a separate debug server will be started on port 9229
(the default --inspect
debugger port for Node.js v6.9.1). You can then attach
to the debugger process with your favorite IDE.
If you started the emulator with the --inspect
flag, you can simply "Attach"
to the emulator from withing Visual Studio Code.
Refer to the documentation for debugging in Visual Studio Code for more information. Basically, you just need a launch.json
file that looks
like this:
{
"version": "0.2.0",
"configurations": [
{
"name": "Attach to Process",
"type": "node2",
"request": "attach",
"port": 9229
}
]
}
In Visual Studio Code, navigate to the source code for your locally deployed function and set a breakpoint inside your function. Then when the function is invoked, execution should pause on your breakpoint inside the Debug View of Visual Studio Code.
To access the debugger in Chrome, you'll need to inspect the log file written by
the emulator, which by default is located in logs\cloud-functions-emulator.log
.
You can quickly view the logs with functions logs read
.
Look for a log entry that appears like this:
Debugger listening on port 9229.
Warning: This is an experimental feature and could change at any time.
To start debugging, open the following URL in Chrome:
chrome-devtools://devtools/remote/serve_file/@60cd6e839b9f557d231sf5bf532f6aec5f284980/inspector.html?experiments=true&v8only=true&ws=localhost:9229/165s71ce-1e76-421f-b52d-e3b8a14bcb0c
When you open the chrome devtools debugger you may not see your function source file. Just invoke your function once to have its source file appear in the debugger window. You can then set breakpoints and debug like normal.
If you can't or won't use the --inspect
flag, you can use the older
--debug
flag and debug your Cloud Functions in the emulator using
node-inspector.
First, install node-inspector:
npm install -g node-inspector
Start the emulator with the --debug
flag:
functions start --debug
Now start the node inspector process in a separate console window:
node-inspector
This will start an HTTP server on port 8080, you can then browse to this URL in Chrome:
open http://127.0.0.1:8080/?port=5858
Now when you invoke your function, you can debug:
functions call helloWorld
When running functions locally you sometimes want to change the behavior of modules which connect to external services. For example you might be accessing a database, API or external system that you don't want to, or can't access from your local environment.
The Cloud Functions Emulator provides a way to inject mock versions of Node.js modules imported into your function.
-
Enable the use of mocks:
functions start --useMocks
or
functions config set useMocks true functions start
-
Edit
mocks.js
and mock the dependencies you want// You can create handcrafted mocks, or use a mocking library var sinon = require('sinon'); /** * Called when the require() method is called * @param {String} func The name of the current function being invoked * @param {String} module The name of the module being required */ exports.onRequire = function (func, module) { // Return an object or module to override the named module argument if (module === 'redis') { // Create a mock of redis var mockRedis = sinon.mock(require('redis')); mockRedis.expects('createClient').returns({}); // Mock more methods as needed... return mockRedis; } return undefined; };
-
You don't need to change your function code at all!
exports.helloRedis = function (event, callback) { var redis = require('redis'); // this will be a mock cvar lient = redis.createClient(); // ... };
-
If you see the following error in the console when you stop the debugger:
Assertion failed: ((err) == (0)), function Stop, file ../src/debug-agent.cc, line 155.
You can safely ignore it. It's an open issue in Node.js
-
If you restart the emulator while the debug server is running you may need to refresh the browser for the default debug breakpoint to fire.
-
Disconnecting the debugger can sometimes leave the emulator in a weird state. If you want to kill the emulator process (because it's stuck), then you'll have to kill the underlying
node
process:functions kill
If that doesn't work, then you may need to go medieval
Mac/Linux: pgrep -f emulator.js | xargs kill
-
If you see the following error when deploying:
Error: Module version mismatch
This usually means that the module you are trying to deploy has a dependency that either conflicts with the same dependency in the emulator, but has a different version, or it indicates that the dependencies in the module being deployed was built with a different version of npm. In most cases, deleting
node_modules
from the module being deployed and re-runningnpm install
will resolve this. -
If you see the following error when trying to invoke a function:
TypeError: res.send is not a function
It means you deployed an HTTP function as a BACKGROUND function (so it's expecting an HTTP request but the emulator didn't give it one). Make sure to deploy HTTP functions with the
--trigger-http
flag. -
If the emulator times out when starting, check the logs (
logs\cloud-functions-emulator.log
). If you see the following error:Unable to open devtools socket: address already in use
It means the chrome devtools debugger is running and using the default debug port. Close the Chrome tab with the debugger and try again.
Copyright 2016, Google, Inc.
Licensed under the Apache License, Version 2.0
See the full license.