fluent-plugin-google-cloud 0.5.3.grpc.alpha.3 → 0.5.3.grpc.alpha.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,309 @@
1
+ # Copyright 2016 Google Inc. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'grpc'
16
+
17
+ require_relative 'base_test'
18
+
19
+ # Unit tests for Google Cloud Logging plugin
20
+ class GoogleCloudOutputGRPCTest < Test::Unit::TestCase
21
+ include BaseTest
22
+
23
+ def test_configure_use_grpc
24
+ setup_gce_metadata_stubs
25
+ d = create_driver
26
+ assert_true d.instance.instance_variable_get(:@use_grpc)
27
+ end
28
+
29
+ def test_client_error
30
+ setup_gce_metadata_stubs
31
+ { 8 => 'ResourceExhausted',
32
+ 12 => 'Unimplemented',
33
+ 16 => 'Unauthenticated' }.each_with_index do |(code, message), index|
34
+ setup_logging_stubs(true, code, message) do
35
+ d = create_driver(USE_GRPC_CONFIG, 'test',
36
+ GRPCLoggingMockFailingService.rpc_stub_class)
37
+ # The API Client should not retry this and the plugin should consume the
38
+ # exception.
39
+ d.emit('message' => log_entry(0))
40
+ d.run
41
+ end
42
+ assert_equal 1, @failed_attempts.size, "Index #{index} failed."
43
+ end
44
+ end
45
+
46
+ def test_server_error
47
+ setup_gce_metadata_stubs
48
+ { 1 => 'Cancelled',
49
+ 2 => 'Unknown',
50
+ 4 => 'DeadlineExceeded',
51
+ 13 => 'Internal',
52
+ 14 => 'Unavailable' }.each_with_index do |(code, message), index|
53
+ exception_count = 0
54
+ setup_logging_stubs(true, code, message) do
55
+ d = create_driver(USE_GRPC_CONFIG, 'test',
56
+ GRPCLoggingMockFailingService.rpc_stub_class)
57
+ # The API client should retry this once, then throw an exception which
58
+ # gets propagated through the plugin
59
+ d.emit('message' => log_entry(0))
60
+ begin
61
+ d.run
62
+ rescue GRPC::Cancelled => error
63
+ assert_equal "GRPC::#{message}", error.message
64
+ exception_count += 1
65
+ rescue GRPC::BadStatus => error
66
+ assert_equal "#{code}:#{message}", error.message
67
+ exception_count += 1
68
+ end
69
+ end
70
+ assert_equal 1, @failed_attempts.size, "Index #{index} failed."
71
+ assert_equal 1, exception_count, "Index #{index} failed."
72
+ end
73
+ end
74
+
75
+ # This test looks similar between the grpc and non-grpc paths except that when
76
+ # parsing "105", the grpc path responds with "DEBUG", while the non-grpc path
77
+ # responds with "100".
78
+ #
79
+ # TODO(lingshi) consolidate the tests between the grpc path and the non-grpc
80
+ # path, or at least split into two tests, one with string severities and one
81
+ # with numeric severities.
82
+ def test_severities
83
+ setup_gce_metadata_stubs
84
+ expected_severity = []
85
+ emit_index = 0
86
+ setup_logging_stubs do
87
+ d = create_driver
88
+ # Array of pairs of [parsed_severity, expected_severity]
89
+ [%w(INFO INFO), %w(warn WARNING), %w(E ERROR), %w(BLAH DEFAULT),
90
+ %w(105 DEBUG), ['', 'DEFAULT']].each do |sev|
91
+ d.emit('message' => log_entry(emit_index), 'severity' => sev[0])
92
+ expected_severity.push(sev[1])
93
+ emit_index += 1
94
+ end
95
+ d.run
96
+ end
97
+ verify_index = 0
98
+ verify_log_entries(emit_index, COMPUTE_PARAMS) do |entry|
99
+ assert_equal_with_default(entry['metadata']['severity'],
100
+ expected_severity[verify_index],
101
+ 'DEFAULT', entry)
102
+ verify_index += 1
103
+ end
104
+ end
105
+
106
+ private
107
+
108
+ GRPC_MOCK_HOST = 'localhost:56789'
109
+
110
+ WriteLogEntriesRequest = Google::Logging::V1::WriteLogEntriesRequest
111
+ WriteLogEntriesResponse = Google::Logging::V1::WriteLogEntriesResponse
112
+
113
+ USE_GRPC_CONFIG = %(
114
+ use_grpc true
115
+ )
116
+
117
+ # The non-grpc path has a unique field 'validatedWithOriginServer', while
118
+ # the grpc path has a unique field 'cacheValidatedWithOriginServer'.
119
+ HTTP_REQUEST_MESSAGE = {
120
+ 'requestMethod' => 'POST',
121
+ 'requestUrl' => 'http://example/',
122
+ 'requestSize' => 210,
123
+ 'status' => 200,
124
+ 'responseSize' => 65,
125
+ 'userAgent' => 'USER AGENT 1.0',
126
+ 'remoteIp' => '55.55.55.55',
127
+ 'referer' => 'http://referer/',
128
+ 'cacheHit' => true,
129
+ 'cacheValidatedWithOriginServer' => true
130
+ }
131
+
132
+ # In the non-grpc path 'referer' is nil, while in the grpc path 'referer' is
133
+ # absent.
134
+ HTTP_REQUEST_MESSAGE_WITHOUT_REFERER = HTTP_REQUEST_MESSAGE.reject do |k, _|
135
+ k == 'referer'
136
+ end
137
+
138
+ # Create a Fluentd output test driver with the Google Cloud Output plugin with
139
+ # grpc enabled. The signature of this method is different between the grpc
140
+ # path and the non-grpc path. For grpc, an additional grpc stub class can be
141
+ # passed in to construct the mock used by the test driver.
142
+ def create_driver(conf = APPLICATION_DEFAULT_CONFIG, tag = 'test',
143
+ grpc_stub = GRPCLoggingMockService.rpc_stub_class)
144
+ conf += USE_GRPC_CONFIG
145
+ Fluent::Test::BufferedOutputTestDriver.new(
146
+ GoogleCloudOutputWithGRPCMock.new(grpc_stub), tag).configure(conf, true)
147
+ end
148
+
149
+ # Google Cloud Fluent output stub with grpc mock.
150
+ class GoogleCloudOutputWithGRPCMock < Fluent::GoogleCloudOutput
151
+ def initialize(grpc_stub)
152
+ super()
153
+ @grpc_stub = grpc_stub
154
+ end
155
+
156
+ def api_client
157
+ ssl_creds = GRPC::Core::ChannelCredentials.new
158
+ authentication = Google::Auth.get_application_default
159
+ creds = GRPC::Core::CallCredentials.new(authentication.updater_proc)
160
+ ssl_creds.compose(creds)
161
+
162
+ # Here we have obtained the creds, but for the mock, we will leave the
163
+ # channel insecure.
164
+ @grpc_stub.new(GRPC_MOCK_HOST, :this_channel_is_insecure)
165
+ end
166
+ end
167
+
168
+ # GRPC logging mock that successfully logs the records.
169
+ class GRPCLoggingMockService < Google::Logging::V1::LoggingService::Service
170
+ def initialize(requests_received)
171
+ super()
172
+ @requests_received = requests_received
173
+ end
174
+
175
+ def write_log_entries(request, _call)
176
+ @requests_received << request
177
+ WriteLogEntriesResponse.new
178
+ end
179
+
180
+ # TODO(lingshi) Remove these dummy methods when grpc/9033 is fixed.
181
+ #
182
+ # These methods should never be called, so they will just fail the tests
183
+ # with "unimplemented" errors..
184
+ def _undefined
185
+ fail "Method #{__callee__} is unimplemented and needs to be overridden."
186
+ end
187
+
188
+ alias_method :list_logs, :_undefined
189
+ alias_method :list_log_services, :_undefined
190
+ alias_method :list_log_service_indexes, :_undefined
191
+ alias_method :delete_log, :_undefined
192
+ undef_method :_undefined
193
+ end
194
+
195
+ # GRPC logging mock that fails and returns server side or client side errors.
196
+ class GRPCLoggingMockFailingService <
197
+ Google::Logging::V1::LoggingService::Service
198
+ # 'code_sent' and 'message_sent' are references of external variables. We
199
+ # will assert the values of them later. 'code_value' and 'message_value'
200
+ # are actual error code and message we expect this mock to return.
201
+ def initialize(code, message, failed_attempts)
202
+ @code = code
203
+ @message = message
204
+ @failed_attempts = failed_attempts
205
+ super()
206
+ end
207
+
208
+ def write_log_entries(_request, _call)
209
+ @failed_attempts << 1
210
+ fail GRPC::BadStatus.new(@code, @message)
211
+ end
212
+
213
+ # TODO(lingshi) Remove these dummy methods when grpc/9033 is fixed.
214
+ #
215
+ # These methods should never be called, so they will just fail the tests
216
+ # with "unimplemented" errors..
217
+ def _undefined
218
+ fail "Method #{__callee__} is unimplemented and needs to be overridden."
219
+ end
220
+
221
+ alias_method :list_logs, :_undefined
222
+ alias_method :list_log_services, :_undefined
223
+ alias_method :list_log_service_indexes, :_undefined
224
+ alias_method :delete_log, :_undefined
225
+ undef_method :_undefined
226
+ end
227
+
228
+ # Set up grpc stubs to mock the external calls.
229
+ def setup_logging_stubs(should_fail = false, code = 0, message = 'Ok')
230
+ srv = GRPC::RpcServer.new
231
+ @failed_attempts = []
232
+ @requests_sent = []
233
+ if should_fail
234
+ grpc = GRPCLoggingMockFailingService.new(code, message, @failed_attempts)
235
+ else
236
+ grpc = GRPCLoggingMockService.new(@requests_sent)
237
+ end
238
+ srv.handle(grpc)
239
+ srv.add_http2_port(GRPC_MOCK_HOST, :this_port_is_insecure)
240
+ t = Thread.new { srv.run }
241
+ srv.wait_till_running
242
+ begin
243
+ yield
244
+ rescue Test::Unit::Failure, StandardError => e
245
+ srv.stop
246
+ t.join
247
+ raise e
248
+ end
249
+ srv.stop
250
+ t.join
251
+ end
252
+
253
+ # Verify the number and the content of the log entries match the expectation.
254
+ # The caller can optionally provide a block which is called for each entry.
255
+ def verify_log_entries(n, params, payload_type = 'textPayload', &block)
256
+ @requests_sent.each do |batch|
257
+ @logs_sent << JSON.parse(batch.to_json)
258
+ end
259
+ verify_json_log_entries(n, params, payload_type, &block)
260
+ end
261
+
262
+ # For an optional field with default values, Protobuf omits the field when it
263
+ # is deserialized to json. So we need to add an extra check for gRPC which
264
+ # uses Protobuf.
265
+ #
266
+ # An optional block can be passed in if we need to assert something other than
267
+ # a plain equal. e.g. assert_in_delta.
268
+ def assert_equal_with_default(field, expected_value, default_value, entry)
269
+ if expected_value == default_value
270
+ assert_nil field
271
+ elsif block_given?
272
+ yield
273
+ else
274
+ assert_equal expected_value, field, entry
275
+ end
276
+ end
277
+
278
+ # A wrapper around the constant HTTP_REQUEST_MESSAGE, so the definition can be
279
+ # skipped in the shared module and defined here.
280
+ def http_request_message
281
+ HTTP_REQUEST_MESSAGE
282
+ end
283
+
284
+ # A wrapper around the constant HTTP_REQUEST_MESSAGE_WITHOUT_REFERER, so the
285
+ # definition can be skipped in the shared module and defined here.
286
+ def http_request_message_without_referer
287
+ HTTP_REQUEST_MESSAGE_WITHOUT_REFERER
288
+ end
289
+
290
+ # Get the fields of the struct payload.
291
+ def get_fields(struct_payload)
292
+ struct_payload['fields']
293
+ end
294
+
295
+ # Get the value of a struct field.
296
+ def get_struct(field)
297
+ field['structValue']
298
+ end
299
+
300
+ # Get the value of a string field.
301
+ def get_string(field)
302
+ field['stringValue']
303
+ end
304
+
305
+ # Get the value of a number field.
306
+ def get_number(field)
307
+ field['numberValue']
308
+ end
309
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-google-cloud
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.3.grpc.alpha.3
4
+ version: 0.5.3.grpc.alpha.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Todd Derr
@@ -9,170 +9,164 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-11-09 00:00:00.000000000 Z
12
+ date: 2016-12-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: fluentd
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - ~>
18
+ - - "~>"
19
19
  - !ruby/object:Gem::Version
