td-client 0.8.85 → 0.9.0dev1

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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/lib/td/client.rb +8 -16
  3. data/lib/td/client/api.rb +46 -62
  4. data/lib/td/client/api/bulk_import.rb +2 -1
  5. data/lib/td/client/api/bulk_load.rb +3 -3
  6. data/lib/td/client/api/export.rb +0 -12
  7. data/lib/td/client/api/import.rb +2 -3
  8. data/lib/td/client/api/job.rb +71 -145
  9. data/lib/td/client/api/schedule.rb +1 -1
  10. data/lib/td/client/api_error.rb +0 -5
  11. data/lib/td/client/model.rb +28 -91
  12. data/lib/td/client/version.rb +1 -1
  13. data/spec/spec_helper.rb +5 -5
  14. data/spec/td/client/account_api_spec.rb +5 -5
  15. data/spec/td/client/api_spec.rb +51 -69
  16. data/spec/td/client/api_ssl_connection_spec.rb +1 -1
  17. data/spec/td/client/bulk_import_spec.rb +29 -28
  18. data/spec/td/client/bulk_load_spec.rb +35 -60
  19. data/spec/td/client/db_api_spec.rb +1 -1
  20. data/spec/td/client/export_api_spec.rb +1 -11
  21. data/spec/td/client/import_api_spec.rb +10 -85
  22. data/spec/td/client/job_api_spec.rb +61 -567
  23. data/spec/td/client/model_job_spec.rb +10 -27
  24. data/spec/td/client/model_schedule_spec.rb +2 -2
  25. data/spec/td/client/partial_delete_api_spec.rb +1 -1
  26. data/spec/td/client/result_api_spec.rb +3 -3
  27. data/spec/td/client/sched_api_spec.rb +4 -12
  28. data/spec/td/client/server_status_api_spec.rb +2 -2
  29. data/spec/td/client/spec_resources.rb +0 -1
  30. data/spec/td/client/table_api_spec.rb +14 -14
  31. data/spec/td/client/user_api_spec.rb +12 -12
  32. data/spec/td/client_sched_spec.rb +6 -31
  33. data/spec/td/client_spec.rb +0 -1
  34. metadata +97 -42
  35. data/spec/td/client/api_error_spec.rb +0 -77
  36. data/spec/td/client/model_schema_spec.rb +0 -134
@@ -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)
17
+ js = checked_json(body, %w[start])
18
18
  return js['start']
19
19
  end
20
20
 
@@ -23,11 +23,6 @@ end
23
23
 
24
24
  # 409 API errors
25
25
  class AlreadyExistsError < APIError
26
- attr_reader :conflicts_with
27
- def initialize(error_message = nil, api_backtrace = nil, conflicts_with=nil)
28
- super(error_message, api_backtrace)
29
- @conflicts_with = conflicts_with
30
- end
31
26
  end
32
27
 
33
28
  # 404 API errors
@@ -1,7 +1,7 @@
1
- require 'timeout'
2
1
 
3
2
  module TreasureData
4
3
 
4
+
5
5
  class Model
6
6
  # @param [TreasureData::Client] client
7
7
  def initialize(client)
@@ -269,62 +269,36 @@ class Table < Model
269
269
  def update_database!
270
270
  @database = @client.database(@db_name)
271
271
  end
