google-gax 0.8.6 → 0.9.0

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: f71e32189b1fb624d4eea6c700022151e4e94134
4
- data.tar.gz: 5885fdf6ce17d16932c891b3677cf60a6b30f574
3
+ metadata.gz: fddb2e602722db6f4c4aa081c4660a6a3291214c
4
+ data.tar.gz: 6be83a2a050318833068ccef972ae886668a5484
5
5
  SHA512:
6
- metadata.gz: 251e5b49190d51b23dca1350d45300687ec8b41c632df5f62198385223f25f7391f828cc5475d7ccd15847b0245128cab5b919494bb9fc6a5cbfc6671eb63a16
7
- data.tar.gz: f8a733a59af40210710c1e1661fc5ef88692178799b37fe5d8f404e120159a461e8cf68a28fb69877dced9190a4cd8c07e965b11707083530574563bbcf0c063
6
+ metadata.gz: 7d6f35c2dcc528491d6a58dd6bf32813708995b20317363cc3eea067ae2358ffdb76da2809a4f12cb1968a1c2361c7cc6235a271c63dcb67e315fbff1a1a9de4
7
+ data.tar.gz: b9e48955378a15a297f967334ed6d7ff629a0a983acfc7e7e61b25bf6e58d87b7340717585aebe70f234973a86b2e86c79fbb1e4fd445f2dea2b010c0a6dfb19
@@ -32,8 +32,6 @@ require 'time'
32
32
  require 'google/gax/errors'
33
33
  require 'google/gax/bundling'
34
34
 
35
- # rubocop:disable Metrics/ModuleLength
36
-
37
35
  module Google
38
36
  module Gax
39
37
  # A class to provide the Enumerable interface for page-streaming method.
@@ -246,21 +244,9 @@ module Google
246
244
  add_timeout_arg(func, this_settings.timeout,
247
245
  this_settings.kwargs)
248
246
  end
249
- api_call = catch_errors(api_call, settings.errors)
250
- api_caller.call(api_call, request, this_settings)
251
- end
252
- end
253
-
254
- # Updates a_func to wrap exceptions with GaxError
255
- #
256
- # @param a_func [Proc]
257
- # @param errors [Array<Exception>] Configures the exceptions to wrap.
258
- # @return [Proc] A proc that will wrap certain exceptions with GaxError.
259
- def catch_errors(a_func, errors)
260
- proc do |request|
261
247
  begin
262
- a_func.call(request)
263
- rescue *errors
248
+ api_caller.call(api_call, request, this_settings)
249
+ rescue *settings.errors
264
250
  raise GaxError, 'RPC failed'
265
251
  end
266
252
  end
@@ -312,8 +298,6 @@ module Google
312
298
  enumerable.method(:start)
313
299
  end
314
300
 
315
- # rubocop:disable Metrics/MethodLength
316
-
317
301
  # Creates a proc equivalent to a_func, but that retries on certain
318
302
  # exceptions.
319
303
  #
@@ -336,29 +320,24 @@ module Google
336
320
  delay = retry_options.backoff_settings.initial_retry_delay_millis
337
321
  timeout = (retry_options.backoff_settings.initial_rpc_timeout_millis /
338
322
  MILLIS_PER_SECOND)
339
- result = nil
340
- now = Time.now
341
- deadline = now + total_timeout
342
- loop do
343
- begin
344
- result = add_timeout_arg(a_func, timeout, kwargs).call(request)
345
- break
346
- rescue => exception
347
- unless exception.respond_to?(:code) &&
348
- retry_options.retry_codes.include?(exception.code)
349
- raise RetryError, 'Exception occurred in retry method that ' \
350
- 'was not classified as transient'
351
- end
352
- sleep(rand(delay) / MILLIS_PER_SECOND)
353
- now = Time.now
354
- delay = [delay * delay_mult, max_delay].min
355
- timeout = [timeout * timeout_mult, max_timeout, deadline - now].min
356
- if now >= deadline
357
- raise RetryError, 'Retry total timeout exceeded with exception'
358
- end
323
+ deadline = Time.now + total_timeout
324
+ begin
325
+ a_func.call(request, deadline: Time.now + timeout, metadata: kwargs)
326
+ rescue => exception
327
+ unless exception.respond_to?(:code) &&
328
+ retry_options.retry_codes.include?(exception.code)
329
+ raise RetryError, 'Exception occurred in retry method that ' \
330
+ 'was not classified as transient'
331
+ end
332
+ sleep(rand(delay) / MILLIS_PER_SECOND)
333
+ now = Time.now
334
+ delay = [delay * delay_mult, max_delay].min
335
+ timeout = [timeout * timeout_mult, max_timeout, deadline - now].min
336
+ if now >= deadline
337
+ raise RetryError, 'Retry total timeout exceeded with exception'
359
338
  end
