embulk-input-marketo-through-proxy 0.6.20

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.
Files changed (90) hide show
  1. checksums.yaml +7 -0
  2. data/.github/CODEOWNERS +1 -0
  3. data/.github/PULL_REQUEST_TEMPLATE.md +37 -0
  4. data/.github/workflows/build.yml +38 -0
  5. data/.gitignore +14 -0
  6. data/CHANGELOG.md +178 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +231 -0
  9. data/build.gradle +105 -0
  10. data/config/checkstyle/checkstyle.xml +128 -0
  11. data/config/checkstyle/default.xml +108 -0
  12. data/gradle/wrapper/gradle-wrapper.jar +0 -0
  13. data/gradle/wrapper/gradle-wrapper.properties +6 -0
  14. data/gradlew +169 -0
  15. data/gradlew.bat +84 -0
  16. data/lib/embulk/input/marketo.rb +3 -0
  17. data/settings.gradle +1 -0
  18. data/src/main/java/org/embulk/input/marketo/CsvTokenizer.java +695 -0
  19. data/src/main/java/org/embulk/input/marketo/MarketoInputPlugin.java +15 -0
  20. data/src/main/java/org/embulk/input/marketo/MarketoInputPluginDelegate.java +100 -0
  21. data/src/main/java/org/embulk/input/marketo/MarketoService.java +47 -0
  22. data/src/main/java/org/embulk/input/marketo/MarketoServiceImpl.java +258 -0
  23. data/src/main/java/org/embulk/input/marketo/MarketoUtils.java +212 -0
  24. data/src/main/java/org/embulk/input/marketo/delegate/ActivityBulkExtractInputPlugin.java +169 -0
  25. data/src/main/java/org/embulk/input/marketo/delegate/CampaignInputPlugin.java +48 -0
  26. data/src/main/java/org/embulk/input/marketo/delegate/CustomObjectInputPlugin.java +124 -0
  27. data/src/main/java/org/embulk/input/marketo/delegate/CustomObjectResponseMapperBuilder.java +81 -0
  28. data/src/main/java/org/embulk/input/marketo/delegate/LeadBulkExtractInputPlugin.java +68 -0
  29. data/src/main/java/org/embulk/input/marketo/delegate/LeadServiceResponseMapperBuilder.java +85 -0
  30. data/src/main/java/org/embulk/input/marketo/delegate/LeadWithListInputPlugin.java +89 -0
  31. data/src/main/java/org/embulk/input/marketo/delegate/LeadWithProgramInputPlugin.java +85 -0
  32. data/src/main/java/org/embulk/input/marketo/delegate/MarketoBaseBulkExtractInputPlugin.java +448 -0
  33. data/src/main/java/org/embulk/input/marketo/delegate/MarketoBaseInputPluginDelegate.java +160 -0
  34. data/src/main/java/org/embulk/input/marketo/delegate/ProgramInputPlugin.java +234 -0
  35. data/src/main/java/org/embulk/input/marketo/exception/MarketoAPIException.java +30 -0
  36. data/src/main/java/org/embulk/input/marketo/model/BulkExtractRangeHeader.java +26 -0
  37. data/src/main/java/org/embulk/input/marketo/model/MarketoAccessTokenResponse.java +92 -0
  38. data/src/main/java/org/embulk/input/marketo/model/MarketoBulkExtractRequest.java +68 -0
  39. data/src/main/java/org/embulk/input/marketo/model/MarketoError.java +40 -0
  40. data/src/main/java/org/embulk/input/marketo/model/MarketoField.java +126 -0
  41. data/src/main/java/org/embulk/input/marketo/model/MarketoResponse.java +82 -0
  42. data/src/main/java/org/embulk/input/marketo/model/filter/DateRangeFilter.java +40 -0
  43. data/src/main/java/org/embulk/input/marketo/rest/MarketoBaseRestClient.java +344 -0
  44. data/src/main/java/org/embulk/input/marketo/rest/MarketoInputStreamResponseEntityReader.java +69 -0
  45. data/src/main/java/org/embulk/input/marketo/rest/MarketoRESTEndpoint.java +47 -0
  46. data/src/main/java/org/embulk/input/marketo/rest/MarketoResponseJetty92EntityReader.java +89 -0
  47. data/src/main/java/org/embulk/input/marketo/rest/MarketoRestClient.java +601 -0
  48. data/src/main/java/org/embulk/input/marketo/rest/RecordPagingIterable.java +180 -0
  49. data/src/test/java/org/embulk/input/marketo/MarketoServiceImplTest.java +147 -0
  50. data/src/test/java/org/embulk/input/marketo/MarketoUtilsTest.java +89 -0
  51. data/src/test/java/org/embulk/input/marketo/delegate/ActivityBulkExtractInputPluginTest.java +129 -0
  52. data/src/test/java/org/embulk/input/marketo/delegate/CampaignInputPluginTest.java +73 -0
  53. data/src/test/java/org/embulk/input/marketo/delegate/CustomObjectInputPluginTest.java +175 -0
  54. data/src/test/java/org/embulk/input/marketo/delegate/LeadBulkExtractInputPluginTest.java +102 -0
  55. data/src/test/java/org/embulk/input/marketo/delegate/LeadServiceResponseMapperBuilderTest.java +119 -0
  56. data/src/test/java/org/embulk/input/marketo/delegate/LeadWithListInputPluginTest.java +132 -0
  57. data/src/test/java/org/embulk/input/marketo/delegate/LeadWithProgramInputPluginTest.java +134 -0
  58. data/src/test/java/org/embulk/input/marketo/delegate/MarketoBaseBulkExtractInputPluginTest.java +171 -0
  59. data/src/test/java/org/embulk/input/marketo/delegate/MarketoBaseInputPluginDelegateTest.java +60 -0
  60. data/src/test/java/org/embulk/input/marketo/delegate/ProgramInputPluginTest.java +325 -0
  61. data/src/test/java/org/embulk/input/marketo/rest/MarketoBaseRestClientTest.java +368 -0
  62. data/src/test/java/org/embulk/input/marketo/rest/MarketoRestClientTest.java +649 -0
  63. data/src/test/resources/config/activity_bulk_extract_config.yaml +7 -0
  64. data/src/test/resources/config/custom_object_config.yaml +8 -0
  65. data/src/test/resources/config/lead_bulk_extract_config.yaml +8 -0
  66. data/src/test/resources/config/rest_config.yaml +3 -0
  67. data/src/test/resources/fixtures/activity_extract1.csv +35 -0
  68. data/src/test/resources/fixtures/activity_extract2.csv +22 -0
  69. data/src/test/resources/fixtures/activity_types.json +22 -0
  70. data/src/test/resources/fixtures/all_program_full.json +53 -0
  71. data/src/test/resources/fixtures/campaign_response.json +38 -0
  72. data/src/test/resources/fixtures/campaign_response_full.json +102 -0
  73. data/src/test/resources/fixtures/custom_object_describe.json +124 -0
  74. data/src/test/resources/fixtures/custom_object_describe_marketo_fields_full.json +22 -0
  75. data/src/test/resources/fixtures/custom_object_expected.json +66 -0
  76. data/src/test/resources/fixtures/custom_object_response.json +24 -0
  77. data/src/test/resources/fixtures/custom_object_response_full.json +23 -0
  78. data/src/test/resources/fixtures/lead_by_list.json +33 -0
  79. data/src/test/resources/fixtures/lead_by_program_response.json +47 -0
  80. data/src/test/resources/fixtures/lead_describe.json +221 -0
  81. data/src/test/resources/fixtures/lead_describe_expected.json +66 -0
  82. data/src/test/resources/fixtures/lead_describe_marketo_fields_full.json +518 -0
  83. data/src/test/resources/fixtures/lead_extract1.csv +11 -0
  84. data/src/test/resources/fixtures/lead_response_full.json +2402 -0
  85. data/src/test/resources/fixtures/lead_with_program_full.json +17 -0
  86. data/src/test/resources/fixtures/leads_extract2.csv +10 -0
  87. data/src/test/resources/fixtures/list_reponse_full.json +191 -0
  88. data/src/test/resources/fixtures/lists_response.json +31 -0
  89. data/src/test/resources/fixtures/program_response.json +71 -0
  90. metadata +173 -0
