right_develop 2.1.5 → 2.2.0
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.
- data/VERSION +1 -1
- data/bin/right_develop +4 -0
- data/lib/right_develop.rb +1 -0
- data/lib/right_develop/commands.rb +2 -1
- data/lib/right_develop/commands/server.rb +194 -0
- data/lib/right_develop/testing.rb +31 -0
- data/lib/right_develop/testing/clients.rb +36 -0
- data/lib/right_develop/testing/clients/rest.rb +34 -0
- data/lib/right_develop/testing/clients/rest/requests.rb +38 -0
- data/lib/right_develop/testing/clients/rest/requests/base.rb +305 -0
- data/lib/right_develop/testing/clients/rest/requests/playback.rb +293 -0
- data/lib/right_develop/testing/clients/rest/requests/record.rb +175 -0
- data/lib/right_develop/testing/recording.rb +33 -0
- data/lib/right_develop/testing/recording/config.rb +571 -0
- data/lib/right_develop/testing/recording/metadata.rb +805 -0
- data/lib/right_develop/testing/servers/might_api/.gitignore +3 -0
- data/lib/right_develop/testing/servers/might_api/Gemfile +6 -0
- data/lib/right_develop/testing/servers/might_api/Gemfile.lock +18 -0
- data/lib/right_develop/testing/servers/might_api/app/base.rb +323 -0
- data/lib/right_develop/testing/servers/might_api/app/echo.rb +73 -0
- data/lib/right_develop/testing/servers/might_api/app/playback.rb +46 -0
- data/lib/right_develop/testing/servers/might_api/app/record.rb +45 -0
- data/lib/right_develop/testing/servers/might_api/config.ru +8 -0
- data/lib/right_develop/testing/servers/might_api/config/init.rb +47 -0
- data/lib/right_develop/testing/servers/might_api/lib/config.rb +204 -0
- data/lib/right_develop/testing/servers/might_api/lib/logger.rb +68 -0
- data/right_develop.gemspec +30 -2
- metadata +84 -34
@@ -0,0 +1,18 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
extlib (0.9.16)
|
5
|
+
mime-types (2.2)
|
6
|
+
rack (1.5.2)
|
7
|
+
rest-client (1.6.7)
|
8
|
+
mime-types (>= 1.16)
|
9
|
+
right_support (2.8.20)
|
10
|
+
|
11
|
+
PLATFORMS
|
12
|
+
ruby
|
13
|
+
|
14
|
+
DEPENDENCIES
|
15
|
+
extlib
|
16
|
+
rack
|
17
|
+
rest-client
|
18
|
+
right_support
|
@@ -0,0 +1,323 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2014 RightScale Inc
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
|
23
|
+
require ::File.expand_path('../../config/init', __FILE__)
|
24
|
+
|
25
|
+
require 'rack/chunked'
|
26
|
+
require 'stringio'
|
27
|
+
require 'uri'
|
28
|
+
|
29
|
+
module RightDevelop::Testing::Server::MightApi
|
30
|
+
module App
|
31
|
+
class Base
|
32
|
+
|
33
|
+
MAX_REDIRECTS = 10 # 500 after so many redirects
|
34
|
+
|
35
|
+
# exceptions
|
36
|
+
class MightError < StandardError; end
|
37
|
+
class MissingRoute < MightError; end
|
38
|
+
|
39
|
+
attr_reader :config, :logger, :state_file_path
|
40
|
+
|
41
|
+
def initialize(state_file_name)
|
42
|
+
@config = ::RightDevelop::Testing::Server::MightApi::Config
|
43
|
+
@logger = ::RightDevelop::Testing::Server::MightApi.logger
|
44
|
+
|
45
|
+
@state_file_path = state_file_name ? ::File.join(@config.fixtures_dir, state_file_name) : nil
|
46
|
+
end
|
47
|
+
|
48
|
+
def call(env)
|
49
|
+
env['rack.logger'] ||= logger
|
50
|
+
|
51
|
+
# read body from stream.
|
52
|
+
request = ::Rack::Request.new(env)
|
53
|
+
body = request.body.read
|
54
|
+
|
55
|
+
# proxy any headers from env starting with HTTP_
|
56
|
+
headers = env.inject({}) do |r, (k,v)|
|
57
|
+
# note that HTTP_HOST refers to this proxy server instead of the
|
58
|
+
# proxied target server. in the case of AWS authentication, it is
|
59
|
+
# necessary to pass the value through unmodified or else AWS auth
|
60
|
+
# fails.
|
61
|
+
if k.start_with?('HTTP_')
|
62
|
+
r[k[5..-1]] = v
|
63
|
+
end
|
64
|
+
r
|
65
|
+
end
|
66
|
+
|
67
|
+
# special cases.
|
68
|
+
['ACCEPT', 'CONTENT_TYPE', 'CONTENT_LENGTH', 'USER_AGENT'].each do |key|
|
69
|
+
headers[key] = env[key] unless env[key].to_s.empty?
|
70
|
+
end
|
71
|
+
|
72
|
+
# handler
|
73
|
+
verb = request.request_method
|
74
|
+
uri = ::URI.parse(request.url)
|
75
|
+
handle_request(env, verb, uri, headers, body)
|
76
|
+
rescue MissingRoute => e
|
77
|
+
message = "#{e.class} #{e.message}"
|
78
|
+
logger.error(message)
|
79
|
+
if config.routes.empty?
|
80
|
+
logger.error("No routes configured.")
|
81
|
+
else
|
82
|
+
logger.error("The following routes are configured:")
|
83
|
+
config.routes.keys.each do |prefix|
|
84
|
+
logger.error(" #{prefix}...")
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# not a 404 because this is a proxy/stub service and 40x might appear to
|
89
|
+
# have come from a proxied request/response whereas 500 is never an
|
90
|
+
# expected response.
|
91
|
+
internal_server_error(message)
|
92
|
+
rescue ::RightDevelop::Testing::Client::Rest::Request::Playback::PlaybackError => e
|
93
|
+
# response has not been recorded.
|
94
|
+
message = e.message
|
95
|
+
trace = [e.class.name] + (e.backtrace || [])
|
96
|
+
logger.error(message)
|
97
|
+
logger.debug(trace.join("\n"))
|
98
|
+
internal_server_error(message)
|
99
|
+
rescue ::Exception => e
|
100
|
+
message = "Unhandled exception: #{e.class} #{e.message}"
|
101
|
+
trace = e.backtrace || []
|
102
|
+
if logger
|
103
|
+
logger.error(message)
|
104
|
+
logger.debug(trace.join("\n"))
|
105
|
+
else
|
106
|
+
env['rack.errors'].puts(message)
|
107
|
+
env['rack.errors'].puts(trace.join("\n"))
|
108
|
+
end
|
109
|
+
internal_server_error(message)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Handler.
|
113
|
+
#
|
114
|
+
# @param [Hash] env from rack
|
115
|
+
# @param [String] verb as one of ['GET', 'POST', etc.]
|
116
|
+
# @param [URI] uri parsed from full url
|
117
|
+
# @param [Hash] headers for proxy call with any non-proxy data omitted
|
118
|
+
# @param [String] body streamed from payload or empty
|
119
|
+
#
|
120
|
+
# @return [TrueClass] always true
|
121
|
+
def handle_request(env, verb, uri, headers, body)
|
122
|
+
raise ::NotImplementedError, 'Must be overridden'
|
123
|
+
end
|
124
|
+
|
125
|
+
# Makes a proxied API request using the given request class.
|
126
|
+
#
|
127
|
+
# @param [Class] request_class for API call
|
128
|
+
# @param [String] verb as one of ['GET', 'POST', etc.]
|
129
|
+
# @param [URI] uri parsed from full url
|
130
|
+
# @param [Hash] headers for proxy call with any non-proxy data omitted
|
131
|
+
# @param [String] body streamed from payload or empty
|
132
|
+
# @param [Integer] throttle for playback or nil
|
133
|
+
#
|
134
|
+
# @return [Array] rack-style tuple of [code, headers, [body]]
|
135
|
+
def proxy(request_class, verb, uri, headers, body, throttle = nil)
|
136
|
+
|
137
|
+
# check routes.
|
138
|
+
unless route = find_route(uri)
|
139
|
+
raise MissingRoute, "No route configured for #{uri.path.inspect}"
|
140
|
+
end
|
141
|
+
route_path, route_data = route
|
142
|
+
response = nil
|
143
|
+
max_redirects = MAX_REDIRECTS
|
144
|
+
while response.nil? do
|
145
|
+
request_proxy = nil
|
146
|
+
begin
|
147
|
+
proxied_url = ::File.join(route_data[:url], uri.path)
|
148
|
+
unless uri.query.to_s.empty?
|
149
|
+
proxied_url << '?' << uri.query
|
150
|
+
end
|
151
|
+
proxied_headers = proxy_headers(headers, route_data)
|
152
|
+
|
153
|
+
request_options = {
|
154
|
+
fixtures_dir: config.fixtures_dir,
|
155
|
+
logger: logger,
|
156
|
+
route_path: route_path,
|
157
|
+
route_data: route_data,
|
158
|
+
state_file_path: state_file_path,
|
159
|
+
method: verb.downcase.to_sym,
|
160
|
+
url: proxied_url,
|
161
|
+
headers: proxied_headers,
|
162
|
+
payload: body
|
163
|
+
}
|
164
|
+
request_options[:throttle] = throttle if throttle
|
165
|
+
request_proxy = request_class.new(request_options)
|
166
|
+
|
167
|
+
# log normalized data for obfuscation.
|
168
|
+
logger.debug("normalized request headers = #{request_proxy.request_metadata.headers.inspect}")
|
169
|
+
logger.debug("normalized request body:\n" << request_proxy.request_metadata.body)
|
170
|
+
|
171
|
+
request_proxy.execute do |rest_response, rest_request, net_http_response, &block|
|
172
|
+
|
173
|
+
# headers.
|
174
|
+
response_headers = normalize_rack_response_headers(net_http_response.to_hash)
|
175
|
+
|
176
|
+
# eliminate headers that interfere with response via proxy.
|
177
|
+
%w(
|
178
|
+
connection status content-encoding
|
179
|
+
).each { |key| response_headers.delete(key) }
|
180
|
+
|
181
|
+
case response_code = Integer(rest_response.code)
|
182
|
+
when 301, 302, 307
|
183
|
+
raise RestClient::Exceptions::EXCEPTIONS_MAP[response_code].new(rest_response, response_code)
|
184
|
+
else
|
185
|
+
# special handling for chunked body.
|
186
|
+
if response_headers['transfer-encoding'] == 'chunked'
|
187
|
+
response_body = ::Rack::Chunked::Body.new([rest_response.body])
|
188
|
+
else
|
189
|
+
response_body = [rest_response.body]
|
190
|
+
end
|
191
|
+
response = [response_code, response_headers, response_body]
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
# log normalized data for obfuscation.
|
196
|
+
logger.debug("normalized response headers = #{request_proxy.response_metadata.headers.inspect}")
|
197
|
+
logger.debug("normalized response body:\n" << request_proxy.response_metadata.body.to_s)
|
198
|
+
rescue RestClient::RequestTimeout
|
199
|
+
net_http_response = request_proxy.handle_timeout
|
200
|
+
response_code = Integer(net_http_response.code)
|
201
|
+
response_headers = normalize_rack_response_headers(net_http_response.to_hash)
|
202
|
+
response_body = [net_http_response.body]
|
203
|
+
response = [response_code, response_headers, response_body]
|
204
|
+
rescue RestClient::Exception => e
|
205
|
+
case e.http_code
|
206
|
+
when 301, 302, 307
|
207
|
+
max_redirects -= 1
|
208
|
+
raise MightError.new('Exceeded max redirects') if max_redirects < 0
|
209
|
+
if location = e.response.headers[:location]
|
210
|
+
redirect_uri = ::URI.parse(location)
|
211
|
+
redirect_uri.path = ''
|
212
|
+
redirect_uri.query = nil
|
213
|
+
logger.debug("#{e.message} from #{route_data[:url]} to #{redirect_uri}")
|
214
|
+
route_data[:url] = redirect_uri.to_s
|
215
|
+
|
216
|
+
# move to end of FIFO queue for retry.
|
217
|
+
request_proxy.forget_outstanding_request
|
218
|
+
else
|
219
|
+
logger.debug("#{e.message} was missing expected location header.")
|
220
|
+
raise
|
221
|
+
end
|
222
|
+
else
|
223
|
+
raise
|
224
|
+
end
|
225
|
+
ensure
|
226
|
+
# remove from FIFO queue in case of any unhandled error.
|
227
|
+
request_proxy.forget_outstanding_request if request_proxy
|
228
|
+
end
|
229
|
+
end
|
230
|
+
response
|
231
|
+
end
|
232
|
+
|
233
|
+
# @param [URI] uri path to find
|
234
|
+
#
|
235
|
+
# @return [Array] pair of [prefix, data] or nil
|
236
|
+
def find_route(uri)
|
237
|
+
find_path = uri.path
|
238
|
+
logger.debug "Route URI path to match = #{find_path.inspect}"
|
239
|
+
config.routes.find do |prefix, data|
|
240
|
+
matched = find_path.start_with?(prefix)
|
241
|
+
logger.debug "Tried = #{prefix.inspect}, matched = #{matched}"
|
242
|
+
matched
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
# Sets the header style using configuration of the proxied service.
|
247
|
+
#
|
248
|
+
# @param [Hash] headers for proxy
|
249
|
+
# @param [Hash] route_data containing header configuration, if any
|
250
|
+
#
|
251
|
+
# @return [Mash] proxied headers
|
252
|
+
def proxy_headers(headers, route_data)
|
253
|
+
proxied = nil
|
254
|
+
if proxy_data = route_data[:proxy]
|
255
|
+
if header_data = proxy_data[:header]
|
256
|
+
to_separator = (header_data[:separator] == :underscore) ? '_' : '-'
|
257
|
+
from_separator = (to_separator == '-') ? '_' : '-'
|
258
|
+
proxied = headers.inject(::Mash.new) do |h, (k, v)|
|
259
|
+
k = k.to_s
|
260
|
+
case header_data[:case]
|
261
|
+
when nil
|
262
|
+
k = k.gsub(from_separator, to_separator)
|
263
|
+
when :lower
|
264
|
+
k = k.downcase.gsub(from_separator, to_separator)
|
265
|
+
when :upper
|
266
|
+
k = k.upcase.gsub(from_separator, to_separator)
|
267
|
+
when :capitalize
|
268
|
+
k = k.split(/-|_/).map { |word| word.capitalize }.join(to_separator)
|
269
|
+
else
|
270
|
+
raise ::ArgumentError,
|
271
|
+
"Unexpected header case: #{route_data.inspect}"
|
272
|
+
end
|
273
|
+
h[k] = v
|
274
|
+
h
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
proxied || ::Mash.new(headers)
|
279
|
+
end
|
280
|
+
|
281
|
+
# rack has a convention of newline-delimited header multi-values.
|
282
|
+
#
|
283
|
+
# HACK: changes underscore to dash to defeat RestClient::AbstractResponse
|
284
|
+
# line 27 (on client side) from failing to parse cookies array; it
|
285
|
+
# incorrectly calls .inject on the stringized form instead of using the
|
286
|
+
# raw array form or parsing the cookies into a hash, but only if the raw
|
287
|
+
# name is 'set_cookie' ('set-cookie' is okay).
|
288
|
+
#
|
289
|
+
# even wierder, on line 78 it assumes the raw name is 'set-cookie' and
|
290
|
+
# that works out for us here.
|
291
|
+
#
|
292
|
+
# @param [Hash] headers to normalize
|
293
|
+
#
|
294
|
+
# @return [Hash] normalized headers
|
295
|
+
def normalize_rack_response_headers(headers)
|
296
|
+
headers.inject({}) do |h, (k, v)|
|
297
|
+
h[k.to_s.gsub('_', '-').downcase] = v.join("\n")
|
298
|
+
h
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
# @return [Array] rack-style response for 500
|
303
|
+
def internal_server_error(message)
|
304
|
+
formal = <<EOF
|
305
|
+
MightAPI internal error
|
306
|
+
|
307
|
+
Problem:
|
308
|
+
#{message}
|
309
|
+
EOF
|
310
|
+
|
311
|
+
[
|
312
|
+
500,
|
313
|
+
{
|
314
|
+
'Content-Type' => 'text/plain',
|
315
|
+
'Content-Length' => ::Rack::Utils.bytesize(formal).to_s
|
316
|
+
},
|
317
|
+
[formal]
|
318
|
+
]
|
319
|
+
end
|
320
|
+
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2014 RightScale Inc
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
|
23
|
+
require ::File.expand_path('../base', __FILE__)
|
24
|
+
|
25
|
+
require 'right_support'
|
26
|
+
|
27
|
+
module RightDevelop::Testing::Server::MightApi::App
|
28
|
+
|
29
|
+
# Implements an echo service.
|
30
|
+
class Echo < ::RightDevelop::Testing::Server::MightApi::App::Base
|
31
|
+
|
32
|
+
# metadata
|
33
|
+
METADATA_CLASS = ::RightDevelop::Testing::Recording::Metadata
|
34
|
+
|
35
|
+
def initialize
|
36
|
+
super(nil)
|
37
|
+
end
|
38
|
+
|
39
|
+
# @see RightDevelop::Testing::Server::MightApi::App::Base#handle_request
|
40
|
+
def handle_request(env, verb, uri, headers, body)
|
41
|
+
|
42
|
+
# check routes.
|
43
|
+
response = ::Rack::Response.new
|
44
|
+
if route = find_route(uri)
|
45
|
+
response.write "URL matched #{route.last[:name].inspect}\n"
|
46
|
+
else
|
47
|
+
response.write "Failed to match any route. The following routes are valid:\n"
|
48
|
+
config.routes.keys.each do |prefix|
|
49
|
+
response.write "Prefix = #{prefix.inspect}\n\n"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# echo request back as response.
|
54
|
+
response.write "\nruby %sp%s\n\n" % [RUBY_VERSION, RUBY_PATCHLEVEL]
|
55
|
+
response.write "Raw configuration = #{::JSON.pretty_generate(config.to_hash)}\n\n" # hash order is significant in config
|
56
|
+
config.routes.each do |route_path, route_config|
|
57
|
+
response.write "=== Compiled route matchers begin for root = #{route_path.inspect}:\nmatchers = {\n"
|
58
|
+
(route_config[METADATA_CLASS::MATCHERS_KEY] || {}).each do |regex, route_data|
|
59
|
+
response.write " #{regex.inspect} =>\n #{route_data.inspect},\n"
|
60
|
+
end
|
61
|
+
response.write "}\n=== Compiled route matchers end.\n\n"
|
62
|
+
end
|
63
|
+
response.write "env = #{METADATA_CLASS.deep_sorted_json(env, true)}\n\n"
|
64
|
+
response.write "ENV = #{METADATA_CLASS.deep_sorted_json(::ENV, true)}\n\n"
|
65
|
+
response.write "verb = #{verb.inspect}\n\n"
|
66
|
+
response.write "uri = #{uri}\n\n"
|
67
|
+
response.write "headers = #{METADATA_CLASS.deep_sorted_json(headers, true)}\n\n"
|
68
|
+
response.write "body = #{body.inspect}\n\n"
|
69
|
+
response.finish
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2014 RightScale Inc
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
|
23
|
+
require ::File.expand_path('../base', __FILE__)
|
24
|
+
|
25
|
+
module RightDevelop::Testing::Server::MightApi::App
|
26
|
+
class Playback < ::RightDevelop::Testing::Server::MightApi::App::Base
|
27
|
+
|
28
|
+
STATE_FILE_NAME = 'playback_state.yml'
|
29
|
+
|
30
|
+
def initialize
|
31
|
+
super(STATE_FILE_NAME)
|
32
|
+
end
|
33
|
+
|
34
|
+
# @see RightDevelop::Testing::Server::MightApi::App::Base#handle_request
|
35
|
+
def handle_request(env, verb, uri, headers, body)
|
36
|
+
proxy(
|
37
|
+
::RightDevelop::Testing::Client::Rest::Request::Playback,
|
38
|
+
verb,
|
39
|
+
uri,
|
40
|
+
headers,
|
41
|
+
body,
|
42
|
+
config.throttle)
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|