339
+ retry
360
340
  end
361
- result
362
341
  end
363
342
  end
364
343
 
@@ -377,9 +356,9 @@ module Google
377
356
  end
378
357
  end
379
358
 
380
- module_function :create_api_call, :catch_errors, :bundleable,
359
+ module_function :create_api_call, :bundleable,
381
360
  :page_streamable, :retryable, :add_timeout_arg
382
- private_class_method :catch_errors, :bundleable, :page_streamable,
361
+ private_class_method :bundleable, :page_streamable,
383
362
  :retryable, :add_timeout_arg
384
363
  end
385
364
  end
@@ -29,16 +29,21 @@
29
29
 
30
30
  require 'English'
31
31
 
32
+ require 'google/gax/grpc'
33
+
32
34
  module Google
33
35
  module Gax
34
36
  # Common base class for exceptions raised by GAX.
35
37
  class GaxError < StandardError
38
+ attr_reader :details
39
+
36
40
  # @param msg [String] describes the error that occurred.
37
41
  def initialize(msg)
38
42
  msg = "GaxError #{msg}"
39
43
  msg += ", caused by #{$ERROR_INFO}" if $ERROR_INFO
40
44
  super(msg)
41
45
  @cause = $ERROR_INFO
46
+ @details = Google::Gax::Grpc.deserialize_error_status_details(@cause)
42
47
  end
43
48
 
44
49
  # cause is a new method introduced in 2.1.0, bring this
@@ -28,8 +28,12 @@
28
28
  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
29
 
30
30
  require 'grpc'
31
+ require 'grpc/google_rpc_status_utils'
31
32
  require 'googleauth'
32
33
  require 'google/gax/errors'
34
+ require 'google/protobuf/well_known_types'
35
+ # Required in order to deserialize common error detail proto types
36
+ require 'google/rpc/error_details_pb'
33
37
 
34
38
  module Google
35
39
  module Gax
@@ -43,6 +47,35 @@ module Google
43
47
 
44
48
  API_ERRORS = [GRPC::BadStatus, GRPC::Cancelled].freeze
45
49
 
50
+ def deserialize_error_status_details(error)
51
+ return unless error.is_a? GRPC::BadStatus
52
+ # If error status is malformed, swallow the gRPC error that gets raised.
53
+ begin
54
+ details =
55
+ GRPC::GoogleRpcStatusUtils.extract_google_rpc_status(
56
+ error.to_status
57
+ ).details
58
+ rescue
59
+ return 'Could not parse error details due to a malformed server '\
60
+ 'response trailer.'
61
+ end
62
+ return if details.nil?
63
+ details =
64
+ GRPC::GoogleRpcStatusUtils.extract_google_rpc_status(
65
+ error.to_status
66
+ ).details
67
+ details.map do |any|
68
+ # If the type of the proto wrapped by the Any instance is not
69
+ # available, do not deserialize.
70
+ candidate_class_name = class_case(any.type_name.split('.')).join('::')
71
+ begin
72
+ any.unpack(Object.const_get(candidate_class_name))
73
+ rescue NameError
74
+ any
75
+ end
76
+ end
77
+ end
78
+
46
79
  # rubocop:disable Metrics/ParameterLists
47
80
 
48
81
  # Creates a gRPC client stub.
@@ -97,7 +130,7 @@ module Google
97
130
  end
98
131
  end
99
132
 
100
- module_function :create_stub
133
+ module_function :create_stub, :deserialize_error_status_details
101
134
 
102
135
  def self.verify_params(channel, chan_creds, updater_proc)
103
136
  if (channel && chan_creds) ||
@@ -109,7 +142,15 @@ module Google
109
142
  end
110
143
  end
111
144
 
112
- private_class_method :verify_params
145
+ # Capitalize all modules except the message class, which is already
146
+ # correctly cased
147
+ def self.class_case(modules)
148
+ message = modules.pop
149
+ modules = modules.map(&:capitalize)
150
+ modules << message
151
+ end
152
+
153
+ private_class_method :verify_params, :class_case
113
154
  end
