fluent-plugin-bigquery 0.0.3 → 0.0.4

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: 0802b40a0e2792d20ca2e92f20cfe398d92aa5db
4
- data.tar.gz: a210aa8139c2d82467979adac99f6396096ef6d7
3
+ metadata.gz: 91a4bfe02680f2079998d36ab098c5498bdaea04
4
+ data.tar.gz: 234135f11479a6d364d1c5d0f58d90cfe7d72717
5
5
  SHA512:
6
- metadata.gz: 865a4f9cd3de0d912678768a5a29d3795b62382de2949ac7fc220446d2aaedb2c62616056ad2d44901c64c2782d45c3e2f2f1bb78ca73174394d1b2954291e5f
7
- data.tar.gz: 1bde3427c107b3ac396e808f4856daff92f9a50666d07567dfe1b3cdd0fd50a0ca550b1573368b1913cde125dfa4d874ed6aa96862014fdb2bd22e950ce78bbf
6
+ metadata.gz: a1e3df653dca491e163824f57e6d3d0932314ef59b2cc0cf36caa77f9007df624b183cd2b700caf5c02bd6a477322d136e44c14bed15f44c8c201eb9fb43838e
7
+ data.tar.gz: d20de3a18a7507fb5532480cd51704e23e79740d12a58bde482824095740681b10ede39a9e0611e878bba6e609078dc406e5e983b5ea5160e83b0632a4c83542
data/.travis.yml ADDED
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+
3
+ rvm:
4
+ - 1.9.3
5
+ - 2.0.0
6
+ - 2.1.0
7
+
8
+ script: bundle exec rake test
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # fluent-plugin-bigquery
2
2
 