20
20
  version: '0.10'
21
- - - <=
22
- - !ruby/object:Gem::Version
23
- version: '0.13'
24
21
  type: :runtime
25
22
  prerelease: false
26
23
  version_requirements: !ruby/object:Gem::Requirement
27
24
  requirements:
28
- - - ~>
25
+ - - "~>"
29
26
  - !ruby/object:Gem::Version
30
27
  version: '0.10'
31
- - - <=
32
- - !ruby/object:Gem::Version
33
- version: '0.13'
34
28
  - !ruby/object:Gem::Dependency
35
29
  name: googleapis-common-protos
36
30
  requirement: !ruby/object:Gem::Requirement
37
31
  requirements:
38
- - - ~>
32
+ - - "~>"
39
33
  - !ruby/object:Gem::Version
40
34
  version: '1.3'
41
35
  type: :runtime
42
36
  prerelease: false
43
37
  version_requirements: !ruby/object:Gem::Requirement
44
38
  requirements:
45
- - - ~>
39
+ - - "~>"
46
40
  - !ruby/object:Gem::Version
47
41
  version: '1.3'
48
42
  - !ruby/object:Gem::Dependency
49
43
  name: google-api-client
50
44
  requirement: !ruby/object:Gem::Requirement
51
45
  requirements:
