td-client 0.8.85 → 0.9.0dev1

Sign up to get free protection for your applications and to get access to all the features.
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