td-client 0.8.78 → 0.8.79
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/td/client.rb +1 -1
- data/lib/td/client/api.rb +30 -14
- data/lib/td/client/api/job.rb +2 -2
- data/lib/td/client/api/schedule.rb +1 -1
- data/lib/td/client/version.rb +1 -1
- data/spec/spec_helper.rb +2 -2
- data/spec/td/client/job_api_spec.rb +47 -0
- data/spec/td/client/sched_api_spec.rb +8 -0
- data/spec/td/client_sched_spec.rb +25 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 361771ba9d0d5fd00765c9ce956c2853ae4b3333
|
4
|
+
data.tar.gz: b6863fc4474b7598417d3e1fc776f585577b0b8b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9a36906b042f9fa5f41288a34ae679e54a80af6709f03ca41f94935728ca0450bf2f45adb5c63c348546448d5824c13db3351d6e1f3521963cd453d2f400ca8e
|
7
|
+
data.tar.gz: 3e564144569d8b2dd1b3ee1895a3a8117846802565d7581395deb5246ebc2588237c64868308e609e75dc9a8160c9a12f9d20687dfc254eb43a52623c51c87ac
|
data/lib/td/client.rb
CHANGED
@@ -356,7 +356,7 @@ class Client
|
|
356
356
|
raise ArgumentError, "'cron' option is required" unless opts[:cron] || opts['cron']
|
357
357
|
raise ArgumentError, "'query' option is required" unless opts[:query] || opts['query']
|
358
358
|
start = @api.create_schedule(name, opts)
|
359
|
-
return Time.parse(start)
|
359
|
+
return start && Time.parse(start)
|
360
360
|
end
|
361
361
|
|
362
362
|
# @param [String] name
|
data/lib/td/client/api.rb
CHANGED
@@ -235,16 +235,19 @@ private
|
|
235
235
|
|
236
236
|
# @param [String] url
|
237
237
|
# @param [Hash] params
|
238
|
+
# @param [Hash] opt
|
238
239
|
# @yield [response]
|
239
|
-
def get(url, params=nil, &block)
|
240
|
+
def get(url, params=nil, opt={}, &block)
|
240
241
|
guard_no_sslv3 do
|
241
|
-
do_get(url, params, &block)
|
242
|
+
do_get(url, params, opt, &block)
|
242
243
|
end
|
243
244
|
end
|
245
|
+
|
244
246
|
# @param [String] url
|
245
247
|
# @param [Hash] params
|
248
|
+
# @param [Hash] opt
|
246
249
|
# @yield [response]
|
247
|
-
def do_get(url, params=nil, &block)
|
250
|
+
def do_get(url, params=nil, opt={}, &block)
|
248
251
|
client, header = new_client
|
249
252
|
client.send_timeout = @send_timeout
|
250
253
|
client.receive_timeout = @read_timeout
|
@@ -267,24 +270,29 @@ private
|
|
267
270
|
# for both exceptions and 500+ errors retrying is enabled by default.
|
268
271
|
# The total number of retries cumulatively should not exceed 10 minutes / 600 seconds
|
269
272
|
response = nil
|
273
|
+
etag = nil
|
274
|
+
current_total_chunk_size = 0
|
270
275
|
begin # this block is to allow retry (redo) in the begin part of the begin-rescue block
|
271
276
|
begin
|
272
|
-
if
|
277
|
+
if etag
|
278
|
+
header['If-Range'] = etag
|
279
|
+
header['Range'] = "bytes=#{current_total_chunk_size}-"
|
280
|
+
else
|
273
281
|
current_total_chunk_size = 0
|
282
|
+
end
|
283
|
+
if block
|
274
284
|
response = client.get(target, params, header) {|res, chunk|
|
275
285
|
current_total_chunk_size += chunk.bytesize
|
276
286
|
block.call(res, chunk, current_total_chunk_size)
|
277
287
|
}
|
278
|
-
|
279
|
-
# XXX ext/openssl raises EOFError in case where underlying connection causes an error,
|
280
|
-
# and msgpack-ruby that used in block handles it as an end of stream == no exception.
|
281
|
-
# Therefor, check content size.
|
282
|
-
validate_content_length!(response, current_total_chunk_size) if @ssl
|
283
288
|
else
|
284
289
|
response = client.get(target, params, header)
|
285
|
-
|
286
|
-
validate_content_length!(response, response.body.bytesize) if @ssl
|
290
|
+
current_total_chunk_size += response.body.bytesize
|
287
291
|
end
|
292
|
+
# XXX ext/openssl raises EOFError in case where underlying connection causes an error,
|
293
|
+
# but httpclient ignores it. Therefor, check content size.
|
294
|
+
# https://github.com/nahi/httpclient/issues/296
|
295
|
+
validate_content_length!(response, current_total_chunk_size)
|
288
296
|
|
289
297
|
status = response.code
|
290
298
|
# retry if the HTTP error code is 500 or higher and we did not run out of retrying attempts
|
@@ -296,7 +304,9 @@ private
|
|
296
304
|
redo # restart from beginning of do-while loop
|
297
305
|
end
|
298
306
|
rescue Errno::ECONNREFUSED, Errno::ECONNRESET, Timeout::Error, EOFError, OpenSSL::SSL::SSLError, SocketError, IncompleteError => e
|
299
|
-
if
|
307
|
+
if opt[:resume]
|
308
|
+
etag = response.header['ETag'].first
|
309
|
+
elsif block_given?
|
300
310
|
raise e
|
301
311
|
end
|
302
312
|
$stderr.print "#{e.class}: #{e.message}. "
|
@@ -328,8 +338,14 @@ private
|
|
328
338
|
end
|
329
339
|
|
330
340
|
def validate_content_length!(response, body_size)
|
331
|
-
content_length = response.header['Content-
|
332
|
-
|
341
|
+
if content_length = response.header['Content-Range'].first
|
342
|
+
content_length = content_length[/\d+$/]
|
343
|
+
else
|
344
|
+
content_length = response.header['Content-Length'].first
|
345
|
+
end
|
346
|
+
if content_length && content_length.to_i != body_size
|
347
|
+
raise IncompleteError, "#{content_length} bytes expected, but got #{body_size} bytes"
|
348
|
+
end
|
333
349
|
end
|
334
350
|
|
335
351
|
def inflate_body(response)
|
data/lib/td/client/api/job.rb
CHANGED
@@ -214,8 +214,8 @@ module Job
|
|
214
214
|
def job_result_raw(job_id, format, io = nil, &block)
|
215
215
|
body = nil
|
216
216
|
|
217
|
-
get("/v3/job/result/#{e job_id}", {'format'=>format}) {|res, chunk, current_total_chunk_size|
|
218
|
-
|
217
|
+
get("/v3/job/result/#{e job_id}", {'format'=>format}, {:resume => true}) {|res, chunk, current_total_chunk_size|
|
218
|
+
unless res.ok?
|
219
219
|
raise_error("Get job result failed", res)
|
220
220
|
end
|
221
221
|
|
data/lib/td/client/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -10,10 +10,10 @@ unless ENV['APPVEYOR']
|
|
10
10
|
require 'simplecov'
|
11
11
|
require 'coveralls'
|
12
12
|
|
13
|
-
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
13
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([
|
14
14
|
SimpleCov::Formatter::HTMLFormatter,
|
15
15
|
Coveralls::SimpleCov::Formatter
|
16
|
-
]
|
16
|
+
])
|
17
17
|
SimpleCov.start("test_frameworks")
|
18
18
|
end
|
19
19
|
rescue NameError
|
@@ -311,6 +311,53 @@ describe 'Job API' do
|
|
311
311
|
api.job_result_raw(12345, 'json').should == 'raw binary'
|
312
312
|
end
|
313
313
|
end
|
314
|
+
|
315
|
+
let :packed do
|
316
|
+
# Hard code fixture data to make the size stable
|
317
|
+
# s = StringIO.new
|
318
|
+
# Zlib::GzipWriter.wrap(s) do |f|
|
319
|
+
# pk = MessagePack::Packer.new(f)
|
320
|
+
# pk.write('hello')
|
321
|
+
# pk.write('world')
|
322
|
+
# pk.flush
|
323
|
+
# end
|
324
|
+
# s.string
|
325
|
+
"\x1F\x8B\b\x00#\xA1\x93T\x00\x03[\x9A\x91\x9A\x93\x93\xBF\xB4<\xBF('\x05\x00e 0\xB3\f\x00\x00\x00".force_encoding(Encoding::ASCII_8BIT)
|
326
|
+
end
|
327
|
+
|
328
|
+
it 'can resume' do
|
329
|
+
stub_api_request(:get, '/v3/job/result/12345').
|
330
|
+
with(:query => {'format' => 'msgpack.gz'}).
|
331
|
+
to_return(
|
332
|
+
:headers => {
|
333
|
+
'Content-Length' => 32,
|
334
|
+
'Etag' => '"abcdefghijklmn"',
|
335
|
+
},
|
336
|
+
:body => packed[0, 20]
|
337
|
+
)
|
338
|
+
stub_api_request(:get, '/v3/job/result/12345').
|
339
|
+
with(
|
340
|
+
:headers => {
|
341
|
+
'If-Range' => '"abcdefghijklmn"',
|
342
|
+
'Range' => 'bytes=20-',
|
343
|
+
},
|
344
|
+
:query => {'format' => 'msgpack.gz'}
|
345
|
+
).
|
346
|
+
to_return(
|
347
|
+
:headers => {
|
348
|
+
'Content-Length' => 12,
|
349
|
+
'Content-Range' => 'bytes 20-31/32',
|
350
|
+
'Etag' => '"abcdefghijklmn"',
|
351
|
+
},
|
352
|
+
:body => packed[20, 12]
|
353
|
+
)
|
354
|
+
expect(api).to receive(:sleep).once
|
355
|
+
expect($stderr).to receive(:print)
|
356
|
+
expect($stderr).to receive(:puts)
|
357
|
+
sio = StringIO.new(''.force_encoding(Encoding::ASCII_8BIT))
|
358
|
+
api.job_result_raw(12345, 'msgpack.gz', sio)
|
359
|
+
sio.string.should == packed
|
360
|
+
end
|
314
361
|
end
|
315
362
|
|
316
363
|
describe 'kill' do
|
@@ -23,6 +23,14 @@ describe 'Schedule API' do
|
|
23
23
|
api.create_schedule(sched_name, opts.merge('type' => 'hive')).should == start.to_s
|
24
24
|
end
|
25
25
|
|
26
|
+
it 'should create a dummy schedule' do
|
27
|
+
stub_api_request(:post, "/v3/schedule/create/#{e(sched_name)}").
|
28
|
+
with(:body => opts.merge('type' => 'hive')).
|
29
|
+
to_return(:body => {'name' => sched_name, 'start' => nil}.to_json)
|
30
|
+
|
31
|
+
api.create_schedule(sched_name, opts.merge('type' => 'hive')).should be_nil
|
32
|
+
end
|
33
|
+
|
26
34
|
it 'should return 422 error with invalid name' do
|
27
35
|
name = '1'
|
28
36
|
err_msg = "Validation failed: Name is too short" # " (minimum is 3 characters)"
|
@@ -15,6 +15,31 @@ describe 'Schedule Command' do
|
|
15
15
|
client
|
16
16
|
end
|
17
17
|
|
18
|
+
describe 'create' do
|
19
|
+
let :opts do
|
20
|
+
{:database => db_name, :cron => '', :type => 'hive', :query => 'select 1;'}
|
21
|
+
end
|
22
|
+
|
23
|
+
before do
|
24
|
+
stub_api_request(:post, "/v3/schedule/create/#{e(sched_name)}").
|
25
|
+
with(:body => opts).
|
26
|
+
to_return(:body => {'name' => sched_name, 'start' => start}.to_json)
|
27
|
+
end
|
28
|
+
context 'start is now' do
|
29
|
+
let (:start){ Time.now.round }
|
30
|
+
it 'returns Time object' do
|
31
|
+
client.create_schedule(sched_name, opts).should == start
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'start is nil' do
|
36
|
+
let (:start){ nil }
|
37
|
+
it do
|
38
|
+
client.create_schedule(sched_name, opts).should == start
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
18
43
|
describe 'history' do
|
19
44
|
let :opts do
|
20
45
|
{'database' => db_name}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: td-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.79
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Treasure Data, Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-04-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: msgpack
|