52
- - - '>'
46
+ - - ">"
53
47
  - !ruby/object:Gem::Version
54
48
  version: '0.9'
55
49
  type: :runtime
56
50
  prerelease: false
57
51
  version_requirements: !ruby/object:Gem::Requirement
58
52
  requirements:
59
- - - '>'
53
+ - - ">"
60
54
  - !ruby/object:Gem::Version
61
55
  version: '0.9'
62
56
  - !ruby/object:Gem::Dependency
63
57
  name: googleauth
64
58
  requirement: !ruby/object:Gem::Requirement
65
59
  requirements:
66
- - - ~>
60
+ - - "~>"
67
61
  - !ruby/object:Gem::Version
68
62
  version: '0.4'
69
63
  type: :runtime
70
64
  prerelease: false
71
65
  version_requirements: !ruby/object:Gem::Requirement
72
66
  requirements:
73
- - - ~>
67
+ - - "~>"
74
68
  - !ruby/object:Gem::Version
75
69
  version: '0.4'
76
70
  - !ruby/object:Gem::Dependency
77
71
  name: grpc
78
72
  requirement: !ruby/object:Gem::Requirement
79
73
  requirements:
80
- - - ~>
74
+ - - "~>"
81
75
  - !ruby/object:Gem::Version
82
76
  version: '1.0'
