td-client 1.0.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/data/ca-bundle.crt +3448 -0
  3. data/lib/td-client.rb +1 -0
  4. data/lib/td/client.rb +606 -0
  5. data/lib/td/client/api.rb +707 -0
  6. data/lib/td/client/api/access_control.rb +74 -0
  7. data/lib/td/client/api/account.rb +45 -0
  8. data/lib/td/client/api/bulk_import.rb +184 -0
  9. data/lib/td/client/api/bulk_load.rb +172 -0
  10. data/lib/td/client/api/database.rb +50 -0
  11. data/lib/td/client/api/export.rb +38 -0
  12. data/lib/td/client/api/import.rb +38 -0
  13. data/lib/td/client/api/job.rb +390 -0
  14. data/lib/td/client/api/partial_delete.rb +27 -0
  15. data/lib/td/client/api/result.rb +46 -0
  16. data/lib/td/client/api/schedule.rb +120 -0
  17. data/lib/td/client/api/server_status.rb +21 -0
  18. data/lib/td/client/api/table.rb +132 -0
  19. data/lib/td/client/api/user.rb +134 -0
  20. data/lib/td/client/api_error.rb +37 -0
  21. data/lib/td/client/compat_gzip_reader.rb +22 -0
  22. data/lib/td/client/model.rb +816 -0
  23. data/lib/td/client/version.rb +5 -0
  24. data/lib/td/core_ext/openssl/ssl/sslcontext/set_params.rb +18 -0
  25. data/spec/spec_helper.rb +63 -0
  26. data/spec/td/client/access_control_api_spec.rb +37 -0
  27. data/spec/td/client/account_api_spec.rb +34 -0
  28. data/spec/td/client/api_error_spec.rb +77 -0
  29. data/spec/td/client/api_spec.rb +269 -0
  30. data/spec/td/client/api_ssl_connection_spec.rb +109 -0
  31. data/spec/td/client/bulk_import_spec.rb +199 -0
  32. data/spec/td/client/bulk_load_spec.rb +401 -0
  33. data/spec/td/client/db_api_spec.rb +123 -0
  34. data/spec/td/client/export_api_spec.rb +51 -0
  35. data/spec/td/client/import_api_spec.rb +148 -0
  36. data/spec/td/client/job_api_spec.rb +833 -0
  37. data/spec/td/client/model_job_spec.rb +136 -0
  38. data/spec/td/client/model_schedule_spec.rb +26 -0
  39. data/spec/td/client/model_schema_spec.rb +134 -0
  40. data/spec/td/client/partial_delete_api_spec.rb +58 -0
  41. data/spec/td/client/result_api_spec.rb +77 -0
  42. data/spec/td/client/sched_api_spec.rb +109 -0
  43. data/spec/td/client/server_status_api_spec.rb +25 -0
  44. data/spec/td/client/spec_resources.rb +99 -0
  45. data/spec/td/client/table_api_spec.rb +226 -0
  46. data/spec/td/client/user_api_spec.rb +118 -0
  47. data/spec/td/client_sched_spec.rb +79 -0
  48. data/spec/td/client_spec.rb +46 -0
  49. metadata +271 -0
