td-client 0.8.75 → 0.8.76

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: 1ecd6b8aed80e8f53f2d1558d5d3eb7a46139bb4
4
- data.tar.gz: cf9e411eb507cc49dbd37cce1a9dfa0b1a9b4338
3
+ metadata.gz: bed709b18af78da0d5e9be3b5ff11e52cce7b631
4
+ data.tar.gz: 3280f6e1a3fa77067adf1ef2695eb05b4b0cd30b
5
5
  SHA512:
6
- metadata.gz: ec2506706f26dce0390218f20dd350b0d0389172ad6b1adf1b047a8fff1e233c45c1cdd0ac74ae9b02cea68414b273e63d0ac2aad582a2857e42d795eea8aa35
7
- data.tar.gz: 47094392a7112ef70587f9994a83299cac26da9a86e660ac51046efd429ae998aed4880132dcf2150aff982f0679e19298ac1eac3404c10cb85589623f1e4a36
6
+ metadata.gz: 3bf28abf67a22673d54c387915701fc9775aeb82f02c1e92e9e73df4009656ba489d1c7089369aa6efa3909ddc50f81c6b45411cb56c190718a8cd8655af94f1
7
+ data.tar.gz: c438cc9da912217589d01a3debca817d168eb4a7bdb6840c4c20ae17b8e25a8c2d56a87f481276beacadfc5132da65b3ac7b8c95f6161eea790838342ea093b5
@@ -103,19 +103,6 @@ class API
103
103
  end
104
104
 
105
105
  @http_proxy = opts[:http_proxy] || ENV['HTTP_PROXY']
106
- if @http_proxy
107
- http_proxy = if @http_proxy =~ /\Ahttp:\/\/(.*)\z/
108
- $~[1]
109
- else
110
- @http_proxy
111
- end
112
- proxy_host, proxy_port = http_proxy.split(':', 2)
113
- proxy_port = (proxy_port ? proxy_port.to_i : 80)
114
- @http_class = Net::HTTP::Proxy(proxy_host, proxy_port)
115
- else
116
- @http_class = Net::HTTP
117
- end
118
-
119
106
  @headers = opts[:headers] || {}
120
107
  @api = api_client("#{@ssl ? 'https' : 'http'}://#{@host}:#{@port}")
121
108
  end
@@ -222,7 +209,7 @@ class API
222
209
  when /double/i
223
210
  "double"
224
211
  else
225
- raise "Type name must eather of int, long, string float or double"
212
+ raise "Type name must either of int, long, string float or double"
226
213
  end
227
214
  end
228
215
 
@@ -241,55 +228,6 @@ class API
241
228
 
242
229
  private
243
230
 
244
- module DeflateReadBodyMixin
245
- attr_accessor :gzip
246
-
247
- # @yield [fragment]
248
- def each_fragment(&block)
249
- if @gzip
250
- infl = Zlib::Inflate.new(Zlib::MAX_WBITS + 16)
251
- else
252
- infl = Zlib::Inflate.new
253
- end
254
- begin
255
- read_body {|fragment|
256
- block.call infl.inflate(fragment)
257
- }
258
- ensure
259
- infl.close
260
- end
261
- nil
262
- end
263
- end
264
-
265
- module CountReadBodyTotalSize
266
- attr_reader :total_fragment_size
267
-
268
- def read_body(&block)
269
- return super if @total_fragment_size
270
-
271
- if block_given?
272
- @total_fragment_size = 0
273
-
274
- super {|fragment|
275
- @total_fragment_size += fragment.size
276
- block.call(fragment)
277
- }
278
- else
279
- super().tap {|body|
280
- @total_fragment_size = body.size
281
- }
282
- end
283
- end
284
- end
285
-
286
- module DirectReadBodyMixin
287
- # @yield [fragment]
288
- def each_fragment(&block)
289
- read_body(&block)
290
- end
291
- end
292
-
293
231
  # @param [String] url
