embulk-input-zendesk 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,338 @@
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 TestPlugin < Test::Unit::TestCase
14
+ include OverrideAssertRaise
15
+ include FixtureHelper
16
+ include CaptureIo
17
+
18
+ def run_with(yml)
19
+ silence do
20
+ Embulk::Runner.run(YAML.load fixture_load(yml))
21
+ end
22
+ end
23
+
24
+ sub_test_case "exec" do
25
+ setup do
26
+ stub(Plugin).resume { Hash.new }
27
+ end
28
+
29
+ test "run with valid.yml (basic)" do
30
+ assert_nothing_raised do
31
+ run_with("valid_auth_basic.yml")
32
+ end
33
+ end
34
+
35
+ test "run with valid.yml (token)" do
36
+ assert_nothing_raised do
37
+ run_with("valid_auth_token.yml")
38
+ end
39
+ end
40
+
41
+ test "run with valid.yml (oauth)" do
42
+ assert_nothing_raised do
43
+ run_with("valid_auth_oauth.yml")
44
+ end
45
+ end
46
+
47
+ test "run with invalid username lack" do
48
+ # NOTE: will be raised Java::OrgEmbulkExec::PartialExecutionException, not ConfigError. It is Embulk internally exception handling matter.
49
+ assert_raise do
50
+ run_with("invalid_lack_username.yml")
51
+ end
52
+ end
53
+ end
54
+
55
+ sub_test_case ".transaction" do
56
+ setup do
57
+ stub(Plugin).resume { Hash.new }
58
+ @control = proc { Hash.new }
59
+ end
60
+
61
+ def config(yml)
62
+ conf = YAML.load fixture_load(yml)
63
+ Embulk::DataSource.new(conf["in"])
64
+ end
65
+
66
+ test "lack username config" do
67
+ assert_raise(ConfigError) do
68
+ Plugin.transaction(config("invalid_lack_username.yml"), &@control)
69
+ end
70
+ end
71
+
72
+ test "unknown auth_method" do
73
+ assert_raise(ConfigError) do
74
+ Plugin.transaction(config("invalid_unknown_auth.yml"), &@control)
75
+ end
76
+ end
77
+
78
+ test "invoke Client#validate_config" do
79
+ any_instance_of(Client) do |klass|
80
+ mock(klass).validate_config
81
+ end
82
+ Plugin.transaction(config("valid_auth_oauth.yml"), &@control)
83
+ end
84
+
85
+ test "run as well" do
86
+ actual = nil
87
+ assert_nothing_raised do
88
+ actual = Plugin.transaction(config("valid_auth_oauth.yml"), &@control)
89
+ end
90
+
91
+ expected = {}
92
+ assert_equal expected, actual
93
+ end
94
+ end
95
+
96
+ sub_test_case ".guess" do
97
+ setup do
98
+ @client = Client.new(task)
99
+ stub(Client).new { @client }
100
+ @httpclient = @client.httpclient
101
+ stub(@client).httpclient { @httpclient }
102
+ end
103
+
104
+ test "invoke Client#validate_config" do
105
+ @httpclient.test_loopback_http_response << [
106
+ "HTTP/1.1 200",
107
+ "Content-Type: application/json",
108
+ "",
109
+ {
110
+ tickets: [
111
+ JSON.parse(fixture_load("tickets.json"))
112
+ ]
113
+ }.to_json
114
+ ].join("\r\n")
115
+ mock(@client).validate_config
116
+ Plugin.guess(config)["columns"]
117
+ end
118
+
119
+ test "guessing" do
120
+ @httpclient.test_loopback_http_response << [
121
+ "HTTP/1.1 200",
122
+ "Content-Type: application/json",
123
+ "",
124
+ {
125
+ tickets: [
126
+ JSON.parse(fixture_load("tickets.json"))
127
+ ]
128
+ }.to_json
129
+ ].join("\r\n")
130
+ actual = Plugin.guess(config)["columns"]
131
+ assert actual.include?(name: "url", type: :string)
132
+ assert actual.include?(name: "id", type: :long)
133
+ assert actual.include?(name: "created_at", type: :timestamp, format: "%Y-%m-%dT%H:%M:%S%z")
134
+ assert actual.include?(name: "has_incidents", type: :boolean)
135
+
136
+ # TODO: re-enable these json type tests after this plugin officially support it
137
+ # assert actual.include?(name: "tags", type: :json)
138
+ # assert actual.include?(name: "collaborator_ids", type: :json)
139
+
140
+ # assert actual.include?(name: "custom_fields", type: :json)
141
+ # assert actual.include?(name: "satisfaction_rating", type: :json)
142
+ end
143
+ end
144
+
145
+ sub_test_case "#run" do
146
+ def page_builder
147
+ @page_builder ||= Object.new
148
+ end
149
+
150
+ def schema
151
+ [
152
+ {"name" => "id", "type" => "long"}
153
+ ]
154
+ end
155
+
156
+ def run_task
157
+ task.merge({
158
+ schema: schema,
159
+ retry_limit: 1,
160
+ retry_initial_wait_sec: 0,
161
+ })
162
+ end
163
+
164
+ setup do
165
+ @client = Client.new(run_task)
166
+ stub(Client).new { @client }
167
+ @httpclient = @client.httpclient
168
+ stub(@client).httpclient { @httpclient }
169
+ @plugin = Plugin.new(run_task, nil, nil, page_builder)
170
+ end
171
+
172
+ sub_test_case "preview" do
173
+ setup do
174
+ stub(@plugin).preview? { true }
175
+ end
176
+
177
+ test "call tickets method instead of ticket_all" do
178
+ mock(@client).export(anything, "tickets", anything) { [] }
179
+ mock(@client).incremental_export.never
180
+ mock(page_builder).finish
181
+
182
+ @plugin.run
183
+ end
184
+
185
+ test "task[:schema] columns passed into page_builder.add" do
186
+ tickets = [
187
+ {"id" => 1, "created_at" => "2000-01-01T00:00:00+0900"},
188
+ {"id" => 2, "created_at" => "2000-01-01T00:00:00+0900"},
189
+ ]
190
+
191
+ @httpclient.test_loopback_http_response << [
192
+ "HTTP/1.1 200",
193
+ "Content-Type: application/json",
194
+ "",
195
+ {
196
+ tickets: tickets
197
+ }.to_json
198
+ ].join("\r\n")
199
+
200
+ tickets.each do |ticket|
201
+ mock(page_builder).add([ticket["id"]])
202
+ end
203
+ mock(page_builder).finish
204
+
205
+ @plugin.run
206
+ end
207
+ end
208
+
209
+ sub_test_case "run" do
210
+ setup do
211
+ stub(@plugin).preview? { false }
212
+ end
213
+
214
+ test "call ticket_all method instead of tickets" do
215
+ mock(@client).export.never
216
+ mock(@client).incremental_export(anything, "tickets", 0, []) { [] }
217
+ mock(page_builder).finish
218
+
219
+ @plugin.run
220
+ end
221
+
222
+ test "task[:schema] columns passed into page_builder.add" do
223
+ tickets = [
224
+ {"id" => 1, "created_at" => "2000-01-01T00:00:00+0900"},
225
+ {"id" => 2, "created_at" => "2000-01-01T00:00:00+0900"},
226
+ ]
227
+
228
+ @httpclient.test_loopback_http_response << [
229
+ "HTTP/1.1 200",
230
+ "Content-Type: application/json",
231
+ "",
232
+ {
233
+ tickets: tickets
234
+ }.to_json
235
+ ].join("\r\n")
236
+
237
+ tickets.each do |ticket|
238
+ mock(page_builder).add([ticket["id"]])
239
+ end
240
+ mock(page_builder).finish
241
+
242
+ @plugin.run
243
+ end
244
+
245
+ sub_test_case "casting value" do
246
+ setup do
247
+ stub(@plugin).preview? { false }
248
+ @httpclient.test_loopback_http_response << [
249
+ "HTTP/1.1 200",
250
+ "Content-Type: application/json",
251
+ "",
252
+ {
253
+ tickets: data
254
+ }.to_json
255
+ ].join("\r\n")
256
+ end
257
+
258
+ def schema
259
+ [
260
+ {"name" => "target_l", "type" => "long"},
261
+ {"name" => "target_f", "type" => "double"},
262
+ {"name" => "target_str", "type" => "string"},
263
+ {"name" => "target_bool", "type" => "boolean"},
264
+ {"name" => "target_time", "type" => "timestamp"},
265
+ ]
266
+ end
267
+
268
+ def data
269
+ [
270
+ {
271
+ "id" => 1, "target_l" => "3", "target_f" => "3", "target_str" => "str",
272
+ "target_bool" => false, "target_time" => "2000-01-01",
273
+ },
274
+ {
275
+ "id" => 2, "target_l" => 4.5, "target_f" => 4.5, "target_str" => 999,
276
+ "target_bool" => "truthy", "target_time" => Time.parse("1999-01-01"),
277
+ },
278
+ ]
279
+ end
280
+
281
+ test "cast as given type" do
282
+ mock(page_builder).add([3, 3.0, "str", false, Time.parse("2000-01-01")])
283
+ mock(page_builder).add([4, 4.5, "999", true, Time.parse("1999-01-01")])
284
+ mock(page_builder).finish
285
+
286
+ @plugin.run
287
+ end
288
+ end
289
+
290
+ sub_test_case "start_time option not given" do
291
+ test "Nothing passed to client" do
292
+ stub(page_builder).finish
293
+
294
+ mock(@client).tickets(false)
295
+ @plugin.run
296
+ end
297
+ end
298
+
299
+ sub_test_case "start_time option given" do
300
+ def run_task
301
+ task.merge({
302
+ start_time: "2000-01-01T00:00:00+0000",
303
+ schema: schema,
304
+ retry_limit: 1,
305
+ retry_initial_wait_sec: 0,
306
+ })
307
+ end
308
+
309
+ test "Passed to client as integer (epoch)" do
310
+ stub(page_builder).finish
311
+
312
+ start_time = Time.parse(run_task[:start_time]).to_i
313
+ mock(@client).tickets(false, start_time)
314
+ @plugin.run
315
+ end
316
+ end
317
+ end
318
+
319
+ end
320
+
321
+ def yml
322
+ "valid_auth_basic.yml"
323
+ end
324
+
325
+ def config
326
+ conf = YAML.load fixture_load(yml)
327
+ Embulk::DataSource.new(conf["in"])
328
+ end
329
+
330
+ def task
331
+ config.to_h.each_with_object({}) do |(k,v), result|
332
+ result[k.to_sym] = v
333
+ end
334
+ end
335
+ end
336
+ end
337
+ end
338
+ end
@@ -0,0 +1,11 @@
1
+ require "pathname"
2
+
3
+ module FixtureHelper
4
+ def fixture_dir
5
+ Pathname.new(__FILE__).dirname.join("fixtures")
6
+ end
7
+
8
+ def fixture_load(name)
9
+ fixture_dir.join(name).read
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ in:
2
+ type: zendesk
3
+ login_url: "https://example.zendesk.com/"
4
+ auth_method: basic
5
+ password: password
6
+ columns:
7
+ - {name: id, type: string}
8
+ out:
9
+ type: "null"
@@ -0,0 +1,9 @@
1
+ in:
2
+ type: zendesk
3
+ login_url: "https://example.zendesk.com/"
4
+ auth_method: blah
5
+ password: password
6
+ columns:
7
+ - {name: id, type: string}
8
+ out:
9
+ type: "null"
@@ -0,0 +1,44 @@
1
+ {
2
+ "id": 35436,
3
+ "url": "https://company.zendesk.com/api/v2/tickets/35436.json",
4
+ "external_id": "ahg35h3jh",
5
+ "created_at": "2009-07-20T22:55:29Z",
6
+ "updated_at": "2011-05-05T10:38:52Z",
7
+ "type": "incident",
8
+ "subject": "Help, my printer is on fire!",
9
+ "raw_subject": "{{dc.printer_on_fire}}",
10
+ "description": "The fire is very colorful.",
11
+ "priority": "high",
12
+ "status": "open",
13
+ "recipient": "support@company.com",
14
+ "requester_id": 20978392,
15
+ "submitter_id": 76872,
16
+ "assignee_id": 235323,
17
+ "organization_id": 509974,
18
+ "group_id": 98738,
19
+ "collaborator_ids": [35334, 234],
20
+ "forum_topic_id": 72648221,
21
+ "problem_id": 9873764,
22
+ "has_incidents": false,
23
+ "due_at": null,
24
+ "tags": ["enterprise", "other_tag"],
25
+ "via": {
26
+ "channel": "web"
27
+ },
28
+ "custom_fields": [
29
+ {
30
+ "id": 27642,
31
+ "value": "745"
32
+ },
33
+ {
34
+ "id": 27648,
35
+ "value": "yes"
36
+ }
37
+ ],
38
+ "satisfaction_rating": {
39
+ "id": 1234,
40
+ "score": "good",
41
+ "comment": "Great support!"
42
+ },
43
+ "sharing_agreement_ids": [84432]
44
+ }
@@ -0,0 +1,11 @@
1
+ in:
2
+ type: zendesk
3
+ login_url: "https://example.zendesk.com/"
4
+ auth_method: basic
5
+ target: tickets
6
+ username: foo@example.com
7
+ password: password
8
+ columns:
9
+ - {name: id, type: string}
10
+ out:
11
+ type: "null"
@@ -0,0 +1,10 @@
1
+ in:
2
+ type: zendesk
3
+ login_url: "https://example.zendesk.com/"
4
+ auth_method: oauth
5
+ target: tickets
6
+ access_token: oauth_token
7
+ columns:
8
+ - {name: id, type: string}
9
+ out:
10
+ type: "null"
@@ -0,0 +1,11 @@
1
+ in:
2
+ type: zendesk
3
+ login_url: "https://example.zendesk.com/"
4
+ auth_method: token
5
+ target: tickets
6
+ username: foo@example.com
7
+ token: token
8
+ columns:
9
+ - {name: id, type: string}
10
+ out:
11
+ type: "null"