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 +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
|