3
- Fluentd output plugin to load/insert data into Google BigQuery.
3
+ [Fluentd](http://fluentd.org) output plugin to load/insert data into Google BigQuery.
4
4
 
5
5
  * insert data over streaming inserts
6
6
  * for continuous real-time insertions, under many limitations
@@ -104,6 +104,7 @@ Important options for high rate events are:
104
104
  ### Authentication
105
105
 
106
106
  There are two methods supported to fetch access token for the service account.
107
+
107
108
  1. Public-Private key pair
108
109
  2. Predefined access token (Compute Engine only)
109
110
 
@@ -135,6 +136,73 @@ Compute Engine instance, then you can configure fluentd like this.
135
136
  </match>
136
137
  ```
137
138
 
139
+ ### Table schema
140
+
141
+ There are two methods to describe the schema of the target table.
142
+
143
+ 1. List fields in fluent.conf
144
+ 2. Load a schema file in JSON.
145
+
146
+ The examples above use the first method. In this method,
147
+ you can also specify nested fields by prefixing their belonging record fields.
148
+
149
+ ```apache
150
+ <match dummy>
151
+ type bigquery
152
+
153
+ ...
154
+
155
+ time_format %s
156
+ time_field time
157
+
158
+ field_integer time,response.status,response.bytes
159
+ field_string request.vhost,request.path,request.method,request.protocol,request.agent,request.referer,remote.host,remote.ip,remote.user
160
+ field_float request.time
161
+ field_boolean request.bot_access,request.loginsession
162
+ </match>
163
+ ```
164
+
165
+ This schema accepts structured JSON data like:
166
+
167
+ ```json
168
+ {
169
+ "request":{
170
+ "time":1391748126.7000976,
171
+ "vhost":"www.example.com",
172
+ "path":"/",
173
+ "method":"GET",
174
+ "protocol":"HTTP/1.1",
175
+ "agent":"HotJava",
176
+ "bot_access":false
177
+ },
178
+ "remote":{ "ip": "192.0.2.1" },
179
+ "response":{
180
+ "status":200,
181
+ "bytes":1024
182
+ }
183
+ }
184
+ ```
185
+
186
+ The second method is to specify a path to a BigQuery schema file instead of listing fields. In this case, your fluent.conf looks like:
187
+
188
+ ```apache
189
+ <match dummy>
190
+ type bigquery
191
+
192
+ ...
193
+
194
+ time_format %s
195
+ time_field time
196
+
197
+ schema_path /path/to/httpd.schema
198
+ field_integer time
199
+ </match>
200
+ ```
201
+ where /path/to/httpd.schema is a path to the JSON-encoded schema file which you used for creating the table on BigQuery.
202
+
203
+ NOTE: Since JSON does not define how to encode data of TIMESTAMP type,
204
+ you are still recommended to specify JSON types for TIMESTAMP fields as "time" field does in the example.
205
+
138
206
 
139
207
  ### patches
140
208
 
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.add_development_dependency "rake"
22
+ spec.add_development_dependency "rr"
22
23
  spec.add_runtime_dependency "google-api-client", "~> 0.7.1"
23
24
  spec.add_runtime_dependency "fluentd"
24
25
  spec.add_runtime_dependency "fluent-mixin-plaintextformatter", '>= 0.2.1'
@@ -1,6 +1,6 @@
1
1
  module Fluent
2
2
  module BigQueryPlugin
3
- VERSION = "0.0.3"
3
+ VERSION = "0.0.4"
4
4
  end
5
5
  end
6
6
 
@@ -63,6 +63,7 @@ module Fluent
63
63
  config_param :table, :string, :default => nil
64
64
  config_param :tables, :string, :default => nil
65
65
 
66
+ config_param :schema_path, :string, :default => nil
66
67
  config_param :field_string, :string, :default => nil
67
68
  config_param :field_integer, :string, :default => nil
68
69
  config_param :field_float, :string, :default => nil
@@ -117,6 +118,7 @@ module Fluent
117
118
 
118
119
  def initialize
119
120
  super
121
+ require 'json'
120
122
  require 'google/api_client'
121
123
  require 'google/api_client/client_secrets'
122
124
  require 'google/api_client/auth/installed_app'
@@ -137,13 +139,16 @@ module Fluent
137
139
  raise Fluent::ConfigError, "unrecognized 'auth_method': #{@auth_method}"
138
140
  end
139
141
 
140
- if (!@table && !@tables) || (@table && @table)
142
+ if (!@table && !@tables) || (@table && @tables)
141
143
  raise Fluent::ConfigError, "'table' or 'tables' must be specified, and both are invalid"
142
144
  end
143
145
 
144
146
  @tablelist = @tables ? @tables.split(',') : [@table]
145
147
 
146
148
  @fields = RecordSchema.new
149
+ if @schema_path
150
+ @fields.load_schema(JSON.parse(File.read(@schema_path)))
151
+ end
147
152
  if @field_string
148
153
  @field_string.split(',').each do |fieldname|
149
154
  @fields.register_field fieldname, :string
@@ -171,6 +176,17 @@ module Fluent
171
176
  end
172
177
  end
173
178
  @timef = TimeFormatter.new(@time_format, @localtime)
179
+
180
+ if @time_field
181
+ keys = @time_field.split('.')
182
+ last_key = keys.pop
183
+ @add_time_field = lambda {|record, time|
184
+ keys.inject(record) { |h, k| h[k] ||= {} }[last_key] = @timef.format(time)
185
+ record
186
+ }
187
+ else
188
+ @add_time_field = lambda {|record, time| record }
189
+ end
174
190
  end
175
191
 
176
192
  def start
@@ -260,11 +276,7 @@ module Fluent
260
276
  super
261
277
  buf = ''
262
278
  es.each do |time, record|
263
- row = if @time_field
264
- @fields.format(record.merge({@time_field => @timef.format(time)}))
265
- else
266
- @fields.format(record)
267
- end
279
+ row = @fields.format(@add_time_field.call(record, time))
268
280
  buf << {"json" => row}.to_msgpack unless row.empty?
269
281
  end
270
282
  buf
@@ -350,12 +362,24 @@ module Fluent
350
362
  end
351
363
  end
352
364
 
365
+ class TimestampFieldSchema < FieldSchema
366
+ def type
367
+ :timestamp
368
+ end
369
+
370
+ def format(value)
371
+ value
372
+ end
373
+ end
374
+
353
375
  class RecordSchema < FieldSchema
354
376
  FIELD_TYPES = {
355
377
  :string => StringFieldSchema,
356
378
  :integer => IntegerFieldSchema,
357
379
  :float => FloatFieldSchema,
358
- :boolean => BooleanFieldSchema
380
+ :boolean => BooleanFieldSchema,
381
+ :timestamp => TimestampFieldSchema,
382
+ :record => RecordSchema
359
383
  }.freeze
360
384
 
361
385
  def initialize
@@ -370,8 +394,27 @@ module Fluent
370
394
  @fields[name]
371
395
  end
372
396
 
397
+ def load_schema(schema)
398
+ schema.each do |field|
399
+ raise ConfigError, 'field must have type' unless field.key?('type')
400
+
401
+ type = field['type'].downcase.to_sym
402
+ field_schema_class = FIELD_TYPES[type]
403
+ raise ConfigError, "Invalid field type: #{field['type']}" unless field_schema_class
404
+
405
+ field_schema = field_schema_class.new
406
+ @fields[field['name']] = field_schema
407
+ if type == :record
408
+ raise ConfigError, "record field must have fields" unless field.key?('fields')
409
+ field_schema.load_schema(field['fields'])
410
+ end
411
+ end
412
+ end
413
+
373
414
  def register_field(name, type)
374
- raise ConfigError, "field #{name} is registered twice" if @fields.key?(name)
415
+ if @fields.key?(name) and @fields[name].type != :timestamp
416
+ raise ConfigError, "field #{name} is registered twice"
417
+ end
375
418
  if name[/\./]
376
419
  recordname = $`
377
420
  fieldname = $'
data/test/helper.rb CHANGED
@@ -29,5 +29,7 @@ require 'fluent/plugin/buf_file'
29
29
  require 'fluent/plugin/out_bigquery'
30
30
  require 'fluent/plugin/bigquery/load_request_body_wrapper'
31
31
 
32
+ require 'rr'
33
+
32
34
  class Test::Unit::TestCase
33
35
  end
@@ -0,0 +1,335 @@
1
+ require 'helper'
2
+ require 'google/api_client'
3
+ require 'fluent/plugin/buf_memory'
4
+
5
+ class BigQueryOutputTest < Test::Unit::TestCase
6
+ def setup
7
+ Fluent::Test.setup
8
+ end
9
+
10
+ CONFIG = %[
11
+ table foo
12
+ email foo@bar.example
13
+ private_key_path /path/to/key
14
+ project yourproject_id
15
+ dataset yourdataset_id
16
+
17
+ time_format %s
18
+ time_field time
19
+
20
+ field_integer time,status,bytes
21
+ field_string vhost,path,method,protocol,agent,referer,remote.host,remote.ip,remote.user
22
+ field_float requesttime
23
+ field_boolean bot_access,loginsession
24
+ ]
25
+
26
+ API_SCOPE = "https://www.googleapis.com/auth/bigquery"
27
+
28
+ def create_driver(conf = CONFIG)
29
+ Fluent::Test::OutputTestDriver.new(Fluent::BigQueryOutput).configure(conf)
30
+ end
31
+
32
+ def stub_client(driver)
33
+ stub(client = Object.new) do |expect|
34
+ expect.discovered_api("bigquery", "v2") { stub! }
35
+ yield expect if defined?(yield)
36
+ end
37
+ stub(driver.instance).client { client }
38
+ client
39
+ end
40
+
41
+ def mock_client(driver)
42
+ mock(client = Object.new) do |expect|
43
+ yield expect
44
+ end
45
+ stub(driver.instance).client { client }
46
+ client
47
+ end
48
+
49
+ def test_configure_table
50
+ driver = create_driver
51
+ assert_equal driver.instance.table, 'foo'
52
+ assert_nil driver.instance.tables
53
+
54
+ driver = create_driver(CONFIG.sub(/\btable\s+.*$/, 'tables foo,bar'))
55
+ assert_nil driver.instance.table
56
+ assert_equal driver.instance.tables, 'foo,bar'
57
+
58
+ assert_raise(Fluent::ConfigError, "'table' or 'tables' must be specified, and both are invalid") {
59
+ create_driver(CONFIG + "tables foo,bar")
60
+ }
61
+ end
62
+
63
+ def test_configure_auth
64
+ key = stub!
65
+ mock(Google::APIClient::PKCS12).load_key('/path/to/key', 'notasecret') { key }
66
+ authorization = Object.new
67
+ asserter = mock!.authorize { authorization }
68
+ mock(Google::APIClient::JWTAsserter).new('foo@bar.example', API_SCOPE, key) { asserter }
69
+
70
+ mock.proxy(Google::APIClient).new.with_any_args {
71
+ mock!.__send__(:authorization=, authorization) {}
72
+ }
73
+
74
+ driver = create_driver(CONFIG)
75
+ driver.instance.client()
76
+ end
77
+
78
+ def test_format_stream
79
+ now = Time.now
80
+ input = [
81
+ now,
82
+ {
83
+ "status" => "1",
84
+ "bytes" => 3.0,
85
+ "vhost" => :bar,
86
+ "path" => "/path/to/baz",
87
+ "method" => "GET",
88
+ "protocol" => "HTTP/0.9",
89
+ "agent" => "libwww",
90
+ "referer" => "http://referer.example",
91
+ "requesttime" => (now - 1).to_f.to_s,
92
+ "bot_access" => true,
93
+ "loginsession" => false,
94
+ "something-else" => "would be ignored",
95
+ "yet-another" => {
96
+ "foo" => "bar",
97
+ "baz" => 1,
98
+ },
99
+ "remote" => {
100
+ "host" => "remote.example",
101
+ "ip" => "192.0.2.1",
102
+ "port" => 12345,
103
+ "user" => "tagomoris",
104
+ }
105
+ }
106
+ ]
107
+ expected = {
108
+ "json" => {
109
+ "time" => now.to_i,
110
+ "status" => 1,
111
+ "bytes" => 3,
112
+ "vhost" => "bar",
113
+ "path" => "/path/to/baz",
114
+ "method" => "GET",
115
+ "protocol" => "HTTP/0.9",
116
+ "agent" => "libwww",
117
+ "referer" => "http://referer.example",
118
+ "requesttime" => (now - 1).to_f.to_s.to_f,
119
+ "bot_access" => true,
120
+ "loginsession" => false,
121
+ "remote" => {
122
+ "host" => "remote.example",
123
+ "ip" => "192.0.2.1",
124
+ "user" => "tagomoris",
125
+ }
126
+ }
127
+ }
128
+
129
+ driver = create_driver(CONFIG)
130
+ mock_client(driver) do |expect|
131
+ expect.discovered_api("bigquery", "v2") { stub! }
132
+ end
133
+ driver.instance.start
134
+ buf = driver.instance.format_stream("my.tag", [input])
135
+ driver.instance.shutdown
136
+
137
+ assert_equal expected, MessagePack.unpack(buf)
138
+ end
139
+
140
+ [
141
+ # <time_format>, <time field type>, <time expectation generator>, <assertion>
142
+ [
143
+ "%s.%6N", "field_float",
144
+ lambda{|t| t.strftime("%s.%6N").to_f },
145
+ lambda{|recv, expected, actual|
146
+ recv.assert_in_delta(expected, actual, Float::EPSILON / 10**3)
147
+ }
148
+ ],
149
+ [
150
+ "%Y-%m-%dT%H:%M:%SZ", "field_string",
151
+ lambda{|t| t.iso8601 },
152
+ :assert_equal.to_proc
153
+ ],
154
+ [
155
+ "%a, %d %b %Y %H:%M:%S GMT", "field_string",
156
+ lambda{|t| t.httpdate },
157
+ :assert_equal.to_proc
158
+ ],
159
+ ].each do |format, type, expect_time, assert|
160
+ define_method("test_time_formats_#{format}") do
161
+ now = Time.now.utc
162
+ input = [ now, {} ]
163
+ expected = { "json" => { "time" => expect_time[now], } }
164
+
165
+ driver = create_driver(<<-CONFIG)
166
+ table foo
167
+ email foo@bar.example
168
+ private_key_path /path/to/key
169
+ project yourproject_id
170
+ dataset yourdataset_id
171
+
172
+ time_format #{format}
173
+ time_field time
174
+ #{type} time
175
+ CONFIG
176
+ stub_client(driver)
177
+
178
+ driver.instance.start
179
+ buf = driver.instance.format_stream("my.tag", [input])
180
+ driver.instance.shutdown
181
+
182
+ assert[self, expected["json"]["time"], MessagePack.unpack(buf)["json"]["time"]]
183
+ end
184
+ end
185
+
186
+ def test_format_nested_time
187
+ now = Time.now
188
+ input = [
189
+ now,
190
+ {
191
+ "metadata" => {
192
+ "node" => "mynode.example",
193
+ },
194
+ "log" => "something",
195
+ }
196
+ ]
197
+ expected = {
198
+ "json" => {
199
+ "metadata" => {
200
+ "time" => now.strftime("%s").to_i,
201
+ "node" => "mynode.example",
202
+ },
203
+ "log" => "something",
204
+ }
205
+ }
206
+
207
+ driver = create_driver(<<-CONFIG)
208
+ table foo
209
+ email foo@bar.example
210
+ private_key_path /path/to/key
211
+ project yourproject_id
212
+ dataset yourdataset_id
213
+
214
+ time_format %s
215
+ time_field metadata.time
216
+
217
+ field_integer metadata.time
218
+ field_string metadata.node,log
219
+ CONFIG
220
+ stub_client(driver)
221
+ driver.instance.start
222
+ buf = driver.instance.format_stream("my.tag", [input])
223
+ driver.instance.shutdown
224
+
225
+ assert_equal expected, MessagePack.unpack(buf)
226
+ end
227
+
228
+ def test_format_with_schema
229
+ now = Time.now
230
+ input = [
231
+ now,
232
+ {
233
+ "request" => {
234
+ "vhost" => :bar,
235
+ "path" => "/path/to/baz",
236
+ "method" => "GET",
237
+ "protocol" => "HTTP/0.9",
238
+ "agent" => "libwww",
239
+ "referer" => "http://referer.example",
240
+ "time" => (now - 1).to_f,
241
+ "bot_access" => true,
242
+ "loginsession" => false,
243
+ },
244
+ "response" => {
245
+ "status" => "1",
246
+ "bytes" => 3.0,
247
+ },
248
+ "remote" => {
249
+ "host" => "remote.example",
250
+ "ip" => "192.0.2.1",
251
+ "port" => 12345,
252
+ "user" => "tagomoris",
253
+ },
254
+ "something-else" => "would be ignored",
255
+ "yet-another" => {
256
+ "foo" => "bar",
257
+ "baz" => 1,
258
+ },
259
+ }
260
+ ]
261
+ expected = {
262
+ "json" => {
263
+ "time" => now.to_i,
264
+ "request" => {
265
+ "vhost" => "bar",
266
+ "path" => "/path/to/baz",
267
+ "method" => "GET",
268
+ "protocol" => "HTTP/0.9",
269
+ "agent" => "libwww",
270
+ "referer" => "http://referer.example",
271
+ "time" => (now - 1).to_f,
272
+ "bot_access" => true,
273
+ "loginsession" => false,
274
+ },
275
+ "remote" => {
276
+ "host" => "remote.example",
277
+ "ip" => "192.0.2.1",
278
+ "user" => "tagomoris",
279
+ },
280
+ "response" => {
281
+ "status" => 1,
282
+ "bytes" => 3,
283
+ },
284
+ }
285
+ }
286
+
287
+ driver = create_driver(<<-CONFIG)
288
+ table foo
289
+ email foo@bar.example
290
+ private_key_path /path/to/key
291
+ project yourproject_id
292
+ dataset yourdataset_id
293
+
294
+ time_format %s
295
+ time_field time
296
+
297
+ schema_path #{File.join(File.dirname(__FILE__), "testdata", "apache.schema")}
298
+ field_integer time
299
+ CONFIG
300
+ mock_client(driver) do |expect|
301
+ expect.discovered_api("bigquery", "v2") { stub! }
302
+ end
303
+ driver.instance.start
304
+ buf = driver.instance.format_stream("my.tag", [input])
305
+ driver.instance.shutdown
306
+
307
+ assert_equal expected, MessagePack.unpack(buf)
308
+ end
309
+
310
+ def test_write
311
+ entry = {"json" => {"a" => "b"}}, {"json" => {"b" => "c"}}
312
+ driver = create_driver(CONFIG)
313
+ mock_client(driver) do |expect|
314
+ expect.discovered_api("bigquery", "v2") { mock!.tabledata.mock!.insert_all { Object.new } }
315
+ expect.execute(
316
+ :api_method => anything,
317
+ :parameters => {
318
+ 'projectId' => 'yourproject_id',
319
+ 'datasetId' => 'yourdataset_id',
320
+ 'tableId' => 'foo',
321
+ },
322
+ :body_object => {
323
+ 'rows' => [entry]
324
+ }
325
+ ) { stub!.success? { true } }
326
+ end
327
+
328
+ chunk = Fluent::MemoryBufferChunk.new("my.tag")
329
+ chunk << entry.to_msgpack
330
+
331
+ driver.instance.start
332
+ driver.instance.write(chunk)
333
+ driver.instance.shutdown
334
+ end
335
+ end
@@ -0,0 +1,98 @@
1
+ [
2
+ {
3
+ "name": "time",
4
+ "type": "TIMESTAMP",
5
+ "mode": "REQUIRED"
6
+ },
7
+ {
8
+ "name": "request",
9
+ "type": "RECORD",
10
+ "mode": "REQUIRED",
11
+ "fields": [
12
+ {
13
+ "name": "vhost",
14
+ "type": "STRING",
15
+ "mode": "NULLABLE"
16
+ },
17
+ {
18
+ "name": "path",
19
+ "type": "STRING",
20
+ "mode": "REQUIRED"
21
+ },
22
+ {
23
+ "name": "method",
24
+ "type": "STRING",
25
+ "mode": "REQUIRED"
26
+ },
27
+ {
28
+ "name": "protocol",
29
+ "type": "STRING",
30
+ "mode": "REQUIRED"
31
+ },
32
+ {
33
+ "name": "agent",
34
+ "type": "STRING",
35
+ "mode": "REQUIRED"
36
+ },
37
+ {
38
+ "name": "referer",
39
+ "type": "STRING",
40
+ "mode": "NULLABLE"
41
+ },
42
+ {
43
+ "name": "time",
44
+ "type": "TIMESTAMP",
45
+ "mode": "NULLABLE"
46
+ },
47
+ {
48
+ "name": "bot_access",
49
+ "type": "BOOLEAN",
50
+ "mode": "NULLABLE"
51
+ },
52
+ {
53
+ "name": "loginsession",
54
+ "type": "BOOLEAN",
55
+ "mode": "NULLABLE"
56
+ }
57
+ ]
58
+ },
59
+ {
60
+ "name": "remote",
61
+ "type": "RECORD",
62
+ "mode": "NULLABLE",
63
+ "fields": [
64
+ {
65
+ "name": "host",
66
+ "type": "STRING",
67
+ "mode": "NULLABLE"
68
+ },
69
+ {
70
+ "name": "ip",
71
+ "type": "STRING",
72
+ "mode": "REQUIRED"
73
+ },
74
+ {
75
+ "name": "user",
76
+ "type": "STRING",
77
+ "mode": "NULLABLE"
78
+ }
79
+ ]
80
+ },
81
+ {
82
+ "name": "response",
83
+ "type": "RECORD",
84
+ "mode": "REQUIRED",
85
+ "fields": [
86
+ {
87
+ "name": "status",
88
+ "type": "INTEGER",
89
+ "mode": "REQUIRED"
90
+ },
91
+ {
92
+ "name": "bytes",
93
+ "type": "INTEGER",
94
+ "mode": "REQUIRED"
95
+ }
96
+ ]
97
+ }
98
+ ]
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-bigquery
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - TAGOMORI Satoshi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-06 00:00:00.000000000 Z
11
+ date: 2014-02-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - '>='
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rr
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: google-api-client
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -117,6 +131,7 @@ extensions: []
117
131
  extra_rdoc_files: []
118
132
  files:
119
133
  - .gitignore
134
+ - .travis.yml
120
135
  - Gemfile
121
136
  - LICENSE.txt
122
137
  - README.md
@@ -126,6 +141,8 @@ files:
126
141
  - lib/fluent/plugin/bigquery/version.rb
127
142
  - lib/fluent/plugin/out_bigquery.rb
128
143
  - test/helper.rb
144
+ - test/plugin/test_out_bigquery.rb
145
+ - test/plugin/testdata/apache.schema
129
146
  - test/test_load_request_body_wrapper.rb
130
147
  homepage: https://github.com/tagomoris/fluent-plugin-bigquery
131
148
  licenses:
@@ -153,5 +170,7 @@ specification_version: 4
153
170
  summary: Fluentd plugin to store data on Google BigQuery
154
171
  test_files:
155
172
  - test/helper.rb
173
+ - test/plugin/test_out_bigquery.rb
174
+ - test/plugin/testdata/apache.schema
156
175
  - test/test_load_request_body_wrapper.rb
157
176
  has_rdoc: