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,56 @@
|
|
|
1
|
+
package org.embulk.input.zendesk.services;
|
|
2
|
+
|
|
3
|
+
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
|
4
|
+
import org.embulk.EmbulkTestRuntime;
|
|
5
|
+
import org.embulk.input.zendesk.ZendeskInputPlugin;
|
|
6
|
+
import org.embulk.input.zendesk.clients.ZendeskRestClient;
|
|
7
|
+
import org.embulk.input.zendesk.utils.ZendeskTestHelper;
|
|
8
|
+
import org.junit.Before;
|
|
9
|
+
import org.junit.Rule;
|
|
10
|
+
import org.junit.Test;
|
|
11
|
+
|
|
12
|
+
import static org.junit.Assert.assertEquals;
|
|
13
|
+
import static org.mockito.Mockito.mock;
|
|
14
|
+
import static org.mockito.Mockito.spy;
|
|
15
|
+
|
|
16
|
+
import static org.mockito.Mockito.when;
|
|
17
|
+
|
|
18
|
+
public class TestZendeskNPSService
|
|
19
|
+
{
|
|
20
|
+
@Rule
|
|
21
|
+
@SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
|
|
22
|
+
public EmbulkTestRuntime runtime = new EmbulkTestRuntime();
|
|
23
|
+
|
|
24
|
+
private ZendeskRestClient zendeskRestClient;
|
|
25
|
+
|
|
26
|
+
private ZendeskNPSService zendeskNPSService;
|
|
27
|
+
|
|
28
|
+
@Before
|
|
29
|
+
public void prepare()
|
|
30
|
+
{
|
|
31
|
+
zendeskRestClient = mock(ZendeskRestClient.class);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@Test
|
|
35
|
+
public void testBuildURL()
|
|
36
|
+
{
|
|
37
|
+
setup();
|
|
38
|
+
String expectedString = "https://abc.zendesk.com/api/v2/nps/incremental/responses.json?start_time=10000";
|
|
39
|
+
// only use start_time so page any value
|
|
40
|
+
String actualString = zendeskNPSService.buildURI(0, 10000);
|
|
41
|
+
assertEquals(expectedString, actualString);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
private void setupZendeskNPSService(ZendeskInputPlugin.PluginTask task)
|
|
45
|
+
{
|
|
46
|
+
zendeskNPSService = spy(new ZendeskNPSService(task));
|
|
47
|
+
when(zendeskNPSService.getZendeskRestClient()).thenReturn(zendeskRestClient);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
private void setup()
|
|
51
|
+
{
|
|
52
|
+
ZendeskInputPlugin.PluginTask task = ZendeskTestHelper.getConfigSource("nps.yml")
|
|
53
|
+
.loadConfig(ZendeskInputPlugin.PluginTask.class);
|
|
54
|
+
setupZendeskNPSService(task);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,261 @@
|
|
|
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
|
+
import org.embulk.config.ConfigSource;
|
|
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.models.Target;
|
|
12
|
+
import org.embulk.input.zendesk.utils.ZendeskConstants;
|
|
13
|
+
import org.embulk.input.zendesk.utils.ZendeskTestHelper;
|
|
14
|
+
import org.junit.Assert;
|
|
15
|
+
import org.junit.Before;
|
|
16
|
+
import org.junit.Rule;
|
|
17
|
+
import org.junit.Test;
|
|
18
|
+
import org.mockito.ArgumentCaptor;
|
|
19
|
+
|
|
20
|
+
import java.time.Instant;
|
|
21
|
+
|
|
22
|
+
import static org.junit.Assert.assertEquals;
|
|
23
|
+
import static org.mockito.ArgumentMatchers.any;
|
|
24
|
+
import static org.mockito.ArgumentMatchers.anyBoolean;
|
|
25
|
+
import static org.mockito.Mockito.mock;
|
|
26
|
+
import static org.mockito.Mockito.spy;
|
|
27
|
+
import static org.mockito.Mockito.times;
|
|
28
|
+
import static org.mockito.Mockito.verify;
|
|
29
|
+
import static org.mockito.Mockito.when;
|
|
30
|
+
|
|
31
|
+
public class TestZendeskNormalService
|
|
32
|
+
{
|
|
33
|
+
@Rule
|
|
34
|
+
@SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
|
|
35
|
+
public EmbulkTestRuntime runtime = new EmbulkTestRuntime();
|
|
36
|
+
|
|
37
|
+
private ZendeskRestClient zendeskRestClient;
|
|
38
|
+
|
|
39
|
+
private ZendeskSupportAPIService zendeskSupportAPIService;
|
|
40
|
+
|
|
41
|
+
private RecordImporter recordImporter;
|
|
42
|
+
|
|
43
|
+
@Before
|
|
44
|
+
public void prepare()
|
|
45
|
+
{
|
|
46
|
+
zendeskRestClient = mock(ZendeskRestClient.class);
|
|
47
|
+
recordImporter = mock(RecordImporter.class);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@Test
|
|
51
|
+
public void testAddRecordToImporterWithIncremental()
|
|
52
|
+
{
|
|
53
|
+
setupSupportAPIService("incremental.yml");
|
|
54
|
+
loadData("data/tickets.json");
|
|
55
|
+
|
|
56
|
+
TaskReport taskReport = zendeskSupportAPIService.addRecordToImporter(0, recordImporter);
|
|
57
|
+
verify(recordImporter, times(4)).addRecord(any());
|
|
58
|
+
Assert.assertFalse(taskReport.isEmpty());
|
|
59
|
+
Assert.assertEquals(1550647054, taskReport.get(JsonNode.class, ZendeskConstants.Field.START_TIME).asLong());
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@Test
|
|
63
|
+
public void testAddRecordToImporterWithIncrementalAndWithoutDedup()
|
|
64
|
+
{
|
|
65
|
+
ConfigSource src = ZendeskTestHelper.getConfigSource("incremental.yml");
|
|
66
|
+
src.set("dedup", false);
|
|
67
|
+
ZendeskInputPlugin.PluginTask task = src.loadConfig(ZendeskInputPlugin.PluginTask.class);
|
|
68
|
+
setupZendeskSupportAPIService(task);
|
|
69
|
+
loadData("data/tickets.json");
|
|
70
|
+
|
|
71
|
+
TaskReport taskReport = zendeskSupportAPIService.addRecordToImporter(0, recordImporter);
|
|
72
|
+
verify(recordImporter, times(5)).addRecord(any());
|
|
73
|
+
Assert.assertFalse(taskReport.isEmpty());
|
|
74
|
+
Assert.assertEquals(1550647054, taskReport.get(JsonNode.class, ZendeskConstants.Field.START_TIME).asLong());
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
@Test
|
|
78
|
+
public void testAddRecordToImporterIncrementalContainUpdatedBySystemRecords()
|
|
79
|
+
{
|
|
80
|
+
setupSupportAPIService("incremental.yml");
|
|
81
|
+
loadData("data/ticket_with_updated_by_system_records.json");
|
|
82
|
+
|
|
83
|
+
TaskReport taskReport = zendeskSupportAPIService.addRecordToImporter(0, recordImporter);
|
|
84
|
+
verify(recordImporter, times(3)).addRecord(any());
|
|
85
|
+
Assert.assertFalse(taskReport.isEmpty());
|
|
86
|
+
Assert.assertEquals(1550647054, taskReport.get(JsonNode.class, ZendeskConstants.Field.START_TIME).asLong());
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
@Test
|
|
90
|
+
public void testAddRecordToImporterIncrementalUpdateStartTimeWhenEmptyResult()
|
|
91
|
+
{
|
|
92
|
+
ConfigSource src = ZendeskTestHelper.getConfigSource("incremental.yml");
|
|
93
|
+
src.set("target", Target.TICKETS.toString());
|
|
94
|
+
|
|
95
|
+
src.set("start_time", "2219-02-20T06:52:00Z");
|
|
96
|
+
ZendeskInputPlugin.PluginTask task = src.loadConfig(ZendeskInputPlugin.PluginTask.class);
|
|
97
|
+
setupZendeskSupportAPIService(task);
|
|
98
|
+
loadData("data/empty_result.json");
|
|
99
|
+
|
|
100
|
+
TaskReport taskReport = zendeskSupportAPIService.addRecordToImporter(0, recordImporter);
|
|
101
|
+
Assert.assertFalse(taskReport.isEmpty());
|
|
102
|
+
Assert.assertTrue(Instant.now().getEpochSecond() <= taskReport.get(JsonNode.class, ZendeskConstants.Field.START_TIME).asLong() + 50);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
@Test
|
|
106
|
+
public void testAddRecordToImporterNonIncremental()
|
|
107
|
+
{
|
|
108
|
+
setupSupportAPIService("non-incremental.yml");
|
|
109
|
+
loadData("data/ticket_fields.json");
|
|
110
|
+
|
|
111
|
+
TaskReport taskReport = zendeskSupportAPIService.addRecordToImporter(0, recordImporter);
|
|
112
|
+
verify(recordImporter, times(7)).addRecord(any());
|
|
113
|
+
Assert.assertTrue(taskReport.isEmpty());
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
@Test
|
|
117
|
+
public void testAddRecordToImporterIncrementalForSupportAndAllRecordsShareTheSameTime()
|
|
118
|
+
{
|
|
119
|
+
setupSupportAPIService("incremental.yml");
|
|
120
|
+
loadData("data/ticket_share_same_time_without_next_page.json");
|
|
121
|
+
|
|
122
|
+
TaskReport taskReport = zendeskSupportAPIService.addRecordToImporter(0, recordImporter);
|
|
123
|
+
verify(recordImporter, times(4)).addRecord(any());
|
|
124
|
+
// api_end_time of ticket_share_same_time_without_next_page.json + 1
|
|
125
|
+
Assert.assertEquals(1551419520, taskReport.get(JsonNode.class, ZendeskConstants.Field.START_TIME).asLong());
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
@Test
|
|
129
|
+
public void testTicketEventsAddRecordToImporterIncrementalWithNextPageAndAllRecordsShareTheSameTime()
|
|
130
|
+
{
|
|
131
|
+
// api_end_time of ticket_events_share_same_time_with_next_page.json
|
|
132
|
+
String expectedURL = "https://abc.zendesk.com/api/v2/incremental/ticket_events.json?start_time=1550645443";
|
|
133
|
+
setupSupportAPIService("incremental.yml");
|
|
134
|
+
ZendeskInputPlugin.PluginTask task = ZendeskTestHelper.getConfigSource("incremental.yml")
|
|
135
|
+
.set("target", "ticket_events")
|
|
136
|
+
.loadConfig(ZendeskInputPlugin.PluginTask.class);
|
|
137
|
+
setupZendeskSupportAPIService(task);
|
|
138
|
+
|
|
139
|
+
JsonNode dataJson = ZendeskTestHelper.getJsonFromFile("data/ticket_events_share_same_time_with_next_page.json");
|
|
140
|
+
JsonNode dataJsonNext = ZendeskTestHelper.getJsonFromFile("data/ticket_events_updated_by_system_records.json");
|
|
141
|
+
when(zendeskRestClient.doGet(any(), any(), anyBoolean()))
|
|
142
|
+
.thenReturn(dataJson.toString())
|
|
143
|
+
.thenReturn(dataJsonNext.toString());
|
|
144
|
+
|
|
145
|
+
TaskReport taskReport = zendeskSupportAPIService.addRecordToImporter(0, recordImporter);
|
|
146
|
+
final ArgumentCaptor<String> url = ArgumentCaptor.forClass(String.class);
|
|
147
|
+
verify(zendeskRestClient, times(2)).doGet(url.capture(), any(), anyBoolean());
|
|
148
|
+
assertEquals(expectedURL, url.getValue());
|
|
149
|
+
|
|
150
|
+
verify(recordImporter, times(4)).addRecord(any());
|
|
151
|
+
// api_end_time of ticket_events_updated_by_system_records.json + 1
|
|
152
|
+
Assert.assertEquals(1550645523, taskReport.get(JsonNode.class, ZendeskConstants.Field.START_TIME).asLong());
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
@Test
|
|
156
|
+
public void testTicketEventsAddRecordToImporterIncrementalAndAllRecordsShareTheSameTime()
|
|
157
|
+
{
|
|
158
|
+
setupSupportAPIService("incremental.yml");
|
|
159
|
+
ZendeskInputPlugin.PluginTask task = ZendeskTestHelper.getConfigSource("incremental.yml")
|
|
160
|
+
.set("target", "ticket_events")
|
|
161
|
+
.loadConfig(ZendeskInputPlugin.PluginTask.class);
|
|
162
|
+
setupZendeskSupportAPIService(task);
|
|
163
|
+
loadData("data/ticket_events_share_same_time_without_next_page.json");
|
|
164
|
+
|
|
165
|
+
TaskReport taskReport = zendeskSupportAPIService.addRecordToImporter(0, recordImporter);
|
|
166
|
+
verify(recordImporter, times(4)).addRecord(any());
|
|
167
|
+
// api_end_time of ticket_events_share_same_time_without_next_page.json + 1
|
|
168
|
+
Assert.assertEquals(1550645444, taskReport.get(JsonNode.class, ZendeskConstants.Field.START_TIME).asLong());
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
@Test
|
|
172
|
+
public void executeIncrementalContainEndTime()
|
|
173
|
+
{
|
|
174
|
+
ConfigSource src = ZendeskTestHelper.getConfigSource("incremental.yml");
|
|
175
|
+
// same updated_at time of last record
|
|
176
|
+
src.set("end_time", "2019-02-20T07:17:32Z");
|
|
177
|
+
ZendeskInputPlugin.PluginTask task = src.loadConfig(ZendeskInputPlugin.PluginTask.class);
|
|
178
|
+
setupZendeskSupportAPIService(task);
|
|
179
|
+
loadData("data/tickets.json");
|
|
180
|
+
|
|
181
|
+
TaskReport taskReport = zendeskSupportAPIService.addRecordToImporter(0, recordImporter);
|
|
182
|
+
verify(recordImporter, times(3)).addRecord(any());
|
|
183
|
+
Assert.assertFalse(taskReport.isEmpty());
|
|
184
|
+
// start_time = end_time + 1
|
|
185
|
+
Assert.assertEquals(1550647053, taskReport.get(JsonNode.class, ZendeskConstants.Field.START_TIME).asLong());
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
@Test
|
|
189
|
+
public void executeIncrementalContainEndTimeFilterOutLastRecord()
|
|
190
|
+
{
|
|
191
|
+
ConfigSource src = ZendeskTestHelper.getConfigSource("incremental.yml");
|
|
192
|
+
// earlier than updated_at time of last record
|
|
193
|
+
src.set("end_time", "2019-02-20T07:17:32Z");
|
|
194
|
+
ZendeskInputPlugin.PluginTask task = src.loadConfig(ZendeskInputPlugin.PluginTask.class);
|
|
195
|
+
setupZendeskSupportAPIService(task);
|
|
196
|
+
loadData("data/tickets.json");
|
|
197
|
+
|
|
198
|
+
TaskReport taskReport = zendeskSupportAPIService.addRecordToImporter(0, recordImporter);
|
|
199
|
+
verify(recordImporter, times(3)).addRecord(any());
|
|
200
|
+
Assert.assertFalse(taskReport.isEmpty());
|
|
201
|
+
//
|
|
202
|
+
Assert.assertEquals(1550647053, taskReport.get(JsonNode.class, ZendeskConstants.Field.START_TIME).asLong());
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
@Test
|
|
206
|
+
public void executeIncrementalContainEndTimeFilterOutLastRecordTicketEvents()
|
|
207
|
+
{
|
|
208
|
+
ConfigSource src = ZendeskTestHelper.getConfigSource("incremental.yml");
|
|
209
|
+
src.set("target", Target.TICKET_EVENTS.toString());
|
|
210
|
+
// earlier than updated_at time of last record
|
|
211
|
+
// 1550645520
|
|
212
|
+
src.set("end_time", "2019-02-20T06:52:00Z");
|
|
213
|
+
ZendeskInputPlugin.PluginTask task = src.loadConfig(ZendeskInputPlugin.PluginTask.class);
|
|
214
|
+
setupZendeskSupportAPIService(task);
|
|
215
|
+
loadData("data/ticket_events_updated_by_system_records.json");
|
|
216
|
+
|
|
217
|
+
TaskReport taskReport = zendeskSupportAPIService.addRecordToImporter(0, recordImporter);
|
|
218
|
+
verify(recordImporter, times(3)).addRecord(any());
|
|
219
|
+
Assert.assertFalse(taskReport.isEmpty());
|
|
220
|
+
// end_time + 1
|
|
221
|
+
Assert.assertEquals(1550645521, taskReport.get(JsonNode.class, ZendeskConstants.Field.START_TIME).asLong());
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
@Test
|
|
225
|
+
public void executeIncrementalContainEndTimeFilterOutLastRecordNPSScore()
|
|
226
|
+
{
|
|
227
|
+
ConfigSource src = ZendeskTestHelper.getConfigSource("nps.yml");
|
|
228
|
+
src.set("target", Target.SCORES.toString());
|
|
229
|
+
// earlier than updated_at time of last record
|
|
230
|
+
// 1550645520
|
|
231
|
+
src.set("end_time", "2019-02-20T06:52:00Z");
|
|
232
|
+
ZendeskInputPlugin.PluginTask task = src.loadConfig(ZendeskInputPlugin.PluginTask.class);
|
|
233
|
+
setupZendeskSupportAPIService(task);
|
|
234
|
+
loadData("data/scores.json");
|
|
235
|
+
|
|
236
|
+
TaskReport taskReport = zendeskSupportAPIService.addRecordToImporter(0, recordImporter);
|
|
237
|
+
verify(recordImporter, times(1)).addRecord(any());
|
|
238
|
+
Assert.assertFalse(taskReport.isEmpty());
|
|
239
|
+
// end_time + 1
|
|
240
|
+
Assert.assertEquals(1550645521, taskReport.get(JsonNode.class, ZendeskConstants.Field.START_TIME).asLong());
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
private void setupSupportAPIService(String file)
|
|
244
|
+
{
|
|
245
|
+
ZendeskInputPlugin.PluginTask task = ZendeskTestHelper.getConfigSource(file)
|
|
246
|
+
.loadConfig(ZendeskInputPlugin.PluginTask.class);
|
|
247
|
+
setupZendeskSupportAPIService(task);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
private void loadData(String fileName)
|
|
251
|
+
{
|
|
252
|
+
JsonNode dataJson = ZendeskTestHelper.getJsonFromFile(fileName);
|
|
253
|
+
when(zendeskRestClient.doGet(any(), any(), anyBoolean())).thenReturn(dataJson.toString());
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
private void setupZendeskSupportAPIService(ZendeskInputPlugin.PluginTask task)
|
|
257
|
+
{
|
|
258
|
+
zendeskSupportAPIService = spy(new ZendeskSupportAPIService(task));
|
|
259
|
+
when(zendeskSupportAPIService.getZendeskRestClient()).thenReturn(zendeskRestClient);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
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
|
+
import org.embulk.config.ConfigSource;
|
|
7
|
+
import org.embulk.input.zendesk.ZendeskInputPlugin;
|
|
8
|
+
import org.embulk.input.zendesk.clients.ZendeskRestClient;
|
|
9
|
+
import org.embulk.input.zendesk.utils.ZendeskTestHelper;
|
|
10
|
+
import org.junit.Before;
|
|
11
|
+
import org.junit.Rule;
|
|
12
|
+
import org.junit.Test;
|
|
13
|
+
|
|
14
|
+
import static org.junit.Assert.assertEquals;
|
|
15
|
+
import static org.mockito.ArgumentMatchers.any;
|
|
16
|
+
import static org.mockito.ArgumentMatchers.anyBoolean;
|
|
17
|
+
import static org.mockito.Mockito.mock;
|
|
18
|
+
import static org.mockito.Mockito.spy;
|
|
19
|
+
import static org.mockito.Mockito.when;
|
|
20
|
+
|
|
21
|
+
import java.util.Collections;
|
|
22
|
+
|
|
23
|
+
public class TestZendeskSupportAPIService
|
|
24
|
+
{
|
|
25
|
+
@Rule
|
|
26
|
+
@SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
|
|
27
|
+
public EmbulkTestRuntime runtime = new EmbulkTestRuntime();
|
|
28
|
+
|
|
29
|
+
private ZendeskRestClient zendeskRestClient;
|
|
30
|
+
|
|
31
|
+
private ZendeskSupportAPIService zendeskSupportAPIService;
|
|
32
|
+
|
|
33
|
+
@Before
|
|
34
|
+
public void prepare()
|
|
35
|
+
{
|
|
36
|
+
zendeskRestClient = mock(ZendeskRestClient.class);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@Test
|
|
40
|
+
public void testBuildPathWithIncremental()
|
|
41
|
+
{
|
|
42
|
+
String expectURL = "https://abc.zendesk.com/api/v2/incremental/tickets.json?start_time=0";
|
|
43
|
+
setup("incremental.yml");
|
|
44
|
+
loadData("data/tickets.json");
|
|
45
|
+
String url = zendeskSupportAPIService.buildURI(0, 0);
|
|
46
|
+
assertEquals(expectURL, url);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@Test
|
|
50
|
+
public void testBuildPathWithIncrementalWithTicketMetrics()
|
|
51
|
+
{
|
|
52
|
+
String expectURL = "https://abc.zendesk.com/api/v2/incremental/tickets.json?start_time=0&include=metric_sets";
|
|
53
|
+
loadData("data/ticket_metrics.json");
|
|
54
|
+
|
|
55
|
+
ConfigSource src = ZendeskTestHelper.getConfigSource("incremental.yml");
|
|
56
|
+
src.set("target", "ticket_metrics");
|
|
57
|
+
ZendeskInputPlugin.PluginTask task = src.loadConfig(ZendeskInputPlugin.PluginTask.class);
|
|
58
|
+
setupZendeskSupportAPIService(task);
|
|
59
|
+
|
|
60
|
+
String url = zendeskSupportAPIService.buildURI(0, 0);
|
|
61
|
+
assertEquals(expectURL, url);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@Test
|
|
65
|
+
public void testBuildPathWithIncrementalIncludeRelatedObject()
|
|
66
|
+
{
|
|
67
|
+
String expectURL = "https://abc.zendesk.com/api/v2/incremental/tickets.json?start_time=0";
|
|
68
|
+
loadData("data/tickets.json");
|
|
69
|
+
|
|
70
|
+
ConfigSource src = ZendeskTestHelper.getConfigSource("incremental.yml");
|
|
71
|
+
src.set("includes", Collections.singletonList("organizations"));
|
|
72
|
+
ZendeskInputPlugin.PluginTask task = src.loadConfig(ZendeskInputPlugin.PluginTask.class);
|
|
73
|
+
setupZendeskSupportAPIService(task);
|
|
74
|
+
|
|
75
|
+
String url = zendeskSupportAPIService.buildURI(0, 0);
|
|
76
|
+
assertEquals(expectURL, url);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
@Test
|
|
80
|
+
public void testBuildPathWithIncrementalTimeChange()
|
|
81
|
+
{
|
|
82
|
+
String expectURL = "https://abc.zendesk.com/api/v2/incremental/tickets.json?start_time=100";
|
|
83
|
+
loadData("data/tickets.json");
|
|
84
|
+
|
|
85
|
+
ConfigSource src = ZendeskTestHelper.getConfigSource("incremental.yml");
|
|
86
|
+
ZendeskInputPlugin.PluginTask task = src.loadConfig(ZendeskInputPlugin.PluginTask.class);
|
|
87
|
+
setupZendeskSupportAPIService(task);
|
|
88
|
+
String url = zendeskSupportAPIService.buildURI(0, 100);
|
|
89
|
+
assertEquals(expectURL, url);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
@Test
|
|
93
|
+
public void testBuildPathWithNonIncremental()
|
|
94
|
+
{
|
|
95
|
+
String expectURL = "https://abc.zendesk.com/api/v2/ticket_fields.json?sort_by=id&per_page=100&page=0";
|
|
96
|
+
setup("non-incremental.yml");
|
|
97
|
+
loadData("data/ticket_fields.json");
|
|
98
|
+
String url = zendeskSupportAPIService.buildURI(0, 0);
|
|
99
|
+
assertEquals(expectURL, url);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
@Test
|
|
103
|
+
public void testBuildPathWithNonIncrementalChangePageNumber()
|
|
104
|
+
{
|
|
105
|
+
String expectURL = "https://abc.zendesk.com/api/v2/ticket_fields.json?sort_by=id&per_page=100&page=2";
|
|
106
|
+
setup("non-incremental.yml");
|
|
107
|
+
loadData("data/ticket_fields.json");
|
|
108
|
+
String url = zendeskSupportAPIService.buildURI(2, 0);
|
|
109
|
+
assertEquals(expectURL, url);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private void loadData(String fileName)
|
|
113
|
+
{
|
|
114
|
+
JsonNode dataJson = ZendeskTestHelper.getJsonFromFile(fileName);
|
|
115
|
+
when(zendeskRestClient.doGet(any(), any(), anyBoolean())).thenReturn(dataJson.toString());
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
private void setupZendeskSupportAPIService(ZendeskInputPlugin.PluginTask task)
|
|
119
|
+
{
|
|
120
|
+
zendeskSupportAPIService = spy(new ZendeskSupportAPIService(task));
|
|
121
|
+
when(zendeskSupportAPIService.getZendeskRestClient()).thenReturn(zendeskRestClient);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
private void setup(String file)
|
|
125
|
+
{
|
|
126
|
+
ZendeskInputPlugin.PluginTask task = ZendeskTestHelper.getConfigSource(file)
|
|
127
|
+
.loadConfig(ZendeskInputPlugin.PluginTask.class);
|
|
128
|
+
setupZendeskSupportAPIService(task);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
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
|
+
import org.embulk.input.zendesk.RecordImporter;
|
|
7
|
+
import org.embulk.input.zendesk.ZendeskInputPlugin.PluginTask;
|
|
8
|
+
import org.embulk.input.zendesk.clients.ZendeskRestClient;
|
|
9
|
+
import org.embulk.input.zendesk.utils.ZendeskTestHelper;
|
|
10
|
+
import org.junit.Before;
|
|
11
|
+
import org.junit.Rule;
|
|
12
|
+
import org.junit.Test;
|
|
13
|
+
import org.mockito.ArgumentCaptor;
|
|
14
|
+
|
|
15
|
+
import java.util.Arrays;
|
|
16
|
+
import java.util.List;
|
|
17
|
+
|
|
18
|
+
import static org.junit.Assert.assertEquals;
|
|
19
|
+
import static org.junit.Assert.assertFalse;
|
|
20
|
+
import static org.junit.Assert.assertTrue;
|
|
21
|
+
import static org.mockito.ArgumentMatchers.any;
|
|
22
|
+
import static org.mockito.ArgumentMatchers.anyBoolean;
|
|
23
|
+
import static org.mockito.ArgumentMatchers.eq;
|
|
24
|
+
import static org.mockito.Mockito.mock;
|
|
25
|
+
import static org.mockito.Mockito.spy;
|
|
26
|
+
import static org.mockito.Mockito.times;
|
|
27
|
+
import static org.mockito.Mockito.verify;
|
|
28
|
+
import static org.mockito.Mockito.when;
|
|
29
|
+
|
|
30
|
+
public class TestZendeskUserEventService
|
|
31
|
+
{
|
|
32
|
+
private RecordImporter recordImporter;
|
|
33
|
+
|
|
34
|
+
@Rule
|
|
35
|
+
@SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
|
|
36
|
+
public EmbulkTestRuntime runtime = new EmbulkTestRuntime();
|
|
37
|
+
private ZendeskRestClient zendeskRestClient;
|
|
38
|
+
private ZendeskUserEventService zendeskUserEventService;
|
|
39
|
+
|
|
40
|
+
@Before
|
|
41
|
+
public void prepare()
|
|
42
|
+
{
|
|
43
|
+
zendeskRestClient = mock(ZendeskRestClient.class);
|
|
44
|
+
recordImporter = mock(RecordImporter.class);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
@Test
|
|
48
|
+
public void testGetData()
|
|
49
|
+
{
|
|
50
|
+
setup();
|
|
51
|
+
|
|
52
|
+
JsonNode jsonNode = zendeskUserEventService.getDataFromPath("https://abc.zendesk.com/api/sunshine/objects/records?type=user&per_page=1000", 0, true, 0);
|
|
53
|
+
assertFalse(jsonNode.isNull());
|
|
54
|
+
assertTrue(jsonNode.has("data"));
|
|
55
|
+
assertTrue(jsonNode.get("data").isArray());
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@Test
|
|
59
|
+
public void testAddRecordToImporterInPreviewMode()
|
|
60
|
+
{
|
|
61
|
+
setup();
|
|
62
|
+
ZendeskTestHelper.setPreviewMode(runtime, true);
|
|
63
|
+
zendeskUserEventService.addRecordToImporter(0, recordImporter);
|
|
64
|
+
verify(recordImporter, times(1)).addRecord(any());
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@Test
|
|
68
|
+
public void testUrlForUserEvent()
|
|
69
|
+
{
|
|
70
|
+
ZendeskTestHelper.setPreviewMode(runtime, false);
|
|
71
|
+
setup();
|
|
72
|
+
JsonNode dataJsonOrganization = ZendeskTestHelper.getJsonFromFile("data/simple_organization.json");
|
|
73
|
+
JsonNode dataJsonUser = ZendeskTestHelper.getJsonFromFile("data/simple_user.json");
|
|
74
|
+
JsonNode dataJsonUserEventWithLatterTime = ZendeskTestHelper.getJsonFromFile("data/user_event_contain_latter_create_at.json");
|
|
75
|
+
|
|
76
|
+
when(zendeskRestClient.doGet(any(), any(), anyBoolean()))
|
|
77
|
+
.thenReturn(dataJsonOrganization.toString())
|
|
78
|
+
.thenReturn(dataJsonUser.toString())
|
|
79
|
+
.thenReturn(dataJsonUserEventWithLatterTime.toString());
|
|
80
|
+
|
|
81
|
+
String expectedURIForOrganization = "https://abc.zendesk.com/api/v2/organizations?per_page=100&page=1";
|
|
82
|
+
String expectedURIForUser = "https://abc.zendesk.com/api/v2/organizations/360857467053/users.json?per_page=100&page=1";
|
|
83
|
+
String expectedURIForUserEvent = "https://abc.zendesk.com/api/sunshine/events?identifier=support%3Auser_id%3A1194092277&start_time=2019-01-20T07%3A14%3A50Z&end_time=2019-06-20T07%3A14%3A53Z";
|
|
84
|
+
List<String> expectedURI = Arrays.asList(expectedURIForOrganization, expectedURIForUser, expectedURIForUserEvent);
|
|
85
|
+
|
|
86
|
+
zendeskUserEventService.addRecordToImporter(0, recordImporter);
|
|
87
|
+
ArgumentCaptor<String> uri = ArgumentCaptor.forClass(String.class);
|
|
88
|
+
verify(zendeskRestClient, times(3)).doGet(uri.capture(), any(), anyBoolean());
|
|
89
|
+
assertEquals(expectedURI, uri.getAllValues());
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
@Test
|
|
93
|
+
public void testAddRecordToImporterInNonPreviewMode()
|
|
94
|
+
{
|
|
95
|
+
ZendeskTestHelper.setPreviewMode(runtime, false);
|
|
96
|
+
PluginTask task = setup();
|
|
97
|
+
|
|
98
|
+
JsonNode dataJsonOrganization = ZendeskTestHelper.getJsonFromFile("data/organization.json");
|
|
99
|
+
JsonNode dataJsonUser = ZendeskTestHelper.getJsonFromFile("data/simple_user.json");
|
|
100
|
+
JsonNode dataJsonUserEvent = ZendeskTestHelper.getJsonFromFile("data/user_event.json");
|
|
101
|
+
|
|
102
|
+
// 2 organizations but return the same user.
|
|
103
|
+
when(zendeskRestClient.doGet(eq("https://abc.zendesk.com/api/v2/organizations?per_page=100&page=1"), eq(task), eq(false)))
|
|
104
|
+
.thenReturn(dataJsonOrganization.toString());
|
|
105
|
+
when(zendeskRestClient.doGet(eq("https://abc.zendesk.com/api/v2/organizations/360857467053/users.json?per_page=100&page=1"), eq(task), eq(false)))
|
|
106
|
+
.thenReturn(dataJsonUser.toString());
|
|
107
|
+
when(zendeskRestClient.doGet(eq("https://abc.zendesk.com/api/v2/organizations/360857467055/users.json?per_page=100&page=1"), eq(task), eq(false)))
|
|
108
|
+
.thenReturn(dataJsonUser.toString());
|
|
109
|
+
when(zendeskRestClient.doGet(eq("https://abc.zendesk.com/api/sunshine/events?identifier=support%3Auser_id%3A1194092277&start_time=2019-01-20T07%3A14%3A50Z&end_time=2019-06-20T07%3A14%3A53Z"), eq(task), eq(false)))
|
|
110
|
+
.thenReturn(dataJsonUserEvent.toString());
|
|
111
|
+
|
|
112
|
+
zendeskUserEventService.addRecordToImporter(0, recordImporter);
|
|
113
|
+
// non dedup
|
|
114
|
+
verify(recordImporter, times(2)).addRecord(any());
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@Test
|
|
118
|
+
public void testAddRecordToImporterWithDuplicateUser()
|
|
119
|
+
{
|
|
120
|
+
ZendeskTestHelper.setPreviewMode(runtime, false);
|
|
121
|
+
PluginTask task = ZendeskTestHelper.getConfigSource("user_events.yml")
|
|
122
|
+
.set("dedup", true)
|
|
123
|
+
.loadConfig(PluginTask.class);
|
|
124
|
+
setupZendeskSupportAPIService(task);
|
|
125
|
+
|
|
126
|
+
JsonNode dataJsonOrganization = ZendeskTestHelper.getJsonFromFile("data/organization.json");
|
|
127
|
+
JsonNode dataJsonUser = ZendeskTestHelper.getJsonFromFile("data/simple_user.json");
|
|
128
|
+
JsonNode dataJsonUserEvent = ZendeskTestHelper.getJsonFromFile("data/user_event.json");
|
|
129
|
+
// 2 organizations but return the same user.
|
|
130
|
+
when(zendeskRestClient.doGet(eq("https://abc.zendesk.com/api/v2/organizations?per_page=100&page=1"), eq(task), eq(false)))
|
|
131
|
+
.thenReturn(dataJsonOrganization.toString());
|
|
132
|
+
when(zendeskRestClient.doGet(eq("https://abc.zendesk.com/api/v2/organizations/360857467053/users.json?per_page=100&page=1"), eq(task), eq(false)))
|
|
133
|
+
.thenReturn(dataJsonUser.toString());
|
|
134
|
+
when(zendeskRestClient.doGet(eq("https://abc.zendesk.com/api/v2/organizations/360857467055/users.json?per_page=100&page=1"), eq(task), eq(false)))
|
|
135
|
+
.thenReturn(dataJsonUser.toString());
|
|
136
|
+
when(zendeskRestClient.doGet(eq("https://abc.zendesk.com/api/sunshine/events?identifier=support%3Auser_id%3A1194092277&start_time=2019-01-20T07%3A14%3A50Z&end_time=2019-06-20T07%3A14%3A53Z"), eq(task), eq(false)))
|
|
137
|
+
.thenReturn(dataJsonUserEvent.toString());
|
|
138
|
+
|
|
139
|
+
zendeskUserEventService.addRecordToImporter(0, recordImporter);
|
|
140
|
+
|
|
141
|
+
// expected to call fetchUserEvent only one time
|
|
142
|
+
verify(recordImporter, times(1)).addRecord(any());
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
private void setupZendeskSupportAPIService(PluginTask task)
|
|
146
|
+
{
|
|
147
|
+
zendeskUserEventService = spy(new ZendeskUserEventService(task));
|
|
148
|
+
when(zendeskUserEventService.getZendeskRestClient()).thenReturn(zendeskRestClient);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
private PluginTask setup()
|
|
152
|
+
{
|
|
153
|
+
PluginTask task = ZendeskTestHelper.getConfigSource("user_events.yml")
|
|
154
|
+
.loadConfig(PluginTask.class);
|
|
155
|
+
setupZendeskSupportAPIService(task);
|
|
156
|
+
return task;
|
|
157
|
+
}
|
|
158
|
+
}
|