xamarin-test-cloud 2.0.0.pre1 → 2.0.0.pre2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +2 -1
- data/README.md +4 -4
- data/lib/xamarin-test-cloud/cli.rb +18 -19
- data/lib/xamarin-test-cloud/http/payload.rb +268 -0
- data/lib/xamarin-test-cloud/http/request.rb +46 -0
- data/lib/xamarin-test-cloud/http/retriable_client.rb +166 -0
- data/lib/xamarin-test-cloud/version.rb +1 -1
- metadata +33 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a5fb53a5aad5e3006ce408c5bcdc838fc9710b27
|
4
|
+
data.tar.gz: 08f838fe24bacc453b7b6b3479a3a23e467c376e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7715a00158c011e57f6671c25590577113bece273948659f9f01037147ab95a04d65546c7ee81515ad556a05a044412c65eca920598dc9cb6021aa35e87f3ed2
|
7
|
+
data.tar.gz: ff1dcb9dae040573210204b0dad1cc1a5343368b5148bceb477e9a1c9ea797ea836301715b9220d1c5327932ec91a15808524bb9195c62f9f681dcce429a9328
|
data/CHANGELOG.md
CHANGED
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.
|
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.
|
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
|
-
|
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 =
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
response
|
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
|
-
|
720
|
-
response
|
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
|
+
|
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.
|
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:
|
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
|