right_develop 2.1.5 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|