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.
@@ -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"