114
155
  end
115
156
  end
@@ -42,12 +42,21 @@ module Google
42
42
  # messages using hashes but does not allow for nested hashes to instantiate
43
43
  # nested submessages.
44
44
  #
45
- # @param hash [Hash] The hash to be converted into a proto message.
45
+ # @param hash [Hash || Class] The hash to be converted into a proto message.
46
+ # If an instance of the proto message class is given, it is returned
47
+ # unchanged.
46
48
  # @param message_class [Class] The corresponding protobuf message class of
47
49
  # the given hash.
48
50
  #
49
51
  # @return [Object] An instance of the given message class.
50
52
  def to_proto(hash, message_class)
53
+ return hash if hash.is_a? message_class
54
+
55
+ # Sanity check: input must be a Hash
56
+ unless hash.is_a? Hash
57
+ raise ArgumentError,
58
+ "Value #{hash} must be a Hash or a #{message_class.name}"
59
+ end
51
60
  hash = coerce_submessages(hash, message_class)
52
61
  message_class.new(hash)
53
62
  end
@@ -29,6 +29,6 @@
29
29
 
30
30
  module Google
31
31
  module Gax
32
- VERSION = '0.8.6'.freeze
32
+ VERSION = '0.9.0'.freeze
33
33
  end
34
34
  end
data/lib/google/gax.rb CHANGED
@@ -29,7 +29,6 @@
29
29
 
30
30
  require 'google/gax/api_callable'
31
31
  require 'google/gax/constants'
32
- require 'google/gax/credentials'
33
32
  require 'google/gax/errors'
34
33
  require 'google/gax/path_template'
35
34
  require 'google/gax/settings'
@@ -40,6 +40,7 @@ require "json"
40
40
  require "pathname"
41
41
 
42
42
  require "google/gax"
43
+ require "googleauth"
43
44
 
44
45
  require "google/longrunning/operations_pb"
45
46
 
@@ -82,15 +83,10 @@ module Google
82
83
  ALL_SCOPES = [
83
84
  ].freeze
84
85
 
85
- # @param service_path [String]
86
- # The domain name of the API remote host.
87
- # @param port [Integer]
88
- # The port on which to connect to the remote host.
89
- # @param credentials
90
- # [Google::Gax::Credentials, String, Hash, GRPC::Core::Channel, GRPC::Core::ChannelCredentials, Proc]
86
+ # @param credentials [Google::Auth::Credentials, String, Hash, GRPC::Core::Channel, GRPC::Core::ChannelCredentials, Proc]
91
87
  # Provides the means for authenticating requests made by the client. This parameter can
92
88
  # be many types.
93
- # A `Google::Gax::Credentials` uses a the properties of its represented keyfile for
89
+ # A `Google::Auth::Credentials` uses a the properties of its represented keyfile for
94
90
  # authenticating requests made by this client.
95
91
  # A `String` will be treated as the path to the keyfile to be used for the construction of
96
92
  # credentials for this client.
@@ -104,7 +100,7 @@ module Google
104
100
  # @param scopes [Array<String>]
105
101
  # The OAuth scopes for this service. This parameter is ignored if
106
102
  # an updater_proc is supplied.
107
- # @param client_config[Hash]
103
+ # @param client_config [Hash]
108
104
  # A Hash for call options for each method. See
109
105
  # Google::Gax#construct_settings for the structure of
110
106
  # this data. Falls back to the default config if not specified
@@ -121,8 +117,6 @@ module Google
121
117
  scopes: ALL_SCOPES,
122
118
  client_config: {},
123
119
  timeout: DEFAULT_TIMEOUT,
124
- app_name: nil,
125
- app_version: nil,
126
120
  lib_name: nil,
127
121
  lib_version: ""
128
122
  # These require statements are intentionally placed here to initialize
@@ -138,14 +132,14 @@ module Google
138
132
  credentials ||= chan_creds
139
133
  credentials ||= updater_proc
140
134
  end
141
- if app_name || app_version
142
- warn "`app_name` and `app_version` are no longer being used in the request headers."
135
+ if service_path != SERVICE_ADDRESS || port != DEFAULT_SERVICE_PORT
136
+ warn "`service_path` and `port` parameters are deprecated and will be removed"
143
137
  end
