Module: FunctionsFramework::Testing

Extended by:
Testing
Included in:
Testing
Defined in:
lib/functions_framework/testing.rb

Overview

Helpers for writing unit tests.

Methods on this module can be called as module methods, or this module can be included in a test class.

Example

Suppose we have the following app that uses the functions framework:

# app.rb

require "functions_framework"

FunctionsFramework.http "my-function" do |request|
  "Hello, world!"
end

The following is a test that could be run against that app:

# test_app.rb

require "minitest/autorun"
require "functions_framework/testing"

class MyTest < Minitest::Test
  # Make the testing methods available.
  include FunctionsFramework::Testing

  def test_my_function
    # Load app.rb and apply its functions within this block
    load_temporary "app.rb" do
      # Create a mock http (rack) request
      request = make_get_request "http://example.com"

      # Call the function and get a rack response
      response = call_http "my-function", request

      # Assert against the response
      assert_equal "Hello, world!", response.body.join
    end
  end
end

Instance Method Summary collapse

Instance Method Details

#call_event(name, event, globals: nil, logger: nil) ⇒ nil

Call the given event function for testing. The underlying function must be of type :cloud_event`.

By default, the startup tasks will be run for the given function if they have not already been run. You can, however, disable running startup tasks by providing an explicit globals hash.

By default, the FunctionsFramework.logger will be used, but you can override that by providing your own logger. In particular, to disable logging, you can pass Logger.new(nil).

Parameters:

  • name (String)

    The name of the function to call

  • event (::CloudEvents::Event)

    The event to send

  • globals (Hash) (defaults to: nil)

    Do not run startup tasks, and instead provide the globals directly. Optional.

  • logger (Logger) (defaults to: nil)

    Use the given logger instead of the Functions Framework's global logger. Optional.

Returns:

  • (nil)


196
197
198
199
200
201
202
# File 'lib/functions_framework/testing.rb', line 196

def call_event name, event, globals: nil, logger: nil
  globals ||= run_startup_tasks name, logger: logger, lenient: true
  Testing.call :cloud_event, name, readable_name: "CloudEvent" do |function|
    function.call event, globals: globals, logger: logger
    nil
  end
end

#call_http(name, request, globals: nil, logger: nil) ⇒ Rack::Response

Call the given HTTP function for testing. The underlying function must be of type :http. Returns the Rack response.

By default, the startup tasks will be run for the given function if they have not already been run. You can, however, disable running startup tasks by providing an explicit globals hash.

By default, the FunctionsFramework.logger will be used, but you can override that by providing your own logger. In particular, to disable logging, you can pass Logger.new(nil).

Parameters:

  • name (String)

    The name of the function to call

  • request (Rack::Request)

    The Rack request to send

  • globals (Hash) (defaults to: nil)

    Do not run startup tasks, and instead provide the globals directly. Optional.

  • logger (Logger) (defaults to: nil)

    Use the given logger instead of the Functions Framework's global logger. Optional.

Returns:

  • (Rack::Response)


135
136
137
138
139
140
141
142
# File 'lib/functions_framework/testing.rb', line 135

def call_http name, request, globals: nil, logger: nil
  globals ||= run_startup_tasks name, logger: logger, lenient: true
  Testing.call :http, name, readable_name: "HTTP" do |function|
    Testing.interpret_response do
      function.call request, globals: globals, logger: logger
    end
  end
end

#call_typed(name, request, globals: nil, logger: nil) ⇒ Rack::Response

Call the given Typed function for testing. The underlying function must be of type :typed. Returns the Rack response.

By default, the startup tasks will be run for the given function if they have not already been run. You can, however, disable running startup tasks by providing an explicit globals hash.

By default, the FunctionsFramework.logger will be used, but you can override that by providing your own logger. In particular, to disable logging, you can pass Logger.new(nil).

Parameters:

  • name (String)

    The name of the function to call

  • request (Rack::Request)

    The Rack request to send

  • globals (Hash) (defaults to: nil)

    Do not run startup tasks, and instead provide the globals directly. Optional.

  • logger (Logger) (defaults to: nil)

    Use the given logger instead of the Functions Framework's global logger. Optional.

Returns:

  • (Rack::Response)


164
165
166
167
168
169
170
171
172
173
174
# File 'lib/functions_framework/testing.rb', line 164

def call_typed name, request, globals: nil, logger: nil
  globals ||= run_startup_tasks name, logger: logger, lenient: true
  Testing.call :typed, name, readable_name: "Typed" do |function|
    Testing.interpret_response do
      config = FunctionsFramework::Server::Config.new
      config.logger = logger
      app = FunctionsFramework::Server::TypedApp.new function, globals, config
      app.call request.env
    end
  end
end

#load_temporary(path, &block) ⇒ Object

Load the given functions source for the duration of the given block, and restore the previous status afterward.

Parameters:

  • path (String)

    File path to load



73
74
75
76
# File 'lib/functions_framework/testing.rb', line 73

def load_temporary path, &block
  path = ::File.expand_path path
  Testing.load_for_testing path, &block
end

#make_cloud_event(data, id: nil, source: nil, type: nil, spec_version: nil, data_content_type: nil, data_schema: nil, subject: nil, time: nil) ⇒ ::CloudEvents::Event

Make a simple CloudEvent, for passing to a function test. The event data is required, but all other parameters are optional (i.e. a reasonable or random value will be generated if not provided).

Parameters:

  • data (Object)

    The data

  • id (String) (defaults to: nil)

    Event ID (optional)

  • source (String, URI) (defaults to: nil)

    Event source (optional)

  • type (String) (defaults to: nil)

    Event type (optional)

  • spec_version (String) (defaults to: nil)

    Spec version (optional)

  • data_content_type (String, ::CloudEvents::ContentType) (defaults to: nil)

    Content type for the data (optional)

  • data_schema (String, URI) (defaults to: nil)

    Data schema (optional)

  • subject (String) (defaults to: nil)

    Subject (optional)

  • time (String, DateTime) (defaults to: nil)

    Event timestamp (optional)

Returns:

  • (::CloudEvents::Event)


269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
# File 'lib/functions_framework/testing.rb', line 269

def make_cloud_event data,
                     id: nil,
                     source: nil,
                     type: nil,
                     spec_version: nil,
                     data_content_type: nil,
                     data_schema: nil,
                     subject: nil,
                     time: nil
  id ||= "random-id-#{rand 100_000_000}"
  source ||= "functions-framework-testing"
  type ||= "com.example.test"
  spec_version ||= "1.0"
  ::CloudEvents::Event.new id:                id,
                           source:            source,
                           type:              type,
                           spec_version:      spec_version,
                           data_content_type: data_content_type,
                           data_schema:       data_schema,
                           subject:           subject,
                           time:              time,
                           data:              data
end

#make_get_request(url, headers = []) ⇒ Rack::Request

Make a simple GET request, for passing to a function test.

Parameters:

  • url (URI, String)

    The URL to get.

  • headers (Array, Hash) (defaults to: [])

    HTTP headers. May be given as a hash (of header names mapped to values), an array of strings (where each string is of the form Header-Name: Header value), or an array of two-element string arrays.

Returns:

  • (Rack::Request)


233
234
235
# File 'lib/functions_framework/testing.rb', line 233

def make_get_request url, headers = []
  make_request url, headers: headers
end

#make_post_request(url, body, headers = []) ⇒ Rack::Request

Make a simple POST request, for passing to a function test.

Parameters:

  • url (URI, String)

    The URL to post to.

  • body (String)

    The body to post.

  • headers (Array, Hash) (defaults to: [])

    HTTP headers. May be given as a hash (of header names mapped to values), an array of strings (where each string is of the form Header-Name: Header value), or an array of two-element string arrays.

Returns:

  • (Rack::Request)


248
249
250
# File 'lib/functions_framework/testing.rb', line 248

def make_post_request url, body, headers = []
  make_request url, method: ::Rack::POST, body: body, headers: headers
end

#make_request(url, method: ::Rack::GET, body: nil, headers: []) ⇒ Rack::Request

Make a Rack request, for passing to a function test.

Parameters:

  • url (URI, String)

    The URL to get, including query params.

  • method (String) (defaults to: ::Rack::GET)

    The HTTP method (defaults to "GET").

  • body (String) (defaults to: nil)

    The HTTP body, if any.

  • headers (Array, Hash) (defaults to: [])

    HTTP headers. May be given as a hash (of header names mapped to values), an array of strings (where each string is of the form Header-Name: Header value), or an array of two-element string arrays.

Returns:

  • (Rack::Request)


216
217
218
219
220
221
# File 'lib/functions_framework/testing.rb', line 216

def make_request url, method: ::Rack::GET, body: nil, headers: []
  env = Testing.build_standard_env URI(url), headers
  env[::Rack::REQUEST_METHOD] = method
  env[::Rack::RACK_INPUT] = ::StringIO.new body if body
  ::Rack::Request.new env
end

#run_startup_tasks(name, logger: nil, lenient: false) ⇒ Hash

Run startup tasks for the given function name and return the initialized globals hash.

Normally, this will be run automatically prior to the first call to the function using #call_http or #call_event, if it has not already been run. However, you can call it explicitly to test its behavior. It cannot be called more than once for any given function.

By default, the FunctionsFramework.logger will be used, but you can override that by providing your own logger. In particular, to disable logging, you can pass Logger.new(nil).

Parameters:

  • name (String)

    The name of the function to start up.

  • logger (Logger) (defaults to: nil)

    Use the given logger instead of the Functions Framework's global logger. Optional.

  • lenient (Boolean) (defaults to: false)

    If false (the default), raise an error if the given function has already had its startup tasks run. If true, duplicate requests to run startup tasks are ignored.

Returns:

  • (Hash)

    The initialized globals.



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/functions_framework/testing.rb', line 99

def run_startup_tasks name, logger: nil, lenient: false
  function = Testing.current_registry[name]
  raise "Unknown function name #{name}" unless function
  globals = Testing.current_globals name
  if globals
    raise "Function #{name} has already been started up" unless lenient
  else
    globals = function.populate_globals
    Testing.current_registry.startup_tasks.each do |task|
      task.call function, globals: globals, logger: logger
    end
    Testing.current_globals name, globals
  end
  globals.freeze
end