td-client 1.0.0-java

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