144
138
 
145
- credentials ||= Google::Gax::Credentials.default
139
+ credentials ||= Google::Auth::Credentials.default(scopes: scopes)
146
140
 
147
141
  if credentials.is_a?(String) || credentials.is_a?(Hash)
148
- updater_proc = Google::Gax::Credentials.new(credentials).updater_proc
142
+ updater_proc = Google::Auth::Credentials.new(credentials).updater_proc
149
143
  end
150
144
  if credentials.is_a?(GRPC::Core::Channel)
151
145
  channel = credentials
@@ -156,7 +150,7 @@ module Google
156
150
  if credentials.is_a?(Proc)
157
151
  updater_proc = credentials
158
152
  end
159
- if credentials.is_a?(Google::Gax::Credentials)
153
+ if credentials.is_a?(Google::Auth::Credentials)
160
154
  updater_proc = credentials.updater_proc
161
155
  end
162
156
 
@@ -114,4 +114,37 @@ describe Google::Gax::Grpc do
114
114
  end.to raise_error(ArgumentError)
115
115
  end
116
116
  end
117
+ describe '#deserialize_error_status_details' do
118
+ it 'deserializes a known error type' do
119
+ expected_error = Google::Rpc::DebugInfo.new(detail: 'shoes are untied')
120
+
121
+ any = Google::Protobuf::Any.new
122
+ any.pack(expected_error)
123
+ status = Google::Rpc::Status.new(details: [any])
124
+ encoded = Google::Rpc::Status.encode(status)
125
+ metadata = {
126
+ 'grpc-status-details-bin' => encoded
127
+ }
128
+ error = GRPC::BadStatus.new(1, '', metadata)
129
+
130
+ expect(Google::Gax::Grpc.deserialize_error_status_details(error))
131
+ .to eq [expected_error]
132
+ end
133
+ it 'does not deserialize an unknown error type' do
134
+ expected_error = Random.new.bytes(8)
135
+
136
+ any = Google::Protobuf::Any.new(
137
+ type_url: 'unknown-type', value: expected_error
138
+ )
139
+ status = Google::Rpc::Status.new(details: [any])
140
+ encoded = Google::Rpc::Status.encode(status)
141
+ metadata = {
142
+ 'grpc-status-details-bin' => encoded
143
+ }
144
+ error = GRPC::BadStatus.new(1, '', metadata)
145
+
146
+ expect(Google::Gax::Grpc.deserialize_error_status_details(error))
147
+ .to eq [any]
148
+ end
149
+ end
117
150
  end
@@ -28,6 +28,7 @@
28
28
  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
29
 
30
30
  require 'google/gax'
31
+ require 'google/protobuf/any_pb'
31
32
  require 'spec/fixtures/fixture_pb'
32
33
 
33
34
  describe Google::Gax do
@@ -118,5 +119,20 @@ describe Google::Gax do
118
119
  Google::Gax.to_proto(user_hash, Google::Protobuf::User)
119
120
  end.to raise_error(ArgumentError)
120
121
  end
122
+
123
+ it 'handles proto messages' do
124
+ user_message = Google::Protobuf::User.new(
125
+ name: USER_NAME, type: USER_TYPE
126
+ )
127
+ user = Google::Gax.to_proto(user_message, Google::Protobuf::User)
128
+ expect(user).to eq user_message
129
+ end
130
+
131
+ it 'fails if proto message has unexpected type' do
132
+ user_message = Google::Protobuf::Any
133
+ expect do
134
+ Google::Gax.to_proto(user_message, Google::Protobuf::User)
135
+ end.to raise_error(ArgumentError)
136
+ end
121
137
  end
122
138
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: google-gax
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.6
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Google API Authors
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-08-15 00:00:00.000000000 Z
11
+ date: 2017-11-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: googleauth
@@ -16,42 +16,54 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.5.1
19
+ version: 0.6.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.5.1
26
+ version: 0.6.1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: grpc
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.7.2
34
+ - - "<"
32
35
  - !ruby/object:Gem::Version
33
- version: '1.0'
36
+ version: '2.0'
34
37
  type: :runtime
35
38
  prerelease: false
36
39
  version_requirements: !ruby/object:Gem::Requirement
37
40
  requirements:
38
- - - "~>"
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 1.7.2
44
+ - - "<"
39
45
  - !ruby/object:Gem::Version
