File: stub_responses.rb

package info (click to toggle)
ruby-aws-sdk-core 3.242.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,420 kB
  • sloc: ruby: 18,795; makefile: 4
file content (154 lines) | stat: -rw-r--r-- 4,978 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
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
# frozen_string_literal: true

module Aws
  module Plugins
    # @api private
    class StubResponses < Seahorse::Client::Plugin

      option(:stub_responses,
        default: false,
        doc_type: 'Boolean',
        rbs_type: 'untyped',
        docstring: <<-DOCS)
Causes the client to return stubbed responses. By default
fake responses are generated and returned. You can specify
the response data to return or errors to raise by calling
{ClientStubs#stub_responses}. See {ClientStubs} for more information.

** Please note ** When response stubbing is enabled, no HTTP
requests are made, and retries are disabled.
        DOCS

      option(:region) do |config|
        'us-stubbed-1' if config.stub_responses
      end

      option(:credentials) do |config|
        if config.stub_responses
          Credentials.new('stubbed-akid', 'stubbed-secret')
        end
      end

      option(:token_provider) do |config|
        if config.stub_responses
          StaticTokenProvider.new('stubbed-token')
        end
      end

      option(:stubs) { {} }
      option(:stubs_mutex) { Mutex.new }
      option(:api_requests) { [] }
      option(:api_requests_mutex) { Mutex.new }

      def add_handlers(handlers, config)
        return unless config.stub_responses

        handlers.add(ApiRequestsHandler)
        handlers.add(StubbingHandler, step: :send)
      end

      def after_initialize(client)
        if client.config.stub_responses
          client.setup_stubbing
          client.handlers.remove(RetryErrors::Handler)
          client.handlers.remove(RetryErrors::LegacyHandler)
          client.handlers.remove(ClientMetricsPlugin::Handler)
          client.handlers.remove(ClientMetricsSendPlugin::LatencyHandler)
          client.handlers.remove(ClientMetricsSendPlugin::AttemptHandler)
          client.handlers.remove(Seahorse::Client::Plugins::RequestCallback::OptionHandler)
          client.handlers.remove(Seahorse::Client::Plugins::RequestCallback::ReadCallbackHandler)
        end
      end

      class ApiRequestsHandler < Seahorse::Client::Handler
        def call(context)
          context.config.api_requests_mutex.synchronize do
            context.config.api_requests << {
              operation_name: context.operation_name,
              params: context.params,
              context: context
            }
          end
          @handler.call(context)
        end
      end

      class StubbingHandler < Seahorse::Client::Handler
        def call(context)
          span_wrapper(context) do
            stub_responses(context)
          end
        end

        private

        def stub_responses(context)
          resp = Seahorse::Client::Response.new(context: context)
          async_mode = context.client.is_a? Seahorse::Client::AsyncBase
          stub = context.client.next_stub(context)
          stub[:mutex].synchronize { apply_stub(stub, resp, async_mode) }

          if async_mode
            Seahorse::Client::AsyncResponse.new(
              context: context,
              stream: context[:input_event_stream_handler].event_emitter.stream,
              sync_queue: Queue.new
            )
          else
            resp
          end
        end

        def apply_stub(stub, response, async_mode = false)
          http_resp = response.context.http_response
          case
          when stub[:error] then signal_error(stub[:error], http_resp)
          when stub[:http] then signal_http(stub[:http], http_resp, async_mode)
          when stub[:data] then response.data = stub[:data]
          end
        end

        def signal_error(error, http_resp)
          if Exception === error
            http_resp.signal_error(error)
          else
            http_resp.signal_error(error.new)
          end
        end

        # @param [Seahorse::Client::Http::Response] stub
        # @param [Seahorse::Client::Http::Response | Seahorse::Client::Http::AsyncResponse] http_resp
        # @param [Boolean] async_mode
        def signal_http(stub, http_resp, async_mode = false)
          if async_mode
            h2_headers = stub.headers.to_h.inject([]) do |arr, (k, v)|
              arr << [k, v]
            end
            h2_headers << [":status", stub.status_code]
            http_resp.signal_headers(h2_headers)
          else
            http_resp.signal_headers(stub.status_code, stub.headers.to_h)
          end
          while chunk = stub.body.read(1024 * 1024)
            http_resp.signal_data(chunk)
          end
          stub.body.rewind
          http_resp.signal_done
        end

        def span_wrapper(context, &block)
          context.tracer.in_span(
            'Handler.StubResponses',
            attributes: Aws::Telemetry.http_request_attrs(context)
          ) do |span|
            block.call.tap do
              span.add_attributes(
                Aws::Telemetry.http_response_attrs(context)
              )
            end
          end
        end
      end
    end
  end
end