embulk-input-mixpanel 0.2.0 → 0.2.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5fca90578e059bd058fa52d1d8283afbd85a58a1
4
- data.tar.gz: 09305de32323e4284f33a005330d522f2afc98e7
3
+ metadata.gz: 9a688fb2eb175f13ee5c82b8ea2da6c74ed69839
4
+ data.tar.gz: af0fdae8cc6fba0911ab269d7d8f354d51803f25
5
5
  SHA512:
6
- metadata.gz: 8a200ccc100c2baa7552e933846648253bace0b944a7cefa8bfcc87198ab0e5dfe2a8a754a3195ac2aeca096114a92defc74c3d7e35176a2d8475bcac830cf83
7
- data.tar.gz: 91c0591f7bf83a14dc5bdb7f56f2915c97ba8e3d3b81cac8f37ac411541c0ae5302bf2712c6f4e6347a542955c5278a085cab67925a8da6559ce0195dc12edaf
6
+ metadata.gz: 25381a19a9743a0b945d5d453931b1f93ab87009a79185b72eba32577a496550f1050b38ff8baa81c164d628a1c67714e785c27bf6833a04e69431bcad2e6ace
7
+ data.tar.gz: d69d65730c8c3a3d1ea1c85182e274ea8bde716662c132ee628e1c0be7d25e2b97c0a2c15dc0a7269b714677cf1635f04fcdd8a8237ec7353714d4f1ede05094
data/.travis.yml CHANGED
@@ -23,3 +23,4 @@ gemfile:
23
23
  matrix:
24
24
  allow_failures:
25
25
  - gemfile: gemfiles/embulk-0.6.22
