td-client 0.8.78 → 0.8.79
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 +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
|