embulk-input-zendesk 0.2.14 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +9 -3
  3. data/.travis.yml +5 -44
  4. data/CHANGELOG.md +3 -0
  5. data/README.md +5 -5
  6. data/build.gradle +123 -0
  7. data/classpath/commons-codec-1.10.jar +0 -0
  8. data/classpath/commons-logging-1.2.jar +0 -0
  9. data/classpath/embulk-input-zendesk-0.3.0.jar +0 -0
  10. data/classpath/httpclient-4.5.6.jar +0 -0
  11. data/classpath/httpcore-4.4.10.jar +0 -0
  12. data/config/checkstyle/checkstyle.xml +128 -0
  13. data/config/checkstyle/default.xml +108 -0
  14. data/gradle/wrapper/gradle-wrapper.jar +0 -0
  15. data/gradle/wrapper/gradle-wrapper.properties +5 -0
  16. data/gradlew +172 -0
  17. data/gradlew.bat +84 -0
  18. data/lib/embulk/guess/zendesk.rb +21 -0
  19. data/lib/embulk/input/zendesk.rb +3 -9
  20. data/src/main/java/org/embulk/input/zendesk/ZendeskInputPlugin.java +471 -0
  21. data/src/main/java/org/embulk/input/zendesk/clients/ZendeskRestClient.java +268 -0
  22. data/src/main/java/org/embulk/input/zendesk/models/AuthenticationMethod.java +23 -0
  23. data/src/main/java/org/embulk/input/zendesk/models/Target.java +46 -0
  24. data/src/main/java/org/embulk/input/zendesk/models/ZendeskException.java +25 -0
  25. data/src/main/java/org/embulk/input/zendesk/services/ZendeskSupportAPIService.java +109 -0
  26. data/src/main/java/org/embulk/input/zendesk/utils/ZendeskConstants.java +61 -0
  27. data/src/main/java/org/embulk/input/zendesk/utils/ZendeskDateUtils.java +51 -0
  28. data/src/main/java/org/embulk/input/zendesk/utils/ZendeskUtils.java +150 -0
  29. data/src/main/java/org/embulk/input/zendesk/utils/ZendeskValidatorUtils.java +92 -0
  30. data/src/test/java/org/embulk/input/zendesk/TestZendeskInputPlugin.java +232 -0
  31. data/src/test/java/org/embulk/input/zendesk/clients/TestZendeskRestClient.java +351 -0
  32. data/src/test/java/org/embulk/input/zendesk/services/TestZendeskSupportAPIService.java +172 -0
  33. data/src/test/java/org/embulk/input/zendesk/utils/TestZendeskDateUtils.java +36 -0
  34. data/src/test/java/org/embulk/input/zendesk/utils/TestZendeskUtil.java +160 -0
  35. data/src/test/java/org/embulk/input/zendesk/utils/TestZendeskValidatorUtils.java +138 -0
  36. data/src/test/java/org/embulk/input/zendesk/utils/ZendeskPluginTestRuntime.java +133 -0
  37. data/src/test/java/org/embulk/input/zendesk/utils/ZendeskTestHelper.java +63 -0
  38. data/src/test/resources/config/base.yml +14 -0
  39. data/src/test/resources/config/base_validator.yml +48 -0
  40. data/src/test/resources/config/incremental.yml +54 -0
  41. data/src/test/resources/config/non-incremental.yml +39 -0
  42. data/src/test/resources/config/util.yml +18 -0
  43. data/src/test/resources/data/client.json +293 -0
  44. data/src/test/resources/data/error_data.json +187 -0
  45. data/src/test/resources/data/expected/ticket_column.json +148 -0
  46. data/src/test/resources/data/expected/ticket_column_with_related_objects.json +152 -0
  47. data/src/test/resources/data/expected/ticket_fields_column.json +92 -0
  48. data/src/test/resources/data/expected/ticket_metrics_column.json +98 -0
  49. data/src/test/resources/data/ticket_fields.json +225 -0
  50. data/src/test/resources/data/ticket_metrics.json +397 -0
  51. data/src/test/resources/data/ticket_with_related_objects.json +67 -0
  52. data/src/test/resources/data/tickets.json +232 -0
  53. data/src/test/resources/data/tickets_continue.json +52 -0
  54. data/src/test/resources/data/util.json +19 -0
  55. data/src/test/resources/data/util_page.json +227 -0
  56. metadata +65 -221
  57. data/.ruby-version +0 -1
  58. data/.travis.yml.erb +0 -43
  59. data/Gemfile +0 -2
  60. data/Rakefile +0 -21
  61. data/embulk-input-zendesk.gemspec +0 -29
  62. data/gemfiles/embulk-0.8.0-latest +0 -4
  63. data/gemfiles/embulk-0.8.1 +0 -4
  64. data/gemfiles/embulk-latest +0 -4
  65. data/gemfiles/template.erb +0 -4
  66. data/lib/embulk/input/zendesk/client.rb +0 -434
  67. data/lib/embulk/input/zendesk/plugin.rb +0 -199
  68. data/test/capture_io.rb +0 -45
  69. data/test/embulk/input/zendesk/test_client.rb +0 -722
  70. data/test/embulk/input/zendesk/test_plugin.rb +0 -628
  71. data/test/fixture_helper.rb +0 -11
  72. data/test/fixtures/invalid_app_marketplace_lack_one_property.yml +0 -13
  73. data/test/fixtures/invalid_app_marketplace_lack_two_property.yml +0 -12
  74. data/test/fixtures/invalid_lack_username.yml +0 -9
  75. data/test/fixtures/invalid_unknown_auth.yml +0 -9
  76. data/test/fixtures/tickets.json +0 -44
  77. data/test/fixtures/valid_app_marketplace.yml +0 -14
  78. data/test/fixtures/valid_auth_basic.yml +0 -11
  79. data/test/fixtures/valid_auth_oauth.yml +0 -10
  80. data/test/fixtures/valid_auth_token.yml +0 -11
  81. data/test/override_assert_raise.rb +0 -21
  82. data/test/run-test.rb +0 -26
