right_develop 3.1.9 → 3.1.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/lib/right_develop/testing/clients/rest/requests/playback.rb +13 -5
- data/lib/right_develop/testing/clients/rest/requests/record.rb +17 -0
- data/lib/right_develop/testing/recording/metadata.rb +26 -7
- data/lib/right_develop/testing/servers/might_api/app/base.rb +49 -1
- data/right_develop.gemspec +3 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ca1ee47286ed9116bc3e025b1596019d85b1b59c
|
4
|
+
data.tar.gz: 524daf75dc03226c0fa94d0c265dc494f24e7ac2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2264a0ad0de1f8cef1de281cca8d9ab688c3d2d14006d5a4225decb2cf7fd346cb67226832abee3933f43b65b9a5f157b5a121159d90591223a40b2ed05463a3
|
7
|
+
data.tar.gz: c00c17b93fb059d26181ebc335f25fcbecee4e8c7f0d0e7e6542a179b05a47ced720c0973e7ec9d8dc56ad1bf6a0e1801128b74b2afdfadcdcc07a70069251cc
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.1.
|
1
|
+
3.1.10
|
@@ -89,7 +89,7 @@ module RightDevelop::Testing::Client::Rest::Request
|
|
89
89
|
end
|
90
90
|
|
91
91
|
RETRY_DELAY = 0.5
|
92
|
-
MAX_RETRIES =
|
92
|
+
MAX_RETRIES = 240 # = 120 seconds; a socket usually times out in 60-120 seconds
|
93
93
|
|
94
94
|
# Overrides transmit to catch halt thrown by log_request.
|
95
95
|
#
|
@@ -176,7 +176,6 @@ module RightDevelop::Testing::Client::Rest::Request
|
|
176
176
|
# allowed due to multithreaded requests causing the epoch to advance
|
177
177
|
# (in a non-throttled playback) before all requests for a past epoch have
|
178
178
|
# been made. the current epoch is always preferred over past.
|
179
|
-
logger.debug("BEGIN playback state = #{state.inspect}") if logger.debug?
|
180
179
|
file_path = nil
|
181
180
|
past_epochs = state[:past_epochs] ||= []
|
182
181
|
try_epochs = [state[:epoch]] + past_epochs
|
@@ -203,11 +202,20 @@ module RightDevelop::Testing::Client::Rest::Request
|
|
203
202
|
response_hash[:body])
|
204
203
|
result = FakeNetHttpResponse.new(response_hash, response_metadata)
|
205
204
|
else
|
206
|
-
msg =
|
207
|
-
|
208
|
-
|
205
|
+
msg = <<EOF
|
206
|
+
Unable to locate response file(s) in epoch range [#{first_tried_epoch} - #{last_tried_epoch}]:
|
207
|
+
#{first_tried_path.inspect}
|
208
|
+
request checksum_data = #{request_metadata.checksum_data.inspect}
|
209
|
+
state = #{state.inspect}
|
210
|
+
EOF
|
209
211
|
raise PLAYBACK_ERROR, msg
|
210
212
|
end
|
213
|
+
|
214
|
+
# defer any verbose debug logging (i.e. the current state) until after
|
215
|
+
# metadata has been successfully loaded because a retryable missing
|
216
|
+
# variable may occur a couple hundred times before the condition is
|
217
|
+
# satisfied, if ever.
|
218
|
+
logger.debug("BEGIN playback state = #{state.inspect}") if logger.debug?
|
211
219
|
logger.debug("Played back response from #{file_path.inspect}.")
|
212
220
|
|
213
221
|
# determine if epoch is done, which it is if every known request has been
|
@@ -63,6 +63,23 @@ module RightDevelop::Testing::Client::Rest::Request
|
|
63
63
|
def to_hash; @headers; end
|
64
64
|
end
|
65
65
|
|
66
|
+
# Overrides transmit to catch halt thrown by log_request.
|
67
|
+
#
|
68
|
+
# @param [URI[ uri of some kind
|
69
|
+
# @param [Net::HTTP] req of some kind
|
70
|
+
# @param [RestClient::Payload] of some kind
|
71
|
+
#
|
72
|
+
# @return
|
73
|
+
def transmit(uri, req, payload, &block)
|
74
|
+
super
|
75
|
+
rescue ::Interrupt
|
76
|
+
if @request_timestamp
|
77
|
+
logger.warn('Interrupted with at least one request outstanding; will record a timeout response.')
|
78
|
+
handle_timeout
|
79
|
+
end
|
80
|
+
raise
|
81
|
+
end
|
82
|
+
|
66
83
|
# Overrides log_request for basic logging.
|
67
84
|
#
|
68
85
|
# @param [RestClient::Response] to capture
|
@@ -88,7 +88,7 @@ module RightDevelop::Testing::Recording
|
|
88
88
|
class RecordingError < StandardError; end
|
89
89
|
class PlaybackError < StandardError; end
|
90
90
|
|
91
|
-
attr_reader :uri, :verb, :http_status, :headers, :body
|
91
|
+
attr_reader :uri, :verb, :http_status, :headers, :body, :checksum_data
|
92
92
|
attr_reader :mode, :logger, :effective_route_config, :variables
|
93
93
|
attr_reader :typenames_to_values
|
94
94
|
|
@@ -636,8 +636,15 @@ module RightDevelop::Testing::Recording
|
|
636
636
|
result = variable # use macro as substituted value
|
637
637
|
elsif values = @variables[variable]
|
638
638
|
# quick out for same as initial value; don't show array index.
|
639
|
+
# special case for 'any_variable_name[*]' which always uses the last
|
640
|
+
# given value instead of keeping an array of values.
|
639
641
|
if values.first == real_value
|
640
642
|
result = variable
|
643
|
+
elsif variable.end_with?('[*]')
|
644
|
+
# special case for wildcard index; update 1-sized array 0th entry with
|
645
|
+
# latest value instead of appending a new unique value.
|
646
|
+
@variables[variable][0] = real_value
|
647
|
+
result = variable
|
641
648
|
else
|
642
649
|
# show zero-based array index beyond the zero index.
|
643
650
|
unless value_index = values.index(real_value)
|
@@ -667,8 +674,17 @@ module RightDevelop::Testing::Recording
|
|
667
674
|
end
|
668
675
|
result = variable # use macro as substituted value
|
669
676
|
else
|
670
|
-
|
671
|
-
|
677
|
+
value_index = nil
|
678
|
+
if values = @variables[variable]
|
679
|
+
# special wildcard index notation means 'always latest value'; the
|
680
|
+
# recorded variable name will be the wildcard index name.
|
681
|
+
if variable.end_with?('[*]')
|
682
|
+
value_index = 0
|
683
|
+
else
|
684
|
+
value_index = values.index(real_value)
|
685
|
+
end
|
686
|
+
end
|
687
|
+
case value_index
|
672
688
|
when nil
|
673
689
|
message = 'A variable referenced by a response has not yet been ' +
|
674
690
|
'defined by a request while replacing variable = ' +
|
@@ -702,7 +718,10 @@ module RightDevelop::Testing::Recording
|
|
702
718
|
raise PlaybackError, message
|
703
719
|
end
|
704
720
|
elsif variable_array = @variables[variable]
|
705
|
-
if
|
721
|
+
if variable.end_with?('[*]')
|
722
|
+
# special case for wildcard
|
723
|
+
variable_array_index = 0
|
724
|
+
elsif matched = VARIABLE_INDEX_REGEX.match(target_value)
|
706
725
|
variable_array_index = Integer(matched[1])
|
707
726
|
else
|
708
727
|
variable_array_index = 0
|
@@ -791,12 +810,12 @@ module RightDevelop::Testing::Recording
|
|
791
810
|
end
|
792
811
|
|
793
812
|
# use deep-sorted JSON to prevent random ordering changing the checksum.
|
794
|
-
checksum_data = self.class.deep_sorted_json(significant_data)
|
813
|
+
@checksum_data = self.class.deep_sorted_json(significant_data)
|
795
814
|
if logger.debug?
|
796
815
|
logger.debug("#{@kind} significant = #{significant.inspect}")
|
797
|
-
logger.debug("#{@kind} checksum_data = #{checksum_data.inspect}")
|
816
|
+
logger.debug("#{@kind} checksum_data = #{@checksum_data.inspect}")
|
798
817
|
end
|
799
|
-
::Digest::MD5.hexdigest(checksum_data)
|
818
|
+
::Digest::MD5.hexdigest(@checksum_data)
|
800
819
|
end
|
801
820
|
|
802
821
|
# Performs a selective copy of any significant fields (recursively) or else
|
@@ -23,6 +23,7 @@
|
|
23
23
|
require ::File.expand_path('../../config/init', __FILE__)
|
24
24
|
|
25
25
|
require 'rack/chunked'
|
26
|
+
require 'set'
|
26
27
|
require 'stringio'
|
27
28
|
require 'uri'
|
28
29
|
|
@@ -30,6 +31,8 @@ module RightDevelop::Testing::Server::MightApi
|
|
30
31
|
module App
|
31
32
|
class Base
|
32
33
|
|
34
|
+
MUTEX = ::Mutex.new # semaphore for critical sections
|
35
|
+
|
33
36
|
MAX_REDIRECTS = 10 # 500 after so many redirects
|
34
37
|
|
35
38
|
# Rack (and Skeletor) apps and some known AWS apps only accept dash and
|
@@ -63,6 +66,18 @@ module RightDevelop::Testing::Server::MightApi
|
|
63
66
|
nil
|
64
67
|
end
|
65
68
|
|
69
|
+
def self.interrupted?
|
70
|
+
!!@interrupted
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.interrupted=(value)
|
74
|
+
@interrupted = value
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.app_threads
|
78
|
+
@app_threads ||= ::Set.new
|
79
|
+
end
|
80
|
+
|
66
81
|
def call(env)
|
67
82
|
# HACK: chain trap interrupt on first call to app because the trap chain
|
68
83
|
# does not exist, in rack terms, until just before app is run.
|
@@ -75,7 +90,11 @@ module RightDevelop::Testing::Server::MightApi
|
|
75
90
|
# cleaned-up on shutdown, etc. admin mode has a workaround whereby it is
|
76
91
|
# able to clean-up any temporary files immediately after reading its
|
77
92
|
# config and whenever the administered configuration changes.
|
78
|
-
|
93
|
+
raise ::Interrupt if self.class.interrupted?
|
94
|
+
MUTEX.synchronize do
|
95
|
+
entrapment unless Base.trapped?
|
96
|
+
self.class.app_threads << ::Thread.current
|
97
|
+
end
|
79
98
|
|
80
99
|
env['rack.logger'] ||= logger
|
81
100
|
|
@@ -145,6 +164,13 @@ module RightDevelop::Testing::Server::MightApi
|
|
145
164
|
logger.error(message)
|
146
165
|
logger.debug(trace.join("\n"))
|
147
166
|
internal_server_error(message)
|
167
|
+
rescue ::Interrupt
|
168
|
+
# setting interrupted=true may or may not be redundant, depending on
|
169
|
+
# visibility of interrupted flag to all outstanding app threads.
|
170
|
+
# the problem is that we are not allowed to synchronize a mutex inside
|
171
|
+
# of a trap context.
|
172
|
+
self.class.interrupted = true
|
173
|
+
internal_server_error('interrupt')
|
148
174
|
rescue ::Exception => e
|
149
175
|
message = "Unhandled exception: #{e.class} #{e.message}"
|
150
176
|
trace = e.backtrace || []
|
@@ -156,6 +182,12 @@ module RightDevelop::Testing::Server::MightApi
|
|
156
182
|
env['rack.errors'].puts(trace.join("\n"))
|
157
183
|
end
|
158
184
|
internal_server_error(message)
|
185
|
+
ensure
|
186
|
+
unless self.class.interrupted?
|
187
|
+
MUTEX.synchronize do
|
188
|
+
self.class.app_threads.delete(::Thread.current)
|
189
|
+
end
|
190
|
+
end
|
159
191
|
end
|
160
192
|
|
161
193
|
# Handler.
|
@@ -434,6 +466,22 @@ EOF
|
|
434
466
|
app.logger.warn('cannot log traps') # no exception raised
|
435
467
|
end
|
436
468
|
|
469
|
+
# interrupt any running app threads to resolve outstanding requests.
|
470
|
+
#
|
471
|
+
# note that Mutex#synchronize is not allowed inside a trap context.
|
472
|
+
#
|
473
|
+
# FIX: duplicating the set is slightly unsafe but not sure how else
|
474
|
+
# to deal with data protected by critical section in a trap. we also
|
475
|
+
# have logic in ensure block to avoid modifying set on interrupt.
|
476
|
+
app.class.interrupted = true
|
477
|
+
app_threads = app.class.app_threads.dup
|
478
|
+
app_threads.each do |app_thread|
|
479
|
+
if app_thread.alive?
|
480
|
+
app_thread.raise(::Interrupt)
|
481
|
+
app_thread.join
|
482
|
+
end
|
483
|
+
end
|
484
|
+
|
437
485
|
# cleanup fixtures, if requested.
|
438
486
|
app.cleanup
|
439
487
|
if previous_trap && previous_trap.respond_to?(:call)
|
data/right_develop.gemspec
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: right_develop 3.1.
|
5
|
+
# stub: right_develop 3.1.10 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "right_develop"
|
9
|
-
s.version = "3.1.
|
9
|
+
s.version = "3.1.10"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib"]
|
13
13
|
s.authors = ["Tony Spataro"]
|
14
|
-
s.date = "2014-12-
|
14
|
+
s.date = "2014-12-10"
|
15
15
|
s.description = "A toolkit of development tools created by RightScale."
|
16
16
|
s.email = "support@rightscale.com"
|
17
17
|
s.executables = ["right_develop"]
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: right_develop
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.1.
|
4
|
+
version: 3.1.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tony Spataro
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-12-
|
11
|
+
date: 2014-12-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: right_support
|