xamarin-test-cloud 2.0.0.pre1 → 2.0.0.pre2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b8ce3574021504d1c37d218b7816a8be26b0e958
4
- data.tar.gz: 5eee5e4df2534d4b7e1211ff4b05863b2ce6b24c
3
+ metadata.gz: a5fb53a5aad5e3006ce408c5bcdc838fc9710b27
4
+ data.tar.gz: 08f838fe24bacc453b7b6b3479a3a23e467c376e
5
5
  SHA512:
6
- metadata.gz: 879ebe1c1ce04963405374a2b5510eac9bb1e0ae8a8e902d7956242da95e47346df7874d18b5173d14876f774859ecd5eb9f870ec7d6fcd216fe1f1bb390c7cc
7
- data.tar.gz: 3c936024d954fe9702e9617b733fc238ece5c777d5ee5f813b6b2d58523acd660f67b6c1485d5ee7a2876af51f6f1a036d63a2bc0535384a16f35c0c32ebc2a6
6
+ metadata.gz: 7715a00158c011e57f6671c25590577113bece273948659f9f01037147ab95a04d65546c7ee81515ad556a05a044412c65eca920598dc9cb6021aa35e87f3ed2
7
+ data.tar.gz: ff1dcb9dae040573210204b0dad1cc1a5343368b5148bceb477e9a1c9ea797ea836301715b9220d1c5327932ec91a15808524bb9195c62f9f681dcce429a9328
data/CHANGELOG.md CHANGED
@@ -1,6 +1,7 @@
1
1
  ### 2.0.0
2
2
 
3
- * Set minimum ruby verision to 2.0
3
+ * Replace RestClient with HTTPClient
4
+ * Set minimum ruby version to 2.0
4
5
  * Gem does not work in Windows environment: ffi cannot be found. #34
5
6
 
6
7
  ### 1.1.2
data/README.md CHANGED
@@ -10,9 +10,9 @@
10
10
 
11
11
  ```
12
12
  $ bundle update
13
- $ rake test # All tests.
14
- $ rake unit # Unit tests.
15
- $ rake integration # Integration tests.
16
- $ rake spec # rspec tests
13
+ $ bundle exec rake test # All tests.
14
+ $ bundle exec rake unit # Unit tests.
15
+ $ bundle exec rake integration # Integration tests.
16
+ $ bundle exec rake spec # rspec tests
17
17
  ```
18
18
 
@@ -4,7 +4,6 @@ require 'erb'
4
4
  require 'rubygems'
5
5
  require 'zip'
6
6
  require 'digest'
7
- require 'rest_client'
8
7
  require 'json'
9
8
  require 'rbconfig'
10
9
  require 'tmpdir'
@@ -12,6 +11,8 @@ require 'fileutils'
12
11
  require 'retriable'
13
12
  require 'xamarin-test-cloud/version'
14
13
  require 'xamarin-test-cloud/retriable_options'
14
+ require 'xamarin-test-cloud/http/request'
15
+ require 'xamarin-test-cloud/http/retriable_client'
15
16
  require 'securerandom'
16
17
  require 'open3'
17
18
 
@@ -391,7 +392,6 @@ module XamarinTestCloud
391
392
  if debug?
392
393
  log "Packaging gems in: #{tmpdir}"
393
394
  end
394
- start_at = Time.now
395
395
 
396
396
  server = verify_app_and_extract_test_server
397
397
 
@@ -471,14 +471,13 @@ module XamarinTestCloud
471
471
  puts "Will upload to file path: #{self.endpoint_path}"
472
472
  end
473
473
 
474
-
475
- response = http_post(endpoint_path, upload_data) do |response, request, result, &block|
474
+ response = http_post(endpoint_path, upload_data) do |response, request|
476
475
  if debug?
477
476
  puts "Request url: #{request.url}"
478
477
  puts "Response code: #{response.code}"
479
478
  puts "Response body: #{response.body}"
480
479
  end
481
- case response.code
480
+ case response.status_code
482
481
  when 200..202
483
482
  response
484
483
  when 400
@@ -496,7 +495,7 @@ module XamarinTestCloud
496
495
  end
