Skip to content

AdminDevelopment/cloud-functions-emulator

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

19 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Google Cloud Functions Emulator NPM Tests Coverage

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.

Table of Contents

Installation

npm install -g @google-cloud/functions-emulator

Authentication

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.

Using the CLI

Print the available commands:

functions --help

Usage

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]

Deployment

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.

Invoking a Function

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

Invoking Functions with arguments

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.

Config

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

Logs

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.)

Debugging

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.

Debugging with Visual Studio Code

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.

Debugging with Chrome Developer Tools

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.

Debugging with Chrome Developer Tools

Using the old debugger

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

Using Mocks

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.

  1. Enable the use of mocks:

     functions start --useMocks
    

    or

     functions config set useMocks true
     functions start
    
  2. 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;
     };
    
  3. 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();
    
       // ...
     };
    

Known Issues and FAQ

  • 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-running npm 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.

License

Copyright 2016, Google, Inc.

Licensed under the Apache License, Version 2.0

See the full license.

About

A local emulator for Google Cloud Functions.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • JavaScript 100.0%