functions_framework 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.yardopts +10 -0
- data/CHANGELOG.md +10 -0
- data/LICENSE +201 -0
- data/README.md +218 -0
- data/bin/functions-framework +19 -0
- data/lib/functions_framework.rb +237 -0
- data/lib/functions_framework/cli.rb +113 -0
- data/lib/functions_framework/cloud_events.rb +143 -0
- data/lib/functions_framework/cloud_events/binary_content.rb +59 -0
- data/lib/functions_framework/cloud_events/content_type.rb +139 -0
- data/lib/functions_framework/cloud_events/event.rb +277 -0
- data/lib/functions_framework/cloud_events/json_structure.rb +88 -0
- data/lib/functions_framework/function.rb +75 -0
- data/lib/functions_framework/registry.rb +137 -0
- data/lib/functions_framework/server.rb +436 -0
- data/lib/functions_framework/testing.rb +244 -0
- data/lib/functions_framework/version.rb +21 -0
- metadata +187 -0
@@ -0,0 +1,244 @@
|
|
1
|
+
# Copyright 2020 Google LLC
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require "json"
|
16
|
+
|
17
|
+
require "rack"
|
18
|
+
|
19
|
+
require "functions_framework"
|
20
|
+
|
21
|
+
module FunctionsFramework
|
22
|
+
##
|
23
|
+
# Helpers for writing unit tests.
|
24
|
+
#
|
25
|
+
# Methods on this module can be called as module methods, or this module can
|
26
|
+
# be included in a test class.
|
27
|
+
#
|
28
|
+
# ## Example
|
29
|
+
#
|
30
|
+
# Suppose we have the following app that uses the functions framework:
|
31
|
+
#
|
32
|
+
# # app.rb
|
33
|
+
#
|
34
|
+
# require "functions_framework"
|
35
|
+
#
|
36
|
+
# FunctionsFramework.http "my-function" do |request|
|
37
|
+
# "Hello, world!"
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# The following is a test that could be run against that app:
|
41
|
+
#
|
42
|
+
# # test_app.rb
|
43
|
+
#
|
44
|
+
# require "minitest/autorun"
|
45
|
+
# require "functions_framework/testing"
|
46
|
+
#
|
47
|
+
# class MyTest < Minitest::Test
|
48
|
+
# # Make the testing methods available.
|
49
|
+
# include FunctionsFramework::Testing
|
50
|
+
#
|
51
|
+
# def test_my_function
|
52
|
+
# # Load app.rb and apply its functions within this block
|
53
|
+
# load_temporary "app.rb" do
|
54
|
+
# # Create a mock http (rack) request
|
55
|
+
# request = make_get_request "http://example.com"
|
56
|
+
#
|
57
|
+
# # Call the function and get a rack response
|
58
|
+
# response = call_http "my-function", request
|
59
|
+
#
|
60
|
+
# # Assert against the response
|
61
|
+
# assert_equal "Hello, world!", response.body.join
|
62
|
+
# end
|
63
|
+
# end
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
module Testing
|
67
|
+
##
|
68
|
+
# Load the given functions source for the duration of the given block,
|
69
|
+
# and restore the previous status afterward.
|
70
|
+
#
|
71
|
+
# @param path [String] File path to load
|
72
|
+
#
|
73
|
+
def load_temporary path
|
74
|
+
registry = ::FunctionsFramework::Registry.new
|
75
|
+
old_registry = ::FunctionsFramework.global_registry
|
76
|
+
::FunctionsFramework.global_registry = registry
|
77
|
+
begin
|
78
|
+
::Kernel.load path
|
79
|
+
yield
|
80
|
+
ensure
|
81
|
+
::FunctionsFramework.global_registry = old_registry
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
##
|
86
|
+
# Call the given HTTP function for testing. The underlying function must
|
87
|
+
# be of type `:http`.
|
88
|
+
#
|
89
|
+
# @param name [String] The name of the function to call
|
90
|
+
# @param request [Rack::Request] The Rack request to send
|
91
|
+
# @return [Rack::Response]
|
92
|
+
#
|
93
|
+
def call_http name, request
|
94
|
+
function = ::FunctionsFramework.global_registry[name]
|
95
|
+
case function&.type
|
96
|
+
when :http
|
97
|
+
Testing.interpret_response { function.call request }
|
98
|
+
when nil
|
99
|
+
raise "Unknown function name #{name}"
|
100
|
+
else
|
101
|
+
raise "Function #{name} is not an HTTP function"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
##
|
106
|
+
# Call the given event function for testing. The underlying function must
|
107
|
+
# be of type `:event` or `:cloud_event`.
|
108
|
+
#
|
109
|
+
# @param name [String] The name of the function to call
|
110
|
+
# @param event [FunctionsFramework::CloudEvets::Event] The event to send
|
111
|
+
# @return [nil]
|
112
|
+
#
|
113
|
+
def call_event name, event
|
114
|
+
function = ::FunctionsFramework.global_registry[name]
|
115
|
+
case function&.type
|
116
|
+
when :event, :cloud_event
|
117
|
+
function.call event
|
118
|
+
nil
|
119
|
+
when nil
|
120
|
+
raise "Unknown function name #{name}"
|
121
|
+
else
|
122
|
+
raise "Function #{name} is not a CloudEvent function"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
##
|
127
|
+
# Make a simple GET request, for passing to a function test.
|
128
|
+
#
|
129
|
+
# @param url [URI,String] The URL to get.
|
130
|
+
# @return [Rack::Request]
|
131
|
+
#
|
132
|
+
def make_get_request url, headers = []
|
133
|
+
env = Testing.build_standard_env URI(url), headers
|
134
|
+
env[::Rack::REQUEST_METHOD] = ::Rack::GET
|
135
|
+
::Rack::Request.new env
|
136
|
+
end
|
137
|
+
|
138
|
+
##
|
139
|
+
# Make a simple POST request, for passing to a function test.
|
140
|
+
#
|
141
|
+
# @param url [URI,String] The URL to post to.
|
142
|
+
# @param data [String] The body to post.
|
143
|
+
# @return [Rack::Request]
|
144
|
+
#
|
145
|
+
def make_post_request url, data, headers = []
|
146
|
+
env = Testing.build_standard_env URI(url), headers
|
147
|
+
env[::Rack::REQUEST_METHOD] = ::Rack::POST
|
148
|
+
env[::Rack::RACK_INPUT] = ::StringIO.new data
|
149
|
+
::Rack::Request.new env
|
150
|
+
end
|
151
|
+
|
152
|
+
##
|
153
|
+
# Make a simple CloudEvent, for passing to a function test. The event data
|
154
|
+
# is required, but all other parameters are optional (i.e. a reasonable or
|
155
|
+
# random value will be generated if not provided).
|
156
|
+
#
|
157
|
+
# @param data [Object] The data
|
158
|
+
# @param id [String] Event ID (optional)
|
159
|
+
# @param source [String,URI] Event source (optional)
|
160
|
+
# @param type [String] Event type (optional)
|
161
|
+
# @param spec_version [String] Spec version (optional)
|
162
|
+
# @param data_content_type [String,FunctionsFramework::CloudEvents::ContentType]
|
163
|
+
# Content type for the data (optional)
|
164
|
+
# @param data_schema [String,URI] Data schema (optional)
|
165
|
+
# @param subject [String] Subject (optional)
|
166
|
+
# @param time [String,DateTime] Event timestamp (optional)
|
167
|
+
# @return [FunctionsFramework::CloudEvents::Event]
|
168
|
+
#
|
169
|
+
def make_cloud_event data,
|
170
|
+
id: nil, source: nil, type: nil, spec_version: nil,
|
171
|
+
data_content_type: nil, data_schema: nil, subject: nil, time: nil
|
172
|
+
id ||= "random-id-#{rand 100_000_000}"
|
173
|
+
source ||= "functions-framework-testing"
|
174
|
+
type ||= "com.example.test"
|
175
|
+
spec_version ||= "1.0"
|
176
|
+
CloudEvents::Event.new id: id, source: source, type: type, spec_version: spec_version,
|
177
|
+
data_content_type: data_content_type, data_schema: data_schema,
|
178
|
+
subject: subject, time: time, data: data
|
179
|
+
end
|
180
|
+
|
181
|
+
extend self
|
182
|
+
|
183
|
+
class << self
|
184
|
+
## @private
|
185
|
+
def interpret_response
|
186
|
+
response =
|
187
|
+
begin
|
188
|
+
yield
|
189
|
+
rescue ::StandardError => e
|
190
|
+
e
|
191
|
+
end
|
192
|
+
case response
|
193
|
+
when ::Rack::Response
|
194
|
+
response
|
195
|
+
when ::Array
|
196
|
+
::Rack::Response.new response[2], response[0], response[1]
|
197
|
+
when ::String
|
198
|
+
string_response response, "text/plain", 200
|
199
|
+
when ::Hash
|
200
|
+
json = ::JSON.dump response
|
201
|
+
string_response json, "application/json", 200
|
202
|
+
when ::StandardError
|
203
|
+
message = "#{response.class}: #{response.message}\n#{response.backtrace}\n"
|
204
|
+
string_response message, "text/plain", 500
|
205
|
+
else
|
206
|
+
raise "Unexpected response type: #{response.inspect}"
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
## @private
|
211
|
+
def string_response string, content_type, status
|
212
|
+
headers = {
|
213
|
+
"Content-Type" => content_type,
|
214
|
+
"Content-Length" => string.bytesize
|
215
|
+
}
|
216
|
+
::Rack::Response.new string, status, headers
|
217
|
+
end
|
218
|
+
|
219
|
+
## @private
|
220
|
+
def build_standard_env url, headers
|
221
|
+
env = {
|
222
|
+
::Rack::SCRIPT_NAME => "",
|
223
|
+
::Rack::PATH_INFO => url.path,
|
224
|
+
::Rack::QUERY_STRING => url.query,
|
225
|
+
::Rack::SERVER_NAME => url.host,
|
226
|
+
::Rack::SERVER_PORT => url.port,
|
227
|
+
::Rack::RACK_URL_SCHEME => url.scheme,
|
228
|
+
::Rack::RACK_VERSION => ::Rack::VERSION,
|
229
|
+
::Rack::RACK_LOGGER => ::FunctionsFramework.logger,
|
230
|
+
::Rack::RACK_INPUT => ::StringIO.new,
|
231
|
+
::Rack::RACK_ERRORS => ::StringIO.new
|
232
|
+
}
|
233
|
+
headers.each do |header|
|
234
|
+
name, value = header.split ":"
|
235
|
+
next unless name && value
|
236
|
+
name = name.strip.upcase.tr "-", "_"
|
237
|
+
name = "HTTP_#{name}" unless ["CONTENT_TYPE", "CONTENT_LENGTH"].include? name
|
238
|
+
env[name] = value.strip
|
239
|
+
end
|
240
|
+
env
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# Copyright 2020 Google LLC
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module FunctionsFramework
|
16
|
+
##
|
17
|
+
# Version of the Ruby Functions Framework
|
18
|
+
# @return [String]
|
19
|
+
#
|
20
|
+
VERSION = "0.1.1".freeze
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,187 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: functions_framework
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Daniel Azuma
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-02-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: puma
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.3'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rack
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.1'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.1'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: google-style
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.24.0
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.24.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: minitest
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '5.13'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '5.13'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: minitest-focus
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.1'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.1'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: minitest-rg
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '5.2'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '5.2'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: redcarpet
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '3.5'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '3.5'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: toys
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 0.10.0
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 0.10.0
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: yard
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 0.9.24
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 0.9.24
|
139
|
+
description: The Functions Framework implementation for Ruby.
|
140
|
+
email:
|
141
|
+
- dazuma@google.com
|
142
|
+
executables:
|
143
|
+
- functions-framework
|
144
|
+
extensions: []
|
145
|
+
extra_rdoc_files: []
|
146
|
+
files:
|
147
|
+
- ".yardopts"
|
148
|
+
- CHANGELOG.md
|
149
|
+
- LICENSE
|
150
|
+
- README.md
|
151
|
+
- bin/functions-framework
|
152
|
+
- lib/functions_framework.rb
|
153
|
+
- lib/functions_framework/cli.rb
|
154
|
+
- lib/functions_framework/cloud_events.rb
|
155
|
+
- lib/functions_framework/cloud_events/binary_content.rb
|
156
|
+
- lib/functions_framework/cloud_events/content_type.rb
|
157
|
+
- lib/functions_framework/cloud_events/event.rb
|
158
|
+
- lib/functions_framework/cloud_events/json_structure.rb
|
159
|
+
- lib/functions_framework/function.rb
|
160
|
+
- lib/functions_framework/registry.rb
|
161
|
+
- lib/functions_framework/server.rb
|
162
|
+
- lib/functions_framework/testing.rb
|
163
|
+
- lib/functions_framework/version.rb
|
164
|
+
homepage: https://github.com/GoogleCloudPlatform/functions-framework-ruby
|
165
|
+
licenses:
|
166
|
+
- Apache-2.0
|
167
|
+
metadata: {}
|
168
|
+
post_install_message:
|
169
|
+
rdoc_options: []
|
170
|
+
require_paths:
|
171
|
+
- lib
|
172
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
173
|
+
requirements:
|
174
|
+
- - ">="
|
175
|
+
- !ruby/object:Gem::Version
|
176
|
+
version: 2.4.0
|
177
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
178
|
+
requirements:
|
179
|
+
- - ">="
|
180
|
+
- !ruby/object:Gem::Version
|
181
|
+
version: '0'
|
182
|
+
requirements: []
|
183
|
+
rubygems_version: 3.1.2
|
184
|
+
signing_key:
|
185
|
+
specification_version: 4
|
186
|
+
summary: Functions Framework for Ruby
|
187
|
+
test_files: []
|