@@ -0,0 +1,61 @@
1
+ package org.embulk.input.zendesk.utils;
2
+
3
+ public class ZendeskConstants
4
+ {
5
+ private ZendeskConstants()
6
+ {
7
+ }
8
+
9
+ public static class Header
10
+ {
11
+ public static final String APPLICATION_JSON = "application/json";
12
+
13
+ public static final String ZENDESK_MARKETPLACE_NAME = "X-Zendesk-Marketplace-Name";
14
+ public static final String ZENDESK_MARKETPLACE_ORGANIZATION_ID = "X-Zendesk-Marketplace-Organization-Id";
15
+ public static final String ZENDESK_MARKETPLACE_APP_ID = "X-Zendesk-Marketplace-App-Id";
16
+ }
17
+
18
+ public static class Field
19
+ {
20
+ public static final String START_TIME = "start_time";
21
+ public static final String END_TIME = "end_time";
22
+ public static final String COUNT = "count";
23
+ public static final String GENERATED_TIMESTAMP = "generated_timestamp";
24
+ public static final String UPDATED_AT = "updated_at";
25
+ public static final String ID = "id";
26
+ }
27
+
28
+ public static class Url
29
+ {
30
+ public static final String API = "api/v2";
31
+ public static final String API_INCREMENTAL = API + "/incremental";
32
+ }
33
+
34
+ public static class Misc
35
+ {
36
+ public static final String RUBY_TIMESTAMP_FORMAT = "%Y-%m-%dT%H:%M:%S%z";
37
+ public static final String RUBY_TIMESTAMP_FORMAT_INPUT = "yyyy-MM-dd HH:mm:ss Z";
38
+ public static final String JAVA_TIMESTAMP_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
39
+ public static final String ISO_TIMESTAMP_FORMAT = "yyyy-MM-dd'T'HH:mm:ssXXX";
40
+ public static final String ISO_INSTANT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
41
+ public static final String TOO_RECENT_START_TIME = "Too recent start_time.";
42
+ public static final String INVALID_END_POINT_RESPONSE = "\"error\":\"InvalidEndpoint\"";
43
+ public static final int RECORDS_SIZE_PER_PAGE = 100;
44
+ public static final int MAXIMUM_RECORDS_INCREMENTAL = 1000;
45
+ public static final int TOO_MANY_REQUEST = 429;
46
+
47
+ // 1 MB
48
+ public static final int GUESS_BUFFER_SIZE = 1024 * 1024;
49
+ }
50
+
51
+ public static class Regex
52
+ {
53
+ public static final String ID = "_id$";
54
+ public static final String HOST = "^(https:\\/\\/)?(www.)?([a-zA-Z0-9]+).zendesk.com/$";
55
+ }
56
+
57
+ public static class HttpStatus
58
+ {
59
+ public static final int TOO_MANY_REQUEST = 429;
60
+ }
61
+ }
@@ -0,0 +1,51 @@
1
+ package org.embulk.input.zendesk.utils;
2
+
3
+ import com.google.common.base.Joiner;
4
+ import org.embulk.spi.DataException;
5
+
6
+ import java.time.LocalDateTime;
7
+ import java.time.OffsetDateTime;
8
+ import java.time.ZoneOffset;
9
+ import java.time.format.DateTimeFormatter;
10
+ import java.time.format.DateTimeParseException;
11
+ import java.util.Arrays;
12
+
13
+ import java.util.List;
14
+ import java.util.Optional;
15
+
16
+ public class ZendeskDateUtils
17
+ {
18
+ private ZendeskDateUtils()
19
+ {
20
+ }
21
+
22
+ private static final List<String> supportedFormats = Arrays.asList(ZendeskConstants.Misc.ISO_INSTANT, ZendeskConstants.Misc.RUBY_TIMESTAMP_FORMAT_INPUT,
23
+ ZendeskConstants.Misc.JAVA_TIMESTAMP_FORMAT, ZendeskConstants.Misc.ISO_TIMESTAMP_FORMAT);
24
+
25
+ public static long isoToEpochSecond(final String time)
26
+ {
27
+ Optional<String> pattern = supportedTimeFormat(time, supportedFormats);
28
+ if (pattern.isPresent()) {
29
+ final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern.get()).withZone(ZoneOffset.UTC);
30
+ final OffsetDateTime offsetDateTime = LocalDateTime.parse(time, formatter).atOffset(ZoneOffset.UTC);
31
+ return offsetDateTime.toInstant().getEpochSecond();
32
+ }
33
+
34
+ throw new DataException("Fail to parse value '" + time + "' follow formats " + "[ " + Joiner.on(",").join(supportedFormats) + "]");
35
+ }
36
+
37
+ private static Optional<String> supportedTimeFormat(final String value, final List<String> supportedFormats)
38
+ {
39
+ for (final String fmt : supportedFormats) {
40
+ final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(fmt);
41
+ try {
42
+ formatter.parse(value);
43
+ return Optional.of(fmt);
44
+ }
45
+ catch (final DateTimeParseException e) {
46
+ // Do nothing
47
+ }
48
+ }
49
+ return Optional.empty();
50
+ }
51
+ }
@@ -0,0 +1,150 @@
1
+ package org.embulk.input.zendesk.utils;
2
+
3
+ import com.fasterxml.jackson.databind.JsonNode;
4
+ import com.google.common.base.Charsets;
5
+ import org.embulk.input.zendesk.models.Target;
6
+
7
+ import org.embulk.spi.Column;
8
+ import org.embulk.spi.ColumnVisitor;
9
+
10
+ import org.embulk.spi.Exec;
11
+ import org.embulk.spi.PageBuilder;
12
+ import org.embulk.spi.Schema;
13
+ import org.embulk.spi.json.JsonParser;
14
+ import org.embulk.spi.time.Timestamp;
15
+ import org.slf4j.Logger;
16
+
17
+ import java.util.Base64;
18
+ import java.util.function.Function;
19
+
20
+ public class ZendeskUtils
21
+ {
22
+ private static final Logger logger = Exec.getLogger(ZendeskUtils.class);
23
+
24
+ private ZendeskUtils()
25
+ {}
26
+
27
+ public static boolean isSupportAPIIncremental(final Target target)
28
+ {
29
+ return !Target.TICKET_FORMS.equals(target)
30
+ && !Target.TICKET_FIELDS.equals(target);
31
+ }
32
+
33
+ public static String convertBase64(final String text)
34
+ {
35
+ return Base64.getEncoder().encodeToString(text.getBytes(Charsets.UTF_8));
36
+ }
37
+
38
+ public static int numberToSplitWithHintingInTask(int count)
39
+ {
40
+ return (int) Math.ceil((double) count / ZendeskConstants.Misc.RECORDS_SIZE_PER_PAGE);
41
+ }
42
+
43
+ public static synchronized void addRecord(JsonNode record, Schema schema, PageBuilder pageBuilder)
44
+ {
45
+ schema.visitColumns(new ColumnVisitor() {
46
+ @Override
47
+ public void jsonColumn(Column column)
48
+ {
49
+ JsonNode data = record.get(column.getName());
50
+
51
+ setColumn(column, data, (value) -> {
52
+ pageBuilder.setJson(column, new JsonParser().parse(value.toString()));
53
+ return null;
54
+ });
55
+ }
56
+
57
+ @Override
58
+ public void stringColumn(Column column)
59
+ {
60
+ JsonNode data = record.get(column.getName());
61
+
62
+ setColumn(column, data, (value) -> {
63
+ pageBuilder.setString(column, value.asText());
64
+ return null;
65
+ });
66
+ }
67
+
68
+ @Override
69
+ public void timestampColumn(Column column)
70
+ {
71
+ JsonNode data = record.get(column.getName());
72
+ setColumn(column, data, (value) -> {
73
+ Timestamp timestamp = getTimestampValue(value.asText());
74
+ if (timestamp == null) {
75
+ pageBuilder.setNull(column);
76
+ }
77
+ else {
78
+ pageBuilder.setTimestamp(column, timestamp);
79
+ }
80
+ return null;
81
+ });
82
+ }
83
+
84
+ @Override
85
+ public void booleanColumn(Column column)
86
+ {
87
+ JsonNode data = record.get(column.getName());
88
+
89
+ setColumn(column, data, (value) -> {
90
+ pageBuilder.setBoolean(column, value.asBoolean());
91
+ return null;
92
+ });
93
+ }
94
+
95
+ @Override
96
+ public void longColumn(Column column)
97
+ {
98
+ JsonNode data = record.get(column.getName());
99
+
100
+ setColumn(column, data, (value) -> {
101
+ pageBuilder.setLong(column, value.asLong());
102
+ return null;
103
+ });
104
+ }
105
+
106
+ @Override
107
+ public void doubleColumn(Column column)
108
+ {
109
+ JsonNode data = record.get(column.getName());
110
+
111
+ setColumn(column, data, (value) -> {
112
+ pageBuilder.setDouble(column, value.asDouble());
113
+ return null;
114
+ });
115
+ }
116
+
117
+ private void setColumn(Column column, JsonNode data, Function<JsonNode, Void> setter)
118
+ {
119
+ if (isNull(data)) {
120
+ pageBuilder.setNull(column);
121
+ return;
122
+ }
123
+ setter.apply(data);
124
+ }
125
+ });
126
+ pageBuilder.addRecord();
127
+ }
128
+
129
+ private static boolean isNull(JsonNode jsonNode)
130
+ {
131
+ return jsonNode == null || jsonNode.isNull();
132
+ }
133
+
134
+ /*
135
+ * For getting the timestamp value of the node
136
+ * Sometime if the parser could not parse the value then return null
137
+ * */
138
+ private static Timestamp getTimestampValue(String value)
139
+ {
140
+ Timestamp result = null;
141
+ try {
142
+ long timeStamp = ZendeskDateUtils.isoToEpochSecond(value);
143
+ result = Timestamp.ofEpochSecond(timeStamp);
144
+ }
145
+ catch (Exception e) {
146
+ logger.warn("Error when parse time stamp data " + value);
147
+ }
148
+ return result;
149
+ }
150
+ }
@@ -0,0 +1,92 @@
1
+ package org.embulk.input.zendesk.utils;
2
+
3
+ import org.embulk.config.ConfigException;
4
+ import org.embulk.input.zendesk.ZendeskInputPlugin;
5
+ import org.embulk.input.zendesk.services.ZendeskSupportAPIService;
6
+ import org.embulk.spi.Exec;
7
+ import org.slf4j.Logger;
8
+
9
+ import java.util.regex.Matcher;
10
+ import java.util.regex.Pattern;
11
+
12
+ public class ZendeskValidatorUtils
13
+ {
14
+ private ZendeskValidatorUtils(){}
15
+
16
+ private static final Logger logger = Exec.getLogger(ZendeskValidatorUtils.class);
17
+
18
+ public static void validateInputTask(final ZendeskInputPlugin.PluginTask task, final ZendeskSupportAPIService zendeskSupportAPIService)
19
+ {
20
+ validateHost(task.getLoginUrl());
21
+ validateAppMarketPlace(task.getAppMarketPlaceIntegrationName().isPresent(),
22
+ task.getAppMarketPlaceAppId().isPresent(),
23
+ task.getAppMarketPlaceOrgId().isPresent());
24
+ validateCredentials(task);
25
+ validateIncremental(task);
26
+ }
27
+
28
+ private static void validateHost(final String loginUrl)
29
+ {
30
+ final Matcher matcher = Pattern.compile(ZendeskConstants.Regex.HOST).matcher(loginUrl);
31
+ if (!matcher.matches()) {
32
+ throw new ConfigException(String.format("Login URL, '%s', is unmatched expectation. " +
33
+ "It should be followed this format: https://abc.zendesk.com/", loginUrl));
34
+ }
35
+ }
36
+
37
+ private static void validateCredentials(final ZendeskInputPlugin.PluginTask task)
38
+ {
39
+ switch (task.getAuthenticationMethod()) {
40
+ case OAUTH:
41
+ if (!task.getAccessToken().isPresent()) {
42
+ throw new ConfigException(String.format("access_token is required for authentication method '%s'",
43
+ task.getAuthenticationMethod().name().toLowerCase()));
44
+ }
45
+ break;
46
+ case TOKEN:
47
+ if (!task.getUsername().isPresent() || !task.getToken().isPresent()) {
48
+ throw new ConfigException(String.format("username and token are required for authentication method '%s'",
49
+ task.getAuthenticationMethod().name().toLowerCase()));
50
+ }
51
+ break;
52
+ case BASIC:
53
+ if (!task.getUsername().isPresent() || !task.getPassword().isPresent()) {
54
+ throw new ConfigException(String.format("username and password are required for authentication method '%s'",
55
+ task.getAuthenticationMethod().name().toLowerCase()));
56
+ }
57
+ break;
58
+ default:
59
+ throw new ConfigException("Unknown authentication method");
60
+ }
61
+ }
62
+
63
+ private static void validateAppMarketPlace(final boolean isAppMarketIntegrationNamePresent,
64
+ final boolean isAppMarketAppIdPresent,
65
+ final boolean isAppMarketOrgIdPresent)
66
+ {
67
+ final boolean isAllAvailable =
68
+ isAppMarketIntegrationNamePresent && isAppMarketAppIdPresent && isAppMarketOrgIdPresent;
69
+ final boolean isAllUnAvailable =
70
+ !isAppMarketIntegrationNamePresent && !isAppMarketAppIdPresent && !isAppMarketOrgIdPresent;
71
+ // All or nothing needed
72
+ if (!(isAllAvailable || isAllUnAvailable)) {
73
+ throw new ConfigException("All of app_marketplace_integration_name, app_marketplace_org_id, " +
74
+ "app_marketplace_app_id " +
75
+ "are required to fill out for Apps Marketplace API header");
76
+ }
77
+ }
78
+
79
+ private static void validateIncremental(final ZendeskInputPlugin.PluginTask task)
80
+ {
81
+ if (task.getIncremental()) {
82
+ if (!task.getDedup()) {
83
+ logger.warn("You've selected to skip de-duplicating records, result may contain duplicated data");
84
+ }
85
+
86
+ if (!ZendeskUtils.isSupportAPIIncremental(task.getTarget()) && task.getStartTime().isPresent()) {
87
+ logger.warn(String.format("Target: '%s' doesn't support incremental export API. Will be ignored start_time option",
88
+ task.getTarget()));
89
+ }
90
+ }
91
+ }
92
+ }
@@ -0,0 +1,232 @@
1
+ package org.embulk.input.zendesk;
2
+
3
+ import com.fasterxml.jackson.databind.JsonNode;
4
+ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
5
+ import org.embulk.config.ConfigDiff;
6
+ import org.embulk.config.ConfigException;
7
+ import org.embulk.config.ConfigSource;
8
+ import org.embulk.config.TaskReport;
9
+ import org.embulk.config.TaskSource;
10
+ import org.embulk.input.zendesk.services.ZendeskSupportAPIService;
11
+ import org.embulk.input.zendesk.utils.ZendeskPluginTestRuntime;
12
+ import org.embulk.input.zendesk.utils.ZendeskTestHelper;
13
+
14
+ import org.embulk.spi.InputPlugin;
15
+ import org.embulk.spi.PageBuilder;
16
+ import org.embulk.spi.PageOutput;
17
+ import org.embulk.spi.Schema;
18
+ import org.embulk.spi.TestPageBuilderReader;
19
+ import org.junit.Assert;
20
+
21
+ import org.junit.Before;
22
+ import org.junit.Rule;
23
+ import org.junit.Test;
24
+ import org.mockito.Mockito;
25
+
26
+ import static org.junit.Assert.assertEquals;
27
+
28
+ import static org.mockito.ArgumentMatchers.any;
29
+ import static org.mockito.ArgumentMatchers.anyBoolean;
30
+ import static org.mockito.ArgumentMatchers.anyInt;
31
+ import static org.mockito.ArgumentMatchers.anyLong;
32
+ import static org.mockito.ArgumentMatchers.anyString;
33
+
34
+ import static org.mockito.Mockito.doReturn;
35
+ import static org.mockito.Mockito.mock;
36
+ import static org.mockito.Mockito.spy;
37
+ import static org.mockito.Mockito.times;
38
+ import static org.mockito.Mockito.verify;
39
+ import static org.mockito.Mockito.when;
40
+
41
+ import java.util.Collections;
42
+ import java.util.List;
43
+ import java.util.stream.Collectors;
44
+ import java.util.stream.IntStream;
45
+
46
+ public class TestZendeskInputPlugin
47
+ {
48
+ @Rule
49
+ @SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
50
+ public ZendeskPluginTestRuntime embulk = new ZendeskPluginTestRuntime();
51
+
52
+ private ZendeskSupportAPIService zendeskSupportAPIService = mock(ZendeskSupportAPIService.class);
53
+
54
+ private ZendeskInputPlugin zendeskInputPlugin;
55
+
56
+ private TestPageBuilderReader.MockPageOutput output = new TestPageBuilderReader.MockPageOutput();
57
+
58
+ private PageBuilder pageBuilder = Mockito.mock(PageBuilder.class);
59
+
60
+ @Before
61
+ public void prepare()
62
+ {
63
+ zendeskInputPlugin = spy(new ZendeskInputPlugin());
64
+ when(zendeskInputPlugin.getZendeskSupportAPIService(any(ZendeskInputPlugin.PluginTask.class))).thenReturn(zendeskSupportAPIService);
65
+ doReturn(pageBuilder).when(zendeskInputPlugin).getPageBuilder(any(Schema.class), any(PageOutput.class));
66
+ }
67
+
68
+ @Test
69
+ public void testGuessGenerateColumnsForIncrementalTarget()
70
+ {
71
+ final ConfigSource src = ZendeskTestHelper.getConfigSource("base.yml");
72
+ src.set("target", "tickets");
73
+ setupTestGuessGenerateColumn(src, "data/tickets.json", "data/expected/ticket_column.json");
74
+ }
75
+
76
+ @Test
77
+ public void testGuessGenerateColumnsForIncrementalTargetIncludeRelatedObject()
78
+ {
79
+ final ConfigSource src = ZendeskTestHelper.getConfigSource("base.yml");
80
+ src.set("target", "tickets");
81
+ src.set("includes", Collections.singletonList("organizations"));
82
+ setupTestGuessGenerateColumn(src, "data/tickets.json", "data/expected/ticket_column_with_related_objects.json");
83
+ }
84
+
85
+ @Test
86
+ public void testGuessGenerateColumnsForTicketMetrics()
87
+ {
88
+ final ConfigSource src = ZendeskTestHelper.getConfigSource("base.yml");
89
+ src.set("target", "ticket_metrics");
90
+ setupTestGuessGenerateColumn(src, "data/ticket_metrics.json", "data/expected/ticket_metrics_column.json");
91
+ }
92
+
93
+ @Test
94
+ public void testGuessGenerateColumnsForNonIncrementalTarget()
95
+ {
96
+ final ConfigSource src = ZendeskTestHelper.getConfigSource("base.yml");
97
+ src.set("target", "ticket_fields");
98
+ setupTestGuessGenerateColumn(src, "data/ticket_fields.json", "data/expected/ticket_fields_column.json");
99
+ }
100
+
101
+ @Test(expected = ConfigException.class)
102
+ public void testGuessFail()
103
+ {
104
+ final ConfigSource src = ZendeskTestHelper.getConfigSource("base.yml");
105
+ src.set("target", "tickets");
106
+ loadData("data/error_data.json");
107
+
108
+ zendeskInputPlugin.guess(src);
109
+ }
110
+
111
+ @Test
112
+ public void testRunIncrementalDedup()
113
+ {
114
+ final ConfigSource src = ZendeskTestHelper.getConfigSource("incremental.yml");
115
+ JsonNode dataJson = ZendeskTestHelper.getJsonFromFile("data/tickets.json");
116
+
117
+ when(zendeskSupportAPIService.getData(anyString(), anyInt(), anyBoolean(), anyLong())).thenReturn(dataJson);
118
+
119
+ ConfigDiff configDiff = zendeskInputPlugin.transaction(src, new Control());
120
+ String nextStartTime = configDiff.get(String.class, "start_time");
121
+ verify(pageBuilder, times(4)).addRecord();
122
+ verify(pageBuilder, times(1)).finish();
123
+ assertEquals("2019-02-20 07:17:34 +0000", nextStartTime);
124
+ }
125
+
126
+ @Test
127
+ public void testRunIncrementalWithNextPage()
128
+ {
129
+ final ConfigSource src = ZendeskTestHelper.getConfigSource("incremental.yml");
130
+ JsonNode dataJson = ZendeskTestHelper.getJsonFromFile("data/tickets_continue.json");
131
+ JsonNode dataJsonNext = ZendeskTestHelper.getJsonFromFile("data/tickets.json");
132
+ when(zendeskSupportAPIService.getData(anyString(), anyInt(), anyBoolean(), anyLong()))
133
+ .thenReturn(dataJson)
134
+ .thenReturn(dataJsonNext);
135
+
136
+ ConfigDiff configDiff = zendeskInputPlugin.transaction(src, new Control());
137
+ String nextStartTime = configDiff.get(String.class, "start_time");
138
+ verify(pageBuilder, times(1)).addRecord();
139
+ verify(pageBuilder, times(1)).finish();
140
+ assertEquals("2019-02-20 07:17:34 +0000", nextStartTime);
141
+ }
142
+
143
+ @Test
144
+ public void testRunIncrementalNonDedup()
145
+ {
146
+ final ConfigSource src = ZendeskTestHelper.getConfigSource("incremental.yml");
147
+ src.set("dedup", false);
148
+
149
+ JsonNode dataJsonNext = ZendeskTestHelper.getJsonFromFile("data/tickets.json");
150
+ when(zendeskSupportAPIService.getData(anyString(), anyInt(), anyBoolean(), anyLong())).thenReturn(dataJsonNext);
151
+
152
+ ConfigDiff configDiff = zendeskInputPlugin.transaction(src, new Control());
153
+ String nextStartTime = configDiff.get(String.class, "start_time");
154
+ verify(pageBuilder, times(5)).addRecord();
155
+ verify(pageBuilder, times(1)).finish();
156
+ assertEquals("2019-02-20 07:17:34 +0000", nextStartTime);
157
+ }
158
+
159
+ @Test
160
+ public void testRunIncrementalForTicketMetrics()
161
+ {
162
+ final ConfigSource src = ZendeskTestHelper.getConfigSource("incremental.yml");
163
+ src.set("target", "ticket_metrics");
164
+ JsonNode dataJson = ZendeskTestHelper.getJsonFromFile("data/ticket_metrics.json");
165
+
166
+ when(zendeskSupportAPIService.getData(anyString(), anyInt(), anyBoolean(), anyLong())).thenReturn(dataJson);
167
+
168
+ ConfigDiff configDiff = zendeskInputPlugin.transaction(src, new Control());
169
+ String nextStartTime = configDiff.get(String.class, "start_time");
170
+ verify(pageBuilder, times(3)).addRecord();
171
+ verify(pageBuilder, times(1)).finish();
172
+ assertEquals("2019-02-20 07:17:34 +0000", nextStartTime);
173
+ }
174
+
175
+ @Test
176
+ public void testRunIncrementalWithRelatedObject()
177
+ {
178
+ final ConfigSource src = ZendeskTestHelper.getConfigSource("incremental.yml");
179
+ src.set("includes", Collections.singletonList("organizations"));
180
+
181
+ JsonNode dataJson = ZendeskTestHelper.getJsonFromFile("data/tickets.json");
182
+ JsonNode dataJsonObject = ZendeskTestHelper.getJsonFromFile("data/ticket_with_related_objects.json");
183
+ when(zendeskSupportAPIService.getData(anyString(), anyInt(), anyBoolean(), anyLong()))
184
+ .thenReturn(dataJson)
185
+ .thenReturn(dataJsonObject);
186
+
187
+ ConfigDiff configDiff = zendeskInputPlugin.transaction(src, new Control());
188
+
189
+ verify(pageBuilder, times(1)).finish();
190
+ String nextStartTime = configDiff.get(String.class, "start_time");
191
+ assertEquals("2019-02-20 07:17:34 +0000", nextStartTime);
192
+ }
193
+
194
+ @Test
195
+ public void testRunNonIncremental()
196
+ {
197
+ final ConfigSource src = ZendeskTestHelper.getConfigSource("non-incremental.yml");
198
+ loadData("data/ticket_fields.json");
199
+
200
+ ConfigDiff configDiff = zendeskInputPlugin.transaction(src, new Control());
201
+ // running in 2 pages
202
+ verify(pageBuilder, times(7 * 2)).addRecord();
203
+ verify(pageBuilder, times(2)).finish();
204
+ Assert.assertTrue(configDiff.isEmpty());
205
+ }
206
+
207
+ private class Control implements InputPlugin.Control
208
+ {
209
+ @Override
210
+ public List<TaskReport> run(final TaskSource taskSource, final Schema schema, final int taskCount)
211
+ {
212
+ List<TaskReport> reports = IntStream.range(0, taskCount)
213
+ .mapToObj(i -> zendeskInputPlugin.run(taskSource, schema, i, output))
214
+ .collect(Collectors.toList());
215
+ return reports;
216
+ }
217
+ }
218
+
219
+ private void loadData(String fileName)
220
+ {
221
+ JsonNode dataJson = ZendeskTestHelper.getJsonFromFile(fileName);
222
+ when(zendeskSupportAPIService.getData(anyString(), anyInt(), anyBoolean(), anyLong())).thenReturn(dataJson);
223
+ }
224
+
225
+ private void setupTestGuessGenerateColumn(ConfigSource src, String fileName, String expectedSource)
226
+ {
227
+ loadData(fileName);
228
+ ConfigDiff configDiff = zendeskInputPlugin.guess(src);
229
+ JsonNode columns = configDiff.get(JsonNode.class, "columns");
230
+ assertEquals(ZendeskTestHelper.getJsonFromFile(expectedSource), columns);
231
+ }
232
+ }