40
- version: '1.0'
46
+ version: '2.0'
41
47
  - !ruby/object:Gem::Dependency
42
48
  name: googleapis-common-protos
43
49
  requirement: !ruby/object:Gem::Requirement
44
50
  requirements:
45
- - - "~>"
51
+ - - ">="
46
52
  - !ruby/object:Gem::Version
47
53
  version: 1.3.5
54
+ - - "<"
55
+ - !ruby/object:Gem::Version
56
+ version: '2.0'
48
57
  type: :runtime
49
58
  prerelease: false
50
59
  version_requirements: !ruby/object:Gem::Requirement
51
60
  requirements:
52
- - - "~>"
61
+ - - ">="
53
62
  - !ruby/object:Gem::Version
54
63
  version: 1.3.5
64
+ - - "<"
65
+ - !ruby/object:Gem::Version
66
+ version: '2.0'
55
67
  - !ruby/object:Gem::Dependency
56
68
  name: google-protobuf
57
69
  requirement: !ruby/object:Gem::Requirement
@@ -162,7 +174,6 @@ files:
162
174
  - lib/google/gax/api_callable.rb
163
175
  - lib/google/gax/bundling.rb
164
176
  - lib/google/gax/constants.rb
165
- - lib/google/gax/credentials.rb
166
177
  - lib/google/gax/errors.rb
167
178
  - lib/google/gax/grpc.rb
168
179
  - lib/google/gax/operation.rb
@@ -176,7 +187,6 @@ files:
176
187
  - spec/fixtures/fixture_pb.rb
177
188
  - spec/google/gax/api_callable_spec.rb
178
189
  - spec/google/gax/bundling_spec.rb
179
- - spec/google/gax/credentials_spec.rb
180
190
  - spec/google/gax/grpc_spec.rb
181
191
  - spec/google/gax/operation_spec.rb
182
192
  - spec/google/gax/path_template_spec.rb