497
496
  end
498
497
 
499
- return :status => response.code, :body => JSON.parse(response)
498
+ return :status => response.status_code, :body => JSON.parse(response.body)
500
499
 
501
500
  end
502
501
 
@@ -562,7 +561,6 @@ module XamarinTestCloud
562
561
 
563
562
  response = http_post('check_hash', out)
564
563
 
565
-
566
564
  cache_status = JSON.parse(response)
567
565
 
568
566
  log_header('Gathering files based on negotiation')
@@ -701,26 +699,27 @@ module XamarinTestCloud
701
699
  def http_post(address, args = {}, &block)
702
700
  args['uploader_version'] = XamarinTestCloud::VERSION
703
701
  args['session_id'] = session_id
704
- exec_options = {}
702
+
703
+ request = XamarinTestCloud::HTTP::Request.new(address, args)
704
+
705
+ exec_options = {:header => { 'Content-Type' => 'application/x-www-form-urlencoded' }}
705
706
  if ENV['XTC_USERNAME'] && ENV['XTC_PASSWORD']
706
707
  exec_options[:user] = ENV['XTC_USERNAME']
707
708
  exec_options[:password] = ENV['XTC_PASSWORD']
708
709
  end
709
710
 
711
+ client = XamarinTestCloud::HTTP::RetriableClient.new("#{host}/")
712
+
710
713
  if block_given?
711
- exec_options = exec_options.merge({:method => :post, :url => "#{host}/#{address}", :payload => args,
712
- :timeout => 90000000,
713
- :open_timeout => 15,
714
- :headers => {:content_type => 'multipart/form-data'}})
715
- response = RestClient::Request.execute(exec_options) do |response, request, result, &other_block|
716
- block.call(response, request, result, &other_block)
717
- end
714
+ exec_options[:header] = {'Content-Type' => 'multipart/form-data'}
715
+ exec_options[:timeout] = 90000000
716
+ response = client.post(request, exec_options)
717
+ block.call(response, request)
718
+ response
718
719
  else
719
- exec_options = exec_options.merge(:method => :post, :url => "#{host}/#{address}", :payload => args)
720
- response = RestClient::Request.execute(exec_options)
720
+ response = client.post(request, exec_options)
721
+ response.body
721
722
  end
722
-
723
- response.body
724
723
  end
725
724
 
726
725
  def is_windows?