@@ -0,0 +1,180 @@
1
+ package org.embulk.input.marketo.rest;
2
+
3
+ import java.util.Iterator;
4
+ import java.util.List;
5
+ import java.util.NoSuchElementException;
6
+
7
+ /**
8
+ * Record Iterable class that will go through Marketo Paging
9
+ * Warning this iterator implementation do not cached page due to reduce memory usage. So iterate through a
10
+ * RecordIterate multiple time is not recommended since it will sent query to Marketo on every call.
11
+ * Created by tai.khuu on 9/5/17.
12
+ */
13
+ public class RecordPagingIterable<T> implements Iterable<T>
14
+ {
15
+ private PagingFunction<Page<T>> pagingFunction;
16
+
17
+ public RecordPagingIterable(PagingFunction pagingFunction)
18
+ {
19
+ this.pagingFunction = pagingFunction;
20
+ }
21
+
22
+ @Override
23
+ public Iterator<T> iterator()
24
+ {
25
+ return this.new RecordIterator();
26
+ }
27
+
28
+ private class RecordIterator implements Iterator<T>
29
+ {
30
+ Page<T> currentPage;
31
+ private Iterator<T> currentIterator;
32
+
33
+ public RecordIterator()
34
+ {
35
+ }
36
+
37
+ @Override
38
+ public boolean hasNext()
39
+ {
40
+ if (currentPage == null) {
41
+ currentPage = pagingFunction.getFirstPage();
42
+ this.currentIterator = currentPage.getRecordsIter();
43
+ }
44
+ if (currentIterator.hasNext()) {
45
+ return true;
46
+ }
47
+ if (!currentPage.hasNext) {
48
+ return false;
49
+ }
50
+ Page<T> nextPage = pagingFunction.getNextPage(currentPage);
51
+ currentIterator = nextPage.getRecordsIter();
52
+ currentPage = nextPage;
53
+ return currentIterator.hasNext();
54
+ }
55
+
56
+ @Override
57
+ public T next()
58
+ {
59
+ if (!hasNext()) {
60
+ throw new NoSuchElementException("Call next on an empty iterator");
61
+ }
62
+ return currentIterator.next();
63
+ }
64
+
65
+ @Override
66
+ public void remove()
67
+ {
68
+ throw new UnsupportedOperationException("RecordIterator not support remove");
69
+ }
70
+ }
71
+
72
+ public interface PagingFunction<P extends Page>
73
+ {
74
+ P getNextPage(P currentPage);
75
+ /**
76
+ * All implementation must make sure calling get first page multiple time should always return.
77
+ * @return P
78
+ */
79
+ P getFirstPage();
80
+ }
81
+
82
+ public static class Page<T>
83
+ {
84
+ private Iterable<T> records;
85
+
86
+ private boolean hasNext;
87
+
88
+ public Page(Iterable<T> records, boolean hasNext)
89
+ {
90
+ this.records = records;
91
+ this.hasNext = hasNext;
92
+ }
93
+
94
+ public Iterable<T> getRecords()
95
+ {
96
+ return records;
97
+ }
98
+ public Iterator<T> getRecordsIter()
99
+ {
100
+ return records.iterator();
101
+ }
102
+ public void setRecords(List<T> records)
103
+ {
104
+ this.records = records;
105
+ }
106
+
107
+ public boolean isHasNext()
108
+ {
109
+ return hasNext;
110
+ }
111
+
112
+ public void setHasNext(boolean hasNext)
113
+ {
114
+ this.hasNext = hasNext;
115
+ }
116
+ }
117
+
118
+ public static class TokenPage<T> extends Page<T>
119
+ {
120
+ private String nextPageToken;
121
+
122
+ public TokenPage(Iterable<T> records, String nextPageToken, boolean moreResult)
123
+ {
124
+ super(records, moreResult);
125
+ this.nextPageToken = nextPageToken;
126
+ }
127
+
128
+ public String getNextPageToken()
129
+ {
130
+ return nextPageToken;
131
+ }
132
+
133
+ public void setNextPageToken(String nextPageToken)
134
+ {
135
+ this.nextPageToken = nextPageToken;
136
+ }
137
+ }
138
+
139
+ public static class OffsetPage<T> extends Page<T>
140
+ {
141
+ private int nextOffSet;
142
+
143
+ public OffsetPage(Iterable<T> records, int nextOffSet, boolean moreResult)
144
+ {
145
+ super(records, moreResult);
146
+ this.nextOffSet = nextOffSet;
147
+ }
148
+
149
+ public int getNextOffSet()
150
+ {
151
+ return nextOffSet;
152
+ }
153
+ }
154
+ public static class OffsetWithTokenPage<T> extends Page<T>
155
+ {
156
+ private int nextOffSet;
157
+ private String nextPageToken;
158
+ public OffsetWithTokenPage(Iterable<T> records, int nextOffSet, String nextPageToken, boolean moreResult)
159
+ {
160
+ super(records, moreResult);
161
+ this.nextOffSet = nextOffSet;
162
+ this.nextPageToken = nextPageToken;
163
+ }
164
+
165
+ public int getNextOffSet()
166
+ {
167
+ return nextOffSet;
168
+ }
169
+
170
+ public String getNextPageToken()
171
+ {
172
+ return nextPageToken;
173
+ }
174
+
175
+ public void setNextPageToken(String nextPageToken)
176
+ {
177
+ this.nextPageToken = nextPageToken;
178
+ }
179
+ }
180
+ }
@@ -0,0 +1,147 @@
1
+ package org.embulk.input.marketo;
2
+
3
+ import com.fasterxml.jackson.databind.ObjectMapper;
4
+ import com.fasterxml.jackson.databind.node.ObjectNode;
5
+ import com.google.common.io.ByteStreams;
6
+ import org.embulk.EmbulkTestRuntime;
7
+ import org.embulk.input.marketo.model.BulkExtractRangeHeader;
8
+ import org.embulk.input.marketo.rest.MarketoRestClient;
9
+ import org.embulk.input.marketo.rest.RecordPagingIterable;
10
+ import org.junit.Assert;
11
+ import org.junit.Before;
12
+ import org.junit.Rule;
13
+ import org.junit.Test;
14
+ import org.mockito.Mockito;
15
+
16
+ import java.io.ByteArrayInputStream;
17
+ import java.io.File;
18
+ import java.io.FileInputStream;
19
+ import java.io.IOException;
20
+ import java.util.ArrayList;
21
+ import java.util.Arrays;
22
+ import java.util.Date;
23
+ import java.util.List;
24
+
25
+ import static org.mockito.ArgumentMatchers.any;
26
+
27
+ /**
28
+ * Created by tai.khuu on 10/9/17.
29
+ */
30
+ public class MarketoServiceImplTest
31
+ {
32
+ private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
33
+ @Rule
34
+ public EmbulkTestRuntime embulkTestRuntime = new EmbulkTestRuntime();
35
+ private MarketoService marketoService;
36
+
37
+ private MarketoRestClient mockMarketoRestClient;
38
+ @Before
39
+ public void prepare()
40
+ {
41
+ mockMarketoRestClient = Mockito.mock(MarketoRestClient.class);
42
+ marketoService = new MarketoServiceImpl(mockMarketoRestClient);
43
+ }
44
+
45
+ @Test
46
+ public void extractLead() throws Exception
47
+ {
48
+ Date startDate = new Date(1507223374000L);
49
+ Date endDate = new Date(1507655374000L);
50
+ List<String> extractedFields = Arrays.asList("field1", "fActivityBulkExtractInputPluginTest.java:78ield2");
51
+ String filerField = "field1";
52
+ String exportId = "exportId";
53
+ Mockito.when(mockMarketoRestClient.createLeadBulkExtract(Mockito.eq(startDate), Mockito.eq(endDate), Mockito.eq(extractedFields), Mockito.eq(filerField))).thenReturn(exportId);
54
+ ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream("Test File Content".getBytes());
55
+ Mockito.when(mockMarketoRestClient.getLeadBulkExtractResult(Mockito.eq(exportId), any(BulkExtractRangeHeader.class))).thenReturn(byteArrayInputStream);
56
+ File file = marketoService.extractLead(startDate, endDate, extractedFields, filerField, 1, 3);
57
+ Assert.assertEquals("Test File Content", new String(ByteStreams.toByteArray(new FileInputStream(file))));
58
+ Mockito.verify(mockMarketoRestClient, Mockito.times(1)).startLeadBulkExtract(Mockito.eq(exportId));
59
+ Mockito.verify(mockMarketoRestClient, Mockito.times(1)).waitLeadExportJobComplete(Mockito.eq(exportId), Mockito.eq(1), Mockito.eq(3));
60
+ }
61
+
62
+ @Test
63
+ public void extractAllActivity() throws Exception
64
+ {
65
+ Date startDate = new Date(1507223374000L);
66
+ Date endDate = new Date(1507655374000L);
67
+ List<Integer> activityTypeIds = new ArrayList<>();
68
+ String exportId = "exportId";
69
+ Mockito.when(mockMarketoRestClient.createActivityExtract(any(List.class), Mockito.eq(startDate), Mockito.eq(endDate))).thenReturn(exportId);
70
+ ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream("Test File Content".getBytes());
71
+ Mockito.when(mockMarketoRestClient.getActivitiesBulkExtractResult(Mockito.eq(exportId), any(BulkExtractRangeHeader.class))).thenReturn(byteArrayInputStream);
72
+ File file = marketoService.extractAllActivity(activityTypeIds, startDate, endDate, 1, 3);
73
+ Assert.assertEquals("Test File Content", new String(ByteStreams.toByteArray(new FileInputStream(file))));
74
+ Mockito.verify(mockMarketoRestClient, Mockito.times(1)).startActitvityBulkExtract(Mockito.eq(exportId));
75
+ Mockito.verify(mockMarketoRestClient, Mockito.times(1)).waitActitvityExportJobComplete(Mockito.eq(exportId), Mockito.eq(1), Mockito.eq(3));
76
+ }
77
+
78
+ @Test
79
+ public void getAllListLead() throws Exception
80
+ {
81
+ List<String> extractFields = Arrays.asList("field1", "field2");
82
+ List<ObjectNode> allLists = mockParent();
83
+
84
+ List<ObjectNode> lead1 = new ArrayList<>();
85
+ lead1.add((ObjectNode) OBJECT_MAPPER.readTree("{\"id\":\"lead1\"}"));
86
+ List<ObjectNode> lead2 = new ArrayList<>();
87
+ lead2.add((ObjectNode) OBJECT_MAPPER.readTree("{\"id\":\"lead2\"}"));
88
+
89
+ RecordPagingIterable leadIterable1 = Mockito.mock(RecordPagingIterable.class);
90
+ RecordPagingIterable leadsIterable2 = Mockito.mock(RecordPagingIterable.class);
91
+ Mockito.when(leadIterable1.iterator()).thenReturn(lead1.iterator());
92
+ Mockito.when(leadsIterable2.iterator()).thenReturn(lead2.iterator());
93
+
94
+ Mockito.when(mockMarketoRestClient.getLeadsByList(Mockito.eq("1"), Mockito.eq("field1,field2"))).thenReturn(leadIterable1);
95
+ Mockito.when(mockMarketoRestClient.getLeadsByList(Mockito.eq("2"), Mockito.eq("field1,field2"))).thenReturn(leadsIterable2);
96
+
97
+ Iterable<ObjectNode> allListLead = marketoService.getAllListLead(extractFields, allLists);
98
+ Assert.assertEquals(lead1.get(0), allListLead.iterator().next());
99
+ Assert.assertEquals(lead2.get(0), allListLead.iterator().next());
100
+ }
101
+
102
+ private List<ObjectNode> mockParent() throws IOException
103
+ {
104
+ List<ObjectNode> allLists = new ArrayList<>();
105
+ allLists.add((ObjectNode) OBJECT_MAPPER.readTree("{\"id\": 1}"));
106
+ allLists.add((ObjectNode) OBJECT_MAPPER.readTree("{\"id\": 2}"));
107
+ return allLists;
108
+ }
109
+
110
+ @Test
111
+ public void getAllProgramLead() throws Exception
112
+ {
113
+ RecordPagingIterable<ObjectNode> listObjectNodes = Mockito.mock(RecordPagingIterable.class);
114
+ Iterable listIterator = mockParent();
115
+
116
+ List<ObjectNode> leadList1 = new ArrayList<>();
117
+ leadList1.add((ObjectNode) OBJECT_MAPPER.readTree("{\"id\":\"lead1\"}"));
118
+ List<ObjectNode> leadList2 = new ArrayList<>();
119
+ leadList2.add((ObjectNode) OBJECT_MAPPER.readTree("{\"id\":\"lead2\"}"));
120
+ Mockito.when(mockMarketoRestClient.getPrograms()).thenReturn(listObjectNodes);
121
+ RecordPagingIterable leadIterable1 = Mockito.mock(RecordPagingIterable.class);
122
+ RecordPagingIterable leadsIterable2 = Mockito.mock(RecordPagingIterable.class);
123
+ Mockito.when(leadIterable1.iterator()).thenReturn(leadList1.iterator());
124
+ Mockito.when(leadsIterable2.iterator()).thenReturn(leadList2.iterator());
125
+
126
+ Mockito.when(mockMarketoRestClient.getLeadsByProgram(Mockito.eq("1"), Mockito.eq("field1,field2"))).thenReturn(leadIterable1);
127
+ Mockito.when(mockMarketoRestClient.getLeadsByProgram(Mockito.eq("2"), Mockito.eq("field1,field2"))).thenReturn(leadsIterable2);
128
+
129
+ Iterable<ObjectNode> allListLead = marketoService.getAllProgramLead(Arrays.asList("field1", "field2"), listIterator);
130
+ Assert.assertEquals(leadList1.get(0), allListLead.iterator().next());
131
+ Assert.assertEquals(leadList2.get(0), allListLead.iterator().next());
132
+ }
133
+
134
+ @Test
135
+ public void getCampaign() throws Exception
136
+ {
137
+ marketoService.getCampaign();
138
+ Mockito.verify(mockMarketoRestClient, Mockito.times(1)).getCampaign();
139
+ }
140
+
141
+ @Test
142
+ public void describeLead() throws Exception
143
+ {
144
+ marketoService.describeLead();
145
+ Mockito.verify(mockMarketoRestClient, Mockito.times(1)).describeLead();
146
+ }
147
+ }
@@ -0,0 +1,89 @@
1
+ package org.embulk.input.marketo;
2
+
3
+ import org.embulk.base.restclient.ServiceResponseMapper;
4
+ import org.embulk.base.restclient.record.ValueLocator;
5
+ import org.embulk.input.marketo.model.MarketoField;
6
+ import org.embulk.spi.Column;
7
+ import org.embulk.spi.type.Types;
8
+ import org.junit.Test;
9
+
10
+ import java.time.Instant;
11
+ import java.time.OffsetDateTime;
12
+ import java.time.ZoneOffset;
13
+ import java.util.ArrayList;
14
+ import java.util.List;
15
+
16
+ import static org.junit.Assert.assertEquals;
17
+ import static org.junit.Assert.assertFalse;
18
+
19
+ /**
20
+ * Created by tai.khuu on 10/7/17.
21
+ */
22
+ public class MarketoUtilsTest
23
+ {
24
+ @Test
25
+ public void buildDynamicResponseMapper()
26
+ {
27
+ List<MarketoField> marketoFields = new ArrayList<>();
28
+ marketoFields.add(new MarketoField("marketoField1", "text"));
29
+ marketoFields.add(new MarketoField("marketoField2", "date"));
30
+ marketoFields.add(new MarketoField("marketoField3", "datetime"));
31
+ ServiceResponseMapper<? extends ValueLocator> mapper = MarketoUtils.buildDynamicResponseMapper("marketo", marketoFields);
32
+ List<Column> columns = mapper.getEmbulkSchema().getColumns();
33
+ Column column1 = columns.get(0);
34
+ assertEquals("marketo_marketoField1", column1.getName());
35
+ assertEquals(Types.STRING, column1.getType());
36
+ Column column2 = columns.get(1);
37
+ assertEquals(Types.TIMESTAMP, column2.getType());
38
+ assertEquals("marketo_marketoField2", column2.getName());
39
+ Column column3 = columns.get(2);
40
+ assertEquals("marketo_marketoField3", column3.getName());
41
+ assertEquals(Types.TIMESTAMP, column3.getType());
42
+ }
43
+
44
+ @Test
45
+ public void getFieldNameFromMarketoFields()
46
+ {
47
+ List<MarketoField> marketoFields = new ArrayList<>();
48
+ marketoFields.add(new MarketoField("marketoField1", "text"));
49
+ marketoFields.add(new MarketoField("marketoField2", "date"));
50
+ marketoFields.add(new MarketoField("marketoField3", "datetime"));
51
+ List<String> marketoFieldList = MarketoUtils.getFieldNameFromMarketoFields(marketoFields, "marketoField2");
52
+ assertEquals(2, marketoFieldList.size());
53
+ assertFalse(marketoFieldList.contains("marketoField2"));
54
+ }
55
+
56
+ @Test
57
+ public void buildColumnName()
58
+ {
59
+ String columnName = MarketoUtils.buildColumnName("prefix", "columnName");
60
+ assertEquals("prefix_columnName", columnName);
61
+ }
62
+
63
+ @Test
64
+ public void getIdentityEndPoint()
65
+ {
66
+ String identityEndPoint = MarketoUtils.getIdentityEndPoint("accountId");
67
+ assertEquals("https://accountId.mktorest.com/identity", identityEndPoint);
68
+ }
69
+
70
+ @Test
71
+ public void getEndPoint()
72
+ {
73
+ String endPoint = MarketoUtils.getEndPoint("accountId");
74
+ assertEquals("https://accountId.mktorest.com", endPoint);
75
+ }
76
+
77
+ @Test
78
+ public void sliceRange()
79
+ {
80
+ OffsetDateTime startDate = OffsetDateTime.ofInstant(Instant.ofEpochMilli(1507369760000L), ZoneOffset.UTC);
81
+ List<MarketoUtils.DateRange> dateRanges1 = MarketoUtils.sliceRange(startDate, startDate.plusDays(7), 2);
82
+ assertEquals(4, dateRanges1.size());
83
+ assertEquals(startDate.plusDays(7), dateRanges1.get(3).toDate);
84
+
85
+ List<MarketoUtils.DateRange> dateRanges2 = MarketoUtils.sliceRange(startDate, startDate.plusDays(1), 2);
86
+ assertEquals(1, dateRanges2.size());
87
+ assertEquals(startDate.plusDays(1), dateRanges2.get(0).toDate);
88
+ }
89
+ }
@@ -0,0 +1,129 @@
1
+ package org.embulk.input.marketo.delegate;
2
+
3
+ import com.fasterxml.jackson.databind.JavaType;
4
+ import com.fasterxml.jackson.databind.ObjectMapper;
5
+ import com.fasterxml.jackson.databind.node.ObjectNode;
6
+ import org.embulk.EmbulkTestRuntime;
7
+ import org.embulk.base.restclient.ServiceResponseMapper;
8
+ import org.embulk.base.restclient.record.ValueLocator;
9
+ import org.embulk.config.ConfigDiff;
10
+ import org.embulk.config.ConfigException;
11
+ import org.embulk.config.ConfigLoader;
12
+ import org.embulk.config.ConfigSource;
13
+ import org.embulk.config.TaskReport;
14
+ import org.embulk.input.marketo.MarketoUtils;
15
+ import org.embulk.input.marketo.model.BulkExtractRangeHeader;
16
+ import org.embulk.input.marketo.rest.MarketoRestClient;
17
+ import org.embulk.input.marketo.rest.RecordPagingIterable;
18
+ import org.embulk.spi.Column;
19
+ import org.embulk.spi.PageBuilder;
20
+ import org.embulk.spi.Schema;
21
+ import org.junit.Assert;
22
+ import org.junit.Before;
23
+ import org.junit.Rule;
24
+ import org.junit.Test;
25
+ import org.junit.function.ThrowingRunnable;
26
+ import org.mockito.ArgumentCaptor;
27
+ import org.mockito.Mockito;
28
+
29
+ import java.io.IOException;
30
+ import java.text.DateFormat;
31
+ import java.text.SimpleDateFormat;
32
+ import java.time.OffsetDateTime;
33
+ import java.time.ZoneOffset;
34
+ import java.util.ArrayList;
35
+ import java.util.Arrays;
36
+ import java.util.Date;
37
+ import java.util.List;
38
+
39
+ import static org.mockito.ArgumentMatchers.any;
40
+
41
+ /**
42
+ * Created by khuutantaitai on 10/3/17.
43
+ */
44
+ public class ActivityBulkExtractInputPluginTest
45
+ {
46
+ private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
47
+
48
+ @Rule
49
+ public EmbulkTestRuntime embulkTestRuntime = new EmbulkTestRuntime();
50
+
51
+ private ActivityBulkExtractInputPlugin activityBulkExtractInputPlugin;
52
+
53
+ private ConfigSource configSource;
54
+
55
+ private MarketoRestClient mockMarketoRestclient;
56
+
57
+ @Before
58
+ public void prepare() throws IOException
59
+ {
60
+ activityBulkExtractInputPlugin = Mockito.spy(new ActivityBulkExtractInputPlugin());
61
+ ConfigLoader configLoader = embulkTestRuntime.getInjector().getInstance(ConfigLoader.class);
62
+ configSource = configLoader.fromYaml(this.getClass().getResourceAsStream("/config/activity_bulk_extract_config.yaml"));
63
+ mockMarketoRestclient = Mockito.mock(MarketoRestClient.class);
64
+ Mockito.doReturn(mockMarketoRestclient).when(activityBulkExtractInputPlugin).createMarketoRestClient(any(ActivityBulkExtractInputPlugin.PluginTask.class));
65
+ }
66
+
67
+ @Test
68
+ public void testInvalidActivityTypeIds()
69
+ {
70
+ configSource.set("activity_type_ids", Arrays.asList(" ", "abc", "123"));
71
+ final ActivityBulkExtractInputPlugin.PluginTask task = configSource.loadConfig(ActivityBulkExtractInputPlugin.PluginTask.class);
72
+
73
+ Assert.assertThrows("Invalid activity type id: [ , abc]", ConfigException.class, new ThrowingRunnable()
74
+ {
75
+ @Override
76
+ public void run() throws Throwable
77
+ {
78
+ activityBulkExtractInputPlugin.validateInputTask(task);
79
+ }
80
+ });
81
+ }
82
+
83
+ @Test
84
+ public void testActivityTypeIdsValid() throws IOException
85
+ {
86
+ configSource.set("activity_type_ids", Arrays.asList("1", "2", "3 "));
87
+ final ActivityBulkExtractInputPlugin.PluginTask task = configSource.loadConfig(ActivityBulkExtractInputPlugin.PluginTask.class);
88
+
89
+ RecordPagingIterable<ObjectNode> mockRecordPagingIterable = Mockito.mock(RecordPagingIterable.class);
90
+ JavaType javaType = OBJECT_MAPPER.getTypeFactory().constructParametrizedType(List.class, List.class, ObjectNode.class);
91
+ List<ObjectNode> objectNodeList = OBJECT_MAPPER.readValue(this.getClass().getResourceAsStream("/fixtures/activity_types.json"), javaType);
92
+ Mockito.when(mockRecordPagingIterable.iterator()).thenReturn(objectNodeList.iterator());
93
+
94
+ Mockito.when(mockMarketoRestclient.getActivityTypes()).thenReturn(mockRecordPagingIterable);
95
+ activityBulkExtractInputPlugin.validateInputTask(task);
96
+ }
97
+
98
+ @Test
99
+ public void testRun() throws InterruptedException
100
+ {
101
+ ActivityBulkExtractInputPlugin.PluginTask task = configSource.loadConfig(ActivityBulkExtractInputPlugin.PluginTask.class);
102
+
103
+ OffsetDateTime startDate = OffsetDateTime.ofInstant(task.getFromDate().toInstant(), ZoneOffset.UTC);
104
+ List<Integer> activityTypeIds = new ArrayList<>();
105
+
106
+ PageBuilder pageBuilder = Mockito.mock(PageBuilder.class);
107
+ String exportId1 = "exportId1";
108
+ String exportId2 = "exportId2";
109
+ Mockito.when(mockMarketoRestclient.createActivityExtract(any(List.class), any(Date.class), any(Date.class))).thenReturn(exportId1).thenReturn(exportId2).thenReturn(null);
110
+ Mockito.when(mockMarketoRestclient.getActivitiesBulkExtractResult(Mockito.eq(exportId1), any(BulkExtractRangeHeader.class))).thenReturn(this.getClass().getResourceAsStream("/fixtures/activity_extract1.csv"));
111
+ Mockito.when(mockMarketoRestclient.getActivitiesBulkExtractResult(Mockito.eq(exportId2), any(BulkExtractRangeHeader.class))).thenReturn(this.getClass().getResourceAsStream("/fixtures/activity_extract2.csv"));
112
+ ServiceResponseMapper<? extends ValueLocator> mapper = activityBulkExtractInputPlugin.buildServiceResponseMapper(task);
113
+ activityBulkExtractInputPlugin.validateInputTask(task);
114
+ TaskReport taskReport = activityBulkExtractInputPlugin.ingestServiceData(task, mapper.createRecordImporter(), 1, pageBuilder);
115
+ ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
116
+ Column marketoGUID = mapper.getEmbulkSchema().lookupColumn("marketoGUID");
117
+ Mockito.verify(pageBuilder, Mockito.times(55)).setString(Mockito.eq(marketoGUID), argumentCaptor.capture());
118
+ Mockito.verify(mockMarketoRestclient, Mockito.times(1)).startActitvityBulkExtract(Mockito.eq(exportId1));
119
+ Mockito.verify(mockMarketoRestclient, Mockito.times(1)).waitActitvityExportJobComplete(Mockito.eq(exportId1), Mockito.eq(task.getPollingIntervalSecond()), Mockito.eq(task.getBulkJobTimeoutSecond()));
120
+ Mockito.verify(mockMarketoRestclient, Mockito.times(1)).startActitvityBulkExtract(Mockito.eq(exportId2));
121
+ Mockito.verify(mockMarketoRestclient, Mockito.times(1)).waitActitvityExportJobComplete(Mockito.eq(exportId2), Mockito.eq(task.getPollingIntervalSecond()), Mockito.eq(task.getBulkJobTimeoutSecond()));
122
+ Mockito.verify(mockMarketoRestclient, Mockito.times(1)).createActivityExtract(activityTypeIds, Date.from(startDate.toInstant()), Date.from(startDate.plusDays(30).toInstant()));
123
+ OffsetDateTime startDate2 = startDate.plusDays(30).plusSeconds(1);
124
+ Mockito.verify(mockMarketoRestclient, Mockito.times(1)).createActivityExtract(activityTypeIds, Date.from(startDate2.toInstant()), Date.from(startDate.plusDays(task.getFetchDays()).toInstant()));
125
+ ConfigDiff configDiff = activityBulkExtractInputPlugin.buildConfigDiff(task, Mockito.mock(Schema.class), 1, Arrays.asList(taskReport));
126
+ DateFormat df = new SimpleDateFormat(MarketoUtils.MARKETO_DATE_SIMPLE_DATE_FORMAT);
127
+ Assert.assertEquals(df.format(Date.from(startDate.plusDays(task.getFetchDays()).toInstant())), configDiff.get(String.class, "from_date"));
128
+ }
129
+ }