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.
@@ -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: []