File: rest.rb

package info (click to toggle)
ruby-aws-sdk-core 3.104.3-3%2Bdeb11u2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 1,444 kB
  • sloc: ruby: 11,201; makefile: 4
file content (198 lines) | stat: -rw-r--r-- 6,390 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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# frozen_string_literal: true

require 'aws-eventstream'

module Aws
  module Stubbing
    module Protocols
      class Rest

        include Seahorse::Model::Shapes

        def stub_data(api, operation, data)
          resp = new_http_response
          apply_status_code(operation, resp, data)
          apply_headers(operation, resp, data)
          apply_body(api, operation, resp, data)
          resp
        end

        private

        def new_http_response
          resp = Seahorse::Client::Http::Response.new
          resp.status_code = 200
          resp.headers["x-amzn-RequestId"] = "stubbed-request-id"
          resp
        end

        def apply_status_code(operation, resp, data)
          operation.output.shape.members.each do |member_name, member_ref|
            if member_ref.location == 'statusCode'
              resp.status_code = data[member_name] if data.key?(member_name)
            end
          end
        end

        def apply_headers(operation, resp, data)
          Aws::Rest::Request::Headers.new(operation.output).apply(resp, data)
        end

        def apply_body(api, operation, resp, data)
          resp.body = build_body(api, operation, data)
        end

        def build_body(api, operation, data)
          rules = operation.output
          if head_operation(operation)
            ''
          elsif streaming?(rules)
            data[rules[:payload]]
          elsif rules[:payload]
            body_for(api, operation, rules[:payload_member], data[rules[:payload]])
          else
            filtered = Seahorse::Model::Shapes::ShapeRef.new(
              shape: Seahorse::Model::Shapes::StructureShape.new.tap do |s|
                rules.shape.members.each do |member_name, member_ref|
                  s.add_member(member_name, member_ref) if member_ref.location.nil?
                end
              end
            )
            body_for(api, operation, filtered, data)
          end
        end

        def streaming?(ref)
          if ref[:payload]
            case ref[:payload_member].shape
            when StringShape then true
            when BlobShape then true
            else false
            end
          else
            false
          end
        end

        def head_operation(operation)
          operation.http_method == 'HEAD'
        end

        def eventstream?(rules)
          rules.eventstream
        end

        def encode_eventstream_response(rules, data, builder)
          data.inject('') do |stream, event_data|
            # construct message headers and payload
            opts = {headers: {}}
            case event_data.delete(:message_type)
            when 'event'
              encode_event(opts, rules, event_data, builder)
            when 'error'
              # errors are unmodeled
              encode_error(opts, event_data)
            when 'exception'
              # Pending
              raise 'Stubbing :exception event is not supported'
            end
            [stream, Aws::EventStream::Encoder.new.encode(
              Aws::EventStream::Message.new(opts)
            )].pack('a*a*')
          end
        end

        def encode_error(opts, event_data)
          opts[:headers][':error-message'] = Aws::EventStream::HeaderValue.new(
            value: event_data[:error_message],
            type: 'string'
          )
          opts[:headers][':error-code'] = Aws::EventStream::HeaderValue.new(
            value: event_data[:error_code],
            type: 'string'
          )
          opts[:headers][':message-type'] = Aws::EventStream::HeaderValue.new(
            value: 'error',
            type: 'string'
          )
          opts
        end

        def encode_unknown_event(opts, event_type, event_data)
          # right now h2 events are only rest_json
          opts[:payload] = StringIO.new(JSON.dump(event_data))
          opts[:headers][':event-type'] = Aws::EventStream::HeaderValue.new(
            value: event_type.to_s,
            type: 'string'
          )
          opts[:headers][':message-type'] = Aws::EventStream::HeaderValue.new(
            value: 'event',
            type: 'string'
          )
          opts
        end

        def encode_modeled_event(opts, rules, event_type, event_data, builder)
          event_ref = rules.shape.member(event_type)
          explicit_payload = false
          implicit_payload_members = {}
          event_ref.shape.members.each do |name, ref|
            if ref.eventpayload
              explicit_payload = true
            else
              implicit_payload_members[name] = ref
            end
          end

          if !explicit_payload && !implicit_payload_members.empty?
            unless implicit_payload_members.size > 1
              m_name, _ = implicit_payload_members.first
              value = {}
              value[m_name] = event_data[m_name]
              opts[:payload] = StringIO.new(builder.new(event_ref).serialize(value))
            end
          end

          event_data.each do |k, v|
            member_ref = event_ref.shape.member(k)
            if member_ref.eventheader
              opts[:headers][member_ref.location_name] = Aws::EventStream::HeaderValue.new(
                value: v,
                type: member_ref.eventheader_type
              )
            elsif member_ref.eventpayload
              case member_ref.eventpayload_type
              when 'string'
                opts[:payload] = StringIO.new(v)
              when 'blob'
                opts[:payload] = v
              when 'structure'
                opts[:payload] = StringIO.new(builder.new(member_ref).serialize(v))
              end
            end
          end
          opts[:headers][':event-type'] = Aws::EventStream::HeaderValue.new(
            value: event_ref.location_name,
            type: 'string'
          )
          opts[:headers][':message-type'] = Aws::EventStream::HeaderValue.new(
            value: 'event',
            type: 'string'
          )
          opts
        end

        def encode_event(opts, rules, event_data, builder)
          event_type = event_data.delete(:event_type)

          if rules.shape.member?(event_type)
            encode_modeled_event(opts, rules, event_type, event_data, builder)
          else
            encode_unknown_event(opts, event_type, event_data)
          end
        end

      end
    end
  end
end