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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f9bea4294ac48a9bb1c124143e96594b3993867c
4
- data.tar.gz: 1817c459f9d80fea412f1e1e7a66c011c6629f0d
3
+ metadata.gz: ca1ee47286ed9116bc3e025b1596019d85b1b59c
4
+ data.tar.gz: 524daf75dc03226c0fa94d0c265dc494f24e7ac2
5
5
  SHA512:
6
- metadata.gz: 814de826f973fd7678c8723ea686bebc140aa18e39497e7d77d683c208dc6dddaa8895ab0bf121400c0005862ba01b49806c2ee9462863d4be55d27b71d20b5c
7
- data.tar.gz: 65416ad1cbe5429b1e74b842449b739992f9d1e2d32e53569c209932f6ab8204e43c1596e576ff290d7995d15d393e9bfc62d3057b50bb4d28d7691bb8443e7e
6
+ metadata.gz: 2264a0ad0de1f8cef1de281cca8d9ab688c3d2d14006d5a4225decb2cf7fd346cb67226832abee3933f43b65b9a5f157b5a121159d90591223a40b2ed05463a3
7
+ data.tar.gz: c00c17b93fb059d26181ebc335f25fcbecee4e8c7f0d0e7e6542a179b05a47ced720c0973e7ec9d8dc56ad1bf6a0e1801128b74b2afdfadcdcc07a70069251cc
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.1.9
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 = 100 # = 50 seconds; a socket usually times out in 60-120 seconds
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 = 'Unable to locate response file(s) in epoch range ' +
207
- "[#{first_tried_epoch} - #{last_tried_epoch}]:\n " +
208
- first_tried_path.inspect
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
- values = @variables[variable]
671
- case value_index = values && values.index(real_value)
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 matched = VARIABLE_INDEX_REGEX.match(target_value)
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
- entrapment unless Base.trapped?
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)
@@ -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.9 ruby lib
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"
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-01"
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.9
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-08 00:00:00.000000000 Z
11
+ date: 2014-12-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: right_support