83
77
  type: :runtime
84
78
  prerelease: false
85
79
  version_requirements: !ruby/object:Gem::Requirement
86
80
  requirements:
87
- - - ~>
81
+ - - "~>"
88
82
  - !ruby/object:Gem::Version
89
83
  version: '1.0'
90
84
  - !ruby/object:Gem::Dependency
91
85
  name: json
92
86
  requirement: !ruby/object:Gem::Requirement
93
87
  requirements:
94
- - - ~>
88
+ - - "~>"
95
89
  - !ruby/object:Gem::Version
96
90
  version: '1.8'
97
91
  type: :runtime
98
92
  prerelease: false
99
93
  version_requirements: !ruby/object:Gem::Requirement
100
94
  requirements:
101
- - - ~>
95
+ - - "~>"
102
96
  - !ruby/object:Gem::Version
103
97
  version: '1.8'
104
98
  - !ruby/object:Gem::Dependency
105
99
  name: mocha
106
100
  requirement: !ruby/object:Gem::Requirement
107
101
  requirements:
108
- - - ~>
102
+ - - "~>"
109
103
  - !ruby/object:Gem::Version
110
104
  version: '1.1'
111
105
  type: :development
112
106
  prerelease: false
113
107
  version_requirements: !ruby/object:Gem::Requirement
114
108
  requirements:
115
- - - ~>
109
+ - - "~>"
116
110
  - !ruby/object:Gem::Version
117
111
  version: '1.1'
118
112
  - !ruby/object:Gem::Dependency
119
113
  name: rake
120
114
  requirement: !ruby/object:Gem::Requirement
121
115
  requirements:
122
- - - ~>
116
+ - - "~>"
123
117
  - !ruby/object:Gem::Version
124
118
  version: '10.3'
125
119
  type: :development
126
120
  prerelease: false
127
121
  version_requirements: !ruby/object:Gem::Requirement
128
122
  requirements:
129
- - - ~>
123
+ - - "~>"
130
124
  - !ruby/object:Gem::Version
131
125
  version: '10.3'
132
126
  - !ruby/object:Gem::Dependency
133
127
  name: rubocop
134
128
  requirement: !ruby/object:Gem::Requirement
135
129
  requirements:
136
- - - '='
130
+ - - "~>"
137
131
  - !ruby/object:Gem::Version
