td-client 0.8.75 → 0.8.76
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/api.rb +66 -167
- data/lib/td/client/api/bulk_load.rb +2 -2
- data/lib/td/client/api/job.rb +69 -61
- data/lib/td/client/model.rb +1 -2
- data/lib/td/client/version.rb +1 -1
- data/spec/spec_helper.rb +1 -2
- data/spec/td/client/bulk_load_spec.rb +2 -2
- data/spec/td/client/job_api_spec.rb +37 -18
- data/spec/td/client/spec_resources.rb +2 -2
- data/spec/td/client/user_api_spec.rb +2 -2
- metadata +4 -6
- data/spec/td/client/api_http_access_spec.rb +0 -50
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bed709b18af78da0d5e9be3b5ff11e52cce7b631
|
4
|
+
data.tar.gz: 3280f6e1a3fa77067adf1ef2695eb05b4b0cd30b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3bf28abf67a22673d54c387915701fc9775aeb82f02c1e92e9e73df4009656ba489d1c7089369aa6efa3909ddc50f81c6b45411cb56c190718a8cd8655af94f1
|
7
|
+
data.tar.gz: c438cc9da912217589d01a3debca817d168eb4a7bdb6840c4c20ae17b8e25a8c2d56a87f481276beacadfc5132da65b3ac7b8c95f6161eea790838342ea093b5
|
data/lib/td/client/api.rb
CHANGED
@@ -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
|
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
|
-
|
307
|
-
|
308
|
-
|
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
|
-
|
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
|
-
|
336
|
-
|
337
|
-
|
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 =
|
341
|
-
end
|
279
|
+
response = client.get(target, params, header)
|
342
280
|
|
343
|
-
|
344
|
-
|
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
|
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
|
404
|
-
|
405
|
-
|
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
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
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
|
-
|
357
|
+
target = build_endpoint(url, @host)
|
430
358
|
|
431
|
-
|
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: " +
|
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 =
|
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
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
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'] =
|
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
|
-
|
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
|
-
|
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
|
data/lib/td/client/api/job.rb
CHANGED
@@ -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
|
-
|
139
|
-
|
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
|
-
|
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
|
-
|
160
|
-
|
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
|
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
|
-
|
183
|
-
|
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
|
189
|
-
|
190
|
-
|
191
|
-
|
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
|
-
|
205
|
-
|
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
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
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 !=
|
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
|
-
|
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
|
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
|
data/lib/td/client/model.rb
CHANGED
@@ -577,7 +577,7 @@ class ScheduledJob < Job
|
|
577
577
|
|
578
578
|
# @param [TreasureData::Client] client
|
579
579
|
# @param [String] scheduled_at
|
580
|
-
# @param [...]
|
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
|
-
|
data/lib/td/client/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -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 =>
|
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
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
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
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
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
|
-
'
|
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
|
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
|
57
|
-
api.add_user('! @#$%^&*()_
|
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.
|
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-
|
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:
|
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
|