functions_framework 0.1.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
- 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
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
  ##
@@ -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
- env = Testing.build_standard_env URI(url), headers
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 data [String] The body to post.
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, data, headers = []
146
- env = Testing.build_standard_env URI(url), headers
147
- env[::Rack::REQUEST_METHOD] = ::Rack::POST
148
- env[::Rack::INPUT_STREAM] = ::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
- name, value = header.split ":"
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
@@ -17,5 +17,5 @@ module FunctionsFramework
17
17
  # Version of the Ruby Functions Framework
18
18
  # @return [String]
19
19
  #
20
- VERSION = "0.1.0".freeze
20
+ VERSION = "0.3.1".freeze
21
21
  end
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.1.0
4
+ version: 0.3.1
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-01-30 00:00:00.000000000 Z
11
+ date: 2020-06-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: puma
@@ -114,14 +114,14 @@ dependencies:
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: 0.9.3
117
+ version: 0.10.0
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: 0.9.3
124
+ version: 0.10.0
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: yard
127
127
  requirement: !ruby/object:Gem::Requirement
@@ -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,23 @@ 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/json_structure.rb
165
+ - lib/functions_framework/cloud_events/event/v1.rb
166
+ - lib/functions_framework/cloud_events/http_binding.rb
167
+ - lib/functions_framework/cloud_events/json_format.rb
159
168
  - lib/functions_framework/function.rb
169
+ - lib/functions_framework/legacy_event_converter.rb
160
170
  - lib/functions_framework/registry.rb
161
171
  - lib/functions_framework/server.rb
162
172
  - 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