294
232
  # @param [Hash] params
295
233
  # @yield [response]
@@ -298,22 +236,17 @@ private
298
236
  do_get(url, params, &block)
299
237
  end
300
238
  end
301
-
302
239
  # @param [String] url
303
240
  # @param [Hash] params
304
241
  # @yield [response]
305
242
  def do_get(url, params=nil, &block)
306
- http, header = new_http
307
-
308
- path = @base_path + url
309
- if params && !params.empty?
310
- path << "?"+params.map {|k,v|
311
- "#{k}=#{e v}"
312
- }.join('&')
313
- end
243
+ client, header = new_client
244
+ client.send_timeout = @send_timeout
245
+ client.receive_timeout = @read_timeout
314
246
 
315
247
  header['Accept-Encoding'] = 'deflate, gzip'
316
- request = Net::HTTP::Get.new(path, header)
248
+
249
+ target = build_endpoint(url, @host)
317
250
 
318
251
  unless ENV['TD_CLIENT_DEBUG'].nil?
319
252
  puts "DEBUG: REST GET call:"
@@ -332,20 +265,23 @@ private
332
265
  begin # this block is to allow retry (redo) in the begin part of the begin-rescue block
333
266
  begin
334
267
  if block
335
- response = http.request(request) {|res|
336
- res.extend(CountReadBodyTotalSize)
337
- block.call(res)
268
+ current_total_chunk_size = 0
269
+ response = client.get(target, params, header) {|res, chunk|
270
+ current_total_chunk_size += chunk.size
271
+ block.call(res, chunk, current_total_chunk_size)
338
272
  }
273
+
274
+ # XXX ext/openssl raises EOFError in case where underlying connection causes an error,
275
+ # and msgpack-ruby that used in block handles it as an end of stream == no exception.
276
+ # Therefor, check content size.
277
+ validate_content_length!(response, current_total_chunk_size) if @ssl
339
278
  else
340
- response = http.request(request)
341
- end
279
+ response = client.get(target, params, header)
342
280
 
343
- # XXX ext/openssl raises EOFError in case where underlying connection causes an error,
344
- # and msgpack-ruby that used in block handles it as an end of stream == no exception.
345
- # Therefor, check content size.
346
- raise IncompleteError if @ssl && !completed_body?(response)
281
+ validate_content_length!(response, response.body.size) if @ssl
282
+ end
347
283
 
348
- status = response.code.to_i
284
+ status = response.code
349
285
  # retry if the HTTP error code is 500 or higher and we did not run out of retrying attempts
350
286
  if !block_given? && status >= 500 && cumul_retry_delay < @max_cumul_retry_delay
351
287
  $stderr.puts "Error #{status}: #{get_error(response)}. Retrying after #{retry_delay} seconds..."
@@ -381,37 +317,29 @@ private
381
317
  puts "DEBUG: body: " + response.body.to_s
382
318
  end
383
319
 
384
- body = response.body
385
- unless block
386
- if ce = response.header['content-encoding']
387
- if ce == 'gzip'
388
- infl = Zlib::Inflate.new(Zlib::MAX_WBITS + 16)
389
- begin
390
- body = infl.inflate(body)
391
- ensure
392
- infl.close
393
- end
394
- else
395
- body = Zlib::Inflate.inflate(body)
396
- end
397
- end
398
- end
320
+ body = block ? response.body : inflate_body(response)
399
321
 
400
- return [response.code, body, response]
322
+ return [response.code.to_s, body, response]
401
323
  end
402
324
 
403
- def completed_body?(response)
404
- # NOTE If response doesn't have content_length, we assume it succeeds.
405
- return true unless (content_length = response.header.content_length)
325
+ def validate_content_length!(response, body_size)
326
+ content_length = response.header['Content-Length'].first
327
+ raise IncompleteError if @ssl && content_length && content_length.to_i != body_size
328
+ end
406
329
 
407
- if response.body.instance_of? String
408
- content_length == response.body.length
409
- else
410
- if response.respond_to? :total_fragment_size
411
- content_length == response.total_fragment_size
412
- else
413
- true
330
+ def inflate_body(response)
331
+ return response.body if (ce = response.header['Content-Encoding']).empty?
332
+
333
+ if ce.include?('gzip')
334
+ infl = Zlib::Inflate.new(Zlib::MAX_WBITS + 16)
335
+ begin
336
+ infl.inflate(response.body)
337
+ ensure
338
+ infl.close
414
339
  end
340
+ else
341
+ # NOTE maybe for content-encoding is msgpack.gz ?
342
+ Zlib::Inflate.inflate(response.body)
415
343
  end
416
344
  end
417
345
 
@@ -426,25 +354,20 @@ private
426
354
  # @param [String] url
427
355
  # @param [Hash] params
428
356
  def do_post(url, params=nil)
429
- http, header = new_http
357
+ target = build_endpoint(url, @host)
430
358
 
431
- path = @base_path + url
359
+ client, header = new_client
360
+ client.send_timeout = @send_timeout
361
+ client.receive_timeout = @read_timeout
362
+ header['Accept-Encoding'] = 'gzip'
432
363
 
433
364
  unless ENV['TD_CLIENT_DEBUG'].nil?
434
365
  puts "DEBUG: REST POST call:"
435
366
  puts "DEBUG: header: " + header.to_s
436
- puts "DEBUG: path: " + path.to_s
367
+ puts "DEBUG: path: " + (@base_path + url).to_s
437
368
  puts "DEBUG: params: " + params.to_s
438
369
  end
439
370
 
440
- if params && !params.empty?
441
- request = Net::HTTP::Post.new(path, header)
442
- request.set_form_data(params)
443
- else
444
- header['Content-Length'] = 0.to_s
445
- request = Net::HTTP::Post.new(path, header)
446
- end
447
-
448
371
  # up to 7 retries with exponential (base 2) back-off starting at 'retry_delay'
449
372
  retry_delay = @retry_delay
450
373
  cumul_retry_delay = 0
@@ -455,7 +378,7 @@ private
455
378
  response = nil
456
379
  begin # this block is to allow retry (redo) in the begin part of the begin-rescue block
457
380
  begin
458
- response = http.request(request)
381
+ response = client.post(target, params || {}, header)
459
382
 
460
383
  # if the HTTP error code is 500 or higher and the user requested retrying
461
384
  # on post request, attempt a retry
@@ -488,14 +411,18 @@ private
488
411
  end
489
412
  end while false
490
413
 
491
- unless ENV['TD_CLIENT_DEBUG'].nil?
492
- puts "DEBUG: REST POST response:"
493
- puts "DEBUG: header: " + response.header.to_s
494
- puts "DEBUG: status: " + response.code.to_s
495
- puts "DEBUG: body: <omitted>"
414
+ begin
415
+ unless ENV['TD_CLIENT_DEBUG'].nil?
416
+ puts "DEBUG: REST POST response:"
417
+ puts "DEBUG: header: " + response.header.to_s
418
+ puts "DEBUG: status: " + response.code.to_s
419
+ puts "DEBUG: body: <omitted>"
420
+ end
421
+ return [response.code.to_s, response.body, response]
422
+ ensure
423
+ # Disconnect keep-alive connection explicitly here, not by GC.
424
+ client.reset(target) rescue nil
496
425
  end
497
-
498
- return [response.code, response.body, response]
499
426
  end
500
427
 
501
428
  # @param [String] url
@@ -561,38 +488,6 @@ private
561
488
  end
562
489
  end
563
490
 
564
- # @param [Hash] opts
565
- # @return [http, Hash]
566
- def new_http(opts = {})
567
- host = opts[:host] || @host
568
- http = @http_class.new(host, @port)
569
- http.open_timeout = 60
570
- if @ssl
571
- http.use_ssl = true
572
- http.verify_mode = OpenSSL::SSL::VERIFY_PEER
573
- #store = OpenSSL::X509::Store.new
574
- #http.cert_store = store
575
- http.ca_file = File.join(ssl_ca_file)
576
- # Disable SSLv3 connection in favor of POODLE Attack protection
577
- # ruby 1.8.7 uses own @ssl_context instead of calling
578
- # SSLContext#set_params.
579
- if ctx = http.instance_eval { @ssl_context }
580
- ctx.options = OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_SSLv3
581
- end
582
- end
583
-
584
- header = {}
585
- if @apikey
586
- header['Authorization'] = "TD1 #{apikey}"
587
- end
588
- header['Date'] = Time.now.rfc2822
589
- header['User-Agent'] = @user_agent
590
-
591
- header.merge!(@headers)
592
-
593
- return http, header
594
- end
595
-
596
491
  # @param [Hash] opts
597
492
  # @return [HTTPClient, Hash]
598
493
  def new_client(opts = {})
@@ -694,11 +589,7 @@ private
694
589
  begin
695
590
  js = JSON.load(res.body)
696
591
  if js.nil?
697
- error['message'] = if res.respond_to?(:message)
698
- res.message # Net::HTTP
699
- else
700
- res.reason # HttpClient
701
- end
592
+ error['message'] = res.reason
702
593
  else
703
594
  error['message'] = js['message'] || js['error']
704
595
  error['stacktrace'] = js['stacktrace']
@@ -747,14 +638,22 @@ private
747
638
  if ''.respond_to?(:encode)
748
639
  # @param [String] s
749
640
  # @return [String]
641
+ # * ' ' and '+' must be escaped into %20 and %2B because escaped text may be
642
+ # used as both URI and query.
643
+ # * '.' must be escaped as %2E because it may be cunfused with extension.
750
644
  def e(s)
751
- CGI.escape(s.to_s.encode("UTF-8"))
645
+ s = s.to_s.encode(Encoding::UTF_8).force_encoding(Encoding::ASCII_8BIT)
646
+ s.gsub!(/[^\-_!~*'()~0-9A-Z_a-z]/){|x|'%%%02X' % x.ord}
647
+ s
752
648
  end
753
649
  else
754
650
  # @param [String] s
755
651
  # @return [String]
652
+ # * ' ' and '+' must be escaped into %20 and %2B because escaped text may be
653
+ # used as both URI and query.
654
+ # * '.' must be escaped as %2E because it may be cunfused with extension.
756
655
  def e(s)
757
- CGI.escape(s.to_s)
656
+ s.to_s.gsub(/[^\-_!~*'()~0-9A-Z_a-z]/){|x|'%%%02X' % x.ord}
758
657
  end
759
658
  end
760
659
 
@@ -149,8 +149,8 @@ module BulkLoad
149
149
  def bulk_load_run(name, scheduled_time = nil)
150
150
  path = job_path(name)
151
151
  opts = {}
152
- opts[:scheduled_time] = scheduled_time unless scheduled_time.nil?
153
- res = api { post(path, opts) }
152
+ opts[:scheduled_time] = scheduled_time.to_s unless scheduled_time.nil?
153
+ res = api { post(path, opts.to_json) }
154
154
  unless res.ok?
155
155
  raise_error("BulkLoadSession: #{name} job create failed", res)
156
156
  end
@@ -135,38 +135,21 @@ module Job
135
135
  # @return [nil, String]
136
136
  def job_result_format(job_id, format, io=nil, &block)
137
137
  if io
138
- code, body, res = get("/v3/job/result/#{e job_id}", {'format'=>format}) {|res|
139
- if res.code != "200"
138
+ infl = nil
139
+ code, body, res = get("/v3/job/result/#{e job_id}", {'format'=>format}) {|res, chunk, current_total_chunk_size|
140
+ if res.code != 200
140
141
  raise_error("Get job result failed", res)
141
142
  end
142
143
 
143
- if ce = res.header['Content-Encoding']
144
- res.extend(DeflateReadBodyMixin)
145
- res.gzip = true if ce == 'gzip'
146
- else
147
- res.extend(DirectReadBodyMixin)
148
- end
149
-
150
- res.extend(DirectReadBodyMixin)
151
- if ce = res.header['Content-Encoding']
152
- if ce == 'gzip'
153
- infl = Zlib::Inflate.new(Zlib::MAX_WBITS + 16)
154
- else
155
- infl = Zlib::Inflate.new
156
- end
157
- end
144
+ infl ||= create_inflalte_or_null_inflate(res)
158
145
 
159
- res.each_fragment {|fragment|
160
- # uncompressed if the 'Content-Enconding' header is set in response
161
- fragment = infl.inflate(fragment) if ce
162
- io.write(fragment)
163
- block.call(res.total_fragment_size) if block_given?
164
- }
146
+ io.write infl.inflate(chunk)
147
+ block.call(current_total_chunk_size) if block_given?
165
148
  }
166
149
  nil
167
150
  else
168
151
  code, body, res = get("/v3/job/result/#{e job_id}", {'format'=>format})
169
- if res.code != "200"
152
+ if code != "200"
170
153
  raise_error("Get job result failed", res)
171
154
  end
172
155
  body
@@ -174,56 +157,55 @@ module Job
174
157
  end
175
158
 
176
159
  # block is optional and must accept 1 argument
177
- #
160
+ #
178
161
  # @param [String] job_id
179
162
  # @param [Proc] block
180
163
  # @return [nil]
181
164
  def job_result_each(job_id, &block)
182
- get("/v3/job/result/#{e job_id}", {'format'=>'msgpack'}) {|res|
183
- if res.code != "200"
165
+ upkr = MessagePack::Unpacker.new
166
+ infl = nil
167
+
168
+ get("/v3/job/result/#{e job_id}", {'format'=>'msgpack'}) {|res, chunk, current_total_chunk_size|
169
+ if res.code != 200
184
170
  raise_error("Get job result failed", res)
185
171
  end
186
172
 
187
173
  # default to decompressing the response since format is fixed to 'msgpack'
188
- res.extend(DeflateReadBodyMixin)
189
- res.gzip = (res.header['Content-Encoding'] == 'gzip')
190
- upkr = MessagePack::Unpacker.new
191
- res.each_fragment {|inflated_fragment|
192
- upkr.feed_each(inflated_fragment, &block)
193
- }
174
+ infl ||= create_inflate(res)
175
+
176
+ inflated_fragment = infl.inflate(chunk)
177
+ upkr.feed_each(inflated_fragment, &block)
194
178
  }
195
179
  nil
180
+ ensure
181
+ infl.close if infl
196
182
  end
197
183
 
198
184
  # block is optional and must accept 1 argument
199
- #
185
+ #
200
186
  # @param [String] job_id
201
187
  # @param [Proc] block
202
188
  # @return [nil]
203
189
  def job_result_each_with_compr_size(job_id, &block)
204
- get("/v3/job/result/#{e job_id}", {'format'=>'msgpack'}) {|res|
205
- if res.code != "200"
190
+ upkr = MessagePack::Unpacker.new
191
+ infl = nil
192
+
193
+ get("/v3/job/result/#{e job_id}", {'format'=>'msgpack'}) {|res, chunk, current_total_chunk_size|
194
+ if res.code != 200
206
195
  raise_error("Get job result failed", res)
207
196
  end
208
197
 
209
- res.extend(DirectReadBodyMixin)
210
- if res.header['Content-Encoding'] == 'gzip'
211
- infl = Zlib::Inflate.new(Zlib::MAX_WBITS + 16)
212
- else
213
- infl = Zlib::Inflate.new
214
- end
215
- upkr = MessagePack::Unpacker.new
216
- begin
217
- res.each_fragment {|fragment|
218
- upkr.feed_each(infl.inflate(fragment)) {|unpacked|
219
- block.call(unpacked, res.total_fragment_size) if block_given?
220
- }
221
- }
222
- ensure
223
- infl.close
224
- end
198
+ # default to decompressing the response since format is fixed to 'msgpack'
199
+ infl ||= create_inflate(res)
200
+
201
+ inflated_fragment = infl.inflate(chunk)
202
+ upkr.feed_each(inflated_fragment) {|unpacked|
203
+ block.call(unpacked, current_total_chunk_size) if block_given?
204
+ }
225
205
  }
226
206
  nil
207
+ ensure
208
+ infl.close if infl
227
209
  end
228
210
 
229
211
  # @param [String] job_id
@@ -232,20 +214,20 @@ module Job
232
214
  def job_result_raw(job_id, format, io = nil, &block)
233
215
  body = nil
234
216
 
235
- get("/v3/job/result/#{e job_id}", {'format'=>format}) {|res|
236
- if res.code != "200"
217
+ get("/v3/job/result/#{e job_id}", {'format'=>format}) {|res, chunk, current_total_chunk_size|
218
+ if res.code != 200
237
219
  raise_error("Get job result failed", res)
238
220
  end
239
221
 
240
222
  if io
241
- res.extend(DirectReadBodyMixin)
242
-
243
- res.each_fragment {|fragment|
244
- io.write(fragment)
245
- block.call(res.total_fragment_size) if block_given?
246
- }
223
+ io.write(chunk)
224
+ block.call(current_total_chunk_size) if block_given?
247
225
  else
248
- body = res.read_body
226
+ if body
227
+ body += chunk
228
+ else
229
+ body = chunk
230
+ end
249
231
  end
250
232
  }
251
233
  body
@@ -303,5 +285,31 @@ module Job
303
285
  return js['job_id'].to_s
304
286
  end
305
287
 
288
+ private
289
+
290
+ class NullInflate
291
+ def inflate(chunk)
292
+ chunk
293
+ end
294
+
295
+ def close
296
+ end
297
+ end
298
+
299
+ def create_inflalte_or_null_inflate(response)
300
+ if response.header['Content-Encoding'].empty?
301
+ NullInflate.new
302
+ else
303
+ create_inflate(response)
304
+ end
305
+ end
306
+
307
+ def create_inflate(response)
308
+ if response.header['Content-Encoding'].include?('gzip')
309
+ Zlib::Inflate.new(Zlib::MAX_WBITS + 16)
310
+ else
311
+ Zlib::Inflate.new
312
+ end
313
+ end
306
314
  end
307
315
  end
@@ -577,7 +577,7 @@ class ScheduledJob < Job
577
577
 
578
578
  # @param [TreasureData::Client] client
579
579
  # @param [String] scheduled_at
580
- # @param [...] args for Job#initialize
580
+ # @param [...] super_args for Job#initialize
581
581
  def initialize(client, scheduled_at, *super_args)
582
582
  super(client, *super_args)
583
583
  if scheduled_at.to_s.empty?
@@ -739,4 +739,3 @@ end
739
739
 
740
740
 
741
741
  end
742
-
@@ -1,5 +1,5 @@
1
1
  module TreasureData
2
2
  class Client
3
- VERSION = '0.8.75'
3
+ VERSION = '0.8.76'
4
4
  end
5
5
  end
@@ -58,7 +58,6 @@ shared_context 'common helper' do
58
58
  end
59
59
 
60
60
  def e(s)
61
- require 'cgi'
62
- CGI.escape(s.to_s)
61
+ s.to_s.gsub(/[^*\-0-9A-Z_a-z]/){|x|'%%%02X' % x.ord}
63
62
  end
64
63
  end
@@ -359,7 +359,7 @@ describe 'BulkImport API' do
359
359
  describe 'run' do
360
360
  it 'returns job_id' do
361
361
  stub_api_request(:post, '/v3/bulk_loads/nahi_test_1/jobs').
362
- with(:body => '').
362
+ with(:body => '{}').
363
363
  to_return(:body => {'job_id' => 12345}.to_json)
364
364
  api.bulk_load_run('nahi_test_1').should == '12345'
365
365
  end
@@ -367,7 +367,7 @@ describe 'BulkImport API' do
367
367
  it 'accepts scheduled_time' do
368
368
  now = Time.now.to_i
369
369
  stub_api_request(:post, '/v3/bulk_loads/nahi_test_1/jobs').
370
- with(:body => "scheduled_time=#{now}").
370
+ with(:body => {scheduled_time: now.to_s}.to_json).
371
371
  to_return(:body => {'job_id' => 12345}.to_json)
372
372
  api.bulk_load_run('nahi_test_1', now).should == '12345'
373
373
  end
@@ -191,26 +191,45 @@ describe 'Job API' do
191
191
  s.string
192
192
  end
193
193
 
194
- it 'returns formatted job result' do
195
- stub_api_request(:get, '/v3/job/result/12345').
196
- with(:query => {'format' => 'json'}).
197
- to_return(
198
- :headers => {'Content-Encoding' => 'gzip'},
199
- :body => packed
200
- )
201
- api.job_result_format(12345, 'json').should == ['hello', 'world'].to_json
194
+ context 'Content-Encoding is empty' do
195
+ let(:io) { StringIO.new }
196
+ let(:json) { ['hello', 'world'].to_json }
197
+
198
+ it 'retrunes json' do
199
+ stub_api_request(:get, '/v3/job/result/12345').
200
+ with(:query => {'format' => 'json'}).
201
+ to_return(:body => json)
202
+
203
+ total_size = 0
204
+ api.job_result_format(12345, 'json', io) {|size| total_size += size }
205
+
206
+ io.string.should == json
207
+ total_size.should == json.size
208
+ end
202
209
  end
203
210
 
204
- it 'writes formatted job result' do
205
- stub_api_request(:get, '/v3/job/result/12345').
206
- with(:query => {'format' => 'json'}).
207
- to_return(
208
- :headers => {'Content-Encoding' => 'gzip'},
209
- :body => packed
210
- )
211
- s = StringIO.new
212
- api.job_result_format(12345, 'json', s)
213
- s.string.should == ['hello', 'world'].to_json
211
+ context 'Content-Encoding is gzip' do
212
+ it 'returns formatted job result' do
213
+ stub_api_request(:get, '/v3/job/result/12345').
214
+ with(:query => {'format' => 'json'}).
215
+ to_return(
216
+ :headers => {'Content-Encoding' => 'gzip'},
217
+ :body => packed
218
+ )
219
+ api.job_result_format(12345, 'json').should == ['hello', 'world'].to_json
220
+ end
221
+
222
+ it 'writes formatted job result' do
223
+ stub_api_request(:get, '/v3/job/result/12345').
224
+ with(:query => {'format' => 'json'}).
225
+ to_return(
226
+ :headers => {'Content-Encoding' => 'gzip'},
227
+ :body => packed
228
+ )
229
+ s = StringIO.new
230
+ api.job_result_format(12345, 'json', s)
231
+ s.string.should == ['hello', 'world'].to_json
232
+ end
214
233
  end
215
234
  end
216
235
 
@@ -15,7 +15,7 @@ shared_context 'spec symbols' do
15
15
  end
16
16
 
17
17
  let :sched_name do
18
- 'sched_test'
18
+ 'sched test'
19
19
  end
20
20
 
21
21
  let :result_name do
@@ -51,7 +51,7 @@ end
51
51
  shared_context 'job resources' do
52
52
  include_context 'database resources'
53
53
 
54
- MAX_JOB = 20
54
+ MAX_JOB ||= 20
55
55
 
56
56
  let :job_types do
57
57
  [
@@ -53,8 +53,8 @@ describe 'User API' do
53
53
 
54
54
  # TODO
55
55
  it 'does not escape sp but it must be a bug' do
56
- stub_api_request(:post, "/v3/user/add/!++++@%23$%25%5E&*()_+%7C~").to_return(:body => {}.to_json)
57
- api.add_user('! @#$%^&*()_+|~', "org", 'name+suffix@example.com', 'password').should == true
56
+ stub_api_request(:post, "/v3/user/add/!%20%20%20%20@%23$%25%5E&*()_%2B%7C~%2Ecom").to_return(:body => {}.to_json)
57
+ api.add_user('! @#$%^&*()_+|~.com', "org", 'name+suffix@example.com', 'password').should == true
58
58
  end
59
59
  end
60
60
 
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.75
4
+ version: 0.8.76
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: 2015-08-11 00:00:00.000000000 Z
11
+ date: 2015-11-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: msgpack
@@ -232,7 +232,6 @@ files:
232
232
  - spec/spec_helper.rb
233
233
  - spec/td/client/access_control_api_spec.rb
234
234
  - spec/td/client/account_api_spec.rb
235
- - spec/td/client/api_http_access_spec.rb
236
235
  - spec/td/client/api_spec.rb
237
236
  - spec/td/client/api_ssl_connection_spec.rb
238
237
  - spec/td/client/bulk_import_spec.rb
@@ -263,7 +262,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
263
262
  requirements:
264
263
  - - ">="
265
264
  - !ruby/object:Gem::Version
266
- version: '0'
265
+ version: 1.8.7
267
266
  required_rubygems_version: !ruby/object:Gem::Requirement
268
267
  requirements:
269
268
  - - ">="
@@ -271,14 +270,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
271
270
  version: '0'
272
271
  requirements: []
273
272
  rubyforge_project:
274
- rubygems_version: 2.4.5
273
+ rubygems_version: 2.4.5.1
275
274
  signing_key:
276
275
  specification_version: 4
277
276
  summary: Treasure Data API library for Ruby
278
277
  test_files:
279
278
  - spec/td/client/access_control_api_spec.rb
280
279
  - spec/td/client/account_api_spec.rb
281
- - spec/td/client/api_http_access_spec.rb
282
280
  - spec/td/client/api_spec.rb
283
281
  - spec/td/client/api_ssl_connection_spec.rb
284
282
  - spec/td/client/bulk_import_spec.rb
@@ -1,50 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe API do
4
- describe '#completed_body?' do
5
- let(:api) { TreasureData::API.new('') }
6
- let(:response) { double(:response) }
7
-
8
- subject { api.__send__(:completed_body?, response) }
9
-
10
- context 'response has no content length' do
11
- before do
12
- response.stub_chain(:header, :content_length).and_return(nil)
13
- end
14
-
15
- it { is_expected.to be }
16
- end
17
-
18
- context 'response has content length' do
19
- let(:content_length) { 10 }
20
-
21
- before do
22
- response.stub_chain(:header, :content_length).and_return(content_length)
23
- end
24
-
25
- context 'content length equal body size' do
26
- before do
27
- response.stub(:body).and_return('a' * content_length)
28
- end
29
-
30
- it { is_expected.to be }
31
- end
32
-
33
- context 'content length lager than body size' do
34
- before do
35
- response.stub(:body).and_return('a' * (content_length - 1))
36
- end
37
-
38
- it { is_expected.not_to be }
39
- end
40
-
41
- context 'content length less than body size' do
42
- before do
43
- response.stub(:body).and_return('a' * (content_length + 1))
44
- end
45
-
46
- it { is_expected.not_to be }
47
- end
48
- end
49
- end
50
- end