embulk-input-zendesk 0.1.0
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.
- checksums.yaml +7 -0
- data/.gitignore +6 -0
- data/.ruby-version +1 -0
- data/.travis.yml +44 -0
- data/.travis.yml.erb +43 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +2 -0
- data/LICENSE.txt +21 -0
- data/README.md +51 -0
- data/Rakefile +21 -0
- data/embulk-input-zendesk.gemspec +28 -0
- data/gemfiles/embulk-0.8.0-latest +4 -0
- data/gemfiles/embulk-0.8.1 +4 -0
- data/gemfiles/embulk-latest +4 -0
- data/gemfiles/template.erb +4 -0
- data/lib/embulk/input/zendesk.rb +9 -0
- data/lib/embulk/input/zendesk/client.rb +199 -0
- data/lib/embulk/input/zendesk/plugin.rb +138 -0
- data/test/capture_io.rb +45 -0
- data/test/embulk/input/zendesk/test_client.rb +469 -0
- data/test/embulk/input/zendesk/test_plugin.rb +338 -0
- data/test/fixture_helper.rb +11 -0
- data/test/fixtures/invalid_lack_username.yml +9 -0
- data/test/fixtures/invalid_unknown_auth.yml +9 -0
- data/test/fixtures/tickets.json +44 -0
- data/test/fixtures/valid_auth_basic.yml +11 -0
- data/test/fixtures/valid_auth_oauth.yml +10 -0
- data/test/fixtures/valid_auth_token.yml +11 -0
- data/test/override_assert_raise.rb +21 -0
- data/test/run-test.rb +26 -0
- metadata +253 -0
@@ -0,0 +1,138 @@
|
|
1
|
+
require "perfect_retry"
|
2
|
+
|
3
|
+
module Embulk
|
4
|
+
module Input
|
5
|
+
module Zendesk
|
6
|
+
class Plugin < InputPlugin
|
7
|
+
::Embulk::Plugin.register_input("zendesk", self)
|
8
|
+
|
9
|
+
def self.transaction(config, &control)
|
10
|
+
task = config_to_task(config)
|
11
|
+
client = Client.new(task)
|
12
|
+
client.validate_config
|
13
|
+
|
14
|
+
columns = task[:schema].map do |column|
|
15
|
+
name = column["name"]
|
16
|
+
type = column["type"].to_sym
|
17
|
+
|
18
|
+
Column.new(nil, name, type, column["format"])
|
19
|
+
end
|
20
|
+
|
21
|
+
resume(task, columns, 1, &control)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.resume(task, columns, count, &control)
|
25
|
+
task_reports = yield(task, columns, count)
|
26
|
+
|
27
|
+
next_config_diff = {}
|
28
|
+
return next_config_diff
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.guess(config)
|
32
|
+
task = config_to_task(config)
|
33
|
+
client = Client.new(task)
|
34
|
+
client.validate_config
|
35
|
+
|
36
|
+
records = []
|
37
|
+
client.public_send(task[:target]) do |record|
|
38
|
+
records << record
|
39
|
+
end
|
40
|
+
|
41
|
+
columns = Guess::SchemaGuess.from_hash_records(records).map do |column|
|
42
|
+
hash = column.to_h
|
43
|
+
hash.delete(:index)
|
44
|
+
hash.delete(:format) unless hash[:format]
|
45
|
+
|
46
|
+
# NOTE: Embulk 0.8.1 guesses Hash and Hashes in Array as string.
|
47
|
+
# https://github.com/embulk/embulk/issues/379
|
48
|
+
# This is workaround for that
|
49
|
+
if records.any? {|r| [Array, Hash].include?(r[hash[:name]].class) }
|
50
|
+
hash[:type] = :json
|
51
|
+
end
|
52
|
+
|
53
|
+
# NOTE: current version don't support JSON type
|
54
|
+
next if hash[:type] == :json
|
55
|
+
|
56
|
+
hash
|
57
|
+
end
|
58
|
+
|
59
|
+
return {"columns" => columns.compact}
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.config_to_task(config)
|
63
|
+
{
|
64
|
+
login_url: config.param("login_url", :string),
|
65
|
+
auth_method: config.param("auth_method", :string, default: "basic"),
|
66
|
+
target: config.param("target", :string),
|
67
|
+
username: config.param("username", :string, default: nil),
|
68
|
+
password: config.param("password", :string, default: nil),
|
69
|
+
token: config.param("token", :string, default: nil),
|
70
|
+
access_token: config.param("access_token", :string, default: nil),
|
71
|
+
start_time: config.param("start_time", :string, default: nil),
|
72
|
+
retry_limit: config.param("retry_limit", :integer, default: 5),
|
73
|
+
retry_initial_wait_sec: config.param("retry_initial_wait_sec", :integer, default: 1),
|
74
|
+
schema: config.param(:columns, :array, default: []),
|
75
|
+
}
|
76
|
+
end
|
77
|
+
|
78
|
+
def init
|
79
|
+
@start_time = Time.parse(task[:start_time]) if task[:start_time]
|
80
|
+
end
|
81
|
+
|
82
|
+
def run
|
83
|
+
method = task[:target]
|
84
|
+
args = [preview?]
|
85
|
+
if !preview? && @start_time
|
86
|
+
args << @start_time.to_i
|
87
|
+
end
|
88
|
+
|
89
|
+
client = Client.new(task)
|
90
|
+
client.public_send(method, *args) do |record|
|
91
|
+
values = extract_values(record)
|
92
|
+
page_builder.add(values)
|
93
|
+
end
|
94
|
+
|
95
|
+
page_builder.finish
|
96
|
+
|
97
|
+
task_report = {}
|
98
|
+
return task_report
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
def preview?
|
104
|
+
org.embulk.spi.Exec.isPreview()
|
105
|
+
rescue java.lang.NullPointerException => e
|
106
|
+
false
|
107
|
+
end
|
108
|
+
|
109
|
+
def extract_values(record)
|
110
|
+
values = task[:schema].map do |column|
|
111
|
+
value = record[column["name"].to_s]
|
112
|
+
cast(value, column["type"].to_s)
|
113
|
+
end
|
114
|
+
|
115
|
+
values
|
116
|
+
end
|
117
|
+
|
118
|
+
def cast(value, type)
|
119
|
+
case type
|
120
|
+
when "timestamp"
|
121
|
+
Time.parse(value)
|
122
|
+
when "double"
|
123
|
+
Float(value)
|
124
|
+
when "long"
|
125
|
+
Integer(value)
|
126
|
+
when "boolean"
|
127
|
+
!!value
|
128
|
+
when "string"
|
129
|
+
value.to_s
|
130
|
+
else
|
131
|
+
value
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
data/test/capture_io.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
module CaptureIo
|
2
|
+
def capture(output = :out, &block)
|
3
|
+
_, out = swap_io(output, &block)
|
4
|
+
out
|
5
|
+
end
|
6
|
+
|
7
|
+
def silence(&block)
|
8
|
+
block_result = nil
|
9
|
+
swap_io(:out) do
|
10
|
+
block_result,_ = swap_io(:err, &block)
|
11
|
+
end
|
12
|
+
block_result
|
13
|
+
end
|
14
|
+
|
15
|
+
def swap_io(output = :out, &block)
|
16
|
+
java_import 'java.io.PrintStream'
|
17
|
+
java_import 'java.io.ByteArrayOutputStream'
|
18
|
+
java_import 'java.lang.System'
|
19
|
+
|
20
|
+
ruby_original_stream = output == :out ? $stdout.dup : $stderr.dup
|
21
|
+
java_original_stream = System.send(output) # :out or :err
|
22
|
+
ruby_buf = StringIO.new
|
23
|
+
java_buf = ByteArrayOutputStream.new
|
24
|
+
|
25
|
+
case output
|
26
|
+
when :out
|
27
|
+
$stdout = ruby_buf
|
28
|
+
System.setOut(PrintStream.new(java_buf))
|
29
|
+
when :err
|
30
|
+
$stderr = ruby_buf
|
31
|
+
System.setErr(PrintStream.new(java_buf))
|
32
|
+
end
|
33
|
+
|
34
|
+
[block.call, ruby_buf.string + java_buf.toString]
|
35
|
+
ensure
|
36
|
+
case output
|
37
|
+
when :out
|
38
|
+
$stdout = ruby_original_stream
|
39
|
+
System.setOut(java_original_stream)
|
40
|
+
when :err
|
41
|
+
$stderr = ruby_original_stream
|
42
|
+
System.setErr(java_original_stream)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,469 @@
|
|
1
|
+
require "embulk"
|
2
|
+
Embulk.setup
|
3
|
+
|
4
|
+
require "yaml"
|
5
|
+
require "embulk/input/zendesk"
|
6
|
+
require "override_assert_raise"
|
7
|
+
require "fixture_helper"
|
8
|
+
require "capture_io"
|
9
|
+
|
10
|
+
module Embulk
|
11
|
+
module Input
|
12
|
+
module Zendesk
|
13
|
+
class TestClient < Test::Unit::TestCase
|
14
|
+
include OverrideAssertRaise
|
15
|
+
include FixtureHelper
|
16
|
+
include CaptureIo
|
17
|
+
|
18
|
+
sub_test_case "tickets" do
|
19
|
+
sub_test_case "partial" do
|
20
|
+
def client
|
21
|
+
@client ||= Client.new(login_url: login_url, auth_method: "oauth", access_token: access_token, retry_limit: 1, retry_initial_wait_sec: 0)
|
22
|
+
end
|
23
|
+
|
24
|
+
setup do
|
25
|
+
stub(Embulk).logger { Logger.new(File::NULL) }
|
26
|
+
@httpclient = client.httpclient
|
27
|
+
stub(client).httpclient { @httpclient }
|
28
|
+
end
|
29
|
+
|
30
|
+
test "fetch tickets" do
|
31
|
+
tickets = [
|
32
|
+
{"id" => 1},
|
33
|
+
{"id" => 2},
|
34
|
+
]
|
35
|
+
@httpclient.test_loopback_http_response << [
|
36
|
+
"HTTP/1.1 200",
|
37
|
+
"Content-Type: application/json",
|
38
|
+
"",
|
39
|
+
{
|
40
|
+
tickets: tickets
|
41
|
+
}.to_json
|
42
|
+
].join("\r\n")
|
43
|
+
|
44
|
+
handler = proc { }
|
45
|
+
tickets.each do |ticket|
|
46
|
+
mock(handler).call(ticket)
|
47
|
+
end
|
48
|
+
client.tickets(&handler)
|
49
|
+
end
|
50
|
+
|
51
|
+
test "raise DataError when invalid JSON response" do
|
52
|
+
@httpclient.test_loopback_http_response << [
|
53
|
+
"HTTP/1.1 200",
|
54
|
+
"Content-Type: application/json",
|
55
|
+
"",
|
56
|
+
"[[[" # invalid json
|
57
|
+
].join("\r\n")
|
58
|
+
|
59
|
+
assert_raise(DataError) do
|
60
|
+
client.tickets
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
sub_test_case "all" do
|
66
|
+
def client
|
67
|
+
@client ||= Client.new(login_url: login_url, auth_method: "oauth", access_token: access_token, retry_limit: 1, retry_initial_wait_sec: 0)
|
68
|
+
end
|
69
|
+
|
70
|
+
setup do
|
71
|
+
stub(Embulk).logger { Logger.new(File::NULL) }
|
72
|
+
@httpclient = client.httpclient
|
73
|
+
stub(client).httpclient { @httpclient }
|
74
|
+
end
|
75
|
+
|
76
|
+
test "fetch tickets" do
|
77
|
+
tickets = [
|
78
|
+
{"id" => 1},
|
79
|
+
{"id" => 2},
|
80
|
+
]
|
81
|
+
@httpclient.test_loopback_http_response << [
|
82
|
+
"HTTP/1.1 200",
|
83
|
+
"Content-Type: application/json",
|
84
|
+
"",
|
85
|
+
{
|
86
|
+
tickets: tickets
|
87
|
+
}.to_json
|
88
|
+
].join("\r\n")
|
89
|
+
|
90
|
+
handler = proc { }
|
91
|
+
tickets.each do |ticket|
|
92
|
+
mock(handler).call(ticket)
|
93
|
+
end
|
94
|
+
client.tickets(false, &handler)
|
95
|
+
end
|
96
|
+
|
97
|
+
test "fetch tickets without duplicated" do
|
98
|
+
tickets = [
|
99
|
+
{"id" => 1},
|
100
|
+
{"id" => 2},
|
101
|
+
{"id" => 1},
|
102
|
+
{"id" => 1},
|
103
|
+
]
|
104
|
+
@httpclient.test_loopback_http_response << [
|
105
|
+
"HTTP/1.1 200",
|
106
|
+
"Content-Type: application/json",
|
107
|
+
"",
|
108
|
+
{
|
109
|
+
tickets: tickets
|
110
|
+
}.to_json
|
111
|
+
].join("\r\n")
|
112
|
+
|
113
|
+
handler = proc { }
|
114
|
+
mock(handler).call(anything).twice
|
115
|
+
client.tickets(false, &handler)
|
116
|
+
end
|
117
|
+
|
118
|
+
test "fetch tickets with next_page" do
|
119
|
+
end_time = Time.now.to_i
|
120
|
+
|
121
|
+
response_1 = [
|
122
|
+
"HTTP/1.1 200",
|
123
|
+
"Content-Type: application/json",
|
124
|
+
"",
|
125
|
+
{
|
126
|
+
tickets: [{"id" => 1}],
|
127
|
+
count: 1000,
|
128
|
+
end_time: end_time,
|
129
|
+
}.to_json
|
130
|
+
].join("\r\n")
|
131
|
+
|
132
|
+
response_2 = [
|
133
|
+
"HTTP/1.1 200",
|
134
|
+
"Content-Type: application/json",
|
135
|
+
"",
|
136
|
+
{
|
137
|
+
tickets: [{"id" => 2}],
|
138
|
+
count: 2,
|
139
|
+
}.to_json
|
140
|
+
].join("\r\n")
|
141
|
+
|
142
|
+
@httpclient.test_loopback_http_response << response_1
|
143
|
+
@httpclient.test_loopback_http_response << response_2
|
144
|
+
|
145
|
+
handler = proc { }
|
146
|
+
mock(handler).call(anything).twice
|
147
|
+
client.tickets(false, &handler)
|
148
|
+
end
|
149
|
+
|
150
|
+
test "raise DataError when invalid JSON response" do
|
151
|
+
@httpclient.test_loopback_http_response << [
|
152
|
+
"HTTP/1.1 200",
|
153
|
+
"Content-Type: application/json",
|
154
|
+
"",
|
155
|
+
"[[[" # invalid json
|
156
|
+
].join("\r\n")
|
157
|
+
|
158
|
+
assert_raise(DataError) do
|
159
|
+
client.tickets(false)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
sub_test_case "targets" do
|
166
|
+
def client
|
167
|
+
@client ||= Client.new(login_url: login_url, auth_method: "oauth", access_token: access_token, retry_limit: 1, retry_initial_wait_sec: 0)
|
168
|
+
end
|
169
|
+
|
170
|
+
setup do
|
171
|
+
stub(Embulk).logger { Logger.new(File::NULL) }
|
172
|
+
@httpclient = client.httpclient
|
173
|
+
stub(client).httpclient { @httpclient }
|
174
|
+
end
|
175
|
+
|
176
|
+
sub_test_case "ticket_events" do
|
177
|
+
test "invoke incremental_export when partial=true" do
|
178
|
+
mock(client).incremental_export(anything, "ticket_events", anything, [])
|
179
|
+
client.ticket_events(true)
|
180
|
+
end
|
181
|
+
|
182
|
+
test "invoke incremental_export when partial=false" do
|
183
|
+
mock(client).incremental_export(anything, "ticket_events", anything, [])
|
184
|
+
client.ticket_events(false)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
sub_test_case "ticket_fields" do
|
189
|
+
test "invoke export when partial=true" do
|
190
|
+
mock(client).export(anything, "ticket_fields", anything)
|
191
|
+
client.ticket_fields(true)
|
192
|
+
end
|
193
|
+
|
194
|
+
test "invoke export when partial=false" do
|
195
|
+
mock(client).export(anything, "ticket_fields", anything)
|
196
|
+
client.ticket_fields(false)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
sub_test_case "ticket_forms" do
|
201
|
+
test "invoke export when partial=true" do
|
202
|
+
mock(client).export(anything, "ticket_forms", anything)
|
203
|
+
client.ticket_forms(true)
|
204
|
+
end
|
205
|
+
|
206
|
+
test "invoke export when partial=false" do
|
207
|
+
mock(client).export(anything, "ticket_forms", anything)
|
208
|
+
client.ticket_forms(false)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
|
214
|
+
sub_test_case "auth" do
|
215
|
+
test "httpclient call validate_credentials" do
|
216
|
+
client = Client.new({})
|
217
|
+
mock(client).validate_credentials
|
218
|
+
client.httpclient
|
219
|
+
end
|
220
|
+
|
221
|
+
sub_test_case "auth_method: basic" do
|
222
|
+
test "don't raise on validate when username and password given" do
|
223
|
+
client = Client.new(login_url: login_url, auth_method: "basic", username: username, password: password)
|
224
|
+
assert_nothing_raised do
|
225
|
+
client.validate_credentials
|
226
|
+
end
|
227
|
+
|
228
|
+
any_instance_of(HTTPClient) do |klass|
|
229
|
+
mock(klass).set_auth(login_url, username, password)
|
230
|
+
end
|
231
|
+
client.httpclient
|
232
|
+
end
|
233
|
+
|
234
|
+
test "set_auth called with valid credential" do
|
235
|
+
client = Client.new(login_url: login_url, auth_method: "basic", username: username, password: password)
|
236
|
+
|
237
|
+
any_instance_of(HTTPClient) do |klass|
|
238
|
+
mock(klass).set_auth(login_url, username, password)
|
239
|
+
end
|
240
|
+
client.httpclient
|
241
|
+
end
|
242
|
+
|
243
|
+
data do
|
244
|
+
[
|
245
|
+
["username", {username: "foo@example.com"}],
|
246
|
+
["password", {password: "passWORD"}],
|
247
|
+
["nothing both", {}],
|
248
|
+
]
|
249
|
+
end
|
250
|
+
test "username only given" do |config|
|
251
|
+
client = Client.new(config.merge(auth_method: "basic"))
|
252
|
+
assert_raise(ConfigError) do
|
253
|
+
client.validate_credentials
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
sub_test_case "auth_method: token" do
|
259
|
+
test "don't raise on validate when username and token given" do
|
260
|
+
client = Client.new(login_url: login_url, auth_method: "token", username: username, token: token)
|
261
|
+
assert_nothing_raised do
|
262
|
+
client.validate_credentials
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
test "set_auth called with valid credential" do
|
267
|
+
client = Client.new(login_url: login_url, auth_method: "token", username: username, token: token)
|
268
|
+
|
269
|
+
any_instance_of(HTTPClient) do |klass|
|
270
|
+
mock(klass).set_auth(login_url, "#{username}/token", token)
|
271
|
+
end
|
272
|
+
client.httpclient
|
273
|
+
end
|
274
|
+
|
275
|
+
data do
|
276
|
+
[
|
277
|
+
["username", {username: "foo@example.com"}],
|
278
|
+
["token", {token: "TOKEN"}],
|
279
|
+
["nothing both", {}],
|
280
|
+
]
|
281
|
+
end
|
282
|
+
test "username only given" do |config|
|
283
|
+
client = Client.new(config.merge(auth_method: "token"))
|
284
|
+
assert_raise(ConfigError) do
|
285
|
+
client.validate_credentials
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
sub_test_case "auth_method: oauth" do
|
291
|
+
test "don't raise on validate when access_token given" do
|
292
|
+
client = Client.new(login_url: login_url, auth_method: "oauth", access_token: access_token)
|
293
|
+
assert_nothing_raised do
|
294
|
+
client.validate_credentials
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
test "set default header with valid credential" do
|
299
|
+
client = Client.new(login_url: login_url, auth_method: "oauth", access_token: access_token)
|
300
|
+
|
301
|
+
any_instance_of(HTTPClient) do |klass|
|
302
|
+
mock(klass).default_header = {
|
303
|
+
"Authorization" => "Bearer #{access_token}"
|
304
|
+
}
|
305
|
+
end
|
306
|
+
client.httpclient
|
307
|
+
end
|
308
|
+
|
309
|
+
test "access_token not given" do |config|
|
310
|
+
client = Client.new(auth_method: "oauth")
|
311
|
+
assert_raise(ConfigError) do
|
312
|
+
client.validate_credentials
|
313
|
+
end
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
sub_test_case "auth_method: unknown" do
|
318
|
+
test "raise on validate" do
|
319
|
+
client = Client.new(auth_method: "unknown")
|
320
|
+
assert_raise(ConfigError) do
|
321
|
+
client.validate_credentials
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
sub_test_case "retry" do
|
328
|
+
def client
|
329
|
+
@client ||= Client.new(login_url: login_url, auth_method: "oauth", access_token: access_token, retry_limit: 2, retry_initial_wait_sec: 0)
|
330
|
+
end
|
331
|
+
|
332
|
+
def stub_response(status, headers = [])
|
333
|
+
@httpclient.test_loopback_http_response << [
|
334
|
+
"HTTP/1.1 #{status}",
|
335
|
+
"Content-Type: application/json",
|
336
|
+
headers.join("\r\n"),
|
337
|
+
"",
|
338
|
+
{
|
339
|
+
tickets: []
|
340
|
+
}.to_json
|
341
|
+
].join("\r\n")
|
342
|
+
end
|
343
|
+
|
344
|
+
setup do
|
345
|
+
retryer = PerfectRetry.new do |conf|
|
346
|
+
conf.dont_rescues = [Exception] # Don't care any exceptions to retry
|
347
|
+
end
|
348
|
+
|
349
|
+
stub(Embulk).logger { Logger.new(File::NULL) }
|
350
|
+
@httpclient = client.httpclient
|
351
|
+
stub(client).httpclient { @httpclient }
|
352
|
+
stub(client).retryer { retryer }
|
353
|
+
PerfectRetry.disable!
|
354
|
+
end
|
355
|
+
|
356
|
+
teardown do
|
357
|
+
PerfectRetry.enable!
|
358
|
+
end
|
359
|
+
|
360
|
+
test "400" do
|
361
|
+
stub_response(400)
|
362
|
+
assert_raise(ConfigError) do
|
363
|
+
client.tickets(&proc{})
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
test "401" do
|
368
|
+
stub_response(401)
|
369
|
+
assert_raise(ConfigError) do
|
370
|
+
client.tickets(&proc{})
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
test "409" do
|
375
|
+
stub_response(409)
|
376
|
+
assert_raise(StandardError) do
|
377
|
+
client.tickets(&proc{})
|
378
|
+
end
|
379
|
+
end
|
380
|
+
|
381
|
+
test "429" do
|
382
|
+
after = "123"
|
383
|
+
stub_response(429, ["Retry-After: #{after}"])
|
384
|
+
mock(client).sleep after.to_i
|
385
|
+
assert_throw(:retry) do
|
386
|
+
client.tickets(&proc{})
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
test "500" do
|
391
|
+
stub_response(500)
|
392
|
+
assert_raise(StandardError) do
|
393
|
+
client.tickets(&proc{})
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
test "503" do
|
398
|
+
stub_response(503)
|
399
|
+
assert_raise(StandardError) do
|
400
|
+
client.tickets(&proc{})
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
404
|
+
test "503 with Retry-After" do
|
405
|
+
after = "123"
|
406
|
+
stub_response(503, ["Retry-After: #{after}"])
|
407
|
+
mock(client).sleep after.to_i
|
408
|
+
assert_throw(:retry) do
|
409
|
+
client.tickets(&proc{})
|
410
|
+
end
|
411
|
+
end
|
412
|
+
|
413
|
+
test "Unhandled response code (555)" do
|
414
|
+
stub_response(555)
|
415
|
+
assert_raise(RuntimeError.new("Server returns unknown status code (555)")) do
|
416
|
+
client.tickets(&proc{})
|
417
|
+
end
|
418
|
+
end
|
419
|
+
end
|
420
|
+
|
421
|
+
sub_test_case ".validate_target" do
|
422
|
+
data do
|
423
|
+
[
|
424
|
+
["tickets", ["tickets", nil]],
|
425
|
+
["ticket_events", ["ticket_events", nil]],
|
426
|
+
["users", ["users", nil]],
|
427
|
+
["organizations", ["organizations", nil]],
|
428
|
+
["unknown", ["unknown", Embulk::ConfigError]],
|
429
|
+
]
|
430
|
+
end
|
431
|
+
test "validate with target" do |data|
|
432
|
+
target, error = data
|
433
|
+
client = Client.new({target: target})
|
434
|
+
|
435
|
+
if error
|
436
|
+
assert_raise(error) do
|
437
|
+
client.validate_target
|
438
|
+
end
|
439
|
+
else
|
440
|
+
assert_nothing_raised do
|
441
|
+
client.validate_target
|
442
|
+
end
|
443
|
+
end
|
444
|
+
end
|
445
|
+
end
|
446
|
+
|
447
|
+
def login_url
|
448
|
+
"http://example.com"
|
449
|
+
end
|
450
|
+
|
451
|
+
def username
|
452
|
+
"foo@example.com"
|
453
|
+
end
|
454
|
+
|
455
|
+
def password
|
456
|
+
"passWORD"
|
457
|
+
end
|
458
|
+
|
459
|
+
def token
|
460
|
+
"TOKEN"
|
461
|
+
end
|
462
|
+
|
463
|
+
def access_token
|
464
|
+
"ACCESS_TOKEN"
|
465
|
+
end
|
466
|
+
end
|
467
|
+
end
|
468
|
+
end
|
469
|
+
end
|