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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b7b08bc82aed5007cc2f9b0500847ca78520cc78
4
- data.tar.gz: 1fa61539241cce5a9152f23629f46c5c95a7ec01
3
+ metadata.gz: 361771ba9d0d5fd00765c9ce956c2853ae4b3333
4
+ data.tar.gz: b6863fc4474b7598417d3e1fc776f585577b0b8b
5
5
  SHA512:
6
- metadata.gz: cd680197fab594cf321145804b06b99d9070cecb97115625b7a489d94b4baae685f47744a866172f20baf6d50b7e9c9eca0287b20ab0d4692cfeec38aa5e9448
7
- data.tar.gz: 64fc10d47a765efc4bab85fb24fa12b0cbc459336467f21765007057807117c6177f936f642c84da608d15fa09ddb9dacf5e08a3b50fcb96f900860f78c9c02e
6
+ metadata.gz: 9a36906b042f9fa5f41288a34ae679e54a80af6709f03ca41f94935728ca0450bf2f45adb5c63c348546448d5824c13db3351d6e1f3521963cd453d2f400ca8e
7
+ data.tar.gz: 3e564144569d8b2dd1b3ee1895a3a8117846802565d7581395deb5246ebc2588237c64868308e609e75dc9a8160c9a12f9d20687dfc254eb43a52623c51c87ac
@@ -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
@@ -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 block
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 block_given?
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-Length'].first
332
- raise IncompleteError if @ssl && content_length && content_length.to_i != body_size
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)
@@ -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
- if res.code != 200
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
 
@@ -14,7 +14,7 @@ module Schedule
14
14
  if code != "200"
15
15
  raise_error("Create schedule failed", res)
16
16
  end
17
- js = checked_json(body, %w[start])
17
+ js = checked_json(body)
18
18
  return js['start']
19
19
  end
20
20
 
@@ -1,5 +1,5 @@
1
1
  module TreasureData
2
2
  class Client
3
- VERSION = '0.8.78'
3
+ VERSION = '0.8.79'
4
4
  end
5
5
  end
@@ -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.78
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-01-26 00:00:00.000000000 Z
11
+ date: 2016-04-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: msgpack