@@ -1,150 +0,0 @@
1
- # Copyright 2017, Google Inc.
2
- # All rights reserved.
3
- #
4
- # Redistribution and use in source and binary forms, with or without
5
- # modification, are permitted provided that the following conditions are
6
- # met:
7
- #
8
- # * Redistributions of source code must retain the above copyright
9
- # notice, this list of conditions and the following disclaimer.
10
- # * Redistributions in binary form must reproduce the above
11
- # copyright notice, this list of conditions and the following disclaimer
12
- # in the documentation and/or other materials provided with the
13
- # distribution.
14
- # * Neither the name of Google Inc. nor the names of its
15
- # contributors may be used to endorse or promote products derived from
16
- # this software without specific prior written permission.
17
- #
18
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
- # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
- # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
- # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
- # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
- # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
- # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
- # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
- # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
- # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
- # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
-
30
- require 'forwardable'
31
- require 'googleauth'
32
- require 'json'
33
- require 'signet/oauth_2/client'
34
-
35
- module Google
36
- module Gax
37
- # @private
38
- # Represents the OAuth 2.0 signing logic.
39
- # This class is intended to be inherited by API-specific classes
40
- # which overrides the SCOPE constant.
41
- class Credentials
42
- TOKEN_CREDENTIAL_URI = 'https://accounts.google.com/o/oauth2/token'.freeze
43
- AUDIENCE = 'https://accounts.google.com/o/oauth2/token'.freeze
44
- SCOPE = [].freeze
45
- PATH_ENV_VARS = [].freeze
46
- JSON_ENV_VARS = [].freeze
47
- DEFAULT_PATHS = [].freeze
48
-
49
- attr_accessor :client
50
-
51
- ##
52
- # Delegate client methods to the client object.
53
- extend Forwardable
54
- def_delegators :@client,
55
- :token_credential_uri, :audience,
56
- :scope, :issuer, :signing_key, :updater_proc
57
-
58
- def initialize(keyfile, scope: nil)
59
- verify_keyfile_provided! keyfile
60
- if keyfile.is_a? Signet::OAuth2::Client
61
- @client = keyfile
62
- elsif keyfile.is_a? Hash
63
- hash = stringify_hash_keys keyfile
64
- hash['scope'] ||= scope
65
- @client = init_client hash
66
- else
67
- verify_keyfile_exists! keyfile
68
- json = JSON.parse ::File.read(keyfile)
69
- json['scope'] ||= scope
70
- @client = init_client json
71
- end
72
- @client.fetch_access_token!
73
- end
74
-
75
- ##
76
- # Returns the default credentials.
77
- #
78
- def self.default(scope: nil)
79
- env = ->(v) { ENV[v] }
80
- json = lambda do |v|
81
- unless ENV[v].nil?
82
- begin
83
- JSON.parse ENV[v]
84
- rescue
85
- nil
86
- end
87
- end
88
- end
89
- path = ->(p) { ::File.file? p }
90
-
91
- # First try to find keyfile file from environment variables.
92
- self::PATH_ENV_VARS.map(&env).compact.select(&path)
93
- .each do |file|
94
- return new file, scope: scope
95
- end
96
- # Second try to find keyfile json from environment variables.
97
- self::JSON_ENV_VARS.map(&json).compact.each do |hash|
98
- return new hash, scope: scope
99
- end
100
- # Third try to find keyfile file from known file paths.
101
- self::DEFAULT_PATHS.select(&path).each do |file|
102
- return new file, scope: scope
103
- end
104
- # Finally get instantiated client from Google::Auth.
105
- scope ||= self::SCOPE
106
- client = Google::Auth.get_application_default scope
107
- new client
108
- end
109
-
110
- protected
111
-
112
- # Verify that the keyfile argument is provided.
113
- def verify_keyfile_provided!(keyfile)
114
- return unless keyfile.nil?
115
- raise 'The keyfile passed to Google::Gax::Credentials.new was nil.'
116
- end
117
-
118
- # Verify that the keyfile argument is a file.
119
- def verify_keyfile_exists!(keyfile)
120
- exists = ::File.file? keyfile
121
- raise "The keyfile '#{keyfile}' is not a valid file." unless exists
122
- end
123
-
124
- # Initializes the Signet client.
125
- def init_client(keyfile)
126
- client_opts = client_options keyfile
127
- Signet::OAuth2::Client.new client_opts
128
- end
129
-
130
- # returns a new Hash with string keys instead of symbol keys.
131
- def stringify_hash_keys(hash)
132
- Hash[hash.map { |k, v| [k.to_s, v] }]
133
- end
134
-
135
- def client_options(options)
136
- # Keyfile options have higher priority over constructor defaults
137
- options['token_credential_uri'] ||= self.class::TOKEN_CREDENTIAL_URI
138
- options['audience'] ||= self.class::AUDIENCE
139
- options['scope'] ||= self.class::SCOPE
140
-
141
- # client options for initializing signet client
142
- { token_credential_uri: options['token_credential_uri'],
143
- audience: options['audience'],
144
- scope: Array(options['scope']),
145
- issuer: options['client_email'],
146
- signing_key: OpenSSL::PKey::RSA.new(options['private_key']) }
147
- end
148
- end
149
- end
150
- end
@@ -1,108 +0,0 @@
1
- # Copyright 2017, Google Inc.
2
- # All rights reserved.
3
- #
4
- # Redistribution and use in source and binary forms, with or without
5
- # modification, are permitted provided that the following conditions are
6
- # met:
7
- #
8
- # * Redistributions of source code must retain the above copyright
9
- # notice, this list of conditions and the following disclaimer.
10
- # * Redistributions in binary form must reproduce the above
11
- # copyright notice, this list of conditions and the following disclaimer
12
- # in the documentation and/or other materials provided with the
13
- # distribution.
14
- # * Neither the name of Google Inc. nor the names of its
15
- # contributors may be used to endorse or promote products derived from
16
- # this software without specific prior written permission.
17
- #
18
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
- # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
- # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
- # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
- # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
- # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
- # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
- # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
- # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
- # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
- # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
-
30
- require 'google/gax/credentials'
31
-
32
- # This test is testing the private class Google::Gax::Credentials. We want to
33
- # make sure that the passed in scope propogates to the Signet object. This means
34
- # testing the private API, which is generally frowned on.
35
- describe Google::Gax::Credentials, :private do
36
- let(:default_keyfile_hash) do
37
- {
38
- 'private_key_id' => 'testabc1234567890xyz',
39
- 'private_key' => "-----BEGIN RSA PRIVATE KEY-----\nMIIBOwIBAAJBAOyi0Hy1l4Ym2m2o71Q0TF4O9E81isZEsX0bb+Bqz1SXEaSxLiXM\nUZE8wu0eEXivXuZg6QVCW/5l+f2+9UPrdNUCAwEAAQJAJkqubA/Chj3RSL92guy3\nktzeodarLyw8gF8pOmpuRGSiEo/OLTeRUMKKD1/kX4f9sxf3qDhB4e7dulXR1co/\nIQIhAPx8kMW4XTTL6lJYd2K5GrH8uBMp8qL5ya3/XHrBgw3dAiEA7+3Iw3ULTn2I\n1J34WlJ2D5fbzMzB4FAHUNEV7Ys3f1kCIQDtUahCMChrl7+H5t9QS+xrn77lRGhs\nB50pjvy95WXpgQIhAI2joW6JzTfz8fAapb+kiJ/h9Vcs1ZN3iyoRlNFb61JZAiA8\nNy5NyNrMVwtB/lfJf1dAK/p/Bwd8LZLtgM6PapRfgw==\n-----END RSA PRIVATE KEY-----\n",
40
- 'client_email' => 'credz-testabc1234567890xyz@developer.gserviceaccount.com',
41
- 'client_id' => 'credz-testabc1234567890xyz.apps.googleusercontent.com',
42
- 'type' => 'service_account'
43
- }
44
- end
45
-
46
- it 'uses a default scope' do
47
- mocked_signet = double('Signet::OAuth2::Client')
48
- allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
49
- allow(Signet::OAuth2::Client).to receive(:new) do |options|
50
- expect(options[:token_credential_uri]).to eq('https://accounts.google.com/o/oauth2/token')
51
- expect(options[:audience]).to eq('https://accounts.google.com/o/oauth2/token')
52
- expect(options[:scope]).to eq([])
53
- expect(options[:issuer]).to eq(default_keyfile_hash['client_email'])
54
- expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
55
-
56
- mocked_signet
57
- end
58
-
59
- Google::Gax::Credentials.new default_keyfile_hash
60
- end
61
-
62
- it 'uses a custom scope' do
63
- mocked_signet = double('Signet::OAuth2::Client')
64
- allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
65
- allow(Signet::OAuth2::Client).to receive(:new) do |options|
66
- expect(options[:token_credential_uri]).to eq('https://accounts.google.com/o/oauth2/token')
67
- expect(options[:audience]).to eq('https://accounts.google.com/o/oauth2/token')
68
- expect(options[:scope]).to eq(['http://example.com/scope'])
69
- expect(options[:issuer]).to eq(default_keyfile_hash['client_email'])
70
- expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
71
-
72
- mocked_signet
73
- end
74
-
75
- Google::Gax::Credentials.new default_keyfile_hash, scope: 'http://example.com/scope'
76
- end
77
-
78
- it 'can be subclassed to pass in other env paths' do
79
- TEST_PATH_ENV_VAR = 'TEST_PATH'.freeze
80
- TEST_PATH_ENV_VAL = '/unknown/path/to/file.txt'.freeze
81
- TEST_JSON_ENV_VAR = 'TEST_JSON_VARS'.freeze
82
-
83
- ENV[TEST_PATH_ENV_VAR] = TEST_PATH_ENV_VAL
84
- ENV[TEST_JSON_ENV_VAR] = JSON.generate(default_keyfile_hash)
85
-
86
- class TestCredentials < Google::Gax::Credentials
87
- SCOPE = 'http://example.com/scope'.freeze
88
- PATH_ENV_VARS = [TEST_PATH_ENV_VAR].freeze
89
- JSON_ENV_VARS = [TEST_JSON_ENV_VAR].freeze
90
- end
91
-
92
- allow(::File).to receive(:file?).with(TEST_PATH_ENV_VAL) { false }
93
-
94
- mocked_signet = double('Signet::OAuth2::Client')
95
- allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
96
- allow(Signet::OAuth2::Client).to receive(:new) do |options|
97
- expect(options[:token_credential_uri]).to eq('https://accounts.google.com/o/oauth2/token')
98
- expect(options[:audience]).to eq('https://accounts.google.com/o/oauth2/token')
99
- expect(options[:scope]).to eq(['http://example.com/scope'])
100
- expect(options[:issuer]).to eq(default_keyfile_hash['client_email'])
101
- expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
102
-
103
- mocked_signet
104
- end
105
-
106
- TestCredentials.default
107
- end
108
- end