embulk-input-zendesk-all 0.3.7
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 +12 -0
- data/.travis.yml +5 -0
- data/CHANGELOG.md +126 -0
- data/LICENSE.txt +21 -0
- data/README.md +91 -0
- data/build.gradle +123 -0
- data/config/checkstyle/checkstyle.xml +128 -0
- data/config/checkstyle/default.xml +108 -0
- data/gradle/wrapper/gradle-wrapper.jar +0 -0
- data/gradle/wrapper/gradle-wrapper.properties +5 -0
- data/gradlew +172 -0
- data/gradlew.bat +84 -0
- data/lib/embulk/guess/zendesk.rb +21 -0
- data/lib/embulk/input/zendesk.rb +3 -0
- data/src/main/java/org/embulk/input/zendesk/RecordImporter.java +134 -0
- data/src/main/java/org/embulk/input/zendesk/ZendeskInputPlugin.java +513 -0
- data/src/main/java/org/embulk/input/zendesk/clients/ZendeskRestClient.java +291 -0
- data/src/main/java/org/embulk/input/zendesk/models/AuthenticationMethod.java +23 -0
- data/src/main/java/org/embulk/input/zendesk/models/Target.java +47 -0
- data/src/main/java/org/embulk/input/zendesk/models/ZendeskException.java +25 -0
- data/src/main/java/org/embulk/input/zendesk/services/ZendeskCustomObjectService.java +110 -0
- data/src/main/java/org/embulk/input/zendesk/services/ZendeskNPSService.java +30 -0
- data/src/main/java/org/embulk/input/zendesk/services/ZendeskNormalServices.java +347 -0
- data/src/main/java/org/embulk/input/zendesk/services/ZendeskService.java +14 -0
- data/src/main/java/org/embulk/input/zendesk/services/ZendeskSupportAPIService.java +63 -0
- data/src/main/java/org/embulk/input/zendesk/services/ZendeskUserEventService.java +158 -0
- data/src/main/java/org/embulk/input/zendesk/stream/PagingSpliterator.java +40 -0
- data/src/main/java/org/embulk/input/zendesk/stream/paginator/sunshine/CustomObjectSpliterator.java +42 -0
- data/src/main/java/org/embulk/input/zendesk/stream/paginator/sunshine/SunshineSpliterator.java +66 -0
- data/src/main/java/org/embulk/input/zendesk/stream/paginator/sunshine/UserEventSpliterator.java +35 -0
- data/src/main/java/org/embulk/input/zendesk/stream/paginator/support/OrganizationSpliterator.java +13 -0
- data/src/main/java/org/embulk/input/zendesk/stream/paginator/support/SupportSpliterator.java +44 -0
- data/src/main/java/org/embulk/input/zendesk/stream/paginator/support/UserSpliterator.java +13 -0
- data/src/main/java/org/embulk/input/zendesk/utils/ZendeskConstants.java +72 -0
- data/src/main/java/org/embulk/input/zendesk/utils/ZendeskDateUtils.java +68 -0
- data/src/main/java/org/embulk/input/zendesk/utils/ZendeskUtils.java +92 -0
- data/src/test/java/org/embulk/input/zendesk/TestRecordImporter.java +114 -0
- data/src/test/java/org/embulk/input/zendesk/TestZendeskInputPlugin.java +402 -0
- data/src/test/java/org/embulk/input/zendesk/clients/TestZendeskRestClient.java +337 -0
- data/src/test/java/org/embulk/input/zendesk/services/TestZendeskCustomObjectService.java +161 -0
- data/src/test/java/org/embulk/input/zendesk/services/TestZendeskNPSService.java +56 -0
- data/src/test/java/org/embulk/input/zendesk/services/TestZendeskNormalService.java +261 -0
- data/src/test/java/org/embulk/input/zendesk/services/TestZendeskSupportAPIService.java +130 -0
- data/src/test/java/org/embulk/input/zendesk/services/TestZendeskUserEventService.java +158 -0
- data/src/test/java/org/embulk/input/zendesk/utils/TestZendeskDateUtils.java +87 -0
- data/src/test/java/org/embulk/input/zendesk/utils/TestZendeskUtil.java +22 -0
- data/src/test/java/org/embulk/input/zendesk/utils/ZendeskPluginTestRuntime.java +133 -0
- data/src/test/java/org/embulk/input/zendesk/utils/ZendeskTestHelper.java +92 -0
- data/src/test/resources/config/base.yml +14 -0
- data/src/test/resources/config/base_validator.yml +48 -0
- data/src/test/resources/config/incremental.yml +54 -0
- data/src/test/resources/config/non-incremental.yml +39 -0
- data/src/test/resources/config/nps.yml +31 -0
- data/src/test/resources/config/object_records.yml +24 -0
- data/src/test/resources/config/relationship_records.yml +23 -0
- data/src/test/resources/config/user_events.yml +29 -0
- data/src/test/resources/config/util.yml +18 -0
- data/src/test/resources/data/client.json +293 -0
- data/src/test/resources/data/duplicate_user.json +0 -0
- data/src/test/resources/data/empty_result.json +7 -0
- data/src/test/resources/data/error_data.json +187 -0
- data/src/test/resources/data/expected/ticket_column.json +148 -0
- data/src/test/resources/data/expected/ticket_column_with_related_objects.json +152 -0
- data/src/test/resources/data/expected/ticket_fields_column.json +92 -0
- data/src/test/resources/data/expected/ticket_metrics_column.json +98 -0
- data/src/test/resources/data/expected/user_events_column.json +40 -0
- data/src/test/resources/data/object_records.json +30 -0
- data/src/test/resources/data/organization.json +39 -0
- data/src/test/resources/data/relationship_records.json +57 -0
- data/src/test/resources/data/scores.json +21 -0
- data/src/test/resources/data/scores_share_same_time_with_next_page.json +35 -0
- data/src/test/resources/data/scores_share_same_time_without_next_page.json +35 -0
- data/src/test/resources/data/simple_organization.json +23 -0
- data/src/test/resources/data/simple_user.json +50 -0
- data/src/test/resources/data/simple_user_event.json +19 -0
- data/src/test/resources/data/ticket_events_share_same_time_with_next_page.json +279 -0
- data/src/test/resources/data/ticket_events_share_same_time_without_next_page.json +279 -0
- data/src/test/resources/data/ticket_events_updated_by_system_records.json +279 -0
- data/src/test/resources/data/ticket_fields.json +225 -0
- data/src/test/resources/data/ticket_metrics.json +397 -0
- data/src/test/resources/data/ticket_share_same_time_with_next_page.json +232 -0
- data/src/test/resources/data/ticket_share_same_time_without_next_page.json +232 -0
- data/src/test/resources/data/ticket_with_related_objects.json +67 -0
- data/src/test/resources/data/ticket_with_updated_by_system_records.json +187 -0
- data/src/test/resources/data/tickets.json +232 -0
- data/src/test/resources/data/tickets_continue.json +52 -0
- data/src/test/resources/data/user_event.json +19 -0
- data/src/test/resources/data/user_event_contain_latter_create_at.json +19 -0
- data/src/test/resources/data/user_event_multiple.json +33 -0
- data/src/test/resources/data/util.json +19 -0
- data/src/test/resources/data/util_page.json +227 -0
- metadata +168 -0
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
package org.embulk.input.zendesk.clients;
|
|
2
|
+
|
|
3
|
+
import com.fasterxml.jackson.databind.JsonNode;
|
|
4
|
+
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
|
5
|
+
import org.apache.http.Header;
|
|
6
|
+
|
|
7
|
+
import org.apache.http.HttpResponse;
|
|
8
|
+
import org.apache.http.StatusLine;
|
|
9
|
+
import org.apache.http.client.HttpClient;
|
|
10
|
+
import org.apache.http.client.methods.HttpRequestBase;
|
|
11
|
+
import org.apache.http.entity.StringEntity;
|
|
12
|
+
|
|
13
|
+
import org.embulk.EmbulkTestRuntime;
|
|
14
|
+
import org.embulk.config.ConfigException;
|
|
15
|
+
import org.embulk.config.ConfigSource;
|
|
16
|
+
import org.embulk.input.zendesk.ZendeskInputPlugin.PluginTask;
|
|
17
|
+
import org.embulk.input.zendesk.utils.ZendeskTestHelper;
|
|
18
|
+
|
|
19
|
+
import org.embulk.input.zendesk.utils.ZendeskUtils;
|
|
20
|
+
|
|
21
|
+
import org.junit.Before;
|
|
22
|
+
import org.junit.Rule;
|
|
23
|
+
import org.junit.Test;
|
|
24
|
+
|
|
25
|
+
import org.mockito.ArgumentCaptor;
|
|
26
|
+
|
|
27
|
+
import static org.apache.http.HttpHeaders.AUTHORIZATION;
|
|
28
|
+
import static org.junit.Assert.assertEquals;
|
|
29
|
+
import static org.junit.Assert.assertThrows;
|
|
30
|
+
import static org.junit.Assert.fail;
|
|
31
|
+
import static org.mockito.ArgumentMatchers.any;
|
|
32
|
+
import static org.mockito.Mockito.doReturn;
|
|
33
|
+
import static org.mockito.Mockito.mock;
|
|
34
|
+
import static org.mockito.Mockito.spy;
|
|
35
|
+
import static org.mockito.Mockito.times;
|
|
36
|
+
import static org.mockito.Mockito.verify;
|
|
37
|
+
import static org.mockito.Mockito.when;
|
|
38
|
+
|
|
39
|
+
import java.io.IOException;
|
|
40
|
+
import java.util.Optional;
|
|
41
|
+
|
|
42
|
+
public class TestZendeskRestClient
|
|
43
|
+
{
|
|
44
|
+
@SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
|
|
45
|
+
@Rule
|
|
46
|
+
public EmbulkTestRuntime embulkTestRuntime = new EmbulkTestRuntime();
|
|
47
|
+
|
|
48
|
+
private ZendeskRestClient zendeskRestClient;
|
|
49
|
+
private PluginTask task = ZendeskTestHelper.getConfigSource("incremental.yml").loadConfig(PluginTask.class);
|
|
50
|
+
private JsonNode data = ZendeskTestHelper.getJsonFromFile("data/client.json");
|
|
51
|
+
|
|
52
|
+
private HttpClient client = mock(HttpClient.class);
|
|
53
|
+
private HttpResponse response = mock(HttpResponse.class);
|
|
54
|
+
private Header header = mock(Header.class);
|
|
55
|
+
private StatusLine statusLine = mock(StatusLine.class);
|
|
56
|
+
|
|
57
|
+
@Before
|
|
58
|
+
public void prepare() throws IOException
|
|
59
|
+
{
|
|
60
|
+
zendeskRestClient = spy(new ZendeskRestClient());
|
|
61
|
+
|
|
62
|
+
when(zendeskRestClient.createHttpClient()).thenReturn(client);
|
|
63
|
+
when(client.execute(any())).thenReturn(response);
|
|
64
|
+
when(response.getStatusLine()).thenReturn(statusLine);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@Test
|
|
68
|
+
public void doGetSuccess()
|
|
69
|
+
{
|
|
70
|
+
setup("doGet200");
|
|
71
|
+
JsonNode expectedResult = ZendeskTestHelper.getJsonFromFile("data/tickets.json");
|
|
72
|
+
String result = zendeskRestClient.doGet("dummyString", task, false);
|
|
73
|
+
assertEquals(expectedResult.toString(), result);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
@Test
|
|
77
|
+
public void doGetRetryFail429WithoutRetryAfter()
|
|
78
|
+
{
|
|
79
|
+
String expectedMessage = "Status: '429', error message: 'Number of allowed incremental export API requests per minute exceeded'";
|
|
80
|
+
int expectedRetryTime = 3;
|
|
81
|
+
testExceptionMessageForDoGet("doGet429", expectedMessage, expectedRetryTime);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
@Test
|
|
85
|
+
public void doGetRetryFail429WithRetryAfter()
|
|
86
|
+
{
|
|
87
|
+
String expectedMessage = "Status: '429', error message: 'Number of allowed incremental export API requests per minute exceeded'";
|
|
88
|
+
int expectedRetryTime = 3;
|
|
89
|
+
|
|
90
|
+
when(response.containsHeader("x-rate-limit")).thenReturn(true);
|
|
91
|
+
when(response.getFirstHeader("x-rate-limit")).thenReturn(header);
|
|
92
|
+
when(response.getFirstHeader("Retry-After")).thenReturn(header);
|
|
93
|
+
when(header.getValue())
|
|
94
|
+
.thenReturn("5");
|
|
95
|
+
|
|
96
|
+
setupData("doGet429");
|
|
97
|
+
verifyData(expectedMessage, expectedRetryTime);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
@Test
|
|
101
|
+
public void doGetRetry405()
|
|
102
|
+
{
|
|
103
|
+
String expectedMessage = "Status '405', message 'dummy text'";
|
|
104
|
+
int expectedRetryTime = 1;
|
|
105
|
+
|
|
106
|
+
testExceptionMessageForDoGet("doGet405", expectedMessage, expectedRetryTime);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
@Test
|
|
110
|
+
public void doGetRetry422FailBecauseNotContainTooRecentStartTime()
|
|
111
|
+
{
|
|
112
|
+
String expectedMessage = "Status: '422', error message: 'dummy text'";
|
|
113
|
+
int expectedRetryTime = 1;
|
|
114
|
+
testExceptionMessageForDoGet("doGet422NotContainTooRecentStartTime", expectedMessage, expectedRetryTime);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@Test
|
|
118
|
+
public void doGetNotRetry422BecauseContainTooRecentStartTime()
|
|
119
|
+
{
|
|
120
|
+
String expectedMessage = "Status: '422', error message: 'dummy text'";
|
|
121
|
+
int expectedRetryTime = 1;
|
|
122
|
+
testExceptionMessageForDoGet("doGet422ContainTooRecentStartTime", expectedMessage, expectedRetryTime);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
@Test
|
|
126
|
+
public void doGetRetrySuccess429()
|
|
127
|
+
{
|
|
128
|
+
setupReTrySuccess("doGet429");
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
@Test
|
|
132
|
+
public void doGetRetry500()
|
|
133
|
+
{
|
|
134
|
+
setupReTrySuccess("doGet500");
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
@Test
|
|
138
|
+
public void doGetRetry503()
|
|
139
|
+
{
|
|
140
|
+
setupReTrySuccess("doGet503");
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
@Test
|
|
144
|
+
public void doGetRetry404()
|
|
145
|
+
{
|
|
146
|
+
setup("doGet404");
|
|
147
|
+
String expectedMessage = "Status: '404', error message: 'dummy text'";
|
|
148
|
+
int expectedRetryTime = 1;
|
|
149
|
+
try {
|
|
150
|
+
zendeskRestClient.doGet("any", task, false);
|
|
151
|
+
fail("Should not reach here");
|
|
152
|
+
}
|
|
153
|
+
catch (final Exception e) {
|
|
154
|
+
assertEquals(expectedMessage, e.getMessage());
|
|
155
|
+
}
|
|
156
|
+
verify(zendeskRestClient, times(expectedRetryTime)).createHttpClient();
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
@Test
|
|
160
|
+
public void doGetRetry409()
|
|
161
|
+
{
|
|
162
|
+
setupReTrySuccess("doGet409");
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
@Test
|
|
166
|
+
public void doGetRetryWhenStatusNot400s()
|
|
167
|
+
{
|
|
168
|
+
setupReTrySuccess("doGet502");
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
@Test
|
|
172
|
+
public void doGetRetry503WithRetryAfterNegative()
|
|
173
|
+
{
|
|
174
|
+
setup("doGet503");
|
|
175
|
+
|
|
176
|
+
int expectedRetryTime = 3;
|
|
177
|
+
when(response.getFirstHeader("Retry-After")).thenReturn(header);
|
|
178
|
+
when(header.getValue())
|
|
179
|
+
.thenReturn("5")
|
|
180
|
+
.thenReturn("-5");
|
|
181
|
+
|
|
182
|
+
try {
|
|
183
|
+
zendeskRestClient.doGet("any", task, false);
|
|
184
|
+
}
|
|
185
|
+
catch (final Exception e) {
|
|
186
|
+
}
|
|
187
|
+
verify(zendeskRestClient, times(expectedRetryTime)).createHttpClient();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
@Test
|
|
191
|
+
public void doGetRetryWhenThrowIOException() throws IOException
|
|
192
|
+
{
|
|
193
|
+
setupRateLimit();
|
|
194
|
+
|
|
195
|
+
when(client.execute(any()))
|
|
196
|
+
.thenThrow(new IOException());
|
|
197
|
+
|
|
198
|
+
int expectedRetryTime = 3;
|
|
199
|
+
assertThrows(ConfigException.class, () -> zendeskRestClient.doGet("any", task, false));
|
|
200
|
+
verify(zendeskRestClient, times(expectedRetryTime)).createHttpClient();
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
@Test
|
|
204
|
+
public void authenticationOauthSuccess() throws IOException
|
|
205
|
+
{
|
|
206
|
+
setup("doGet200");
|
|
207
|
+
|
|
208
|
+
String accessToken = "testzendesk";
|
|
209
|
+
|
|
210
|
+
ConfigSource configSource = ZendeskTestHelper.getConfigSource("incremental.yml");
|
|
211
|
+
configSource.set("auth_method", "oauth");
|
|
212
|
+
configSource.set("access_token", accessToken);
|
|
213
|
+
PluginTask pluginTask = configSource.loadConfig(PluginTask.class);
|
|
214
|
+
|
|
215
|
+
String expectedValue = "Bearer " + accessToken;
|
|
216
|
+
setupAndVerifyAuthenticationString(expectedValue, pluginTask);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
@Test
|
|
220
|
+
public void authenticationBasicSuccess() throws IOException
|
|
221
|
+
{
|
|
222
|
+
setup("doGet200");
|
|
223
|
+
|
|
224
|
+
String username = "zendesk_username";
|
|
225
|
+
String password = "zendesk_password";
|
|
226
|
+
|
|
227
|
+
ConfigSource configSource = ZendeskTestHelper.getConfigSource("incremental.yml");
|
|
228
|
+
configSource.set("auth_method", "basic");
|
|
229
|
+
configSource.set("username", Optional.of(username));
|
|
230
|
+
configSource.set("password", password);
|
|
231
|
+
PluginTask pluginTask = configSource.loadConfig(PluginTask.class);
|
|
232
|
+
|
|
233
|
+
String expectedValue = "Basic " + ZendeskUtils.convertBase64(String.format("%s:%s", username, password));
|
|
234
|
+
setupAndVerifyAuthenticationString(expectedValue, pluginTask);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
@Test
|
|
238
|
+
public void authenticationTokenSuccess() throws IOException
|
|
239
|
+
{
|
|
240
|
+
setup("doGet200");
|
|
241
|
+
|
|
242
|
+
String username = "zendesk_username";
|
|
243
|
+
String token = "zendesk_token";
|
|
244
|
+
|
|
245
|
+
ConfigSource configSource = ZendeskTestHelper.getConfigSource("incremental.yml");
|
|
246
|
+
configSource.set("auth_method", "token");
|
|
247
|
+
configSource.set("username", username);
|
|
248
|
+
configSource.set("token", token);
|
|
249
|
+
PluginTask pluginTask = configSource.loadConfig(PluginTask.class);
|
|
250
|
+
|
|
251
|
+
String expectedValue = "Basic " + ZendeskUtils.convertBase64(String.format("%s/token:%s", username, token));
|
|
252
|
+
setupAndVerifyAuthenticationString(expectedValue, pluginTask);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
private void setupRateLimit()
|
|
256
|
+
{
|
|
257
|
+
when(response.containsHeader("x-rate-limit")).thenReturn(true);
|
|
258
|
+
when(response.getFirstHeader("x-rate-limit")).thenReturn(header);
|
|
259
|
+
when(header.getValue()).thenReturn("400");
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
private void setup(String name)
|
|
263
|
+
{
|
|
264
|
+
setupRateLimit();
|
|
265
|
+
setupData(name);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
private void setupData(String name)
|
|
269
|
+
{
|
|
270
|
+
JsonNode messageResponse = data.get(name);
|
|
271
|
+
when(statusLine.getStatusCode()).thenReturn(messageResponse.get("statusCode").asInt());
|
|
272
|
+
try {
|
|
273
|
+
if (name.equals("doGet200")) {
|
|
274
|
+
doReturn(new StringEntity(messageResponse.get("body").toString())).when(response).getEntity();
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
doReturn(new StringEntity(messageResponse.get("description").asText())).when(response).getEntity();
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
catch (Exception e) {
|
|
281
|
+
fail("fail to setup client for UT");
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
private void testExceptionMessageForDoGet(String name, String expectedMessage, int expectedRetryTime)
|
|
286
|
+
{
|
|
287
|
+
setup(name);
|
|
288
|
+
verifyData(expectedMessage, expectedRetryTime);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
private void verifyData(String expectedMessage, int expectedRetryTime)
|
|
292
|
+
{
|
|
293
|
+
try {
|
|
294
|
+
zendeskRestClient.doGet("any", task, false);
|
|
295
|
+
fail("Should not reach here");
|
|
296
|
+
}
|
|
297
|
+
catch (final Exception e) {
|
|
298
|
+
assertEquals(expectedMessage, e.getMessage());
|
|
299
|
+
}
|
|
300
|
+
verify(zendeskRestClient, times(expectedRetryTime)).createHttpClient();
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
private void setupReTrySuccess(String entityName)
|
|
304
|
+
{
|
|
305
|
+
setupRateLimit();
|
|
306
|
+
|
|
307
|
+
JsonNode messageResponse = data.get(entityName);
|
|
308
|
+
JsonNode messageResponseSuccess = data.get("doGet200");
|
|
309
|
+
|
|
310
|
+
when(statusLine.getStatusCode())
|
|
311
|
+
.thenReturn(messageResponse.get("statusCode").asInt())
|
|
312
|
+
.thenReturn(messageResponseSuccess.get("statusCode").asInt());
|
|
313
|
+
|
|
314
|
+
try {
|
|
315
|
+
when(response.getEntity())
|
|
316
|
+
.thenReturn(new StringEntity(messageResponse.get("description").asText()))
|
|
317
|
+
.thenReturn(new StringEntity(messageResponseSuccess.get("body").toString()));
|
|
318
|
+
}
|
|
319
|
+
catch (Exception e) {
|
|
320
|
+
fail("fail to setup client for UT");
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
int expectedRetryTime = 2;
|
|
324
|
+
zendeskRestClient.doGet("any", task, false);
|
|
325
|
+
verify(zendeskRestClient, times(expectedRetryTime)).createHttpClient();
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
private void setupAndVerifyAuthenticationString(String expectedString, PluginTask pluginTask) throws IOException
|
|
329
|
+
{
|
|
330
|
+
zendeskRestClient.doGet("any", pluginTask, false);
|
|
331
|
+
final ArgumentCaptor<HttpRequestBase> request = ArgumentCaptor.forClass(HttpRequestBase.class);
|
|
332
|
+
verify(client).execute(request.capture());
|
|
333
|
+
|
|
334
|
+
String credential = request.getValue().getFirstHeader(AUTHORIZATION).getValue();
|
|
335
|
+
assertEquals(expectedString, credential);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
package org.embulk.input.zendesk.services;
|
|
2
|
+
|
|
3
|
+
import com.fasterxml.jackson.databind.JsonNode;
|
|
4
|
+
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
|
5
|
+
import org.embulk.EmbulkTestRuntime;
|
|
6
|
+
|
|
7
|
+
import org.embulk.config.TaskReport;
|
|
8
|
+
import org.embulk.input.zendesk.RecordImporter;
|
|
9
|
+
import org.embulk.input.zendesk.ZendeskInputPlugin;
|
|
10
|
+
import org.embulk.input.zendesk.clients.ZendeskRestClient;
|
|
11
|
+
import org.embulk.input.zendesk.utils.ZendeskTestHelper;
|
|
12
|
+
import org.junit.Assert;
|
|
13
|
+
import org.junit.Before;
|
|
14
|
+
import org.junit.Rule;
|
|
15
|
+
import org.junit.Test;
|
|
16
|
+
import org.mockito.ArgumentCaptor;
|
|
17
|
+
|
|
18
|
+
import java.util.Arrays;
|
|
19
|
+
import java.util.List;
|
|
20
|
+
|
|
21
|
+
import static org.junit.Assert.assertEquals;
|
|
22
|
+
import static org.junit.Assert.assertFalse;
|
|
23
|
+
import static org.junit.Assert.assertTrue;
|
|
24
|
+
import static org.mockito.ArgumentMatchers.any;
|
|
25
|
+
import static org.mockito.ArgumentMatchers.anyBoolean;
|
|
26
|
+
import static org.mockito.Mockito.atMost;
|
|
27
|
+
import static org.mockito.Mockito.mock;
|
|
28
|
+
import static org.mockito.Mockito.spy;
|
|
29
|
+
import static org.mockito.Mockito.times;
|
|
30
|
+
import static org.mockito.Mockito.verify;
|
|
31
|
+
import static org.mockito.Mockito.when;
|
|
32
|
+
|
|
33
|
+
public class TestZendeskCustomObjectService
|
|
34
|
+
{
|
|
35
|
+
@Rule
|
|
36
|
+
@SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
|
|
37
|
+
public EmbulkTestRuntime runtime = new EmbulkTestRuntime();
|
|
38
|
+
|
|
39
|
+
private ZendeskRestClient zendeskRestClient;
|
|
40
|
+
|
|
41
|
+
private ZendeskCustomObjectService zendeskCustomObjectService;
|
|
42
|
+
|
|
43
|
+
private RecordImporter recordImporter;
|
|
44
|
+
|
|
45
|
+
@Before
|
|
46
|
+
public void prepare()
|
|
47
|
+
{
|
|
48
|
+
zendeskRestClient = mock(ZendeskRestClient.class);
|
|
49
|
+
recordImporter = mock(RecordImporter.class);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
@Test
|
|
53
|
+
public void testGetListPathForObjectRecord()
|
|
54
|
+
{
|
|
55
|
+
setup("object_records.yml");
|
|
56
|
+
List<String> expectedStrings = Arrays.asList(
|
|
57
|
+
"https://abc.zendesk.com/api/sunshine/objects/records?type=account&per_page=1000",
|
|
58
|
+
"https://abc.zendesk.com/api/sunshine/objects/records?type=user&per_page=1000"
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
zendeskCustomObjectService.addRecordToImporter(0, recordImporter);
|
|
62
|
+
final ArgumentCaptor<String> actualString = ArgumentCaptor.forClass(String.class);
|
|
63
|
+
verify(zendeskRestClient, times(2)).doGet(actualString.capture(), any(), anyBoolean());
|
|
64
|
+
assertTrue(actualString.getAllValues().contains(expectedStrings.get(0)));
|
|
65
|
+
assertTrue(actualString.getAllValues().contains(expectedStrings.get(1)));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
@Test
|
|
69
|
+
public void testGetListPathForRelationshipRecord()
|
|
70
|
+
{
|
|
71
|
+
setup("relationship_records.yml");
|
|
72
|
+
String expectedStrings = "https://abc.zendesk.com/api/sunshine/relationships/records?type=ticket_to_account&per_page=1000";
|
|
73
|
+
zendeskCustomObjectService.addRecordToImporter(0, recordImporter);
|
|
74
|
+
final ArgumentCaptor<String> actualString = ArgumentCaptor.forClass(String.class);
|
|
75
|
+
verify(zendeskRestClient).doGet(actualString.capture(), any(), anyBoolean());
|
|
76
|
+
assertEquals(expectedStrings, actualString.getValue());
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
@Test
|
|
80
|
+
public void testAddRecordToImporterObjectRecord()
|
|
81
|
+
{
|
|
82
|
+
ZendeskTestHelper.setPreviewMode(runtime, false);
|
|
83
|
+
setup("object_records.yml");
|
|
84
|
+
loadData("data/object_records.json");
|
|
85
|
+
zendeskCustomObjectService.addRecordToImporter(0, recordImporter);
|
|
86
|
+
// 2 types - each type 2 records
|
|
87
|
+
verify(recordImporter, times(4)).addRecord(any());
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
@Test
|
|
91
|
+
public void testAddRecordToImporterRelationShipRecord()
|
|
92
|
+
{
|
|
93
|
+
ZendeskTestHelper.setPreviewMode(runtime, false);
|
|
94
|
+
setup("relationship_records.yml");
|
|
95
|
+
loadData("data/relationship_records.json");
|
|
96
|
+
zendeskCustomObjectService.addRecordToImporter(0, recordImporter);
|
|
97
|
+
// 7 records
|
|
98
|
+
verify(recordImporter, times(7)).addRecord(any());
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
@Test
|
|
102
|
+
public void testGetData()
|
|
103
|
+
{
|
|
104
|
+
setup("object_records.yml");
|
|
105
|
+
loadData("data/object_records.json");
|
|
106
|
+
JsonNode jsonNode = zendeskCustomObjectService.getDataFromPath("https://abc.zendesk.com/api/sunshine/objects/records?type=user&per_page=1000", 0, true, 0);
|
|
107
|
+
assertFalse(jsonNode.isNull());
|
|
108
|
+
assertTrue(jsonNode.has("data"));
|
|
109
|
+
assertTrue(jsonNode.get("data").isArray());
|
|
110
|
+
|
|
111
|
+
setup("relationship_records.yml");
|
|
112
|
+
loadData("data/relationship_records.json");
|
|
113
|
+
jsonNode = zendeskCustomObjectService.getDataFromPath("https://abc.zendesk.com/api/sunshine/relationships/records?type=user&per_page=1000", 0, true, 0);
|
|
114
|
+
assertFalse(jsonNode.isNull());
|
|
115
|
+
assertTrue(jsonNode.has("data"));
|
|
116
|
+
assertTrue(jsonNode.get("data").isArray());
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
@Test
|
|
120
|
+
public void testAddRecordToImporterInPreviewObjectRecord()
|
|
121
|
+
{
|
|
122
|
+
ZendeskTestHelper.setPreviewMode(runtime, true);
|
|
123
|
+
setup("object_records.yml");
|
|
124
|
+
loadData("data/object_records.json");
|
|
125
|
+
TaskReport taskReport = zendeskCustomObjectService.addRecordToImporter(0, recordImporter);
|
|
126
|
+
|
|
127
|
+
// expect to be break and don't import all records
|
|
128
|
+
verify(recordImporter, atMost(3)).addRecord(any());
|
|
129
|
+
Assert.assertTrue(taskReport.isEmpty());
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
@Test
|
|
133
|
+
public void testAddRecordToImporterInPreviewRelationshipRecord()
|
|
134
|
+
{
|
|
135
|
+
ZendeskTestHelper.setPreviewMode(runtime, true);
|
|
136
|
+
setup("relationship_records.yml");
|
|
137
|
+
loadData("data/relationship_records.json");
|
|
138
|
+
TaskReport taskReport = zendeskCustomObjectService.addRecordToImporter(0, recordImporter);
|
|
139
|
+
// 1 type contain data and break
|
|
140
|
+
verify(recordImporter, times(1)).addRecord(any());
|
|
141
|
+
Assert.assertTrue(taskReport.isEmpty());
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
private void loadData(String fileName)
|
|
145
|
+
{
|
|
146
|
+
JsonNode dataJson = ZendeskTestHelper.getJsonFromFile(fileName);
|
|
147
|
+
when(zendeskRestClient.doGet(any(), any(), anyBoolean())).thenReturn(dataJson.toString());
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
private void setupZendeskSupportAPIService(ZendeskInputPlugin.PluginTask task)
|
|
151
|
+
{
|
|
152
|
+
zendeskCustomObjectService = spy(new ZendeskCustomObjectService(task));
|
|
153
|
+
when(zendeskCustomObjectService.getZendeskRestClient()).thenReturn(zendeskRestClient);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
private void setup(String file)
|
|
157
|
+
{
|
|
158
|
+
ZendeskInputPlugin.PluginTask task = ZendeskTestHelper.getConfigSource(file).loadConfig(ZendeskInputPlugin.PluginTask.class);
|
|
159
|
+
setupZendeskSupportAPIService(task);
|
|
160
|
+
}
|
|
161
|
+
}
|