@@ -0,0 +1,123 @@
1
+ require 'spec_helper'
2
+ require 'td/client/spec_resources'
3
+
4
+ describe 'Database API' do
5
+ include_context 'spec symbols'
6
+ include_context 'common helper'
7
+
8
+ let :api do
9
+ API.new(nil)
10
+ end
11
+
12
+ let :client do
13
+ Client.new(apikey)
14
+ end
15
+
16
+ describe "'create_database' API" do
17
+ it 'should create a new database' do
18
+ stub_api_request(:post, "/v3/database/create/#{e(db_name)}").
19
+ to_return(:body => {'database' => db_name}.to_json)
20
+
21
+ expect(api.create_database(db_name)).to be true
22
+ end
23
+
24
+ it 'should return 400 error with invalid name' do
25
+ invalid_name = 'a'
26
+ err_msg = "Name must be 3 to 256 characters, got #{invalid_name.length} characters. name = '#{invalid_name}'"
27
+ stub_api_request(:post, "/v3/database/create/#{e(invalid_name)}").
28
+ to_return(:status => 400, :body => {'message' => err_msg}.to_json)
29
+
30
+ expect {
31
+ api.create_database(invalid_name)
32
+ }.to raise_error(TreasureData::APIError, /#{err_msg}/)
33
+ end
34
+
35
+ it 'should return 409 error with duplicated name' do
36
+ err_msg = "Database #{db_name} already exists"
37
+ stub_api_request(:post, "/v3/database/create/#{e(db_name)}").
38
+ to_return(:status => 409, :body => {'message' => err_msg}.to_json)
39
+
40
+ expect {
41
+ api.create_database(db_name)
42
+ }.to raise_error(TreasureData::AlreadyExistsError, /#{err_msg}/)
43
+ end
44
+ end
45
+
46
+ describe "'list_databases' API" do
47
+ it 'should list the databases with count, created_at, updated_at, organization, and permission' do
48
+ databases = [
49
+ ["db_1", 111, "2013-01-21 01:51:41 UTC", "2014-01-21 01:51:41 UTC", nil, "administrator"],
50
+ ["db_2", 222, "2013-02-22 02:52:42 UTC", "2014-02-22 02:52:42 UTC", nil, "full_access"],
51
+ ["db_3", 333, "2013-03-23 03:53:43 UTC", "2014-03-23 03:53:43 UTC", nil, "import_only"],
52
+ ["db_4", 444, "2013-04-24 04:54:44 UTC", "2014-04-24 04:54:44 UTC", nil, "query_only"]
53
+ ]
54
+ stub_api_request(:get, "/v3/database/list").
55
+ to_return(:body => {'databases' => [
56
+ {'name' => databases[0][0], 'count' => databases[0][1], 'created_at' => databases[0][2], 'updated_at' => databases[0][3], 'organization' => databases[0][4], 'permission' => databases[0][5]},
57
+ {'name' => databases[1][0], 'count' => databases[1][1], 'created_at' => databases[1][2], 'updated_at' => databases[1][3], 'organization' => databases[1][4], 'permission' => databases[1][5]},
58
+ {'name' => databases[2][0], 'count' => databases[2][1], 'created_at' => databases[2][2], 'updated_at' => databases[2][3], 'organization' => databases[2][4], 'permission' => databases[2][5]},
59
+ {'name' => databases[3][0], 'count' => databases[3][1], 'created_at' => databases[3][2], 'updated_at' => databases[3][3], 'organization' => databases[3][4], 'permission' => databases[3][5]}
60
+ ]}.to_json)
61
+
62
+ db_list = api.list_databases
63
+ databases.each {|db|
64
+ expect(db_list[db[0]]).to eq(db[1..-1])
65
+ }
66
+ end
67
+ end
68
+
69
+ describe "'databases' Client API" do
70
+ it 'should return an array of Databases objects containing name, count, created_at, updated_at, organization, and permission' do
71
+ databases = [
72
+ ["db_1", 111, "2013-01-21 01:51:41 UTC", "2014-01-21 01:51:41 UTC", nil, "administrator"],
73
+ ["db_2", 222, "2013-02-22 02:52:42 UTC", "2014-02-22 02:52:42 UTC", nil, "full_access"],
74
+ ["db_3", 333, "2013-03-23 03:53:43 UTC", "2014-03-23 03:53:43 UTC", nil, "import_only"],
75
+ ["db_4", 444, "2013-04-24 04:54:44 UTC", "2014-04-24 04:54:44 UTC", nil, "query_only"]
76
+ ]
77
+ stub_api_request(:get, "/v3/database/list").
78
+ to_return(:body => {'databases' => [
79
+ {'name' => databases[0][0], 'count' => databases[0][1], 'created_at' => databases[0][2], 'updated_at' => databases[0][3], 'organization' => databases[0][4], 'permission' => databases[0][5]},
80
+ {'name' => databases[1][0], 'count' => databases[1][1], 'created_at' => databases[1][2], 'updated_at' => databases[1][3], 'organization' => databases[1][4], 'permission' => databases[1][5]},
81
+ {'name' => databases[2][0], 'count' => databases[2][1], 'created_at' => databases[2][2], 'updated_at' => databases[2][3], 'organization' => databases[2][4], 'permission' => databases[2][5]},
82
+ {'name' => databases[3][0], 'count' => databases[3][1], 'created_at' => databases[3][2], 'updated_at' => databases[3][3], 'organization' => databases[3][4], 'permission' => databases[3][5]}
83
+ ]}.to_json)
84
+
85
+ db_list = client.databases.sort_by { |e| e.name }
86
+ databases.length.times {|i|
87
+ expect(db_list[i].name).to eq(databases[i][0])
88
+ expect(db_list[i].count).to eq(databases[i][1])
89
+ expect(db_list[i].created_at).to eq(Time.parse(databases[i][2]))
90
+ expect(db_list[i].updated_at).to eq(Time.parse(databases[i][3]))
91
+ expect(db_list[i].org_name).to eq(databases[i][4])
92
+ expect(db_list[i].permission).to eq(databases[i][5].to_sym)
93
+ }
94
+ end
95
+ end
96
+
97
+ describe "'database' Client API" do
98
+ it "should return the Databases object corresponding to the name and containing count, created_at, updated_at, organization, and permission" do
99
+ databases = [
100
+ ["db_1", 111, "2013-01-21 01:51:41 UTC", "2014-01-21 01:51:41 UTC", nil, "administrator"],
101
+ ["db_2", 222, "2013-02-22 02:52:42 UTC", "2014-02-22 02:52:42 UTC", nil, "full_access"],
102
+ ["db_3", 333, "2013-03-23 03:53:43 UTC", "2014-03-23 03:53:43 UTC", nil, "import_only"],
103
+ ["db_4", 444, "2013-04-24 04:54:44 UTC", "2014-04-24 04:54:44 UTC", nil, "query_only"]
104
+ ]
105
+ stub_api_request(:get, "/v3/database/list").
106
+ to_return(:body => {'databases' => [
107
+ {'name' => databases[0][0], 'count' => databases[0][1], 'created_at' => databases[0][2], 'updated_at' => databases[0][3], 'organization' => databases[0][4], 'permission' => databases[0][5]},
108
+ {'name' => databases[1][0], 'count' => databases[1][1], 'created_at' => databases[1][2], 'updated_at' => databases[1][3], 'organization' => databases[1][4], 'permission' => databases[1][5]},
109
+ {'name' => databases[2][0], 'count' => databases[2][1], 'created_at' => databases[2][2], 'updated_at' => databases[2][3], 'organization' => databases[2][4], 'permission' => databases[2][5]},
110
+ {'name' => databases[3][0], 'count' => databases[3][1], 'created_at' => databases[3][2], 'updated_at' => databases[3][3], 'organization' => databases[3][4], 'permission' => databases[3][5]}
111
+ ]}.to_json)
112
+
113
+ i = 1
114
+ db = client.database(databases[i][0])
115
+ expect(db.name).to eq(databases[i][0])
116
+ expect(db.count).to eq(databases[i][1])
117
+ expect(db.created_at).to eq(Time.parse(databases[i][2]))
118
+ expect(db.updated_at).to eq(Time.parse(databases[i][3]))
119
+ expect(db.org_name).to eq(databases[i][4])
120
+ expect(db.permission).to eq(databases[i][5].to_sym)
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+ require 'td/client/spec_resources'
3
+
4
+ describe 'Export API' do
5
+ include_context 'spec symbols'
6
+ include_context 'common helper'
7
+
8
+ let :api do
9
+ API.new(nil)
10
+ end
11
+
12
+ describe 'export' do
13
+ let :storage_type do
14
+ 's3'
15
+ end
16
+
17
+ it 'should export successfully' do
18
+ # TODO: Use correnty values
19
+ params = {'file_format' => 'json.gz', 'bucket' => 'bin', 'access_key_id' => 'id', 'secret_access_key' => 'secret'}
20
+ stub_api_request(:post, "/v3/export/run/#{e(db_name)}/#{e(table_name)}").with(:body => params.merge('storage_type' => storage_type)).
21
+ to_return(:body => {'database' => db_name, 'job_id' => '1', 'debug' => {}}.to_json)
22
+
23
+ expect(api.export(db_name, table_name, storage_type, params)).to eq('1')
24
+ end
25
+
26
+ it 'should return 400 error with invalid storage type' do
27
+ invalid_type = 'gridfs'
28
+ params = {'storage_type' => invalid_type}
29
+ err_msg = "Only s3 output type is supported: #{invalid_type}"
30
+ stub_api_request(:post, "/v3/export/run/#{e(db_name)}/#{e(table_name)}").with(:body => params).
31
+ to_return(:status => 400, :body => {'message' => err_msg}.to_json)
32
+
33
+ expect {
34
+ api.export(db_name, table_name, invalid_type)
35
+ }.to raise_error(TreasureData::APIError, /#{err_msg}/)
36
+ end
37
+
38
+ # TODO: Add other parameters spec
39
+ end
40
+
41
+ describe 'result_export' do
42
+ it 'should export result successfully' do
43
+ params = {'result' => 'mysql://user:pass@host.com/database/table'}
44
+ stub_api_request(:post, "/v3/job/result_export/100").with(:body => params).
45
+ to_return(:body => {'job_id' => '101'}.to_json)
46
+
47
+ expect(api.result_export(100, params)).to eq('101')
48
+ end
49
+ end
50
+ end
51
+
@@ -0,0 +1,148 @@
1
+ require 'spec_helper'
2
+ require 'td/client/spec_resources'
3
+ require 'json'
4
+ require 'tempfile'
5
+
6
+ describe 'Import API' do
7
+ include_context 'spec symbols'
8
+ include_context 'common helper'
9
+
10
+ let :api do
11
+ API.new(nil, :endpoint => endpoint)
12
+ end
13
+
14
+ let :api_old do
15
+ API.new(nil, :endpoint => endpoint_old)
16
+ end
17
+
18
+ let :api_default do
19
+ API.new(nil)
20
+ end
21
+
22
+ let :api_default_http do
23
+ API.new(nil, :ssl => false)
24
+ end
25
+
26
+ let :api_unknown_host do
27
+ API.new(nil, :endpoint => endpoint_unknown)
28
+ end
29
+
30
+ let :api_unknown_host_http do
31
+ API.new(nil, :endpoint => endpoint_unknown, :ssl => false)
32
+ end
33
+
34
+ let(:endpoint) { 'api.treasuredata.com' }
35
+ let(:endpoint_old) { TreasureData::API::OLD_ENDPOINT }
36
+ let(:endpoint_unknown) { "example.com" }
37
+ let(:endpoint_import) { "api-import.treasuredata.com" }
38
+ let(:endpoint_import_old) { "api-import.treasure-data.com" }
39
+ let(:endpoint_import_unknown) { endpoint_unknown }
40
+
41
+ describe 'import' do
42
+ it 'runs with unique_id' do
43
+ t = Tempfile.new('import_api_spec')
44
+ File.open(t.path, 'w') do |f|
45
+ f << '12345'
46
+ end
47
+ stub_request(:put, "https://#{endpoint_import}/v3/table/import_with_id/db/table/unique_id/format").
48
+ with(:body => '12345').
49
+ to_return(:body => '{"elapsed_time":"1.23"}')
50
+ File.open(t.path) do |f|
51
+ expect(api.import('db', 'table', 'format', f, 5, 'unique_id')).to eq(1.23)
52
+ end
53
+ end
54
+
55
+ it 'runs without unique_id' do
56
+ t = Tempfile.new('import_api_spec')
57
+ File.open(t.path, 'w') do |f|
58
+ f << '12345'
59
+ end
60
+ stub_request(:put, "https://#{endpoint_import}/v3/table/import/db/table/format").
61
+ with(:body => '12345').
62
+ to_return(:body => '{"elapsed_time":"1.23"}')
63
+ File.open(t.path) do |f|
64
+ expect(api.import('db', 'table', 'format', f, 5)).to eq(1.23)
65
+ end
66
+ end
67
+
68
+ it 'runs for old endpoint (force "http" instead of "https" for compatibility)' do
69
+ t = Tempfile.new('import_api_spec')
70
+ File.open(t.path, 'w') do |f|
71
+ f << '12345'
72
+ end
73
+ stub_request(:put, "http://#{endpoint_import_old}/v3/table/import/db/table/format").
74
+ with(:body => '12345').
75
+ to_return(:body => '{"elapsed_time":"1.23"}')
76
+ File.open(t.path) do |f|
77
+ expect(api_old.import('db', 'table', 'format', f, 5)).to eq(1.23)
78
+ end
79
+ end
80
+
81
+ it 'runs for no endpoint specified (default behavior)' do
82
+ t = Tempfile.new('import_api_spec')
83
+ File.open(t.path, 'w') do |f|
84
+ f << '12345'
85
+ end
86
+ stub_request(:put, "https://#{endpoint_import}/v3/table/import/db/table/format").
87
+ with(:body => '12345').
88
+ to_return(:body => '{"elapsed_time":"1.23"}')
89
+ File.open(t.path) do |f|
90
+ expect(api_default.import('db', 'table', 'format', f, 5)).to eq 1.23
91
+ end
92
+ end
93
+
94
+ it 'runs for no endpoint specified with ssl: false' do
95
+ t = Tempfile.new('import_api_spec')
96
+ File.open(t.path, 'w') do |f|
97
+ f << '12345'
98
+ end
99
+ stub_request(:put, "http://#{endpoint_import}/v3/table/import/db/table/format").
100
+ with(:body => '12345').
101
+ to_return(:body => '{"elapsed_time":"1.23"}')
102
+ File.open(t.path) do |f|
103
+ expect(api_default_http.import('db', 'table', 'format', f, 5)).to eq 1.23
104
+ end
105
+ end
106
+
107
+ it 'runs for unknown endpoint specified' do
108
+ t = Tempfile.new('import_api_spec')
109
+ File.open(t.path, 'w') do |f|
110
+ f << '12345'
111
+ end
112
+ stub_request(:put, "https://#{endpoint_unknown}/v3/table/import/db/table/format").
113
+ with(:body => '12345').
114
+ to_return(:body => '{"elapsed_time":"1.23"}')
115
+ File.open(t.path) do |f|
116
+ expect(api_unknown_host.import('db', 'table', 'format', f, 5)).to eq 1.23
117
+ end
118
+ end
119
+
120
+ it 'runs for unknown endpoint with ssl=false specified' do
121
+ t = Tempfile.new('import_api_spec')
122
+ File.open(t.path, 'w') do |f|
123
+ f << '12345'
124
+ end
125
+ stub_request(:put, "http://#{endpoint_unknown}/v3/table/import/db/table/format").
126
+ with(:body => '12345').
127
+ to_return(:body => '{"elapsed_time":"1.23"}')
128
+ File.open(t.path) do |f|
129
+ expect(api_unknown_host_http.import('db', 'table', 'format', f, 5)).to eq 1.23
130
+ end
131
+ end
132
+
133
+ it 'raises APIError' do
134
+ t = Tempfile.new('import_api_spec')
135
+ File.open(t.path, 'w') do |f|
136
+ f << '12345'
137
+ end
138
+ stub_request(:put, "https://#{endpoint_import}/v3/table/import/db/table/format").
139
+ with(:body => '12345').
140
+ to_return(:status => 500)
141
+ File.open(t.path) do |f|
142
+ expect {
143
+ api.import('db', 'table', 'format', f, 5)
144
+ }.to raise_error(TreasureData::APIError)
145
+ end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,833 @@
1
+ require 'spec_helper'
2
+ require 'td/client/spec_resources'
3
+ require 'json'
4
+ require 'webrick'
5
+ require 'logger'
6
+
7
+ describe 'Job API' do
8
+ include_context 'spec symbols'
9
+ include_context 'job resources'
10
+
11
+ let :api do
12
+ API.new(nil)
13
+ end
14
+
15
+ let :api_with_short_retry do
16
+ API.new(nil, {:max_cumul_retry_delay => 0})
17
+ end
18
+
19
+ describe 'list_jobs' do
20
+ it 'should returns 20 jobs by default' do
21
+ stub_api_request(:get, "/v3/job/list", :query => {'from' => '0'}).to_return(:body => {'jobs' => raw_jobs}.to_json)
22
+ jobs = api.list_jobs
23
+ expect(jobs.size).to eq(20)
24
+ end
25
+
26
+ (0...MAX_JOB).each {|i|
27
+ it "should get the correct fields for job #{i} of 20" do
28
+ job = raw_jobs[i]
29
+ stub_api_request(:get, "/v3/job/list", :query => {'from' => '0'}).to_return(:body => {'jobs' => raw_jobs}.to_json)
30
+
31
+ jobs = api.list_jobs
32
+ jobs[i..i].map {|job_id, type, status, query, start_at, end_at, cpu_time,
33
+ result_size, result_url, priority, retry_limit, org, db,
34
+ duration, num_records|
35
+ expect(job_id).to eq(job['job_id'])
36
+ expect(type).to eq(job['type'])
37
+ expect(status).to eq(job['status'])
38
+ expect(query).to eq(job['query'])
39
+ expect(start_at).to eq(job['start_at'])
40
+ expect(end_at).to eq(job['end_at'])
41
+ expect(cpu_time).to eq(job['cpu_time'])
42
+ expect(result_size).to eq(job['result_size'])
43
+ expect(result_url).to eq(job['result_url'])
44
+ expect(priority).to eq(job['priority'])
45
+ expect(retry_limit).to eq(job['retry_limit'])
46
+ expect(org).to eq(job['organization'])
47
+ expect(db).to eq(job['database'])
48
+ expect(duration).to eq(job['duration'])
49
+ expect(num_records).to eq(job['num_records'])
50
+ }
51
+ end
52
+ }
53
+
54
+ it 'should returns 10 jobs with to parameter' do
55
+ stub_api_request(:get, "/v3/job/list", :query => {'from' => '0', 'to' => '10'}).to_return(:body => {'jobs' => raw_jobs[0...10]}.to_json)
56
+ jobs = api.list_jobs(0, 10)
57
+ expect(jobs.size).to eq(10)
58
+ end
59
+
60
+ it 'should returns 10 jobs with to status parameter' do
61
+ error_jobs = raw_jobs.select { |j| j['status'] == 'error' }
62
+ stub_api_request(:get, "/v3/job/list", :query => {'from' => '0', 'status' => 'error'}).to_return(:body => {'jobs' => error_jobs}.to_json)
63
+ jobs = api.list_jobs(0, nil, 'error')
64
+ expect(jobs.size).to eq(error_jobs.size)
65
+ end
66
+
67
+ #it 'should contain the result_size field' do
68
+
69
+ end
70
+
71
+ describe 'show_job' do
72
+ (0...MAX_JOB).each { |i|
73
+ it "should get the correct fields for job #{i}" do
74
+ job = raw_jobs[i]
75
+ stub_api_request(:get, "/v3/job/show/#{e(i)}").to_return(:body => job.to_json)
76
+
77
+ type, query, status, url, debug, start_at, end_at, cpu_time,
78
+ result_size, result_url, hive_result_schema, priority, retry_limit, org, db, duration, num_records = api.show_job(i)
79
+ expect(type).to eq(job['type'])
80
+ expect(query).to eq(job['query'])
81
+ expect(status).to eq(job['status'])
82
+ expect(url).to eq(job['url'])
83
+ expect(debug).to eq(job['debug'])
84
+ expect(start_at).to eq(job['start_at'])
85
+ expect(end_at).to eq(job['end_at'])
86
+ expect(cpu_time).to eq(job['cpu_time'])
87
+ expect(result_size).to eq(job['result_size'])
88
+ expect(result_url).to eq(job['result_url'])
89
+ expect(hive_result_schema).to eq(job['hive_result_schema'])
90
+ expect(result_url).to eq(job['result_url'])
91
+ expect(priority).to eq(job['priority'])
92
+ expect(org).to eq(job['organization'])
93
+ expect(db).to eq(job['database'])
94
+ expect(duration).to eq(job['duration'])
95
+ expect(num_records).to eq(job['num_records'])
96
+ end
97
+ }
98
+
99
+ it 'should return an error with unknown id' do
100
+ unknown_id = 10000000000
101
+ body = {"message" => "Couldn't find Job with account_id = #{account_id}, id = #{unknown_id}"}
102
+ stub_api_request(:get, "/v3/job/show/#{e(unknown_id)}").to_return(:status => 404, :body => body.to_json)
103
+
104
+ expect {
105
+ api.show_job(unknown_id)
106
+ }.to raise_error(TreasureData::NotFoundError, /Couldn't find Job with account_id = #{account_id}, id = #{unknown_id}/)
107
+ end
108
+
109
+ it 'should return an error with invalid id' do
110
+ invalid_id = 'bomb!'
111
+ body = {"message" => "'job_id' parameter is required but missing"}
112
+ stub_api_request(:get, "/v3/job/show/#{e(invalid_id)}").to_return(:status => 500, :body => body.to_json)
113
+
114
+ expect {
115
+ api_with_short_retry.show_job(invalid_id)
116
+ }.to raise_error(TreasureData::APIError, /'job_id' parameter is required but missing/)
117
+ end
118
+ end
119
+
120
+ describe 'job status' do
121
+ (0...MAX_JOB).each { |i|
122
+ it "should return the status of a job #{i}" do
123
+ job_id = i.to_s
124
+ raw_job = raw_jobs[i]
125
+ result_job = {
126
+ 'job_id' => raw_job['job_id'],
127
+ 'status' => raw_job['status'],
128
+ 'created_at' => raw_job['created_at'],
129
+ 'start_at' => raw_job['start_at'],
130
+ 'end_at' => raw_job['end_at'],
131
+ }
132
+ stub_api_request(:get, "/v3/job/status/#{e(job_id)}").to_return(:body => result_job.to_json)
133
+
134
+ status = api.job_status(job_id)
135
+ expect(status).to eq(i.odd? ? 'success' : 'error')
136
+ end
137
+ }
138
+ end
139
+
140
+ describe 'hive_query' do
141
+ let :return_body do
142
+ {:body => {'job_id' => '1'}.to_json}
143
+ end
144
+
145
+ it 'issue a query' do
146
+ params = {'query' => query}
147
+ stub_api_request(:post, "/v3/job/issue/hive/#{e(db_name)}").with(:body => params).to_return(return_body)
148
+
149
+ job_id = api.hive_query(query, db_name)
150
+ expect(job_id).to eq('1')
151
+ end
152
+
153
+ it 'issue a query with result_url' do
154
+ params = {'query' => query, 'result' => 'td://@/test/table'}
155
+ stub_api_request(:post, "/v3/job/issue/hive/#{e(db_name)}").with(:body => params).to_return(return_body)
156
+
157
+ job_id = api.hive_query(query, db_name, 'td://@/test/table')
158
+ expect(job_id).to eq('1')
159
+ end
160
+
161
+ it 'issue a query with priority' do
162
+ params = {'query' => query, 'priority' => '1'}
163
+ stub_api_request(:post, "/v3/job/issue/hive/#{e(db_name)}").with(:body => params).to_return(return_body)
164
+
165
+ job_id = api.hive_query(query, db_name, nil, 1)
166
+ expect(job_id).to eq('1')
167
+ end
168
+ end
169
+
170
+ describe 'job_result' do
171
+ let :packed do
172
+ s = StringIO.new(String.new)
173
+ pk = MessagePack::Packer.new(s)
174
+ pk.write('hello')
175
+ pk.write('world')
176
+ pk.flush
177
+ s.string
178
+ end
179
+
180
+ it 'returns job result' do
181
+ stub_api_request(:get, '/v3/job/result/12345').
182
+ with(:query => {'format' => 'msgpack'}).
183
+ to_return(:body => packed)
184
+ expect(api.job_result(12345)).to eq(['hello', 'world'])
185
+ end
186
+
187
+ it '200->200 cannot resume' do
188
+ sz = packed.bytesize / 3
189
+ stub_api_request(:get, '/v3/job/result/12345').
190
+ with(:query => {'format' => 'msgpack'}).
191
+ to_return(
192
+ :headers => {
193
+ 'Content-Length' => packed.bytesize,
194
+ 'Etag' => '"abcdefghijklmn"',
195
+ },
196
+ :body => packed[0, sz]
197
+ )
198
+ stub_api_request(:get, '/v3/job/result/12345').
199
+ with(
200
+ :headers => {
201
+ 'If-Range' => '"abcdefghijklmn"',
202
+ 'Range' => "bytes=#{sz}-",
203
+ },
204
+ :query => {'format' => 'msgpack'}
205
+ ).
206
+ to_return(
207
+ :status => 200,
208
+ :headers => {
209
+ 'Content-Length' => packed.bytesize - sz,
210
+ 'Content-Range' => "bytes #{sz}-#{packed.bytesize-1}/#{packed.bytesize}",
211
+ 'Etag' => '"abcdefghijklmn"',
212
+ },
213
+ :body => packed
214
+ )
215
+ expect(api).to receive(:sleep).once
216
+ expect($stderr).to receive(:print)
217
+ expect($stderr).to receive(:puts)
218
+ expect{api.job_result(12345)}.to raise_error(TreasureData::APIError)
219
+ end
220
+
221
+ it '200->403 cannot resume' do
222
+ sz = packed.bytesize / 3
223
+ stub_api_request(:get, '/v3/job/result/12345').
224
+ with(:query => {'format' => 'msgpack'}).
225
+ to_return(
226
+ :headers => {
227
+ 'Content-Length' => packed.bytesize,
228
+ 'Etag' => '"abcdefghijklmn"',
229
+ },
230
+ :body => packed[0, sz]
231
+ )
232
+ stub_api_request(:get, '/v3/job/result/12345').
233
+ with(
234
+ :headers => {
235
+ 'If-Range' => '"abcdefghijklmn"',
236
+ 'Range' => "bytes=#{sz}-",
237
+ },
238
+ :query => {'format' => 'msgpack'}
239
+ ).
240
+ to_return(
241
+ :status => 403,
242
+ :headers => {
243
+ 'Content-Length' => packed.bytesize - sz,
244
+ 'Content-Range' => "bytes #{sz}-#{packed.bytesize-1}/#{packed.bytesize}",
245
+ 'Etag' => '"abcdefghijklmn"',
246
+ },
247
+ :body => packed
248
+ )
249
+ expect(api).to receive(:sleep).once
250
+ expect($stderr).to receive(:print)
251
+ expect($stderr).to receive(:puts)
252
+ expect{api.job_result(12345)}.to raise_error(TreasureData::APIError)
253
+ end
254
+
255
+ it 'can resume' do
256
+ sz = packed.bytesize / 3
257
+ stub_api_request(:get, '/v3/job/result/12345').
258
+ with(:query => {'format' => 'msgpack'}).
259
+ to_return(
260
+ :headers => {
261
+ 'Content-Length' => packed.bytesize,
262
+ 'Etag' => '"abcdefghijklmn"',
263
+ },
264
+ :body => packed[0, sz]
265
+ )
266
+ stub_api_request(:get, '/v3/job/result/12345').
267
+ with(
268
+ :headers => {
269
+ 'If-Range' => '"abcdefghijklmn"',
270
+ 'Range' => "bytes=#{sz}-",
271
+ },
272
+ :query => {'format' => 'msgpack'}
273
+ ).
274
+ to_return(
275
+ :status => 206,
276
+ :headers => {
277
+ 'Content-Length' => packed.bytesize - sz,
278
+ 'Content-Range' => "bytes #{sz}-#{packed.bytesize-1}/#{packed.bytesize}",
279
+ 'Etag' => '"abcdefghijklmn"',
280
+ },
281
+ :body => packed[sz, packed.bytesize - sz]
282
+ )
283
+ expect(api).to receive(:sleep).once
284
+ expect($stderr).to receive(:print)
285
+ expect($stderr).to receive(:puts)
286
+ expect(api.job_result(12345)).to eq ['hello', 'world']
287
+ end
288
+
289
+ it '200->500->206 can resume' do
290
+ sz = packed.bytesize / 3
291
+ stub_api_request(:get, '/v3/job/result/12345').
292
+ with(:query => {'format' => 'msgpack'}).
293
+ to_return(
294
+ :headers => {
295
+ 'Content-Length' => packed.bytesize,
296
+ 'Etag' => '"abcdefghijklmn"',
297
+ },
298
+ :body => packed[0, sz]
299
+ )
300
+ stub_api_request(:get, '/v3/job/result/12345').
301
+ with(
302
+ :headers => {
303
+ 'If-Range' => '"abcdefghijklmn"',
304
+ 'Range' => "bytes=#{sz}-",
305
+ },
306
+ :query => {'format' => 'msgpack'}
307
+ ).
308
+ to_return(
309
+ :status => 500,
310
+ :headers => {
311
+ 'Content-Length' => packed.bytesize - sz,
312
+ 'Content-Range' => "bytes #{sz}-#{packed.bytesize-1}/#{packed.bytesize}",
313
+ 'Etag' => '"abcdefghijklmn"',
314
+ },
315
+ :body => packed
316
+ )
317
+ stub_api_request(:get, '/v3/job/result/12345').
318
+ with(
319
+ :headers => {
320
+ 'If-Range' => '"abcdefghijklmn"',
321
+ 'Range' => "bytes=#{sz}-",
322
+ },
323
+ :query => {'format' => 'msgpack'}
324
+ ).
325
+ to_return(
326
+ :status => 206,
327
+ :headers => {
328
+ 'Content-Length' => packed.bytesize - sz,
329
+ 'Content-Range' => "bytes #{sz}-#{packed.bytesize-1}/#{packed.bytesize}",
330
+ 'Etag' => '"abcdefghijklmn"',
331
+ },
332
+ :body => packed[sz, packed.bytesize - sz]
333
+ )
334
+ expect(api).to receive(:sleep).once
335
+ expect($stderr).to receive(:print)
336
+ expect($stderr).to receive(:puts)
337
+ expect(api.job_result(12345)).to eq ['hello', 'world']
338
+ end
339
+
340
+ end
341
+
342
+ describe 'job_result_format' do
343
+ let :packed do
344
+ s = StringIO.new(String.new)
345
+ Zlib::GzipWriter.wrap(s) do |f|
346
+ f << ['hello', 'world'].to_json
347
+ end
348
+ s.string
349
+ end
350
+
351
+ context 'Content-Encoding is empty' do
352
+ let(:io) { StringIO.new }
353
+ let(:json) { ['hello', 'world'].to_json }
354
+
355
+ it 'retrunes json' do
356
+ stub_api_request(:get, '/v3/job/result/12345').
357
+ with(:query => {'format' => 'json'}).
358
+ to_return(:body => json)
359
+
360
+ total_size = 0
361
+ api.job_result_format(12345, 'json', io) {|size| total_size += size }
362
+
363
+ expect(io.string).to eq(json)
364
+ expect(total_size).to eq(json.size)
365
+ end
366
+ end
367
+
368
+ context 'Content-Encoding is gzip' do
369
+ it 'returns formatted job result' do
370
+ stub_api_request(:get, '/v3/job/result/12345').
371
+ with(:query => {'format' => 'json'}).
372
+ to_return(
373
+ :headers => {'Content-Encoding' => 'gzip'},
374
+ :body => packed
375
+ )
376
+ expect(api.job_result_format(12345, 'json')).to eq(['hello', 'world'].to_json)
377
+ end
378
+
379
+ it 'writes formatted job result' do
380
+ stub_api_request(:get, '/v3/job/result/12345').
381
+ with(:query => {'format' => 'json'}).
382
+ to_return(
383
+ :headers => {'Content-Encoding' => 'gzip'},
384
+ :body => packed
385
+ )
386
+ s = StringIO.new
387
+ api.job_result_format(12345, 'json', s)
388
+ expect(s.string).to eq(['hello', 'world'].to_json)
389
+ end
390
+
391
+ context 'can resume' do
392
+ before do
393
+ sz = packed.bytesize / 3
394
+ stub_api_request(:get, '/v3/job/result/12345').
395
+ with(:query => {'format' => 'json'}).
396
+ to_return(
397
+ :headers => {
398
+ 'Content-Encoding' => 'gzip',
399
+ 'Content-Length' => packed.bytesize,
400
+ 'Etag' => '"abcdefghijklmn"',
401
+ },
402
+ :body => packed[0, sz]
403
+ )
404
+ stub_api_request(:get, '/v3/job/result/12345').
405
+ with(
406
+ :headers => {
407
+ 'If-Range' => '"abcdefghijklmn"',
408
+ 'Range' => "bytes=#{sz}-",
409
+ },
410
+ :query => {'format' => 'json'}
411
+ ).
412
+ to_return(
413
+ :status => 206,
414
+ :headers => {
415
+ 'Content-Encoding' => 'gzip',
416
+ 'Content-Length' => packed.bytesize-sz,
417
+ 'Content-Range' => "bytes #{sz}-#{packed.bytesize-1}/#{packed.bytesize}",
418
+ 'Etag' => '"abcdefghijklmn"',
419
+ },
420
+ :body => packed[sz, packed.bytesize-sz]
421
+ )
422
+ expect(api).to receive(:sleep).once
423
+ expect($stderr).to receive(:print)
424
+ expect($stderr).to receive(:puts)
425
+ end
426
+ it 'can work with io' do
427
+ s = StringIO.new
428
+ api.job_result_format(12345, 'json', s)
429
+ expect(s.string).to eq ['hello', 'world'].to_json
430
+ end
431
+ it 'can work without block' do
432
+ expect(api.job_result_format(12345, 'json')).to eq ['hello', 'world'].to_json
433
+ end
434
+ end
435
+ end
436
+ end
437
+
438
+ describe 'job_result_each' do
439
+ let :packed do
440
+ s = StringIO.new(String.new)
441
+ Zlib::GzipWriter.wrap(s) do |f|
442
+ pk = MessagePack::Packer.new(f)
443
+ pk.write('hello')
444
+ pk.write('world')
445
+ pk.flush
446
+ end
447
+ s.string
448
+ end
449
+
450
+ it 'yields job result for each row' do
451
+ stub_api_request(:get, '/v3/job/result/12345').
452
+ with(:query => {'format' => 'msgpack'}).
453
+ to_return(
454
+ :headers => {'Content-Encoding' => 'gzip'},
455
+ :body => packed
456
+ )
457
+ result = []
458
+ api.job_result_each(12345) do |row|
459
+ result << row
460
+ end
461
+ expect(result).to eq(['hello', 'world'])
462
+ end
463
+
464
+ it 'can resume' do
465
+ sz= packed.bytesize / 3
466
+ stub_api_request(:get, '/v3/job/result/12345').
467
+ with(:query => {'format' => 'msgpack'}).
468
+ to_return(
469
+ :headers => {
470
+ 'Content-Encoding' => 'gzip',
471
+ 'Content-Length' => packed.bytesize,
472
+ 'Etag' => '"abcdefghijklmn"',
473
+ },
474
+ :body => packed[0, sz]
475
+ )
476
+ stub_api_request(:get, '/v3/job/result/12345').
477
+ with(
478
+ :headers => {
479
+ 'If-Range' => '"abcdefghijklmn"',
480
+ 'Range' => "bytes=#{sz}-",
481
+ },
482
+ :query => {'format' => 'msgpack'}
483
+ ).
484
+ to_return(
485
+ :status => 206,
486
+ :headers => {
487
+ 'Content-Length' => packed.bytesize-sz,
488
+ 'Content-Range' => "bytes #{sz}-#{packed.bytesize-1}/#{packed.bytesize}",
489
+ 'Etag' => '"abcdefghijklmn"',
490
+ },
491
+ :body => packed[sz, packed.bytesize-sz]
492
+ )
493
+ expect(api).to receive(:sleep).once
494
+ expect($stderr).to receive(:print)
495
+ expect($stderr).to receive(:puts)
496
+ result = []
497
+ api.job_result_each(12345) do |row|
498
+ result << row
499
+ end
500
+ expect(result).to eq ['hello', 'world']
501
+ end
502
+ end
503
+
504
+ describe 'job_result_each_with_compr_size' do
505
+ let :packed do
506
+ # Hard code fixture data to make the size stable
507
+ # s = StringIO.new
508
+ # Zlib::GzipWriter.wrap(s) do |f|
509
+ # pk = MessagePack::Packer.new(f)
510
+ # pk.write('hello')
511
+ # pk.write('world')
512
+ # pk.flush
513
+ # end
514
+ # s.string
515
+ "\x1F\x8B\b\x00#\xA1\x93T\x00\x03[\x9A\x91\x9A\x93\x93\xBF\xB4<\xBF('\x05\x00e 0\xB3\f\x00\x00\x00".force_encoding(Encoding::ASCII_8BIT)
516
+ end
517
+
518
+ it 'yields job result for each row with progress' do
519
+ stub_api_request(:get, '/v3/job/result/12345').
520
+ with(:query => {'format' => 'msgpack'}).
521
+ to_return(
522
+ :headers => {'Content-Encoding' => 'gzip'},
523
+ :body => packed
524
+ )
525
+ result = []
526
+ api.job_result_each_with_compr_size(12345) do |row, size|
527
+ result << [row, size]
528
+ end
529
+ expect(result).to eq([['hello', 32], ['world', 32]])
530
+ end
531
+
532
+ it 'can resume' do
533
+ sz = packed.bytesize / 3
534
+ stub_api_request(:get, '/v3/job/result/12345').
535
+ with(:query => {'format' => 'msgpack'}).
536
+ to_return(
537
+ :headers => {
538
+ 'Content-Encoding' => 'gzip',
539
+ 'Content-Length' => packed.bytesize,
540
+ 'Etag' => '"abcdefghijklmn"',
541
+ },
542
+ :body => packed[0, sz]
543
+ )
544
+ stub_api_request(:get, '/v3/job/result/12345').
545
+ with(
546
+ :headers => {
547
+ 'If-Range' => '"abcdefghijklmn"',
548
+ 'Range' => "bytes=#{sz}-",
549
+ },
550
+ :query => {'format' => 'msgpack'}
551
+ ).
552
+ to_return(
553
+ :status => 206,
554
+ :headers => {
555
+ 'Content-Length' => packed.bytesize - sz,
556
+ 'Content-Range' => "bytes #{sz}-#{packed.bytesize-1}/#{packed.bytesize}",
557
+ 'Etag' => '"abcdefghijklmn"',
558
+ },
559
+ :body => packed[sz, packed.bytesize - sz]
560
+ )
561
+ expect(api).to receive(:sleep).once
562
+ expect($stderr).to receive(:print)
563
+ expect($stderr).to receive(:puts)
564
+ result = []
565
+ api.job_result_each_with_compr_size(12345) do |row, size|
566
+ result << [row, size]
567
+ end
568
+ expect(result).to eq [['hello', 32], ['world', 32]]
569
+ end
570
+ end
571
+
572
+ describe 'job_result_raw' do
573
+ context 'with io' do
574
+ let(:io) { StringIO.new }
575
+
576
+ it 'returns raw result' do
577
+ stub_api_request(:get, '/v3/job/result/12345').
578
+ with(:query => {'format' => 'json'}).
579
+ to_return(:body => 'raw binary')
580
+ api.job_result_raw(12345, 'json', io)
581
+
582
+ expect(io.string).to eq('raw binary')
583
+ end
584
+ end
585
+
586
+ context 'witout io' do
587
+ it 'returns raw result' do
588
+ stub_api_request(:get, '/v3/job/result/12345').
589
+ with(:query => {'format' => 'json'}).
590
+ to_return(:body => 'raw binary')
591
+ expect(api.job_result_raw(12345, 'json')).to eq('raw binary')
592
+ end
593
+ end
594
+
595
+ let :packed do
596
+ # Hard code fixture data to make the size stable
597
+ # s = StringIO.new
598
+ # Zlib::GzipWriter.wrap(s) do |f|
599
+ # pk = MessagePack::Packer.new(f)
600
+ # pk.write('hello')
601
+ # pk.write('world')
602
+ # pk.flush
603
+ # end
604
+ # s.string
605
+ "\x1F\x8B\b\x00#\xA1\x93T\x00\x03[\x9A\x91\x9A\x93\x93\xBF\xB4<\xBF('\x05\x00e 0\xB3\f\x00\x00\x00".force_encoding(Encoding::ASCII_8BIT)
606
+ end
607
+
608
+ it 'can resume' do
609
+ sz = packed.bytesize / 3
610
+ stub_api_request(:get, '/v3/job/result/12345').
611
+ with(:query => {'format' => 'msgpack.gz'}).
612
+ to_return(
613
+ :headers => {
614
+ 'Content-Length' => packed.bytesize,
615
+ 'Etag' => '"abcdefghijklmn"',
616
+ },
617
+ :body => packed[0, sz]
618
+ )
619
+ stub_api_request(:get, '/v3/job/result/12345').
620
+ with(
621
+ :headers => {
622
+ 'If-Range' => '"abcdefghijklmn"',
623
+ 'Range' => "bytes=#{sz}-",
624
+ },
625
+ :query => {'format' => 'msgpack.gz'}
626
+ ).
627
+ to_return(
628
+ :status => 206,
629
+ :headers => {
630
+ 'Content-Length' => packed.bytesize - sz,
631
+ 'Content-Range' => "bytes #{sz}-#{packed.bytesize-1}/#{packed.bytesize}",
632
+ 'Etag' => '"abcdefghijklmn"',
633
+ },
634
+ :body => packed[sz, packed.bytesize - sz]
635
+ )
636
+ expect(api).to receive(:sleep).once
637
+ expect($stderr).to receive(:print)
638
+ expect($stderr).to receive(:puts)
639
+ sio = StringIO.new(String.new)
640
+ api.job_result_raw(12345, 'msgpack.gz', sio)
641
+ expect(sio.string).to eq(packed)
642
+ end
643
+ end
644
+
645
+ describe 'kill' do
646
+ it 'kills a job' do
647
+ stub_api_request(:post, '/v3/job/kill/12345').
648
+ to_return(:body => {'former_status' => 'status'}.to_json)
649
+ expect(api.kill(12345)).to eq('status')
650
+ end
651
+ end
652
+
653
+ describe 'job_result_download' do
654
+ let (:data){ [[1, 'hello', nil], [2, 'world', true], [3, '!', false]] }
655
+ let :formatted do
656
+ case format
657
+ when 'json'
658
+ data.map{|a| JSON(a) }.join("\n")
659
+ when 'msgpack'
660
+ pk = MessagePack::Packer.new
661
+ data.each{|x| pk.write(x) }
662
+ pk.to_str
663
+ else
664
+ raise
665
+ end
666
+ end
667
+ let :gziped do
668
+ s = StringIO.new(String.new)
669
+ Zlib::GzipWriter.wrap(s) do |f|
670
+ f.write formatted
671
+ end
672
+ s.string
673
+ end
674
+ let :deflated do
675
+ Zlib::Deflate.deflate(formatted)
676
+ end
677
+ subject do
678
+ str = ''
679
+ api.__send__(:job_result_download, 12345, format){|x| str << x }
680
+ str
681
+ end
682
+ context '200' do
683
+ before do
684
+ sz = packed.bytesize / 3
685
+ stub_api_request(:get, '/v3/job/result/12345').
686
+ with(:query => {'format' => format}).
687
+ to_return(
688
+ :headers => {
689
+ 'Content-Encoding' => content_encoding,
690
+ 'Content-Length' => packed.bytesize,
691
+ 'Etag' => '"abcdefghijklmn"',
692
+ },
693
+ :body => packed
694
+ )
695
+ expect(api).not_to receive(:sleep)
696
+ expect($stderr).not_to receive(:print)
697
+ expect($stderr).not_to receive(:puts)
698
+ end
699
+ context 'Content-Encoding: gzip' do
700
+ let (:content_encoding){ 'gzip' }
701
+ let (:packed){ gziped }
702
+ context 'msgpack' do
703
+ let (:format){ 'msgpack' }
704
+ it { is_expected.to eq formatted }
705
+ end
706
+ context 'json' do
707
+ let (:format){ 'json' }
708
+ it { is_expected.to eq formatted }
709
+ end
710
+ end
711
+ context 'Content-Encoding: deflate' do
712
+ let (:content_encoding){ 'deflate' }
713
+ let (:packed){ deflated }
714
+ context 'msgpack' do
715
+ let (:format){ 'msgpack' }
716
+ it { is_expected.to eq formatted }
717
+ end
718
+ context 'json' do
719
+ let (:format){ 'json' }
720
+ it { is_expected.to eq formatted }
721
+ end
722
+ end
723
+ end
724
+
725
+ context '200 -> 206' do
726
+ before do
727
+ sz = packed.bytesize / 3
728
+ stub_api_request(:get, '/v3/job/result/12345').
729
+ with(:query => {'format' => format}).
730
+ to_return(
731
+ :headers => {
732
+ 'Content-Encoding' => content_encoding,
733
+ 'Content-Length' => packed.bytesize,
734
+ 'Etag' => '"abcdefghijklmn"',
735
+ },
736
+ :body => packed[0, sz]
737
+ )
738
+ stub_api_request(:get, '/v3/job/result/12345').
739
+ with(
740
+ :headers => {
741
+ 'If-Range' => '"abcdefghijklmn"',
742
+ 'Range' => "bytes=#{sz}-",
743
+ },
744
+ :query => {'format' => format}
745
+ ).
746
+ to_return(
747
+ :status => 206,
748
+ :headers => {
749
+ 'Content-Encoding' => content_encoding,
750
+ 'Content-Length' => packed.bytesize - sz,
751
+ 'Content-Range' => "bytes #{sz}-#{packed.bytesize-1}/#{packed.bytesize}",
752
+ 'Etag' => '"abcdefghijklmn"',
753
+ },
754
+ :body => packed[sz, packed.bytesize - sz]
755
+ )
756
+ expect(api).to receive(:sleep).once
757
+ allow($stderr).to receive(:print)
758
+ allow($stderr).to receive(:puts)
759
+ end
760
+ context 'Content-Encoding: gzip' do
761
+ let (:content_encoding){ 'gzip' }
762
+ let (:packed){ gziped }
763
+ context 'msgpack' do
764
+ let (:format){ 'msgpack' }
765
+ it { is_expected.to eq formatted }
766
+ end
767
+ context 'json' do
768
+ let (:format){ 'json' }
769
+ it { is_expected.to eq formatted }
770
+ end
771
+ end
772
+ context 'Content-Encoding: deflate' do
773
+ let (:content_encoding){ 'deflate' }
774
+ let (:packed){ deflated }
775
+ context 'msgpack' do
776
+ let (:format){ 'msgpack' }
777
+ it { is_expected.to eq formatted }
778
+ end
779
+ context 'json' do
780
+ let (:format){ 'json' }
781
+ it { is_expected.to eq formatted }
782
+ end
783
+ end
784
+ end
785
+
786
+ context 'without autodecode' do
787
+ before do
788
+ sz = packed.bytesize / 3
789
+ stub_api_request(:get, '/v3/job/result/12345').
790
+ with(:query => {'format' => format}).
791
+ to_return(
792
+ :headers => {
793
+ 'Content-Length' => packed.bytesize,
794
+ 'Etag' => '"abcdefghijklmn"',
795
+ },
796
+ :body => packed
797
+ )
798
+ expect(api).not_to receive(:sleep)
799
+ expect($stderr).not_to receive(:print)
800
+ expect($stderr).not_to receive(:puts)
801
+ end
802
+ subject do
803
+ str = ''
804
+ api.__send__(:job_result_download, 12345, format, false){|x| str << x }
805
+ str
806
+ end
807
+ context 'Content-Encoding: gzip' do
808
+ let (:content_encoding){ 'gzip' }
809
+ let (:packed){ gziped }
810
+ context 'msgpack' do
811
+ let (:format){ 'msgpack' }
812
+ it { is_expected.to eq packed }
813
+ end
814
+ context 'json' do
815
+ let (:format){ 'json' }
816
+ it { is_expected.to eq packed }
817
+ end
818
+ end
819
+ context 'Content-Encoding: deflate' do
820
+ let (:content_encoding){ 'deflate' }
821
+ let (:packed){ deflated }
822
+ context 'msgpack' do
823
+ let (:format){ 'msgpack' }
824
+ it { is_expected.to eq packed }
825
+ end
826
+ context 'json' do
827
+ let (:format){ 'json' }
828
+ it { is_expected.to eq packed }
829
+ end
830
+ end
831
+ end
832
+ end
833
+ end