embulk-input-marketo 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +3 -0
- data/CHANGELOG.md +5 -0
- data/embulk-input-marketo.gemspec +1 -1
- data/gemfiles/embulk-0.6.26 +4 -0
- data/lib/embulk/input/marketo/activity_log.rb +5 -1
- data/lib/embulk/input/marketo/base.rb +0 -8
- data/lib/embulk/input/marketo/lead.rb +30 -18
- data/lib/embulk/input/marketo/timeslice.rb +59 -2
- data/lib/embulk/input/marketo_api/soap/base.rb +3 -4
- data/lib/embulk/input/marketo_api/soap/lead.rb +20 -20
- data/test/embulk/input/marketo/test_activity_log.rb +20 -0
- data/test/embulk/input/marketo/test_lead.rb +189 -4
- data/test/embulk/input/marketo_api/soap/test_lead.rb +12 -49
- data/test/run-test.rb +3 -0
- metadata +3 -3
- data/lib/embulk/input/marketo_api/soap/timeslice.rb +0 -44
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5485d5527116194e9cf43129e39a686675038d35
|
4
|
+
data.tar.gz: 932cd341055835466e2022c950babd2c0f7966ae
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 31b2aa93cbb0e301b1a71fbf15c0b53f0841558aaeafb8e5d38ce884fd6cd9d34c34bc7d44678d57421e47f10739748b9815e523dffd956a6c9c76d7ebe50e41
|
7
|
+
data.tar.gz: b25b1163d52542cf8f284396f36e428fb55a35f1f4418784b93885cc678cc2fd320d53c98ea6648b8ace4dab920e431e447a60747295cf18e238dbcc2a2a2c76
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
## 0.2.3 - 2015-09-14
|
2
|
+
|
3
|
+
* [enhancement] Catch config error [#33](https://github.com/treasure-data/embulk-input-marketo/pull/33)
|
4
|
+
* [enhancement] Concurrent worker [#31](https://github.com/treasure-data/embulk-input-marketo/pull/31)
|
5
|
+
|
1
6
|
## 0.2.2 - 2015-09-08
|
2
7
|
|
3
8
|
* [fixed] Fix handling for activity_date_time [#32](https://github.com/treasure-data/embulk-input-marketo/pull/32)
|
@@ -41,36 +41,48 @@ module Embulk
|
|
41
41
|
columns
|
42
42
|
end
|
43
43
|
|
44
|
+
def init
|
45
|
+
@last_updated_at = task[:last_updated_at]
|
46
|
+
@columns = task[:columns]
|
47
|
+
@ranges = task[:ranges][index]
|
48
|
+
@soap = MarketoApi.soap_client(task, target)
|
49
|
+
end
|
50
|
+
|
44
51
|
def run
|
45
|
-
count = 0
|
46
52
|
from_datetime = task[:from_datetime]
|
47
|
-
to_datetime = task[:to_datetime]
|
53
|
+
to_datetime = task[:to_datetime] || Time.now
|
54
|
+
|
48
55
|
options = {}
|
49
56
|
options[:batch_size] = PREVIEW_COUNT if preview?
|
50
57
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
58
|
+
@ranges.each do |range|
|
59
|
+
soap.each(range, options) do |lead|
|
60
|
+
values = @columns.map do |column|
|
61
|
+
name = column["name"].to_s
|
62
|
+
value = (lead[name] || {})[:value]
|
63
|
+
next unless value
|
56
64
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
65
|
+
case column["type"]
|
66
|
+
when "timestamp"
|
67
|
+
begin
|
68
|
+
Time.parse(value)
|
69
|
+
rescue => e
|
70
|
+
raise ConfigError, "Can't parse as Time '#{value}' (column is #{column["name"]})"
|
71
|
+
end
|
72
|
+
else
|
73
|
+
value
|
74
|
+
end
|
62
75
|
end
|
63
|
-
end
|
64
|
-
|
65
|
-
page_builder.add(values)
|
66
76
|
|
67
|
-
|
68
|
-
|
77
|
+
page_builder.add(values)
|
78
|
+
end
|
69
79
|
end
|
70
80
|
|
71
81
|
page_builder.finish
|
72
82
|
|
73
|
-
commit_report = {
|
83
|
+
commit_report = {
|
84
|
+
from_datetime: to_datetime
|
85
|
+
}
|
74
86
|
return commit_report
|
75
87
|
end
|
76
88
|
end
|
@@ -2,6 +2,8 @@ module Embulk
|
|
2
2
|
module Input
|
3
3
|
module Marketo
|
4
4
|
module Timeslice
|
5
|
+
TIMESLICE_COUNT_PER_TASK = 24
|
6
|
+
|
5
7
|
def self.included(klass)
|
6
8
|
klass.extend ClassMethods
|
7
9
|
end
|
@@ -28,10 +30,20 @@ module Embulk
|
|
28
30
|
from_datetime = config.param(:from_datetime, :string)
|
29
31
|
to_datetime = config.param(:to_datetime, :string, default: Time.now.to_s)
|
30
32
|
|
33
|
+
# check from/to format to parse
|
34
|
+
begin
|
35
|
+
Time.parse(from_datetime)
|
36
|
+
Time.parse(to_datetime)
|
37
|
+
rescue => e
|
38
|
+
# possibly Time.parse fail
|
39
|
+
raise ConfigError, e.message
|
40
|
+
end
|
41
|
+
|
31
42
|
if Time.parse(from_datetime) > Time.parse(to_datetime)
|
32
43
|
raise ConfigError, "config: from_datetime '#{from_datetime}' is later than '#{to_datetime}'."
|
33
44
|
end
|
34
45
|
|
46
|
+
ranges = timeslice(from_datetime, to_datetime, TIMESLICE_COUNT_PER_TASK)
|
35
47
|
task = {
|
36
48
|
endpoint_url: endpoint_url,
|
37
49
|
wsdl_url: config.param(:wsdl, :string, default: "#{endpoint_url}?WSDL"),
|
@@ -39,6 +51,7 @@ module Embulk
|
|
39
51
|
encryption_key: config.param(:encryption_key, :string),
|
40
52
|
from_datetime: from_datetime,
|
41
53
|
to_datetime: to_datetime,
|
54
|
+
ranges: ranges,
|
42
55
|
columns: config.param(:columns, :array)
|
43
56
|
}
|
44
57
|
|
@@ -51,9 +64,53 @@ module Embulk
|
|
51
64
|
columns << Column.new(nil, name, type, column["format"])
|
52
65
|
end
|
53
66
|
|
54
|
-
|
55
|
-
resume(task, columns, 1, &control)
|
67
|
+
resume(task, columns, ranges.size, &control)
|
56
68
|
end
|
69
|
+
|
70
|
+
def timeslice(from, to, count)
|
71
|
+
generate_time_range(from, to).each_slice(count).to_a
|
72
|
+
end
|
73
|
+
|
74
|
+
def generate_time_range(from, to)
|
75
|
+
# e.g. from = 2010-01-01 15:00, to = 2010-01-03 09:30
|
76
|
+
# convert to such array:
|
77
|
+
# [
|
78
|
+
# {from: 2010-01-01 15:00, to: 2010-01-01 16:00},
|
79
|
+
# {from: 2010-01-01 16:00, to: 2010-01-01 17:00},
|
80
|
+
# ...
|
81
|
+
# {from: 2010-01-03 08:00, to: 2010-01-03 09:00},
|
82
|
+
# {from: 2010-01-03 09:00, to: 2010-01-03 09:30},
|
83
|
+
# ]
|
84
|
+
# to fetch data from Marketo API with each day as
|
85
|
+
# desribed on official blog:
|
86
|
+
# http://developers.marketo.com/blog/performance-tuning-api-requests/
|
87
|
+
to ||= Time.now
|
88
|
+
from = Time.parse(from) unless from.is_a?(Time)
|
89
|
+
to = Time.parse(to) unless to.is_a?(Time)
|
90
|
+
|
91
|
+
result = []
|
92
|
+
since = from
|
93
|
+
while since < to
|
94
|
+
next_since = since + 3600
|
95
|
+
if to < next_since
|
96
|
+
next_since = to
|
97
|
+
end
|
98
|
+
result << {
|
99
|
+
"from" => since,
|
100
|
+
"to" => next_since
|
101
|
+
}
|
102
|
+
since = next_since
|
103
|
+
end
|
104
|
+
result
|
105
|
+
end
|
106
|
+
|
107
|
+
def resume(task, columns, count, &control)
|
108
|
+
commit_reports = yield(task, columns, count)
|
109
|
+
|
110
|
+
# all task returns same report as {from_datetime: to_datetime}
|
111
|
+
return commit_reports.first
|
112
|
+
end
|
113
|
+
|
57
114
|
end
|
58
115
|
end
|
59
116
|
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require "savon"
|
2
|
-
require "embulk/input/marketo_api/soap/timeslice"
|
3
2
|
|
4
3
|
module Embulk
|
5
4
|
module Input
|
@@ -80,10 +79,10 @@ module Embulk
|
|
80
79
|
# unretryable error such as Authentication Failed, Invalid Request, etc.
|
81
80
|
raise ConfigError, soap_message
|
82
81
|
end
|
83
|
-
rescue SocketError => e
|
82
|
+
rescue SocketError, Errno::ECONNREFUSED => e
|
84
83
|
# maybe endpoint/wsdl domain was wrong
|
85
|
-
Embulk.logger.debug "
|
86
|
-
raise ConfigError, "
|
84
|
+
Embulk.logger.debug "Connection error: endpoint=#{endpoint} wsdl=#{wsdl}"
|
85
|
+
raise ConfigError, "Connection error: #{e.message} (endpoint is '#{endpoint}')"
|
87
86
|
end
|
88
87
|
end
|
89
88
|
end
|
@@ -5,8 +5,6 @@ module Embulk
|
|
5
5
|
module MarketoApi
|
6
6
|
module Soap
|
7
7
|
class Lead < Base
|
8
|
-
include Timeslice
|
9
|
-
|
10
8
|
# NOTE: batch_size is allowed at 1000, but that takes 2 minutes in 1 request.
|
11
9
|
# We use 250 for the default (about 30 seconds)
|
12
10
|
BATCH_SIZE_DEFAULT = 250
|
@@ -17,28 +15,30 @@ module Embulk
|
|
17
15
|
response.body[:success_describe_m_object][:result][:metadata][:field_list][:field]
|
18
16
|
end
|
19
17
|
|
20
|
-
def each(
|
18
|
+
def each(range, options = {}, &block)
|
21
19
|
# http://developers.marketo.com/documentation/soap/getmultipleleads/
|
22
|
-
|
20
|
+
from = range["from"]
|
21
|
+
to = range["to"]
|
23
22
|
|
24
|
-
|
25
|
-
|
26
|
-
lead_selector: {
|
27
|
-
oldest_updated_at: range[:from].iso8601,
|
28
|
-
latest_updated_at: range[:to].iso8601,
|
29
|
-
},
|
30
|
-
attributes!: {
|
31
|
-
lead_selector: {"xsi:type" => "ns1:LastUpdateAtSelector"}
|
32
|
-
},
|
33
|
-
batch_size: options[:batch_size] || BATCH_SIZE_DEFAULT,
|
34
|
-
}
|
35
|
-
Embulk.logger.info "Fetching from '#{range[:from]}' to '#{range[:to]}'..."
|
23
|
+
from = Time.parse(from) unless from.is_a?(Time)
|
24
|
+
to = Time.parse(to) unless to.is_a?(Time)
|
36
25
|
|
37
|
-
|
26
|
+
request = {
|
27
|
+
lead_selector: {
|
28
|
+
oldest_updated_at: from.iso8601,
|
29
|
+
latest_updated_at: to.iso8601,
|
30
|
+
},
|
31
|
+
attributes!: {
|
32
|
+
lead_selector: {"xsi:type" => "ns1:LastUpdateAtSelector"}
|
33
|
+
},
|
34
|
+
batch_size: options[:batch_size] || BATCH_SIZE_DEFAULT,
|
35
|
+
}
|
36
|
+
Embulk.logger.info "Fetching from '#{from}' to '#{to}'..."
|
38
37
|
|
39
|
-
|
40
|
-
|
41
|
-
|
38
|
+
stream_position = fetch(request, &block)
|
39
|
+
|
40
|
+
while stream_position
|
41
|
+
stream_position = fetch(request.merge(stream_position: stream_position), &block)
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
@@ -141,6 +141,26 @@ module Embulk
|
|
141
141
|
@plugin.run
|
142
142
|
end
|
143
143
|
|
144
|
+
def test_wrong_type
|
145
|
+
any_instance_of(Savon::Client) do |klass|
|
146
|
+
stub(klass).call(:get_lead_changes, message: request) do
|
147
|
+
next_stream_activity_logs_response
|
148
|
+
end
|
149
|
+
end
|
150
|
+
stub(@page_builder).add {}
|
151
|
+
stub(@page_builder).finish {}
|
152
|
+
|
153
|
+
task = task()
|
154
|
+
task[:columns] = [
|
155
|
+
{"name" => "Old Value", "type" => :timestamp}
|
156
|
+
]
|
157
|
+
@plugin = ActivityLog.new(task, nil, nil, @page_builder)
|
158
|
+
|
159
|
+
assert_raise(Embulk::ConfigError) do
|
160
|
+
@plugin.run
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
144
164
|
private
|
145
165
|
|
146
166
|
def request
|
@@ -22,6 +22,9 @@ module Embulk
|
|
22
22
|
|
23
23
|
def setup_plugin
|
24
24
|
@page_builder = Object.new
|
25
|
+
any_instance_of(Embulk::Input::Marketo::Lead) do |klass|
|
26
|
+
stub(klass).index { 0 }
|
27
|
+
end
|
25
28
|
@plugin = Lead.new(task, nil, nil, @page_builder)
|
26
29
|
mute_logger
|
27
30
|
end
|
@@ -47,6 +50,49 @@ module Embulk
|
|
47
50
|
end
|
48
51
|
end
|
49
52
|
|
53
|
+
def test_invalid_datetime_given
|
54
|
+
control = proc {} # dummy
|
55
|
+
|
56
|
+
settings = {
|
57
|
+
endpoint: "https://marketo.example.com",
|
58
|
+
wsdl: "https://marketo.example.com/?wsdl",
|
59
|
+
user_id: "user_id",
|
60
|
+
encryption_key: "TOPSECRET",
|
61
|
+
from_datetime: "invalid time from",
|
62
|
+
to_datetime: "invalid time to",
|
63
|
+
columns: [
|
64
|
+
{"name" => "Name", "type" => "string"},
|
65
|
+
]
|
66
|
+
}
|
67
|
+
config = DataSource[settings.to_a]
|
68
|
+
|
69
|
+
assert_raise(ConfigError) do
|
70
|
+
Lead.transaction(config, &control)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_wrong_type
|
75
|
+
control = proc {} # dummy
|
76
|
+
|
77
|
+
settings = {
|
78
|
+
endpoint: "https://marketo.example.com",
|
79
|
+
wsdl: "https://marketo.example.com/?wsdl",
|
80
|
+
user_id: "user_id",
|
81
|
+
encryption_key: "TOPSECRET",
|
82
|
+
from_datetime: "invalid time from",
|
83
|
+
to_datetime: "invalid time to",
|
84
|
+
columns: [
|
85
|
+
{"name" => "Name", "type" => "timestamp"},
|
86
|
+
]
|
87
|
+
}
|
88
|
+
|
89
|
+
config = DataSource[settings.to_a]
|
90
|
+
|
91
|
+
assert_raise(ConfigError) do
|
92
|
+
Lead.transaction(config, &control)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
50
96
|
class RunTest < self
|
51
97
|
def setup
|
52
98
|
setup_soap
|
@@ -159,13 +205,84 @@ module Embulk
|
|
159
205
|
end
|
160
206
|
end
|
161
207
|
|
208
|
+
class TestTimeslice < self
|
209
|
+
class TestGenerateTimeRange < self
|
210
|
+
def setup
|
211
|
+
super
|
212
|
+
mute_logger
|
213
|
+
end
|
214
|
+
|
215
|
+
data do
|
216
|
+
{
|
217
|
+
"8/1 to 8/2" => ["2015-08-01 00:00:00", "2015-08-02 00:00:00", 24],
|
218
|
+
"over the days" => ["2015-08-01 19:00:00", "2015-08-03 05:00:00", 34],
|
219
|
+
"odd times" => ["2015-08-01 11:11:11", "2015-08-01 22:22:22", 12],
|
220
|
+
}
|
221
|
+
end
|
222
|
+
def test_generate_time_range_by_1hour(data)
|
223
|
+
from, to, count = data
|
224
|
+
range = Lead.generate_time_range(from, to)
|
225
|
+
assert_equal count, range.length
|
226
|
+
end
|
227
|
+
|
228
|
+
def test_if_to_is_nil_use_time_now
|
229
|
+
from = "2000-01-01"
|
230
|
+
now = Time.now
|
231
|
+
stub(Time).now { now }
|
232
|
+
|
233
|
+
range = Lead.generate_time_range(from, nil)
|
234
|
+
assert_equal now, range.last["to"]
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
def test_timeslice
|
239
|
+
from = "2015-08-02 20:00:00"
|
240
|
+
to = "2015-08-03 08:08:08"
|
241
|
+
count = 4
|
242
|
+
|
243
|
+
raw_expect = [
|
244
|
+
[
|
245
|
+
{from: "2015-08-02 20:00:00", to: "2015-08-02 21:00:00"},
|
246
|
+
{from: "2015-08-02 21:00:00", to: "2015-08-02 22:00:00"},
|
247
|
+
{from: "2015-08-02 22:00:00", to: "2015-08-02 23:00:00"},
|
248
|
+
{from: "2015-08-02 23:00:00", to: "2015-08-03 00:00:00"},
|
249
|
+
],
|
250
|
+
[
|
251
|
+
{from: "2015-08-03 00:00:00", to: "2015-08-03 01:00:00"},
|
252
|
+
{from: "2015-08-03 01:00:00", to: "2015-08-03 02:00:00"},
|
253
|
+
{from: "2015-08-03 02:00:00", to: "2015-08-03 03:00:00"},
|
254
|
+
{from: "2015-08-03 03:00:00", to: "2015-08-03 04:00:00"},
|
255
|
+
],
|
256
|
+
[
|
257
|
+
{from: "2015-08-03 04:00:00", to: "2015-08-03 05:00:00"},
|
258
|
+
{from: "2015-08-03 05:00:00", to: "2015-08-03 06:00:00"},
|
259
|
+
{from: "2015-08-03 06:00:00", to: "2015-08-03 07:00:00"},
|
260
|
+
{from: "2015-08-03 07:00:00", to: "2015-08-03 08:00:00"},
|
261
|
+
],
|
262
|
+
[
|
263
|
+
{from: "2015-08-03 08:00:00", to: "2015-08-03 08:08:08"},
|
264
|
+
]
|
265
|
+
]
|
266
|
+
|
267
|
+
expect = raw_expect.map do |slice|
|
268
|
+
slice.map do |range|
|
269
|
+
{
|
270
|
+
"from" => Time.parse(range[:from]),
|
271
|
+
"to" => Time.parse(range[:to])
|
272
|
+
}
|
273
|
+
end
|
274
|
+
end
|
275
|
+
assert_equal(expect, Lead.timeslice(from, to, count))
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
162
279
|
private
|
163
280
|
|
164
281
|
def request
|
165
282
|
{
|
166
283
|
lead_selector: {
|
167
|
-
oldest_updated_at: timerange.first[
|
168
|
-
latest_updated_at: timerange.first[
|
284
|
+
oldest_updated_at: timerange.first["from"].iso8601,
|
285
|
+
latest_updated_at: timerange.first["to"].iso8601,
|
169
286
|
},
|
170
287
|
attributes!: {lead_selector: {"xsi:type"=>"ns1:LastUpdateAtSelector"}},
|
171
288
|
batch_size: MarketoApi::Soap::Lead::BATCH_SIZE_DEFAULT,
|
@@ -225,8 +342,7 @@ module Embulk
|
|
225
342
|
end
|
226
343
|
|
227
344
|
def timerange
|
228
|
-
|
229
|
-
soap.send(:generate_time_range, from_datetime, to_datetime)
|
345
|
+
Lead.generate_time_range(from_datetime, to_datetime)
|
230
346
|
end
|
231
347
|
|
232
348
|
def task
|
@@ -237,6 +353,7 @@ module Embulk
|
|
237
353
|
encryption_key: "TOPSECRET",
|
238
354
|
from_datetime: from_datetime,
|
239
355
|
to_datetime: to_datetime,
|
356
|
+
ranges: Lead.timeslice(from_datetime, to_datetime, Lead::TIMESLICE_COUNT_PER_TASK),
|
240
357
|
columns: [
|
241
358
|
{"name" => "Name", "type" => "string"},
|
242
359
|
]
|
@@ -260,6 +377,70 @@ module Embulk
|
|
260
377
|
is_dynamic: true,
|
261
378
|
dynamic_field_ref: "leadAttributeList",
|
262
379
|
updated_at: DateTime.parse("2000-01-01 22:22:22")
|
380
|
+
},
|
381
|
+
{
|
382
|
+
name: "FieldInt",
|
383
|
+
description: nil,
|
384
|
+
display_name: "The Name of Field",
|
385
|
+
source_object: "Lead",
|
386
|
+
data_type: "integer",
|
387
|
+
size: nil,
|
388
|
+
is_readonly: false,
|
389
|
+
is_update_blocked: false,
|
390
|
+
is_name: nil,
|
391
|
+
is_primary_key: false,
|
392
|
+
is_custom: true,
|
393
|
+
is_dynamic: true,
|
394
|
+
dynamic_field_ref: "leadAttributeList",
|
395
|
+
updated_at: DateTime.parse("2000-01-01 22:22:22")
|
396
|
+
},
|
397
|
+
{
|
398
|
+
name: "FieldBoolean",
|
399
|
+
description: nil,
|
400
|
+
display_name: "The Name of Field",
|
401
|
+
source_object: "Lead",
|
402
|
+
data_type: "boolean",
|
403
|
+
size: nil,
|
404
|
+
is_readonly: false,
|
405
|
+
is_update_blocked: false,
|
406
|
+
is_name: nil,
|
407
|
+
is_primary_key: false,
|
408
|
+
is_custom: true,
|
409
|
+
is_dynamic: true,
|
410
|
+
dynamic_field_ref: "leadAttributeList",
|
411
|
+
updated_at: DateTime.parse("2000-01-01 22:22:22")
|
412
|
+
},
|
413
|
+
{
|
414
|
+
name: "FieldFloat",
|
415
|
+
description: nil,
|
416
|
+
display_name: "The Name of Field",
|
417
|
+
source_object: "Lead",
|
418
|
+
data_type: "float",
|
419
|
+
size: nil,
|
420
|
+
is_readonly: false,
|
421
|
+
is_update_blocked: false,
|
422
|
+
is_name: nil,
|
423
|
+
is_primary_key: false,
|
424
|
+
is_custom: true,
|
425
|
+
is_dynamic: true,
|
426
|
+
dynamic_field_ref: "leadAttributeList",
|
427
|
+
updated_at: DateTime.parse("2000-01-01 22:22:22")
|
428
|
+
},
|
429
|
+
{
|
430
|
+
name: "FieldString",
|
431
|
+
description: nil,
|
432
|
+
display_name: "The Name of Field",
|
433
|
+
source_object: "Lead",
|
434
|
+
data_type: "string",
|
435
|
+
size: nil,
|
436
|
+
is_readonly: false,
|
437
|
+
is_update_blocked: false,
|
438
|
+
is_name: nil,
|
439
|
+
is_primary_key: false,
|
440
|
+
is_custom: true,
|
441
|
+
is_dynamic: true,
|
442
|
+
dynamic_field_ref: "leadAttributeList",
|
443
|
+
updated_at: DateTime.parse("2000-01-01 22:22:22")
|
263
444
|
}
|
264
445
|
]
|
265
446
|
end
|
@@ -269,6 +450,10 @@ module Embulk
|
|
269
450
|
{name: "id", type: "long"},
|
270
451
|
{name: "email", type: "string"},
|
271
452
|
{name: "FieldName", type: "timestamp"},
|
453
|
+
{name: "FieldInt", type: "long"},
|
454
|
+
{name: "FieldBoolean", type: "boolean"},
|
455
|
+
{name: "FieldFloat", type: "double"},
|
456
|
+
{name: "FieldString", type: "string"},
|
272
457
|
]
|
273
458
|
end
|
274
459
|
end
|
@@ -19,40 +19,31 @@ module Embulk
|
|
19
19
|
super
|
20
20
|
end
|
21
21
|
|
22
|
-
def test_each_invoke_fetch
|
23
|
-
from_datetime = "2015-07-06"
|
24
|
-
to_datetime = "2015-07-07"
|
25
|
-
timerange = soap.send(:generate_time_range, from_datetime, to_datetime)
|
26
|
-
|
27
|
-
stub(soap).fetch { nil }
|
28
|
-
mock(soap).fetch(anything).times(timerange.length)
|
29
|
-
|
30
|
-
soap.each(from_datetime, to_datetime) { }
|
31
|
-
end
|
32
|
-
|
33
22
|
def test_each_invoke_fetch_with_specified_time
|
34
|
-
|
35
|
-
|
36
|
-
|
23
|
+
timerange = {
|
24
|
+
"from" => Time.parse("2015-07-06 00:00:00"),
|
25
|
+
"to" => Time.parse("2015-07-06 12:00:00"),
|
26
|
+
}
|
37
27
|
|
38
28
|
request = {
|
39
29
|
lead_selector: {
|
40
|
-
oldest_updated_at: timerange
|
41
|
-
latest_updated_at: timerange
|
30
|
+
oldest_updated_at: timerange["from"].iso8601,
|
31
|
+
latest_updated_at: timerange["to"].iso8601,
|
42
32
|
},
|
43
33
|
attributes!: {lead_selector: {"xsi:type"=>"ns1:LastUpdateAtSelector"}},
|
44
34
|
batch_size: Lead::BATCH_SIZE_DEFAULT,
|
45
35
|
}
|
46
36
|
|
47
|
-
stub(soap).fetch { nil }
|
48
37
|
mock(soap).fetch(request)
|
49
38
|
|
50
|
-
soap.each(
|
39
|
+
soap.each(timerange) { }
|
51
40
|
end
|
52
41
|
|
53
42
|
def test_each_fetch_next_page
|
54
|
-
|
55
|
-
|
43
|
+
timerange = {
|
44
|
+
"from" => Time.parse("2015-07-06 23:30:00"),
|
45
|
+
"to" => Time.parse("2015-07-07 00:00:00"),
|
46
|
+
}
|
56
47
|
|
57
48
|
any_instance_of(Savon::Client) do |klass|
|
58
49
|
mock(klass).call(:get_multiple_leads, anything) do
|
@@ -64,35 +55,7 @@ module Embulk
|
|
64
55
|
leads_count = next_stream_leads_response.xpath('//leadRecord').length
|
65
56
|
mock(proc).call(anything).times(leads_count)
|
66
57
|
|
67
|
-
soap.each(
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
class TestGenerateTime < self
|
72
|
-
def setup
|
73
|
-
mute_logger
|
74
|
-
end
|
75
|
-
|
76
|
-
data do
|
77
|
-
{
|
78
|
-
"8/1 to 8/2" => ["2015-08-01 00:00:00", "2015-08-02 00:00:00", 24],
|
79
|
-
"over the days" => ["2015-08-01 19:00:00", "2015-08-03 05:00:00", 34],
|
80
|
-
"odd times" => ["2015-08-01 11:11:11", "2015-08-01 22:22:22", 12],
|
81
|
-
}
|
82
|
-
end
|
83
|
-
def test_generate_time_range_by_1hour(data)
|
84
|
-
from, to, count = data
|
85
|
-
range = soap.send(:generate_time_range, from, to)
|
86
|
-
assert_equal count, range.length
|
87
|
-
end
|
88
|
-
|
89
|
-
def test_if_to_is_nil_use_time_now
|
90
|
-
from = "2000-01-01"
|
91
|
-
now = Time.now
|
92
|
-
stub(Time).now { now }
|
93
|
-
|
94
|
-
range = soap.send(:generate_time_range, from, nil)
|
95
|
-
assert_equal now, range.last[:to]
|
58
|
+
soap.each(timerange, {}, &proc)
|
96
59
|
end
|
97
60
|
end
|
98
61
|
|
data/test/run-test.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: embulk-input-marketo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- uu59
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-09-
|
12
|
+
date: 2015-09-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -170,6 +170,7 @@ files:
|
|
170
170
|
- gemfiles/embulk-0.6.23
|
171
171
|
- gemfiles/embulk-0.6.24
|
172
172
|
- gemfiles/embulk-0.6.25
|
173
|
+
- gemfiles/embulk-0.6.26
|
173
174
|
- gemfiles/embulk-latest
|
174
175
|
- gemfiles/template.erb
|
175
176
|
- lib/embulk/input/marketo/activity_log.rb
|
@@ -180,7 +181,6 @@ files:
|
|
180
181
|
- lib/embulk/input/marketo_api/soap/activity_log.rb
|
181
182
|
- lib/embulk/input/marketo_api/soap/base.rb
|
182
183
|
- lib/embulk/input/marketo_api/soap/lead.rb
|
183
|
-
- lib/embulk/input/marketo_api/soap/timeslice.rb
|
184
184
|
- test/activity_log_fixtures.rb
|
185
185
|
- test/embulk/input/marketo/test_activity_log.rb
|
186
186
|
- test/embulk/input/marketo/test_base.rb
|
@@ -1,44 +0,0 @@
|
|
1
|
-
module Embulk
|
2
|
-
module Input
|
3
|
-
module MarketoApi
|
4
|
-
module Soap
|
5
|
-
module Timeslice
|
6
|
-
private
|
7
|
-
|
8
|
-
def generate_time_range(from, to)
|
9
|
-
# e.g. from = 2010-01-01 15:00, to = 2010-01-03 09:30
|
10
|
-
# convert to such array:
|
11
|
-
# [
|
12
|
-
# {from: 2010-01-01 15:00, to: 2010-01-01 16:00},
|
13
|
-
# {from: 2010-01-01 16:00, to: 2010-01-01 17:00},
|
14
|
-
# ...
|
15
|
-
# {from: 2010-01-03 08:00, to: 2010-01-03 09:00},
|
16
|
-
# {from: 2010-01-03 09:00, to: 2010-01-03 09:30},
|
17
|
-
# ]
|
18
|
-
# to fetch data from Marketo API with each day as
|
19
|
-
# desribed on official blog:
|
20
|
-
# http://developers.marketo.com/blog/performance-tuning-api-requests/
|
21
|
-
to ||= Time.now
|
22
|
-
from = Time.parse(from) unless from.is_a?(Time)
|
23
|
-
to = Time.parse(to) unless to.is_a?(Time)
|
24
|
-
|
25
|
-
result = []
|
26
|
-
since = from
|
27
|
-
while since < to
|
28
|
-
next_since = since + 3600
|
29
|
-
if to < next_since
|
30
|
-
next_since = to
|
31
|
-
end
|
32
|
-
result << {
|
33
|
-
from: since,
|
34
|
-
to: next_since
|
35
|
-
}
|
36
|
-
since = next_since
|
37
|
-
end
|
38
|
-
result
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|