138
132
  version: 0.35.0
139
133
  type: :development
140
134
  prerelease: false
141
135
  version_requirements: !ruby/object:Gem::Requirement
142
136
  requirements:
143
- - - '='
137
+ - - "~>"
144
138
  - !ruby/object:Gem::Version
145
139
  version: 0.35.0
146
140
  - !ruby/object:Gem::Dependency
147
141
  name: webmock
148
142
  requirement: !ruby/object:Gem::Requirement
149
143
  requirements:
150
- - - ~>
144
+ - - "~>"
151
145
  - !ruby/object:Gem::Version
152
146
  version: '1.17'
153
147
  type: :development
154
148
  prerelease: false
155
149
  version_requirements: !ruby/object:Gem::Requirement
156
150
  requirements:
157
- - - ~>
151
+ - - "~>"
158
152
  - !ruby/object:Gem::Version
159
153
  version: '1.17'
160
154
  - !ruby/object:Gem::Dependency
161
155
  name: test-unit
162
156
  requirement: !ruby/object:Gem::Requirement
163
157
  requirements:
164
- - - ~>
158
+ - - "~>"
165
159
  - !ruby/object:Gem::Version
166
160
  version: '3.0'
167
161
  type: :development
168
162
  prerelease: false
169
163
  version_requirements: !ruby/object:Gem::Requirement
170
164
  requirements:
171
- - - ~>
165
+ - - "~>"
172
166
  - !ruby/object:Gem::Version
173
167
  version: '3.0'
174
168
  description: |2
175
- Fluentd output plugin for the Google Cloud Logging API, which will make
169
+ Fluentd output plugin for the Stackdriver Logging API, which will make
176
170
  logs viewable in the Developer Console's log viewer and can optionally
177
171
  store them in Google Cloud Storage and/or BigQuery.
178
172
  This is an official Google Ruby gem.
@@ -184,7 +178,6 @@ extra_rdoc_files: []
184
178
  files:
185
179
  - CONTRIBUTING
186
180
  - Gemfile
187
- - Gemfile.lock
188
181
  - LICENSE
189
182
  - README.rdoc
190
183
  - Rakefile
@@ -196,11 +189,13 @@ files:
196
189
  - lib/google/logging/v1/logging_pb.rb
197
190
  - lib/google/logging/v1/logging_services_pb.rb
198
191
  - test/helper.rb
192
+ - test/plugin/base_test.rb
199
193
  - test/plugin/data/c31e573fd7f62ed495c9ca3821a5a85cb036dee1-privatekey.p12
200
194
  - test/plugin/data/credentials.json
201
195
  - test/plugin/data/iam-credentials.json
202
196
  - test/plugin/data/invalid_credentials.json
203
197
  - test/plugin/test_out_google_cloud.rb
198
+ - test/plugin/test_out_google_cloud_grpc.rb
204
199
  homepage: https://github.com/GoogleCloudPlatform/fluent-plugin-google-cloud
205
200
  licenses:
206
201
  - Apache-2.0
@@ -211,12 +206,12 @@ require_paths:
211
206
  - lib
212
207
  required_ruby_version: !ruby/object:Gem::Requirement
213
208
  requirements:
214
- - - '>='
209
+ - - ">="
215
210
  - !ruby/object:Gem::Version
216
211
  version: '2.0'
217
212
  required_rubygems_version: !ruby/object:Gem::Requirement
218
213
  requirements:
219
- - - '>'
214
+ - - ">"
220
215
  - !ruby/object:Gem::Version
221
216
  version: 1.3.1
222
217
  requirements: []
@@ -224,11 +219,13 @@ rubyforge_project:
224
219
  rubygems_version: 2.4.8
225
220
  signing_key:
226
221
  specification_version: 4
227
- summary: fluentd output plugin for the Google Cloud Logging API
222
+ summary: fluentd output plugin for the Stackdriver Logging API
228
223
  test_files:
229
224
  - test/helper.rb
225
+ - test/plugin/base_test.rb
230
226
  - test/plugin/data/c31e573fd7f62ed495c9ca3821a5a85cb036dee1-privatekey.p12
231
227
  - test/plugin/data/credentials.json
232
228
  - test/plugin/data/iam-credentials.json
233
229
  - test/plugin/data/invalid_credentials.json
234
230
  - test/plugin/test_out_google_cloud.rb
231
+ - test/plugin/test_out_google_cloud_grpc.rb