@@ -0,0 +1,268 @@
1
+ # Adapted from RestClient payload.rb and used under the following license:
2
+ #
3
+ # The MIT License (MIT)
4
+ #
5
+ # Copyright (c) 2008-2014 Rest Client Authors
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"), to deal
9
+ # in the Software without restriction, including without limitation the rights
10
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # copies of the Software, and to permit persons to whom the Software is
12
+ # furnished to do so, subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included in all
15
+ # copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ # SOFTWARE.
24
+
25
+ require 'tempfile'
26
+ require 'stringio'
27
+ require 'mime/types'
28
+
29
+ module XamarinTestCloud
30
+ module HTTP
31
+
32
+ # Copied from rest-client
33
+ module Payload
34
+ extend self
35
+
36
+
37
+ def generate(params)
38
+ if params.is_a?(String)
39
+ Base.new(params)
40
+ elsif params.is_a?(Hash)
41
+ if params.delete(:multipart) == true || has_file?(params)
42
+ Multipart.new(params)
43
+ else
44
+ UrlEncoded.new(params)
45
+ end
46
+ elsif params.respond_to?(:read)
47
+ Streamed.new(params)
48
+ else
49
+ nil
50
+ end
51
+ end
52
+
53
+ def has_file?(params)
54
+ params.any? do |_, v|
55
+ case v
56
+ when Hash
57
+ has_file?(v)
58
+ when Array
59
+ has_file_array?(v)
60
+ else
61
+ v.respond_to?(:path) && v.respond_to?(:read)
62
+ end
63
+ end
64
+ end
65
+
66
+ def has_file_array?(params)
67
+ params.any? do |v|
68
+ case v
69
+ when Hash
70
+ has_file?(v)
71
+ when Array
72
+ has_file_array?(v)
73
+ else
74
+ v.respond_to?(:path) && v.respond_to?(:read)
75
+ end
76
+ end
77
+ end
78
+
79
+ class Base
80
+ def initialize(params)
81
+ build_stream(params)
82
+ end
83
+
84
+ def build_stream(params)
85
+ @stream = StringIO.new(params)
86
+ @stream.seek(0)
87
+ end
88
+
89
+ def read(bytes=nil)
90
+ @stream.read(bytes)
91
+ end
92
+
93
+ alias :to_s :read
94
+
95
+ # Flatten parameters by converting hashes of hashes to flat hashes
96
+ # {keys1 => {keys2 => value}} will be transformed into [keys1[key2], value]
97
+ def flatten_params(params, parent_key = nil)
98
+ result = []
99
+ params.each do |key, value|
100
+ calculated_key = parent_key ? "#{parent_key}[#{handle_key(key)}]" : handle_key(key)
101
+ if value.is_a? Hash
102
+ result += flatten_params(value, calculated_key)
103
+ elsif value.is_a? Array
104
+ result += flatten_params_array(value, calculated_key)
105
+ else
106
+ result << [calculated_key, value]
107
+ end
108
+ end
109
+ result
110
+ end
111
+
112
+ def flatten_params_array(value, calculated_key)
113
+ result = []
114
+ value.each do |elem|
115
+ if elem.is_a? Hash
116
+ result += flatten_params(elem, calculated_key)
117
+ elsif elem.is_a? Array
118
+ result += flatten_params_array(elem, calculated_key)
119
+ else
120
+ result << ["#{calculated_key}[]", elem]
121
+ end
122
+ end
123
+ result
124
+ end
125
+
126
+ def headers
127
+ {'Content-Length' => size.to_s}
128
+ end
129
+
130
+ def size
131
+ @stream.size
132
+ end
133
+
134
+ alias :length :size
135
+
136
+ def close
137
+ @stream.close unless @stream.closed?
138
+ end
139
+
140
+ def inspect
141
+ result = to_s.inspect
142
+ @stream.seek(0)
143
+ result
144
+ end
145
+
146
+ def short_inspect
147
+ (size > 500 ? "#{size} byte(s) length" : inspect)
148
+ end
149
+
150
+ end
151
+
152
+ class Streamed < Base
153
+ def build_stream(params = nil)
154
+ @stream = params
155
+ end
156
+
157
+ def size
158
+ if @stream.respond_to?(:size)
159
+ @stream.size
160
+ elsif @stream.is_a?(IO)
161
+ @stream.stat.size
162
+ end
163
+ end
164
+
165
+ alias :length :size
166
+ end
167
+
168
+ class UrlEncoded < Base
169
+ def build_stream(params = nil)
170
+ @stream = StringIO.new(flatten_params(params).collect do |entry|
171
+ "#{entry[0]}=#{handle_key(entry[1])}"
172
+ end.join("&"))
173
+ @stream.seek(0)
174
+ end
175
+
176
+ # for UrlEncoded escape the keys
177
+ def handle_key key
178
+ Parser.escape(key.to_s, Escape)
179
+ end
180
+
181
+ def headers
182
+ super.merge({'Content-Type' => 'application/x-www-form-urlencoded'})
183
+ end
184
+
185
+ Parser = URI.const_defined?(:Parser) ? URI::Parser.new : URI
186
+ Escape = Regexp.new("[^#{URI::PATTERN::UNRESERVED}]")
187
+ end
188
+
189
+ class Multipart < Base
190
+ EOL = "\r\n"
191
+
192
+ def build_stream(params)
193
+ b = "--#{boundary}"
194
+
195
+ @stream = Tempfile.new("RESTClient.Stream.#{rand(1000)}")
196
+ @stream.binmode
197
+ @stream.write(b + EOL)
198
+
199
+ if params.is_a? Hash
200
+ x = flatten_params(params)
201
+ else
202
+ x = params
203
+ end
204
+
205
+ last_index = x.length - 1
206
+ x.each_with_index do |a, index|
207
+ k, v = * a
208
+ if v.respond_to?(:read) && v.respond_to?(:path)
209
+ create_file_field(@stream, k, v)
210
+ else
211
+ create_regular_field(@stream, k, v)
212
+ end
213
+ @stream.write(EOL + b)
214
+ @stream.write(EOL) unless last_index == index
215
+ end
216
+ @stream.write('--')
217
+ @stream.write(EOL)
218
+ @stream.seek(0)
219
+ end
220
+
221
+ def create_regular_field(s, k, v)
222
+ s.write("Content-Disposition: form-data; name=\"#{k}\"")
223
+ s.write(EOL)
224
+ s.write(EOL)
225
+ s.write(v)
226
+ end
227
+
228
+ def create_file_field(s, k, v)
229
+ begin
230
+ s.write("Content-Disposition: form-data;")
231
+ s.write(" name=\"#{k}\";") unless (k.nil? || k=='')
232
+ s.write(" filename=\"#{v.respond_to?(:original_filename) ? v.original_filename : File.basename(v.path)}\"#{EOL}")
233
+ s.write("Content-Type: #{v.respond_to?(:content_type) ? v.content_type : mime_for(v.path)}#{EOL}")
234
+ s.write(EOL)
235
+ while (data = v.read(8124))
236
+ s.write(data)
237
+ end
238
+ ensure
239
+ v.close if v.respond_to?(:close)
240
+ end
241
+ end
242
+
243
+ def mime_for(path)
244
+ mime = MIME::Types.type_for path
245
+ mime.empty? ? 'text/plain' : mime[0].content_type
246
+ end
247
+
248
+ def boundary
249
+ @boundary ||= rand(1_000_000).to_s
250
+ end
251
+
252
+ # for Multipart do not escape the keys
253
+ def handle_key key
254
+ key
255
+ end
256
+
257
+ def headers
258
+ super.merge({'Content-Type' => %Q{multipart/form-data; boundary=#{boundary}}})
259
+ end
260
+
261
+ def close
262
+ @stream.close!
263
+ end
264
+ end
265
+
266
+ end
267
+ end
268
+ end
@@ -0,0 +1,46 @@
1
+ module XamarinTestCloud
2
+ module HTTP
3
+
4
+ class RequestError < RuntimeError; ; end
5
+
6
+ # A representation of an HTTP request that can be passed passed to the HTTP
7
+ # client as an argument for `get` or `post`.
8
+ # @!visibility private
9
+ class Request
10
+ attr_reader :route, :params
11
+
12
+ def initialize(route, params={})
13
+ @route = route
14
+ @params = params
15
+ end
16
+
17
+ # Create a new Request from `route` and `parameters`.
18
+ #
19
+ # @param [String] route The http route for the new request.
20
+ # @param [Array, Hash] parameters An Array or Hash of parameters.
21
+ # @return [Request] A new Request for `route` with `parameters`.
22
+ # @raise [RequestError] Raises an error if the parameters cannot be
23
+ # converted to JSON
24
+ def self.request(route, parameters)
25
+ Request.new(route, Request.data(parameters))
26
+ end
27
+
28
+ private
29
+
30
+ # Converts `parameters` to JSON.
31
+ #
32
+ # @param [Array, Hash] parameters An Array or Hash of parameters.
33
+ # @return [String] A JSON formatted string that represents the parameters.
34
+ # @raise [RequestError] Raises an error if the parameters cannot be
35
+ # converted to JSON
36
+ def self.data(parameters)
37
+ begin
38
+ JSON.generate(parameters)
39
+ rescue *[TypeError, JSON::GeneratorError] => e
40
+ raise RequestError, "#{e}: could not generate JSON from '#{parameters}'"
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+
@@ -0,0 +1,166 @@
1
+ require 'httpclient'
2
+ require 'xamarin-test-cloud/http/payload'
3
+
4
+ module XamarinTestCloud
5
+ module HTTP
6
+
7
+ class Error < RuntimeError; ; end
8
+
9
+ # An HTTP client that retries its connection on errors and can time out.
10
+ # @!visibility private
11
+ class RetriableClient
12
+ attr_reader :client
13
+
14
+ # @!visibility private
15
+ RETRY_ON =
16
+ [
17
+ # Raised for indicating a connection timeout error
18
+ HTTPClient::ConnectTimeoutError,
19
+
20
+ # Raised for indicating a request sending timeout error
21
+ HTTPClient::SendTimeoutError,
22
+
23
+ # Raised for indicating a response receiving timeout error.
24
+ HTTPClient::ReceiveTimeoutError,
25
+
26
+ Errno::ECONNREFUSED,
27
+
28
+ # The server sent a partial response
29
+ # Errno::ECONNRESET,
30
+ #
31
+ # Client sent TCP reset (RST) before server has accepted the
32
+ # connection requested by client.
33
+ Errno::ECONNABORTED,
34
+ ]
35
+
36
+ # @!visibility private
37
+ HEADER =
38
+ {
39
+ 'Content-Type' => 'application/json;charset=utf-8'
40
+ }
41
+
42
+ # Creates a new retriable client.
43
+ #
44
+ # This initializer takes multiple options. If the option is not
45
+ # documented, it should be considered _private_. You use undocumented
46
+ # options at your own risk.
47
+ #
48
+ # @param [String] endpoint The server to make the HTTP request
49
+ # on.
50
+ # @param [Hash] options Control the retry, timeout, and interval.
51
+ # @option options [Number] :retries (5) How often to retry.
52
+ # @option options [Number] :timeout (5) How long to wait for a response
53
+ # before timing out.
54
+ # @option options [Number] :interval (0.5) How long to sleep between
55
+ # retries.
56
+ def initialize(endpoint, options = {})
57
+ @client = options[:client] || ::HTTPClient.new
58
+ @endpoint = endpoint
59
+ @retries = options.fetch(:retries, 3)
60
+ @timeout = options.fetch(:timeout, 15)
61
+ @connect_timeout = options.fetch(:connect_timeout, 15)
62
+ @interval = options.fetch(:interval, 0.5)
63
+ @on_error = {}
64
+ end
65
+
66
+ # @!visibility private
67
+ def on_error(type, &block)
68
+ @on_error[type] = block
69
+ end
70
+
71
+ # Make an HTTP get request.
72
+ #
73
+ # This method takes multiple options. If the option is not documented,
74
+ # it should be considered _private_. You use undocumented options at
75
+ # your own risk.
76
+ #
77
+ # @param [Calabash::HTTP::Request] request The request.
78
+ # @param [Hash] options Control the retry, timeout, and interval.
79
+ # @option options [Number] :retries (5) How often to retry.
80
+ # @option options [Number] :timeout (5) How long to wait for a response
81
+ # before timing out.
82
+ # @option options [Number] :interval (0.5) How long to sleep between
83
+ # retries.
84
+ def get(request, options={})
85
+ request(request, :get, options)
86
+ end
87
+
88
+ # Make an HTTP post request.
89
+ #
90
+ # This method takes multiple options. If the option is not documented,
91
+ # it should be considered _private_. You use undocumented options at
92
+ # your own risk.
93
+ #
94
+ # @param [Calabash::HTTP::Request] request The request.
95
+ # @param [Hash] options Control the retry, timeout, and interval.
96
+ # @option options [Number] :retries (3) How many times to retry.
97
+ # @option options [Number] :timeout (15) How long to wait for a response
98
+ # before timing out.
99
+ # @option options [Number] :connect_timeout (15) How long to wait for a
100
+ # connection.
101
+ # @option options [Number] :interval (0.5) How long to sleep between
102
+ # retries.
103
+ def post(request, options={})
104
+ request(request, :post, options)
105
+ end
106
+
107
+ private
108
+
109
+ def request(request, request_method, options={})
110
+ retries = options.fetch(:retries, @retries)
111
+ timeout = options.fetch(:timeout, @timeout)
112
+ connect_timeout = options.fetch(:timeout, @connect_timeout)
113
+ interval = options.fetch(:interval, @interval)
114
+ header = options.fetch(:header, HEADER)
115
+
116
+ start_time = Time.now
117
+ last_error = nil
118
+
119
+ client = @client.dup
120
+ client.receive_timeout = timeout
121
+ client.connect_timeout = connect_timeout
122
+
123
+ if options.fetch(:user, nil) && options.fetch(:password, nil)
124
+ client.set_auth(options.fetch(:user), options.fetch(:password))
125
+ end
126
+
127
+ retries.times do |i|
128
+ first_try = i == 0
129
+
130
+ # Subtract the aggregate time we've spent thus far to make sure we're
131
+ # not exceeding the request timeout across retries.
132
+ time_diff = start_time + timeout - Time.now
133
+
134
+
135
+ if time_diff <= 0
136
+ raise HTTP::Error, 'Timeout exceeded'
137
+ end
138
+
139
+ client.receive_timeout = [time_diff, client.receive_timeout].min
140
+
141
+ payload = Payload.generate(request.params)
142
+
143
+ header.merge!(payload.headers) if payload
144
+
145
+ begin
146
+ return client.send(request_method, @endpoint + request.route,
147
+ payload.to_s, header)
148
+ rescue *RETRY_ON => e
149
+
150
+ if first_try
151
+ if @on_error[e.class]
152
+ @on_error[e.class].call(@endpoint)
153
+ end
154
+ end
155
+
156
+ last_error = e
157
+ sleep interval
158
+ end
159
+ end
160
+
161
+ raise HTTP::Error, last_error
162
+ end
163
+ end
164
+ end
165
+ end
166
+
@@ -1,3 +1,3 @@
1
1
  module XamarinTestCloud
2
- VERSION = "2.0.0.pre1"
2
+ VERSION = "2.0.0.pre2"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xamarin-test-cloud
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.pre1
4
+ version: 2.0.0.pre2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Karl Krukow
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-11-24 00:00:00.000000000 Z
12
+ date: 2016-01-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: thor
@@ -79,20 +79,6 @@ dependencies:
79
79
  - - "~>"
80
80
  - !ruby/object:Gem::Version
81
81
  version: '1.1'
82
- - !ruby/object:Gem::Dependency
83
- name: rest-client
84
- requirement: !ruby/object:Gem::Requirement
85
- requirements:
86
- - - "~>"
87
- - !ruby/object:Gem::Version
88
- version: '1.6'
89
- type: :runtime
90
- prerelease: false
91
- version_requirements: !ruby/object:Gem::Requirement
92
- requirements:
93
- - - "~>"
94
- - !ruby/object:Gem::Version
95
- version: '1.6'
96
82
  - !ruby/object:Gem::Dependency
97
83
  name: retriable
98
84
  requirement: !ruby/object:Gem::Requirement
@@ -113,6 +99,34 @@ dependencies:
113
99
  - - "<"
114
100
  - !ruby/object:Gem::Version
115
101
  version: '2.1'
102
+ - !ruby/object:Gem::Dependency
103
+ name: httpclient
104
+ requirement: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - "~>"
107
+ - !ruby/object:Gem::Version
108
+ version: '2.6'
109
+ type: :runtime
110
+ prerelease: false
111
+ version_requirements: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - "~>"
114
+ - !ruby/object:Gem::Version
115
+ version: '2.6'
116
+ - !ruby/object:Gem::Dependency
117
+ name: mime-types
118
+ requirement: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - "~>"
121
+ - !ruby/object:Gem::Version
122
+ version: '2.99'
123
+ type: :runtime
124
+ prerelease: false
125
+ version_requirements: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - "~>"
128
+ - !ruby/object:Gem::Version
129
+ version: '2.99'
116
130
  - !ruby/object:Gem::Dependency
117
131
  name: rake
118
132
  requirement: !ruby/object:Gem::Requirement
@@ -259,6 +273,9 @@ files:
259
273
  - README.md
260
274
  - bin/test-cloud
261
275
  - lib/xamarin-test-cloud/cli.rb
276
+ - lib/xamarin-test-cloud/http/payload.rb
277
+ - lib/xamarin-test-cloud/http/request.rb
278
+ - lib/xamarin-test-cloud/http/retriable_client.rb
262
279
  - lib/xamarin-test-cloud/retriable_options.rb
263
280
  - lib/xamarin-test-cloud/version.rb
264
281
  homepage: http://xamarin.com/test-cloud