embulk-input-google_analytics 0.1.17 → 0.1.18.alpha
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 +4 -4
- data/embulk-input-google_analytics.gemspec +2 -1
- data/lib/embulk/input/google_analytics/client.rb +16 -4
- data/lib/embulk/input/google_analytics/plugin.rb +22 -3
- data/test/embulk/input/google_analytics/test_client.rb +58 -0
- data/test/embulk/input/google_analytics/test_plugin.rb +84 -0
- data/test/fixtures/valid_refresh_token.yml +18 -0
- metadata +20 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 840c722b01ba3cf337f7b5e405e8b6b07676810b
|
4
|
+
data.tar.gz: 9416098303f34773cf3df1329a8eaf84fe4594b2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 736e069eb795ba331c2125df44cb5cc48525f8bb4a44f43e62bb1b0b27c2b1affbd9e8e76fd76dfeeaeb8eaa64b5b9e91cde98254d4a3c90600fb30c7534ac64
|
7
|
+
data.tar.gz: 61a3515ba0cd0c28832d39d215b5619e3e62799164155c28ace126f773c8c4c08398e040b5424d38fb775fd08414d0af20833e8c6d5d4ab038ee5cf1373d459e
|
@@ -1,7 +1,7 @@
|
|
1
1
|
|
2
2
|
Gem::Specification.new do |spec|
|
3
3
|
spec.name = "embulk-input-google_analytics"
|
4
|
-
spec.version = "0.1.
|
4
|
+
spec.version = "0.1.18.alpha"
|
5
5
|
spec.authors = ["uu59"]
|
6
6
|
spec.summary = "Google Analytics input plugin for Embulk"
|
7
7
|
spec.description = "Loads records from Google Analytics."
|
@@ -27,5 +27,6 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.add_development_dependency 'simplecov'
|
28
28
|
spec.add_development_dependency "codeclimate-test-reporter"
|
29
29
|
spec.add_development_dependency "pry"
|
30
|
+
spec.add_development_dependency "pry-debugger-jruby"
|
30
31
|
spec.add_development_dependency "gem_release_helper", "~> 1.0"
|
31
32
|
end
|
@@ -208,10 +208,22 @@ module Embulk
|
|
208
208
|
|
209
209
|
def auth
|
210
210
|
retryer.with_retry do
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
211
|
+
case task['auth_method']
|
212
|
+
when Plugin::AUTH_TYPE_JSON_KEY
|
213
|
+
Google::Auth::ServiceAccountCredentials.make_creds(
|
214
|
+
json_key_io: StringIO.new(task["json_key_content"]),
|
215
|
+
scope: "https://www.googleapis.com/auth/analytics.readonly"
|
216
|
+
)
|
217
|
+
when Plugin::AUTH_TYPE_REFRESH_TOKEN
|
218
|
+
Google::Auth::UserRefreshCredentials.new(
|
219
|
+
'token_credential_uri': Google::Auth::UserRefreshCredentials::TOKEN_CRED_URI,
|
220
|
+
'client_id': task['client_id'],
|
221
|
+
'client_secret': task['client_secret'],
|
222
|
+
'refresh_token': task['refresh_token']
|
223
|
+
)
|
224
|
+
else
|
225
|
+
raise Embulk::ConfigError.new("Unknown Authentication method: '#{task['auth_method']}'.")
|
226
|
+
end
|
215
227
|
end
|
216
228
|
rescue Google::Apis::AuthorizationError => e
|
217
229
|
raise ConfigError.new(e.message)
|
@@ -3,6 +3,8 @@ module Embulk
|
|
3
3
|
module GoogleAnalytics
|
4
4
|
class Plugin < InputPlugin
|
5
5
|
::Embulk::Plugin.register_input("google_analytics", self)
|
6
|
+
AUTH_TYPE_JSON_KEY = 'json_key'.freeze
|
7
|
+
AUTH_TYPE_REFRESH_TOKEN = 'refresh_token'.freeze
|
6
8
|
|
7
9
|
# https://developers.google.com/analytics/devguides/reporting/core/dimsmets
|
8
10
|
|
@@ -11,6 +13,15 @@ module Embulk
|
|
11
13
|
unless %w(ga:date ga:dateHour).include?(task["time_series"])
|
12
14
|
raise ConfigError.new("Unknown time_series '#{task["time_series"]}'. Use 'ga:dateHour' or 'ga:date'")
|
13
15
|
end
|
16
|
+
|
17
|
+
raise ConfigError.new("Unknown Authentication method '#{task['auth_method']}'.") unless task['auth_method']
|
18
|
+
|
19
|
+
if task['auth_method'] == Plugin::AUTH_TYPE_REFRESH_TOKEN
|
20
|
+
unless task['client_id'] && task['client_secret'] && task['refresh_token']
|
21
|
+
raise ConfigError.new("client_id, client_secret and refresh_token are required when using Oauth authentication")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
14
25
|
columns_list = Client.new(task).get_columns_list
|
15
26
|
|
16
27
|
columns = columns_from_task(task).map do |col_name|
|
@@ -53,8 +64,16 @@ module Embulk
|
|
53
64
|
end
|
54
65
|
|
55
66
|
def self.task_from_config(config)
|
56
|
-
|
57
|
-
|
67
|
+
refresh_token = config.param('refresh_token', :string, default: nil)
|
68
|
+
json_key_content = config.param("json_key_content", :string, default: nil)
|
69
|
+
|
70
|
+
auth_method = Plugin::AUTH_TYPE_REFRESH_TOKEN if refresh_token
|
71
|
+
auth_method = Plugin::AUTH_TYPE_JSON_KEY if json_key_content && auth_method == nil
|
72
|
+
{
|
73
|
+
"auth_method" => auth_method,
|
74
|
+
"client_id" => config.param("client_id", :string, default: nil),
|
75
|
+
"client_secret" => config.param("client_secret", :string, default: nil),
|
76
|
+
"refresh_token" => refresh_token,
|
58
77
|
"json_key_content" => json_key_content,
|
59
78
|
"view_id" => config.param("view_id", :string),
|
60
79
|
"dimensions" => config.param("dimensions", :array, default: []),
|
@@ -98,7 +117,7 @@ module Embulk
|
|
98
117
|
client = Client.new(task, preview?)
|
99
118
|
columns = self.class.columns_from_task(task) + ["view_id"]
|
100
119
|
|
101
|
-
last_record_time = task["last_record_time"] ? Time.parse(task["last_record_time"]) : nil
|
120
|
+
last_record_time = task['incremental'] && task["last_record_time"] ? Time.parse(task["last_record_time"]) : nil
|
102
121
|
|
103
122
|
latest_time_series = nil
|
104
123
|
skip_counter, total_counter = 0, 0
|
@@ -283,6 +283,60 @@ module Embulk
|
|
283
283
|
end
|
284
284
|
end
|
285
285
|
|
286
|
+
sub_test_case "oauth_refresh_token" do
|
287
|
+
setup do
|
288
|
+
conf = valid_config_oauth["in"]
|
289
|
+
mute_logger
|
290
|
+
@client = Client.new(task(embulk_config(conf)))
|
291
|
+
end
|
292
|
+
|
293
|
+
sub_test_case "retry refresh token" do
|
294
|
+
def should_retry
|
295
|
+
mock(Google::Auth::UserRefreshCredentials).new(anything).times(retryer.config.limit + 1) { raise error }
|
296
|
+
assert_raise do
|
297
|
+
@client.auth
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
def should_not_retry
|
302
|
+
mock(Google::Auth::UserRefreshCredentials).new(anything).times(1) { raise error }
|
303
|
+
assert_raise do
|
304
|
+
@client.auth
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
sub_test_case "Server respones error (5xx)" do
|
309
|
+
def error
|
310
|
+
Google::Apis::ServerError.new("error")
|
311
|
+
end
|
312
|
+
|
313
|
+
test "should retry refresh token" do
|
314
|
+
should_retry
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
sub_test_case "Refresh token reach Rate Limit" do
|
319
|
+
def error
|
320
|
+
Google::Apis::RateLimitError.new("error")
|
321
|
+
end
|
322
|
+
|
323
|
+
test "should retry refresh token" do
|
324
|
+
should_retry
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
sub_test_case "Refresh token Error" do
|
329
|
+
def error
|
330
|
+
Google::Apis::AuthorizationError.new("error")
|
331
|
+
end
|
332
|
+
|
333
|
+
test "should not retry" do
|
334
|
+
should_not_retry
|
335
|
+
end
|
336
|
+
end
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
286
340
|
sub_test_case "too_early_data?" do
|
287
341
|
def stub_timezone(client)
|
288
342
|
stub(client).get_profile { {timezone: "America/Los_Angeles" } }
|
@@ -412,6 +466,10 @@ module Embulk
|
|
412
466
|
fixture_load("valid.yml")
|
413
467
|
end
|
414
468
|
|
469
|
+
def valid_config_oauth
|
470
|
+
fixture_load("valid_refresh_token.yml")
|
471
|
+
end
|
472
|
+
|
415
473
|
def embulk_config(hash)
|
416
474
|
Embulk::DataSource.new(hash)
|
417
475
|
end
|
@@ -75,6 +75,46 @@ module Embulk
|
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
78
|
+
test "missing client_id params for oauth" do
|
79
|
+
conf = valid_config_oauth["in"]
|
80
|
+
conf.delete("client_id")
|
81
|
+
assert_raise(Embulk::ConfigError.new(oauth_expect_message)) do
|
82
|
+
Plugin.transaction(embulk_config(conf))
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
test "missing client_secret params for oauth" do
|
87
|
+
conf = valid_config_oauth["in"]
|
88
|
+
conf.delete('client_secret')
|
89
|
+
assert_raise(Embulk::ConfigError.new(oauth_expect_message)) do
|
90
|
+
Plugin.transaction(embulk_config(conf))
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
test "missing refresh_token params for oauth" do
|
95
|
+
conf = valid_config_oauth["in"]
|
96
|
+
conf.delete("refresh_token")
|
97
|
+
assert_raise(Embulk::ConfigError.new(unknown_auth_method_message)) do
|
98
|
+
Plugin.transaction(embulk_config(conf))
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
test "missing json_key_content params for oauth" do
|
103
|
+
conf = valid_config["in"]
|
104
|
+
conf.delete("json_key_content")
|
105
|
+
assert_raise(Embulk::ConfigError.new(unknown_auth_method_message)) do
|
106
|
+
Plugin.transaction(embulk_config(conf))
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def unknown_auth_method_message
|
111
|
+
"Unknown Authentication method ''."
|
112
|
+
end
|
113
|
+
|
114
|
+
def oauth_expect_message
|
115
|
+
"client_id, client_secret and refresh_token are required when using Oauth authentication"
|
116
|
+
end
|
117
|
+
|
78
118
|
def unknown_col_name
|
79
119
|
"ga:foooooo"
|
80
120
|
end
|
@@ -162,12 +202,14 @@ module Embulk
|
|
162
202
|
|
163
203
|
sub_test_case "last_record_time option" do
|
164
204
|
setup do
|
205
|
+
stub(Plugin).calculate_next_times { {} }
|
165
206
|
Time.zone = "America/Los_Angeles"
|
166
207
|
@last_record_time = Time.zone.parse("2016-06-01 12:00:00").to_time
|
167
208
|
|
168
209
|
conf = valid_config["in"]
|
169
210
|
conf["time_series"] = time_series
|
170
211
|
conf["last_record_time"] = @last_record_time.strftime("%Y-%m-%d %H:%M:%S %z")
|
212
|
+
conf['incremental'] = true
|
171
213
|
@plugin = Plugin.new(embulk_config(conf), nil, nil, @page_builder)
|
172
214
|
end
|
173
215
|
|
@@ -182,6 +224,7 @@ module Embulk
|
|
182
224
|
}
|
183
225
|
block.call row
|
184
226
|
end
|
227
|
+
stub(klass).get_profile { {timezone: "America/Los_Angeles" } }
|
185
228
|
end
|
186
229
|
|
187
230
|
mock(@page_builder).add.never
|
@@ -219,12 +262,15 @@ module Embulk
|
|
219
262
|
|
220
263
|
sub_test_case "last_record_time option" do
|
221
264
|
setup do
|
265
|
+
stub(Plugin).calculate_next_times { {} }
|
222
266
|
Time.zone = "America/Los_Angeles"
|
223
267
|
@last_record_time = Time.zone.parse("2016-06-01 12:00:00").to_time
|
224
268
|
|
225
269
|
conf = valid_config["in"]
|
226
270
|
conf["time_series"] = time_series
|
227
271
|
conf["last_record_time"] = @last_record_time.strftime("%Y-%m-%d %H:%M:%S %z")
|
272
|
+
conf['incremental'] = true
|
273
|
+
|
228
274
|
@plugin = Plugin.new(embulk_config(conf), nil, nil, @page_builder)
|
229
275
|
end
|
230
276
|
|
@@ -239,6 +285,7 @@ module Embulk
|
|
239
285
|
}
|
240
286
|
block.call row
|
241
287
|
end
|
288
|
+
stub(klass).get_profile { {timezone: "America/Los_Angeles" } }
|
242
289
|
end
|
243
290
|
|
244
291
|
mock(@page_builder).add.never
|
@@ -250,6 +297,39 @@ module Embulk
|
|
250
297
|
end
|
251
298
|
end
|
252
299
|
|
300
|
+
sub_test_case "run non-incremental" do
|
301
|
+
sub_test_case " should be added to page_builder" do
|
302
|
+
setup do
|
303
|
+
Time.zone = "America/Los_Angeles"
|
304
|
+
@last_record_time = Time.zone.parse("2016-06-01 12:00:00").to_time
|
305
|
+
|
306
|
+
conf = valid_config["in"]
|
307
|
+
conf["time_series"] = "ga:date"
|
308
|
+
conf["last_record_time"] = @last_record_time.strftime("%Y-%m-%d %H:%M:%S %z")
|
309
|
+
conf['incremental'] = false
|
310
|
+
@plugin = Plugin.new(embulk_config(conf), nil, nil, @page_builder)
|
311
|
+
end
|
312
|
+
|
313
|
+
test "should allow record to be added to page_builder" do
|
314
|
+
any_instance_of(Client) do |klass|
|
315
|
+
stub(klass).each_report_row do |block|
|
316
|
+
row = {
|
317
|
+
"ga:date" => @last_record_time,
|
318
|
+
"ga:browser" => "wget",
|
319
|
+
"ga:visits" => 3,
|
320
|
+
"ga:pageviews" => 4,
|
321
|
+
}
|
322
|
+
block.call row
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
mock(@page_builder).add(anything).at_least(1)
|
327
|
+
mock(@page_builder).finish
|
328
|
+
@plugin.run
|
329
|
+
end
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
253
333
|
sub_test_case "canonicalize_column_name" do
|
254
334
|
data do
|
255
335
|
[
|
@@ -457,6 +537,10 @@ module Embulk
|
|
457
537
|
def embulk_config(hash)
|
458
538
|
Embulk::DataSource.new(hash)
|
459
539
|
end
|
540
|
+
|
541
|
+
def valid_config_oauth
|
542
|
+
fixture_load("valid_refresh_token.yml")
|
543
|
+
end
|
460
544
|
end
|
461
545
|
end
|
462
546
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
in:
|
2
|
+
type: google_analytics
|
3
|
+
refresh_token: "your_refresh_token"
|
4
|
+
client_id: "your_client_id_here"
|
5
|
+
client_secret: "your_client_secret_here"
|
6
|
+
view_id: 101111111
|
7
|
+
time_series: "ga:dateHour"
|
8
|
+
|
9
|
+
dimensions:
|
10
|
+
- "ga:browser"
|
11
|
+
metrics:
|
12
|
+
- "ga:visits"
|
13
|
+
- "ga:pageviews"
|
14
|
+
retry_limit: 2
|
15
|
+
retry_initial_wait_sec: 0
|
16
|
+
|
17
|
+
out:
|
18
|
+
type: stdout
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: embulk-input-google_analytics
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.18.alpha
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- uu59
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-05-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -192,6 +192,20 @@ dependencies:
|
|
192
192
|
- - ">="
|
193
193
|
- !ruby/object:Gem::Version
|
194
194
|
version: '0'
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
requirement: !ruby/object:Gem::Requirement
|
197
|
+
requirements:
|
198
|
+
- - ">="
|
199
|
+
- !ruby/object:Gem::Version
|
200
|
+
version: '0'
|
201
|
+
name: pry-debugger-jruby
|
202
|
+
prerelease: false
|
203
|
+
type: :development
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - ">="
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: '0'
|
195
209
|
- !ruby/object:Gem::Dependency
|
196
210
|
requirement: !ruby/object:Gem::Requirement
|
197
211
|
requirements:
|
@@ -231,6 +245,7 @@ files:
|
|
231
245
|
- test/fixture_helper.rb
|
232
246
|
- test/fixtures/reports.json
|
233
247
|
- test/fixtures/valid.yml
|
248
|
+
- test/fixtures/valid_refresh_token.yml
|
234
249
|
- test/override_assert_raise.rb
|
235
250
|
- test/run-test.rb
|
236
251
|
homepage: https://github.com/treasure-data/embulk-input-google_analytics
|
@@ -248,9 +263,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
248
263
|
version: '0'
|
249
264
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
250
265
|
requirements:
|
251
|
-
- - "
|
266
|
+
- - ">"
|
252
267
|
- !ruby/object:Gem::Version
|
253
|
-
version:
|
268
|
+
version: 1.3.1
|
254
269
|
requirements: []
|
255
270
|
rubyforge_project:
|
256
271
|
rubygems_version: 2.6.6
|
@@ -263,5 +278,6 @@ test_files:
|
|
263
278
|
- test/fixture_helper.rb
|
264
279
|
- test/fixtures/reports.json
|
265
280
|
- test/fixtures/valid.yml
|
281
|
+
- test/fixtures/valid_refresh_token.yml
|
266
282
|
- test/override_assert_raise.rb
|
267
283
|
- test/run-test.rb
|