functions_framework 0.1.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +6 -2
- data/CHANGELOG.md +44 -0
- data/README.md +56 -136
- data/bin/functions-framework-ruby +19 -0
- data/docs/deploying-functions.md +182 -0
- data/docs/overview.md +142 -0
- data/docs/running-a-functions-server.md +122 -0
- data/docs/testing-functions.md +169 -0
- data/docs/writing-functions.md +275 -0
- data/lib/functions_framework.rb +16 -50
- data/lib/functions_framework/cli.rb +71 -13
- data/lib/functions_framework/cloud_events.rb +12 -110
- data/lib/functions_framework/cloud_events/content_type.rb +107 -30
- data/lib/functions_framework/cloud_events/errors.rb +42 -0
- data/lib/functions_framework/cloud_events/event.rb +56 -249
- data/lib/functions_framework/cloud_events/event/field_interpreter.rb +150 -0
- data/lib/functions_framework/cloud_events/event/v0.rb +236 -0
- data/lib/functions_framework/cloud_events/event/v1.rb +223 -0
- data/lib/functions_framework/cloud_events/http_binding.rb +310 -0
- data/lib/functions_framework/cloud_events/json_format.rb +173 -0
- data/lib/functions_framework/function.rb +80 -26
- data/lib/functions_framework/legacy_event_converter.rb +145 -0
- data/lib/functions_framework/registry.rb +0 -39
- data/lib/functions_framework/server.rb +61 -51
- data/lib/functions_framework/testing.rb +64 -24
- data/lib/functions_framework/version.rb +1 -1
- metadata +16 -4
- data/lib/functions_framework/cloud_events/binary_content.rb +0 -59
- data/lib/functions_framework/cloud_events/json_structure.rb +0 -88
@@ -70,16 +70,9 @@ module FunctionsFramework
|
|
70
70
|
#
|
71
71
|
# @param path [String] File path to load
|
72
72
|
#
|
73
|
-
def load_temporary path
|
74
|
-
|
75
|
-
|
76
|
-
::FunctionsFramework.global_registry = registry
|
77
|
-
begin
|
78
|
-
::Kernel.load path
|
79
|
-
yield
|
80
|
-
ensure
|
81
|
-
::FunctionsFramework.global_registry = old_registry
|
82
|
-
end
|
73
|
+
def load_temporary path, &block
|
74
|
+
path = ::File.expand_path path
|
75
|
+
Testing.load_for_testing path, &block
|
83
76
|
end
|
84
77
|
|
85
78
|
##
|
@@ -94,7 +87,7 @@ module FunctionsFramework
|
|
94
87
|
function = ::FunctionsFramework.global_registry[name]
|
95
88
|
case function&.type
|
96
89
|
when :http
|
97
|
-
Testing.interpret_response { function.call request }
|
90
|
+
Testing.interpret_response { function.new_call.call request }
|
98
91
|
when nil
|
99
92
|
raise "Unknown function name #{name}"
|
100
93
|
else
|
@@ -104,7 +97,7 @@ module FunctionsFramework
|
|
104
97
|
|
105
98
|
##
|
106
99
|
# Call the given event function for testing. The underlying function must
|
107
|
-
# be of type
|
100
|
+
# be of type :cloud_event`.
|
108
101
|
#
|
109
102
|
# @param name [String] The name of the function to call
|
110
103
|
# @param event [FunctionsFramework::CloudEvets::Event] The event to send
|
@@ -113,8 +106,8 @@ module FunctionsFramework
|
|
113
106
|
def call_event name, event
|
114
107
|
function = ::FunctionsFramework.global_registry[name]
|
115
108
|
case function&.type
|
116
|
-
when :
|
117
|
-
function.call event
|
109
|
+
when :cloud_event
|
110
|
+
function.new_call.call event
|
118
111
|
nil
|
119
112
|
when nil
|
120
113
|
raise "Unknown function name #{name}"
|
@@ -123,30 +116,52 @@ module FunctionsFramework
|
|
123
116
|
end
|
124
117
|
end
|
125
118
|
|
119
|
+
##
|
120
|
+
# Make a Rack request, for passing to a function test.
|
121
|
+
#
|
122
|
+
# @param url [URI,String] The URL to get, including query params.
|
123
|
+
# @param method [String] The HTTP method (defaults to "GET").
|
124
|
+
# @param body [String] The HTTP body, if any.
|
125
|
+
# @param headers [Array,Hash] HTTP headers. May be given as a hash (of
|
126
|
+
# header names mapped to values), an array of strings (where each
|
127
|
+
# string is of the form `Header-Name: Header value`), or an array of
|
128
|
+
# two-element string arrays.
|
129
|
+
# @return [Rack::Request]
|
130
|
+
#
|
131
|
+
def make_request url, method: ::Rack::GET, body: nil, headers: []
|
132
|
+
env = Testing.build_standard_env URI(url), headers
|
133
|
+
env[::Rack::REQUEST_METHOD] = method
|
134
|
+
env[::Rack::RACK_INPUT] = ::StringIO.new body if body
|
135
|
+
::Rack::Request.new env
|
136
|
+
end
|
137
|
+
|
126
138
|
##
|
127
139
|
# Make a simple GET request, for passing to a function test.
|
128
140
|
#
|
129
141
|
# @param url [URI,String] The URL to get.
|
142
|
+
# @param headers [Array,Hash] HTTP headers. May be given as a hash (of
|
143
|
+
# header names mapped to values), an array of strings (where each
|
144
|
+
# string is of the form `Header-Name: Header value`), or an array of
|
145
|
+
# two-element string arrays.
|
130
146
|
# @return [Rack::Request]
|
131
147
|
#
|
132
148
|
def make_get_request url, headers = []
|
133
|
-
|
134
|
-
env[::Rack::REQUEST_METHOD] = ::Rack::GET
|
135
|
-
::Rack::Request.new env
|
149
|
+
make_request url, headers: headers
|
136
150
|
end
|
137
151
|
|
138
152
|
##
|
139
153
|
# Make a simple POST request, for passing to a function test.
|
140
154
|
#
|
141
155
|
# @param url [URI,String] The URL to post to.
|
142
|
-
# @param
|
156
|
+
# @param body [String] The body to post.
|
157
|
+
# @param headers [Array,Hash] HTTP headers. May be given as a hash (of
|
158
|
+
# header names mapped to values), an array of strings (where each
|
159
|
+
# string is of the form `Header-Name: Header value`), or an array of
|
160
|
+
# two-element string arrays.
|
143
161
|
# @return [Rack::Request]
|
144
162
|
#
|
145
|
-
def make_post_request url,
|
146
|
-
|
147
|
-
env[::Rack::REQUEST_METHOD] = ::Rack::POST
|
148
|
-
env[::Rack::RACK_INPUT] = ::StringIO.new data
|
149
|
-
::Rack::Request.new env
|
163
|
+
def make_post_request url, body, headers = []
|
164
|
+
make_request url, method: ::Rack::POST, body: body, headers: headers
|
150
165
|
end
|
151
166
|
|
152
167
|
##
|
@@ -180,7 +195,28 @@ module FunctionsFramework
|
|
180
195
|
|
181
196
|
extend self
|
182
197
|
|
198
|
+
@testing_registries = {}
|
199
|
+
@mutex = ::Mutex.new
|
200
|
+
|
183
201
|
class << self
|
202
|
+
## @private
|
203
|
+
def load_for_testing path
|
204
|
+
old_registry = ::FunctionsFramework.global_registry
|
205
|
+
@mutex.synchronize do
|
206
|
+
if @testing_registries.key? path
|
207
|
+
::FunctionsFramework.global_registry = @testing_registries[path]
|
208
|
+
else
|
209
|
+
new_registry = ::FunctionsFramework::Registry.new
|
210
|
+
::FunctionsFramework.global_registry = new_registry
|
211
|
+
::Kernel.load path
|
212
|
+
@testing_registries[path] = new_registry
|
213
|
+
end
|
214
|
+
end
|
215
|
+
yield
|
216
|
+
ensure
|
217
|
+
::FunctionsFramework.global_registry = old_registry
|
218
|
+
end
|
219
|
+
|
184
220
|
## @private
|
185
221
|
def interpret_response
|
186
222
|
response =
|
@@ -231,7 +267,11 @@ module FunctionsFramework
|
|
231
267
|
::Rack::RACK_ERRORS => ::StringIO.new
|
232
268
|
}
|
233
269
|
headers.each do |header|
|
234
|
-
|
270
|
+
if header.is_a? String
|
271
|
+
name, value = header.split ":"
|
272
|
+
elsif header.is_a? Array
|
273
|
+
name, value = header
|
274
|
+
end
|
235
275
|
next unless name && value
|
236
276
|
name = name.strip.upcase.tr "-", "_"
|
237
277
|
name = "HTTP_#{name}" unless ["CONTENT_TYPE", "CONTENT_LENGTH"].include? name
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: functions_framework
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Azuma
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-06-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: puma
|
@@ -141,6 +141,7 @@ email:
|
|
141
141
|
- dazuma@google.com
|
142
142
|
executables:
|
143
143
|
- functions-framework
|
144
|
+
- functions-framework-ruby
|
144
145
|
extensions: []
|
145
146
|
extra_rdoc_files: []
|
146
147
|
files:
|
@@ -149,14 +150,25 @@ files:
|
|
149
150
|
- LICENSE
|
150
151
|
- README.md
|
151
152
|
- bin/functions-framework
|
153
|
+
- bin/functions-framework-ruby
|
154
|
+
- docs/deploying-functions.md
|
155
|
+
- docs/overview.md
|
156
|
+
- docs/running-a-functions-server.md
|
157
|
+
- docs/testing-functions.md
|
158
|
+
- docs/writing-functions.md
|
152
159
|
- lib/functions_framework.rb
|
153
160
|
- lib/functions_framework/cli.rb
|
154
161
|
- lib/functions_framework/cloud_events.rb
|
155
|
-
- lib/functions_framework/cloud_events/binary_content.rb
|
156
162
|
- lib/functions_framework/cloud_events/content_type.rb
|
163
|
+
- lib/functions_framework/cloud_events/errors.rb
|
157
164
|
- lib/functions_framework/cloud_events/event.rb
|
158
|
-
- lib/functions_framework/cloud_events/
|
165
|
+
- lib/functions_framework/cloud_events/event/field_interpreter.rb
|
166
|
+
- lib/functions_framework/cloud_events/event/v0.rb
|
167
|
+
- lib/functions_framework/cloud_events/event/v1.rb
|
168
|
+
- lib/functions_framework/cloud_events/http_binding.rb
|
169
|
+
- lib/functions_framework/cloud_events/json_format.rb
|
159
170
|
- lib/functions_framework/function.rb
|
171
|
+
- lib/functions_framework/legacy_event_converter.rb
|
160
172
|
- lib/functions_framework/registry.rb
|
161
173
|
- lib/functions_framework/server.rb
|
162
174
|
- lib/functions_framework/testing.rb
|
@@ -1,59 +0,0 @@
|
|
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
|
-
module CloudEvents
|
17
|
-
##
|
18
|
-
# A content handler for the binary mode.
|
19
|
-
# See https://github.com/cloudevents/spec/blob/master/http-protocol-binding.md
|
20
|
-
#
|
21
|
-
module BinaryContent
|
22
|
-
class << self
|
23
|
-
##
|
24
|
-
# Decode an event from the given Rack environment
|
25
|
-
#
|
26
|
-
# @param env [Hash] Rack environment hash
|
27
|
-
# @param content_type [FunctionsFramework::CloudEvents::ContentType]
|
28
|
-
# the content type from the Rack environment
|
29
|
-
# @return [FunctionsFramework::CloudEvents::Event]
|
30
|
-
#
|
31
|
-
def decode_rack_env env, content_type
|
32
|
-
data = env["rack.input"]&.read
|
33
|
-
spec_version = interpret_header env, "HTTP_CE_SPECVERSION"
|
34
|
-
raise "Unrecognized specversion: #{spec_version}" unless spec_version == "1.0"
|
35
|
-
Event.new \
|
36
|
-
id: interpret_header(env, "HTTP_CE_ID"),
|
37
|
-
source: interpret_header(env, "HTTP_CE_SOURCE"),
|
38
|
-
type: interpret_header(env, "HTTP_CE_TYPE"),
|
39
|
-
spec_version: spec_version,
|
40
|
-
data: data,
|
41
|
-
data_content_type: content_type,
|
42
|
-
data_schema: interpret_header(env, "HTTP_CE_DATASCHEMA"),
|
43
|
-
subject: interpret_header(env, "HTTP_CE_SUBJECT"),
|
44
|
-
time: interpret_header(env, "HTTP_CE_TIME")
|
45
|
-
end
|
46
|
-
|
47
|
-
private
|
48
|
-
|
49
|
-
def interpret_header env, key
|
50
|
-
escaped_value = env[key]
|
51
|
-
return nil if escaped_value.nil?
|
52
|
-
escaped_value.gsub(/%([0-9a-fA-F]{2})/) do
|
53
|
-
[$1.to_i(16)].pack "C" # rubocop:disable Style/PerlBackrefs
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
@@ -1,88 +0,0 @@
|
|
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 "base64"
|
16
|
-
require "json"
|
17
|
-
|
18
|
-
module FunctionsFramework
|
19
|
-
module CloudEvents
|
20
|
-
##
|
21
|
-
# A content handler for the JSON structure and JSON batch format.
|
22
|
-
# See https://github.com/cloudevents/spec/blob/master/json-format.md
|
23
|
-
#
|
24
|
-
module JsonStructure
|
25
|
-
class << self
|
26
|
-
##
|
27
|
-
# Decode an event from the given input string
|
28
|
-
#
|
29
|
-
# @param input [IO] An IO-like object providing a JSON-formatted string
|
30
|
-
# @param content_type [FunctionsFramework::CloudEvents::ContentType]
|
31
|
-
# the content type
|
32
|
-
# @return [FunctionsFramework::CloudEvents::Event]
|
33
|
-
#
|
34
|
-
def decode_structured_content input, content_type
|
35
|
-
input = input.read if input.respond_to? :read
|
36
|
-
charset = content_type.charset
|
37
|
-
input = input.encode charset if charset
|
38
|
-
structure = ::JSON.parse input
|
39
|
-
decode_hash_structure structure
|
40
|
-
end
|
41
|
-
|
42
|
-
##
|
43
|
-
# Decode a batch of events from the given input string
|
44
|
-
#
|
45
|
-
# @param input [IO] An IO-like object providing a JSON-formatted string
|
46
|
-
# @param content_type [FunctionsFramework::CloudEvents::ContentType]
|
47
|
-
# the content type
|
48
|
-
# @return [Array<FunctionsFramework::CloudEvents::Event>]
|
49
|
-
#
|
50
|
-
def decode_batched_content input, content_type
|
51
|
-
input = input.read if input.respond_to? :read
|
52
|
-
charset = content_type.charset
|
53
|
-
input = input.encode charset if charset
|
54
|
-
structure_array = Array(::JSON.parse(input))
|
55
|
-
structure_array.map { |structure| decode_hash_structure structure }
|
56
|
-
end
|
57
|
-
|
58
|
-
##
|
59
|
-
# Decode a single event from a hash data structure with keys and types
|
60
|
-
# conforming to the JSON event format
|
61
|
-
#
|
62
|
-
# @param structure [Hash] Input hash
|
63
|
-
# @return [FunctionsFramework::CloudEvents::Event]
|
64
|
-
#
|
65
|
-
def decode_hash_structure structure
|
66
|
-
data =
|
67
|
-
if structure.key? "data_base64"
|
68
|
-
::Base64.decode64 structure["data_base64"]
|
69
|
-
else
|
70
|
-
structure["data"]
|
71
|
-
end
|
72
|
-
spec_version = structure["specversion"]
|
73
|
-
raise "Unrecognized specversion: #{spec_version}" unless spec_version == "1.0"
|
74
|
-
Event.new \
|
75
|
-
id: structure["id"],
|
76
|
-
source: structure["source"],
|
77
|
-
type: structure["type"],
|
78
|
-
spec_version: spec_version,
|
79
|
-
data: data,
|
80
|
-
data_content_type: structure["datacontenttype"],
|
81
|
-
data_schema: structure["dataschema"],
|
82
|
-
subject: structure["subject"],
|
83
|
-
time: structure["time"]
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|