26
+ - gemfile: gemfiles/embulk-latest # embulk 0.7.1
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## 0.2.1 - 2015-08-26
2
+
3
+ * [fixed] Fix guess with recently from date [#18](https://github.com/treasure-data/embulk-input-mixpanel/pull/18)
4
+ * [fixed] Fix error handling when invalid date set given [#17](https://github.com/treasure-data/embulk-input-mixpanel/pull/17)
5
+
1
6
  ## 0.2.0 - 2015-08-17
2
7
 
3
8
  * [enhanement] Raise config error for unretryable [#15](https://github.com/treasure-data/embulk-input-mixpanel/pull/15) [[Reported by @muga](https://github.com/treasure-data/embulk-input-mixpanel/issues/11). Thanks!!]
data/README.md CHANGED
@@ -35,7 +35,9 @@ To get it, you should log in mixpanel website, and click gear icon at the lower
35
35
  - **api_secret**: project API Secret (string, required)
36
36
  - **timezone**: project timezone(string, required)
37
37
  - **from_date**: From date to export (string, optional, default: today - 2)
38
- - **days**: Count of days range for exporting (integer, optional, default: (today - 1) - from_date)
38
+ - NOTE: Mixpanel API supports to export data from at least 2 days before to at most the previous day.
39
+ - **days**: Count of days range for exporting (integer, optional, default: from_date - (today - 1))
40
+ - NOTE: Mixpanel doesn't support to from_date > today - 2
39
41
  - **event**: The event or events to filter data (array, optional, default: nil)
40
42
  - **where**: Expression to filter data (c.f. https://mixpanel.com/docs/api-documentation/data-export-api#segmentation-expressions) (string, optional, default: nil)
41
43
  - **bucket**:The data backet to filter data (string, optional, default: nil)
@@ -1,7 +1,7 @@
1
1
 
2
2
  Gem::Specification.new do |spec|
3
3
  spec.name = "embulk-input-mixpanel"
4
- spec.version = "0.2.0"
4
+ spec.version = "0.2.1"
5
5
  spec.authors = ["yoshihara", "uu59"]
6
6
  spec.summary = "Mixpanel input plugin for Embulk"
7
7
  spec.description = "Loads records from Mixpanel."
@@ -18,8 +18,40 @@ module Embulk
18
18
 
19
19
  task[:params] = export_params(config)
20
20
 
21
- dates = generate_dates(config)
22
- task[:dates] = dates.map {|date| date.to_s}
21
+ begin
22
+ from_date_str = config.param(:from_date, :string, default: (Date.today - 2).to_s)
23
+ from_date = Date.parse(from_date_str)
24
+ rescue ArgumentError # invalid date
25
+ raise ConfigError, "from_date '#{from_date_str}' is invalid date"
26
+ end
27
+
28
+ if from_date > Date.today - 1
29
+ Embulk.logger.warn "Mixpanel allow 2 days before to from_date, so no data is input."
30
+ target_dates = []
31
+ else
32
+ days = config.param(:days, :integer, default: nil)
33
+
34
+ if days.nil?
35
+ # When no 'days' is specified in config file, so dates is
36
+ # generated by from_date and yeasterday.
37
+ dates = from_date..(Date.today - 1)
38
+ elsif days < 1
39
+ raise ConfigError, "days '#{days}' is invalid. Please specify bigger number than 0."
40
+ else
41
+ # When 'days' is specified in config file and it is satisfied,
42
+ # so it is used for dates.
43
+ dates = from_date..(from_date + days)
44
+ end
45
+
46
+ target_dates = dates.find_all {|date| date < Date.today}
47
+
48
+ overtimes = dates.to_a - target_dates
49
+ unless overtimes.empty?
50
+ Embulk.logger.warn "These dates are too early access, ignored them: #{overtimes.map(&:to_s).join(', ')}"
51
+ end
52
+ end
53
+
54
+ task[:dates] = target_dates.map {|date| date.to_s}
23
55
 
24
56
  task[:api_key] = config.param(:api_key, :string)
25
57
  task[:api_secret] = config.param(:api_secret, :string)
@@ -60,14 +92,22 @@ module Embulk
60
92
  def self.guess(config)
61
93
  client = MixpanelApi::Client.new(config.param(:api_key, :string), config.param(:api_secret, :string))
62
94
 
63
- from_date = config.param(:from_date, :string)
64
- # NOTE: It should have 7 days beteen from_date and to_date
65
- to_date = (Date.parse(from_date) + SLICE_DAYS_COUNT - 1).to_s
95
+ from_date_str = config.param(:from_date, :string, default: (Date.today - 1 - SLICE_DAYS_COUNT).to_s)
96
+
97
+ from_date = Date.parse(from_date_str)
98
+
99
+ if from_date > Date.today - 1
100
+ raise ConfigError, "Please specify date later than yesterday (inclusive) as 'from_date'"
101
+ end
102
+
103
+ # NOTE: to_date is yeasterday if from_date..Date.Today doesn't have
104
+ # more SLICE_DAYS_COUNT days.
105
+ to_date = [from_date + SLICE_DAYS_COUNT, Date.today - 1].min
66
106
 
67
107
  params = export_params(config)
68
108
  params = params.merge(
69
- from_date: from_date,
70
- to_date: to_date,
109
+ from_date: from_date.to_s,
110
+ to_date: to_date.to_s,
71
111
  )
72
112
 
73
113
  records = client.export(params)
@@ -85,25 +125,6 @@ module Embulk
85
125
  return {"columns" => columns}
86
126
  end
87
127
 
88
- def self.generate_dates(config)
89
- default_from_date = (Date.today - 2).to_s
90
-
91
- begin
92
- from_date = Date.parse(config.param(:from_date, :string, default: default_from_date))
93
- rescue ArgumentError # invalid date
94
- raise ConfigError, "from_date '#{from_date}' is invalid date"
95
- end
96
-
97
- default_days = ((Date.today - 1) - from_date).to_i
98
- days = config.param(:days, :integer, default: default_days)
99
-
100
- if days < 1
101
- raise ConfigError, "days '#{days}' is invalid. Please spcify bigger number than 0."
102
- end
103
-
104
- from_date..(from_date + days)
105
- end
106
-
107
128
  def init
108
129
  @api_key = task[:api_key]
109
130
  @api_secret = task[:api_secret]
@@ -147,7 +168,7 @@ module Embulk
147
168
 
148
169
  page_builder.finish
149
170
 
150
- commit_report = {to_date: @dates.last}
171
+ commit_report = {to_date: @dates.last || (Date.today - 1)}
151
172
  return commit_report
152
173
  end
153
174
 
@@ -19,8 +19,13 @@ module Embulk
19
19
  # https://mixpanel.com/docs/api-documentation/exporting-raw-data-you-inserted-into-mixpanel
20
20
  params[:expire] ||= Time.now.to_i + TIMEOUT_SECONDS
21
21
  params[:sig] = signature(params)
22
+
23
+ Embulk.logger.debug "Export param: #{params.to_s}"
24
+
22
25
  response = httpclient.get(ENDPOINT_EXPORT, params)
23
26
 
27
+ Embulk.logger.debug "response code: #{response.code}"
28
+
24
29
  if (400..499).include?(response.code)
25
30
  raise ConfigError, response.body
26
31
  elsif response.code >= 500
@@ -9,6 +9,7 @@ module Embulk
9
9
 
10
10
  def setup
11
11
  @client = Client.new(API_KEY, API_SECRET)
12
+ stub(Embulk).logger { ::Logger.new(IO::NULL) }
12
13
  end
13
14
 
14
15
  # NOTE: Client#signature is private method but this value
@@ -36,6 +36,7 @@ module Embulk
36
36
  from_date = duration[:from_date]
37
37
  to_date = duration[:to_date]
38
38
 
39
+ params = params.merge(from_date: from_date, to_date: to_date)
39
40
  stub(klass).export(params) { records }
40
41
  end
41
42
  end
@@ -45,35 +46,126 @@ module Embulk
45
46
  stub(Embulk).logger { ::Logger.new(IO::NULL) }
46
47
  end
47
48
 
48
- def test_guess
49
- expected = {
50
- "columns" => [
51
- {name: "event", type: :string},
52
- {name: "foo", type: :string},
53
- {name: "time", type: :long},
54
- {name: "int", type: :long},
55
- ]
56
- }
49
+ class GuessTest < self
50
+ def test_from_date_old_date
51
+ config = {
52
+ type: "mixpanel",
53
+ api_key: API_KEY,
54
+ api_secret: API_SECRET,
55
+ from_date: FROM_DATE,
56
+ }
57
57
 
58
- actual = Mixpanel.guess(embulk_config)
59
- assert_equal(expected, actual)
58
+ from_date = config[:from_date]
59
+ to_date = Date.parse(from_date) + Mixpanel::SLICE_DAYS_COUNT
60
+ stub_export(from_date, to_date)
61
+
62
+ actual = Mixpanel.guess(embulk_config(config))
63
+ assert_equal(expected, actual)
64
+ end
65
+
66
+ def test_from_date_today
67
+ config = {
68
+ type: "mixpanel",
69
+ api_key: API_KEY,
70
+ api_secret: API_SECRET,
71
+ from_date: Date.today.to_s,
72
+ }
73
+
74
+ assert_raise(ConfigError) do
75
+ Mixpanel.guess(embulk_config(config))
76
+ end
77
+ end
78
+
79
+ def test_from_date_yesterday
80
+ config = {
81
+ type: "mixpanel",
82
+ api_key: API_KEY,
83
+ api_secret: API_SECRET,
84
+ from_date: (Date.today - 1).to_s,
85
+ }
86
+
87
+ from_date = config[:from_date]
88
+ to_date = from_date
89
+ stub_export(from_date, to_date)
90
+
91
+ actual = Mixpanel.guess(embulk_config(config))
92
+ assert_equal(expected, actual)
93
+ end
94
+
95
+ def test_no_from_date
96
+ config = {
97
+ type: "mixpanel",
98
+ api_key: API_KEY,
99
+ api_secret: API_SECRET,
100
+ }
101
+
102
+ from_date = Date.today - 1 - Mixpanel::SLICE_DAYS_COUNT
103
+ to_date = Date.today - 1
104
+ stub_export(from_date, to_date)
105
+
106
+ actual = Mixpanel.guess(embulk_config(config))
107
+ assert_equal(expected, actual)
108
+ end
109
+
110
+ private
111
+
112
+ def stub_export(from_date, to_date)
113
+ params = {
114
+ api_key: API_KEY,
115
+ event: nil,
116
+ where: nil,
117
+ bucket: nil,
118
+ from_date: from_date.to_s,
119
+ to_date: to_date.to_s,
120
+ }
121
+
122
+ any_instance_of(MixpanelApi::Client) do |klass|
123
+ stub(klass).export(params) { records }
124
+ end
125
+ end
126
+
127
+ def embulk_config(config)
128
+ DataSource[*config.to_a.flatten(1)]
129
+ end
130
+
131
+ def expected
132
+ {
133
+ "columns" => [
134
+ {name: "event", type: :string},
135
+ {name: "foo", type: :string},
136
+ {name: "time", type: :long},
137
+ {name: "int", type: :long},
138
+ ]
139
+ }
140
+ end
60
141
  end
61
142
 
62
- class GenerateDatesTest < self
143
+ class TransactionDateTest < self
63
144
  def test_valid_from_date
64
145
  from_date = "2015-08-14"
65
- parsed_date = Date.parse(from_date)
146
+ mock(Mixpanel).resume(anything, anything, 1)
66
147
 
67
- expected = (parsed_date..(parsed_date + DAYS))
68
- actual = Mixpanel.generate_dates(transaction_config(from_date))
69
- assert_equal(expected, actual)
148
+ Mixpanel.transaction(transaction_config(from_date))
70
149
  end
71
150
 
72
151
  def test_invalid_from_date
73
152
  from_date = "2015-08-41"
74
153
 
75
154
  assert_raise(Embulk::ConfigError) do
76
- Mixpanel.generate_dates(transaction_config(from_date))
155
+ Mixpanel.transaction(transaction_config(from_date))
156
+ end
157
+ end
158
+
159
+ def test_future
160
+ from_date = (Date.today + 10).to_s
161
+ mock(Mixpanel).resume(anything, anything, 1)
162
+
163
+ Mixpanel.transaction(transaction_config(from_date))
164
+ end
165
+
166
+ def test_negative_days
167
+ assert_raise(Embulk::ConfigError) do
168
+ Mixpanel.transaction(transaction_config((Date.today - 1).to_s).merge(days: -1))
77
169
  end
78
170
  end
79
171
 
@@ -91,6 +183,42 @@ module Embulk
91
183
 
92
184
  class TransactionTest < self
93
185
  class FromDateTest < self
186
+ def setup
187
+ end
188
+
189
+ def test_ignore_early_days
190
+ stub(Embulk).logger { Logger.new(File::NULL) }
191
+
192
+ mock(Mixpanel).resume(task.merge(dates: target_dates), columns, 1, &control)
193
+ Mixpanel.transaction(transaction_config, &control)
194
+ end
195
+
196
+ def test_warn
197
+ stub(Mixpanel).resume(task.merge(dates: target_dates), columns, 1, &control)
198
+ mock(Embulk.logger).warn(anything)
199
+
200
+ Mixpanel.transaction(transaction_config, &control)
201
+ end
202
+
203
+ private
204
+
205
+ def dates
206
+ (Date.today - 10)..(Date.today + 10)
207
+ end
208
+
209
+ def target_dates
210
+ dates.find_all{|d| d < Date.today}.map {|date| date.to_s}
211
+ end
212
+
213
+ def transaction_config
214
+ _config = config.merge(
215
+ from_date: dates.first.to_s,
216
+ days: dates.to_a.size,
217
+ timezone: TIMEZONE,
218
+ columns: schema
219
+ )
220
+ DataSource[*_config.to_a.flatten(1)]
221
+ end
94
222
  end
95
223
 
96
224
  class TimezoneTest < self
@@ -223,6 +351,13 @@ module Embulk
223
351
  end
224
352
 
225
353
  class RunTest < self
354
+ def setup_client
355
+
356
+ any_instance_of(MixpanelApi::Client) do |klass|
357
+ stub(klass).export(anything) { records }
358
+ end
359
+ end
360
+
226
361
  def setup
227
362
  super
228
363
 
@@ -286,7 +421,7 @@ module Embulk
286
421
  api_secret: API_SECRET,
287
422
  timezone: TIMEZONE,
288
423
  schema: schema,
289
- dates: DATES.to_a,
424
+ dates: DATES.to_a.map(&:to_s),
290
425
  params: Mixpanel.export_params(embulk_config),
291
426
  }
292
427
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: embulk-input-mixpanel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - yoshihara
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-08-17 00:00:00.000000000 Z
12
+ date: 2015-08-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  requirement: !ruby/object:Gem::Requirement