Class: RightDevelop::Testing::Client::Rest::Request::Playback

Inherits:
Base
  • Object
show all
Defined in:
lib/right_develop/testing/clients/rest/requests/playback.rb

Overview

Provides a middle-ware layer that intercepts transmition of the request and escapes out of the execute call with a stubbed response using throw/catch.

Defined Under Namespace

Classes: FakeNetHttpResponse, PeerResetConnectionError

Constant Summary collapse

HALT_TRANSMIT =
:halt_transmit
PLAYBACK_ERROR =

exceptions

::RightDevelop::Testing::Recording::Metadata::PlaybackError
RETRY_DELAY =
0.5
MAX_RETRIES =

120 seconds; a socket usually times out in 60-120 seconds

240

Constants inherited from Base

Base::METADATA_CLASS, Base::MUTEX

Instance Attribute Summary collapse

Attributes inherited from Base

#fixtures_dir, #logger, #request_metadata, #request_timestamp, #response_metadata, #response_timestamp, #route_data, #route_path, #state_file_path

Instance Method Summary collapse

Methods inherited from Base

#forget_outstanding_request, #log_response

Constructor Details

#initialize(args) ⇒ Playback

Returns a new instance of Playback.



70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/right_develop/testing/clients/rest/requests/playback.rb', line 70

def initialize(args)
  if args[:throttle]
    args = args.dup
    @throttle = Integer(args.delete(:throttle))
    if @throttle < 0 || @throttle > 100
      raise ::ArgumentError, 'throttle must be a percentage between 0 and 100'
    end
  else
    @throttle = 0
  end
  super(args)
end

Instance Attribute Details

#throttleObject (readonly)

Returns the value of attribute throttle.



68
69
70
# File 'lib/right_develop/testing/clients/rest/requests/playback.rb', line 68

def throttle
  @throttle
end

Instance Method Details

#handle_timeoutObject

Raises:

  • (::NotImplementedError)

See Also:

  • Base.handle_timeout


162
163
164
# File 'lib/right_develop/testing/clients/rest/requests/playback.rb', line 162

def handle_timeout
  raise ::NotImplementedError, 'Timeout is unexpected for stubbed API call.'
end

#log_requestObject

Overrides log_request to interrupt transmit before any connection is made.

Raises:

  • (Symbol)

    always throws HALT_TRANSMIT



86
87
88
89
# File 'lib/right_develop/testing/clients/rest/requests/playback.rb', line 86

def log_request
  super
  throw(HALT_TRANSMIT, HALT_TRANSMIT)
end

#transmit(uri, req, payload, &block) ⇒ Object

Overrides transmit to catch halt thrown by log_request.

Parameters:

  • URI[ (URI[ uri of some kind)

    uri of some kind

  • req (Net::HTTP)

    of some kind

  • of (RestClient::Payload)

    some kind

Returns:



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/right_develop/testing/clients/rest/requests/playback.rb', line 101

def transmit(uri, req, payload, &block)
  caught = catch(HALT_TRANSMIT) { super }
  if caught == HALT_TRANSMIT
    response = nil
    try_counter = 0
    while response.nil?
      with_state_lock do |state|
        response = catch(METADATA_CLASS::HALT) do
          fetch_response(state)
        end
      end
      case response
      when METADATA_CLASS::RetryableFailure
        try_counter += 1
        if try_counter >= MAX_RETRIES
          message =
            "Released thread id=#{::Thread.current.object_id} after " <<
            "#{try_counter} attempts to satisfy a retryable condition:\n" <<
            response.message
          raise PLAYBACK_ERROR, message
        end
        if 1 == try_counter
          message = "Blocking thread id=#{::Thread.current.object_id} " <<
                    'until a retryable condition is satisfied...'
          logger.debug(message)
        end
        response = nil
        sleep RETRY_DELAY
      else
        if try_counter > 0
          message = "Released thread id=#{::Thread.current.object_id} " <<
                    'after a retryable condition was satisfied.'
          logger.debug(message)
        end
      end
    end

    # delay, if throttled, to simulate server response time.
    if @throttle > 0 && response.elapsed_seconds > 0
      delay = (Float(response.elapsed_seconds) * @throttle) / 100.0
      logger.debug("throttle delay = #{delay}")
      sleep delay
    end

    # there may be a configured response delay (in addition to throttling)
    # which allows for other responses to complete before the current
    # response thread is unblocked. the response delay is absolute and not
    # subject to the throttle factor.
    if (delay = response.delay_seconds) > 0
      logger.debug("configured response delay = #{delay}")
      sleep delay
    end
    log_response(response)
    process_result(response, &block)
  else
    raise PLAYBACK_ERROR,
          'Unexpected RestClient::Request#transmit returned without calling RestClient::Request#log_request'
  end
end