272
-
273
- # @return [String]
274
- def inspect
275
- %[#<%s:%#0#{1.size*2}x @db_name="%s" @table_name="%s">] %
276
- [self.class.name, self.__id__*2, @db_name, @table_name]
277
- end
278
272
  end
279
273
 
280
274
  class Schema
281
275
  class Field
282
276
  # @param [String] name
283
277
  # @param [String] type
284
- # @param [String] sql_alias
285
- def initialize(name, type, sql_alias=nil)
286
- if name == 'v' || name == 'time'
287
- raise ParameterValidationError, "Column name '#{name}' is reserved."
288
- end
289
- API.validate_column_name(name)
290
- API.validate_sql_alias_name(sql_alias) if sql_alias
278
+ def initialize(name, type)
291
279
  @name = name
292
280
  @type = type
293
- @sql_alias = sql_alias
294
281
  end
295
282
 
296
283
  # @!attribute [r] name
297
284
  # @!attribute [r] type
298
285
  attr_reader :name
299
286
  attr_reader :type
300
- attr_reader :sql_alias
301
287
  end
302
288
 
303
- # @param [String] columns
289
+ # @param [String] cols
304
290
  # @return [Schema]
305
- def self.parse(columns)
306
- schema = Schema.new
307
- columns.each {|column|
308
- unless /\A(?<name>.*)(?::(?<type>[^:@]+))(?:@(?<sql_alias>[^:@]+))?\z/ =~ column
309
- raise ParameterValidationError, "type must be specified"
310
- end
311
- schema.add_field(name, type, sql_alias)
291
+ def self.parse(cols)
292
+ fields = cols.split(',').map {|col|
293
+ name, type, *_ = col.split(':')
294
+ Field.new(name, type)
312
295
  }
313
- schema
296
+ Schema.new(fields)
314
297
  end
315
298
 
316
299
  # @param [Array] fields
317
300
  def initialize(fields=[])
318
301
  @fields = fields
319
- @names = {}
320
- @fields.each do |f|
321
- raise ArgumentError, "Column name '#{f.name}' is duplicated." if @names.key?(f.name)
322
- @names[f.name] = true
323
- if f.sql_alias
324
- raise ArgumentError, "SQL Column alias '#{f.sql_alias}' is duplicated." if @names.key?(f.sql_alias)
325
- @names[f.sql_alias] = true
326
- end
327
- end
328
302
  end
329
303
 
330
304
  # @!attribute [r] fields
@@ -333,16 +307,8 @@ class Schema
333
307
  # @param [String] name
334
308
  # @param [String] type
335
309
  # @return [Array]
336
- def add_field(name, type, sql_alias=nil)
337
- if @names.key?(name)
338
- raise ParameterValidationError, "Column name '#{name}' is duplicated."
339
- end
340
- @names[name] = true
341
- if sql_alias && @names.key?(sql_alias)
342
- raise ParameterValidationError, "SQL Column alias '#{sql_alias}' is duplicated."
343
- end
344
- @names[sql_alias] = true
345
- @fields << Field.new(name, type, sql_alias)
310
+ def add_field(name, type)
311
+ @fields << Field.new(name, type)
346
312
  end
347
313
 
348
314
  # @param [Schema] schema
@@ -361,14 +327,14 @@ class Schema
361
327
 
362
328
  # @return [Array<Field>]
363
329
  def to_json(*args)
364
- @fields.map {|f| f.sql_alias ? [f.name, f.type, f.sql_alias] : [f.name, f.type] }.to_json(*args)
330
+ @fields.map {|f| [f.name, f.type] }.to_json(*args)
365
331
  end
366
332
 
367
333
  # @param [Object] obj
368
334
  # @return [self]
369
335
  def from_json(obj)
370
336
  @fields = obj.map {|f|
371
- Field.new(*f)
337
+ Field.new(f[0], f[1])
372
338
  }
373
339
  self
374
340
  end
@@ -383,6 +349,8 @@ class Job < Model
383
349
  STATUS_KILLED = "killed"
384
350
  FINISHED_STATUS = [STATUS_SUCCESS, STATUS_ERROR, STATUS_KILLED]
385
351
 
352
+ class TimeoutError < StandardError; end
353
+
386
354
  # @param [TreasureData::Client] client
387
355
  # @param [String] job_id
388
356
  # @param [String] type
@@ -402,10 +370,9 @@ class Job < Model
402
370
  # @param [String] org_name
403
371
  # @param [String] db_name
404
372
  # @param [Fixnum] duration
405
- # @param [Fixnum] num_records
406
373
  def initialize(client, job_id, type, query, status=nil, url=nil, debug=nil, start_at=nil, end_at=nil, cpu_time=nil,
407
374
  result_size=nil, result=nil, result_url=nil, hive_result_schema=nil, priority=nil, retry_limit=nil,
408
- org_name=nil, db_name=nil, duration=nil, num_records=nil)
375
+ org_name=nil, db_name=nil, duration=nil)
409
376
  super(client)
410
377
  @job_id = job_id
411
378
  @type = type
@@ -424,7 +391,6 @@ class Job < Model
424
391
  @retry_limit = retry_limit
425
392
  @db_name = db_name
426
393
  @duration = duration
427
- @num_records = num_records
428
394
  end
429
395
 
430
396
  # @!attribute [r] job_id
@@ -435,40 +401,21 @@ class Job < Model
435
401
  # @!attribute [r] org_name
436
402
  # @!attribute [r] db_name
437
403
  # @!attribute [r] duration
438
- # @!attribute [r] num_records
439
404
  attr_reader :job_id, :type, :result_url
440
405
  attr_reader :priority, :retry_limit, :org_name, :db_name
441
- attr_reader :duration, :num_records
442
-
443
- # @option timeout [Integer,nil] timeout in second
444
- # @option wait_interval [Integer,nil] interval in second of polling the job status
445
- # @param detail [Boolean] update job detail or not
446
- # @param verbose [Boolean] out retry log to stderr or not
447
- def wait(*args)
448
- opthash = Hash.try_convert(args.last)
449
- if opthash
450
- args.pop
451
- detail = opthash.fetch(:detail, false)
452
- verbose = opthash.fetch(:verbose, ENV['TD_CLIENT_DEBUG'])
453
- end
454
- timeout = args[0]
455
- wait_interval = args[1] || 2
456
- deadline = monotonic_clock + timeout if timeout
457
- timeout_klass = Class.new(Exception)
458
- begin
459
- if timeout
460
- if deadline <= monotonic_clock
461
- raise timeout_klass, "timeout (#{timeout}) exceeded wait_interval=#{wait_interval}"
462
- end
406
+ attr_reader :duration
407
+
408
+ def wait(timeout=nil, wait_interval=2)
409
+ started_at = Time.now
410
+ until finished?
411
+ if !timeout || ((Time.now - started_at).abs < timeout && wait_interval <= timeout)
412
+ sleep wait_interval
413
+ yield self if block_given?
414
+ else
415
+ raise TimeoutError, "timeout"
463
416
  end
464
- sleep wait_interval
465
- detail ? update_status! : update_progress!
466
- yield self if block_given?
467
- rescue timeout_klass
468
- raise Timeout::Error, $!.message
469
- rescue Timeout::Error, SystemCallError, EOFError, SocketError, HTTPClient::ConnectTimeoutError
470
- $stderr.puts "ignore network error (#{$!}); retry..." if verbose
471
- end until finished?
417
+ update_progress!
418
+ end
472
419
  end
473
420
 
474
421
  def kill!
@@ -617,7 +564,7 @@ class Job < Model
617
564
  def update_status!
618
565
  type, query, status, url, debug, start_at, end_at, cpu_time,
619
566
  result_size, result_url, hive_result_schema, priority, retry_limit,
620
- org_name, db_name , num_records = @client.api.show_job(@job_id)
567
+ org_name, db_name = @client.api.show_job(@job_id)
621
568
  @query = query
622
569
  @status = status
623
570
  @url = url
@@ -631,18 +578,8 @@ class Job < Model
631
578
  @priority = priority
632
579
  @retry_limit = retry_limit
633
580
  @db_name = db_name
634
- @num_records = num_records
635
581
  self
636
582
  end
637
-
638
- private
639
- def monotonic_clock
640
- if defined?(Process.clock_gettime)
641
- Process.clock_gettime(Process::CLOCK_MONOTONIC)
642
- else
643
- Time.now.to_i
644
- end
645
- end
646
583
  end
647
584
 
648
585
 
@@ -1,5 +1,5 @@
1
1
  module TreasureData
2
2
  class Client
3
- VERSION = '0.8.85'
3
+ VERSION = '0.9.0dev1'
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.new([
13
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
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
@@ -48,13 +48,13 @@ shared_context 'common helper' do
48
48
  end
49
49
 
50
50
  def stub_api_request(method, path, opts = nil)
51
- scheme = 'https'
51
+ scheme = 'http'
52
52
  with_opts = {:headers => headers}
53
53
  if opts
54
- scheme = 'http' if opts[:ssl] == false
54
+ scheme = 'https' if opts[:ssl]
55
55
  with_opts[:query] = opts[:query] if opts[:query]
56
56
  end
57
- stub_request(method, "#{scheme}://api.treasuredata.com#{path}").with(with_opts)
57
+ stub_request(method, "#{scheme}://api.treasure-data.com#{path}").with(with_opts)
58
58
  end
59
59
 
60
60
  def e(s)
@@ -14,7 +14,7 @@ describe 'Account API' do
14
14
  it 'returns account properties' do
15
15
  stub_api_request(:get, "/v3/account/show").
16
16
  to_return(:body => {'account' => {'id' => 1, 'plan' => 0, 'storage_size' => 2, 'guaranteed_cores' => 3, 'maximum_cores' => 4, 'created_at' => '2014-12-14T17:24:00+0900'}}.to_json)
17
- expect(api.show_account).to eq([1, 0, 2, 3, 4, "2014-12-14T17:24:00+0900"])
17
+ api.show_account.should == [1, 0, 2, 3, 4, "2014-12-14T17:24:00+0900"]
18
18
  end
19
19
  end
20
20
 
@@ -25,10 +25,10 @@ describe 'Account API' do
25
25
  stub_api_request(:get, "/v3/account/core_utilization", :query => {'from' => from, 'to' => to}).
26
26
  to_return(:body => {'from' => from, 'to' => to, 'interval' => 1, 'history' => ['dummy']}.to_json)
27
27
  r = api.account_core_utilization(from, to)
28
- expect(r[0]).to eq(Time.parse(from))
29
- expect(r[1]).to eq(Time.parse(to))
30
- expect(r[2]).to eq(1)
31
- expect(r[3]).to eq(['dummy'])
28
+ r[0].should == Time.parse(from)
29
+ r[1].should == Time.parse(to)
30
+ r[2].should == 1
31
+ r[3].should == ['dummy']
32
32
  end
33
33
  end
34
34
  end
@@ -40,26 +40,26 @@ describe API do
40
40
 
41
41
  it 'normalize_database_name should return normalized data' do
42
42
  INVALID_NAMES.each_pair {|ng,ok|
43
- expect(API.normalize_database_name(ng)).to eq(ok)
43
+ API.normalize_database_name(ng).should == ok
44
44
  }
45
- expect {
45
+ lambda {
46
46
  API.normalize_database_name('')
47
- }.to raise_error(RuntimeError)
47
+ }.should raise_error(RuntimeError)
48
48
  end
49
49
 
50
50
  it 'normalize_table_name should return normalized data' do
51
51
  INVALID_NAMES.each_pair {|ng,ok|
52
- expect(API.normalize_table_name(ng)).to eq(ok)
52
+ API.normalize_table_name(ng).should == ok
53
53
  }
54
54
  # empty
55
- expect {
55
+ lambda {
56
56
  API.normalize_table_name('')
57
- }.to raise_error(RuntimeError)
57
+ }.should raise_error(RuntimeError)
58
58
  end
59
59
 
60
60
  it 'normalize_database_name should return valid data' do
61
61
  VALID_NAMES.each {|ok|
62
- expect(API.normalize_database_name(ok)).to eq(ok)
62
+ API.normalize_database_name(ok).should == ok
63
63
  }
64
64
  end
65
65
  end
@@ -68,19 +68,19 @@ describe API do
68
68
  describe "'validate_database_name'" do
69
69
  it 'should raise a ParameterValidationError exceptions' do
70
70
  INVALID_NAMES.each_pair {|ng,ok|
71
- expect {
71
+ lambda {
72
72
  API.validate_database_name(ng)
73
- }.to raise_error(ParameterValidationError)
73
+ }.should raise_error(ParameterValidationError)
74
74
  }
75
75
  # empty
76
- expect {
76
+ lambda {
77
77
  API.validate_database_name('')
78
- }.to raise_error(ParameterValidationError)
78
+ }.should raise_error(ParameterValidationError)
79
79
  end
80
80
 
81
81
  it 'should return valid data' do
82
82
  VALID_NAMES.each {|ok|
83
- expect(API.validate_database_name(ok)).to eq(ok)
83
+ API.validate_database_name(ok).should == ok
84
84
  }
85
85
  end
86
86
  end
@@ -88,18 +88,18 @@ describe API do
88
88
  describe "'validate_table_name'" do
89
89
  it 'should raise a ParameterValidationError exception' do
90
90
  INVALID_NAMES.each_pair {|ng,ok|
91
- expect {
91
+ lambda {
92
92
  API.validate_table_name(ng)
93
- }.to raise_error(ParameterValidationError)
93
+ }.should raise_error(ParameterValidationError)
94
94
  }
95
- expect {
95
+ lambda {
96
96
  API.validate_table_name('')
97
- }.to raise_error(ParameterValidationError)
97
+ }.should raise_error(ParameterValidationError)
98
98
  end
99
99
 
100
100
  it 'should return valid data' do
101
101
  VALID_NAMES.each {|ok|
102
- expect(API.validate_database_name(ok)).to eq(ok)
102
+ API.validate_database_name(ok).should == ok
103
103
  }
104
104
  end
105
105
  end
@@ -107,95 +107,69 @@ describe API do
107
107
  describe "'validate_result_set_name'" do
108
108
  it 'should raise a ParameterValidationError exception' do
109
109
  INVALID_NAMES.each_pair {|ng,ok|
110
- expect {
110
+ lambda {
111
111
  API.validate_result_set_name(ng)
112
- }.to raise_error(ParameterValidationError)
112
+ }.should raise_error(ParameterValidationError)
113
113
  }
114
114
  # empty
115
- expect {
115
+ lambda {
116
116
  API.validate_result_set_name('')
117
- }.to raise_error(ParameterValidationError)
117
+ }.should raise_error(ParameterValidationError)
118
118
  end
119
119
 
120
120
  it 'should return valid data' do
121
121
  VALID_NAMES.each {|ok|
122
- expect(API.validate_result_set_name(ok)).to eq(ok)
122
+ API.validate_result_set_name(ok).should == ok
123
123
  }
124
124
  end
125
125
  end
126
126
 
127
127
  describe "'validate_column_name'" do
128
128
  it 'should raise a ParameterValidationError exception' do
129
- [''].each { |ng|
130
- expect {
129
+ ['/', '', 'D'].each { |ng|
130
+ lambda {
131
131
  API.validate_column_name(ng)
132
- }.to raise_error(ParameterValidationError)
132
+ }.should raise_error(ParameterValidationError)
133
133
  }
134
134
  end
135
135
 
136
136
  it 'should return valid data' do
137
137
  VALID_NAMES.each {|ok|
138
- expect(API.validate_column_name(ok)).to eq(ok)
139
- }
140
- ['a', 'a'*255].each {|ok|
141
- expect(API.validate_column_name(ok)).to eq(ok)
138
+ API.validate_column_name(ok).should == ok
142
139
  }
140
+ # columns can be as short as 2 characters
141
+ API.validate_column_name('ab').should == 'ab'
143
142
  end
144
143
  end
145
144
 
146
- describe "'validate_sql_alias_name'" do
147
- it 'should raise a ParameterValidationError exception' do
148
- [''].each { |ng|
149
- expect{API.validate_sql_alias_name(ng)}.to raise_error(ParameterValidationError)
150
- }
151
- valid = ("a".."z").to_a.join<<("0".."9").to_a.join<<"_"
152
- ("\x00".."\x7F").each { |ng|
153
- next if valid.include?(ng)
154
- expect{API.validate_sql_alias_name(ng)}.to raise_error(ParameterValidationError)
155
- }
156
- end
157
-
158
- it 'should return valid data' do
159
- VALID_NAMES.each {|ok|
160
- expect(API.validate_sql_alias_name(ok)).to eq(ok)
161
- }
162
- ['a', '_a', 'a_', 'a'*512].each {|ok|
163
- expect(API.validate_sql_alias_name(ok)).to eq(ok)
164
- }
165
- end
166
- end
167
145
 
168
146
  describe "'generic validate_name'" do
169
147
  it 'should raise a ParameterValidationError exception' do
170
- # wrong target
171
- expect {
172
- API.validate_name("", 3, 256, '')
173
- }.to raise_error(ParameterValidationError)
174
148
  INVALID_NAMES.each_pair {|ng,ok|
175
- expect {
149
+ lambda {
176
150
  API.validate_name("generic", 3, 256, ng)
177
- }.to raise_error(ParameterValidationError)
151
+ }.should raise_error(ParameterValidationError)
178
152
  }
179
153
  # empty
180
- expect {
154
+ lambda {
181
155
  API.validate_name("generic", 3, 256, '')
182
- }.to raise_error(ParameterValidationError)
156
+ }.should raise_error(ParameterValidationError)
183
157
  # too short - one less than left limit
184
- expect {
158
+ lambda {
185
159
  API.validate_name("generic", 3, 256, 'ab')
186
- }.to raise_error(ParameterValidationError)
160
+ }.should raise_error(ParameterValidationError)
187
161
  end
188
162
 
189
163
  it 'should return valid data' do
190
164
  VALID_NAMES.each {|ok|
191
- expect(API.validate_name("generic", 3, 256, ok)).to eq(ok)
165
+ API.validate_name("generic", 3, 256, ok).should == ok
192
166
  }
193
167
  # esplore left boundary
194
- expect(API.validate_name("generic", 2, 256, 'ab')).to eq('ab')
195
- expect(API.validate_name("generic", 1, 256, 'a')).to eq('a')
168
+ API.validate_name("generic", 2, 256, 'ab').should == 'ab'
169
+ API.validate_name("generic", 1, 256, 'a').should == 'a'
196
170
  # explore right boundary
197
- expect(API.validate_name("generic", 3, 256, 'a' * 256)).to eq('a' * 256)
198
- expect(API.validate_name("generic", 3, 128, 'a' * 128)).to eq('a' * 128)
171
+ API.validate_name("generic", 3, 256, 'a' * 256).should == 'a' * 256
172
+ API.validate_name("generic", 3, 128, 'a' * 128).should == 'a' * 128
199
173
  end
200
174
  end
201
175
 
@@ -204,7 +178,7 @@ describe API do
204
178
 
205
179
  let(:api) { API.new(nil, endpoint: endpoint) }
206
180
  let :packed do
207
- s = StringIO.new(String.new)
181
+ s = StringIO.new
208
182
  Zlib::GzipWriter.wrap(s) do |f|
209
183
  f << ['hello', 'world'].to_json
210
184
  end
@@ -221,7 +195,7 @@ describe API do
221
195
  end
222
196
 
223
197
  subject (:get_api_call) {
224
- api.job_result_format(12345, 'json', StringIO.new(String.new))
198
+ api.job_result_format(12345, 'json', StringIO.new)
225
199
  }
226
200
 
227
201
  context 'without ssl' do
@@ -230,7 +204,7 @@ describe API do
230
204
  let(:content_length) { {'Content-Length' => packed.size} }
231
205
 
232
206
  it 'not called #completed_body?' do
233
- expect(api).not_to receive(:completed_body?)
207
+ api.should_not_receive(:completed_body?)
234
208
 
235
209
  get_api_call
236
210
  end
@@ -249,13 +223,21 @@ describe API do
249
223
  end
250
224
 
251
225
  context 'with Content-Length' do
252
- context 'match Content-Length and body.size' do
226
+ context 'macth Content-Length and body.size' do
253
227
  let(:content_length) { {'Content-Length' => packed.size} }
254
228
 
255
229
  it 'api accuess succeded' do
256
230
  expect { get_api_call }.not_to raise_error
257
231
  end
258
232
  end
233
+
234
+ context 'not macth Content-Length and body.size' do
235
+ let(:content_length) { {'Content-Length' => packed.size + 1} }
236
+
237
+ it 'api accuess succeded' do
238
+ expect { get_api_call }.to raise_error(TreasureData::API::IncompleteError)
239
+ end
240
+ end
259
241
  end
260
242
  end
261
243
  end