Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions codegen/templates/services.rb.erb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ module Google
def initialize(
logging_interceptor:,
error_interceptor:,
metadata_interceptor:,
credentials:,
metadata:,
endpoint:,
Expand All @@ -17,6 +18,7 @@ module Google
@interceptors = [
error_interceptor,
logging_interceptor,
metadata_interceptor
].compact
@credentials = credentials
@metadata = metadata
Expand Down
2 changes: 2 additions & 0 deletions lib/google/ads/google_ads/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class Config
attr_accessor :login_customer_id
attr_accessor :linked_customer_id
attr_accessor :use_cloud_org_for_api_access
attr_accessor :gaada

attr_accessor :log_level
attr_accessor :log_target
Expand All @@ -59,6 +60,7 @@ def initialize(&block)
@login_customer_id = nil
@linked_customer_id = nil
@use_cloud_org_for_api_access = false
@gaada = nil

@log_level = nil
@log_target = nil
Expand Down
1 change: 1 addition & 0 deletions lib/google/ads/google_ads/google_ads_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ def load_environment_config
if @config.use_cloud_org_for_api_access.is_a?(String)
@config.use_cloud_org_for_api_access = @config.use_cloud_org_for_api_access.downcase == "true"
end
@config.gaada = ENV.fetch("GOOGLE_ADS_GAADA", @config.gaada)
end

# Return a service for the provided entity type. For example, passing
Expand Down
78 changes: 78 additions & 0 deletions lib/google/ads/google_ads/interceptors/metadata_interceptor.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Encoding: utf-8
#
# Copyright 2022 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Interceptor to add metadata headers to requests.

require 'grpc/generic/interceptors'
require 'google/protobuf'

module Google
module Ads
module GoogleAds
module Interceptors
class MetadataInterceptor < GRPC::ClientInterceptor
def initialize(developer_token, login_customer_id, linked_customer_id, use_cloud_org_for_api_access, gaada)
super()
@developer_token = developer_token
@login_customer_id = login_customer_id
@linked_customer_id = linked_customer_id
@use_cloud_org_for_api_access = use_cloud_org_for_api_access
@gaada = gaada
end

def request_response(request:, call:, method:, metadata: {})
update_metadata(metadata)
yield
end

def server_streamer(request:, call:, method:, metadata: {})
update_metadata(metadata)
yield
end

private

def update_metadata(metadata)
if !@use_cloud_org_for_api_access
metadata[:"developer-token"] = @developer_token
end

if @login_customer_id
metadata[:"login-customer-id"] = @login_customer_id.to_s
end

if @linked_customer_id
metadata[:"linked-customer-id"] = @linked_customer_id.to_s
end

# The python library iterates over metadata and modifies x-goog-api-client
# Here we can directly access it.
if metadata.key?(:"x-goog-api-client")
if @gaada
metadata[:"x-goog-api-client"] += " gaada/#{@gaada}"
end

# Check if "pb" is already in the header
unless metadata[:"x-goog-api-client"].include?("pb")
metadata[:"x-goog-api-client"] += " pb/#{Gem.loaded_specs["google-protobuf"].version}"
end
end
end
end
end
end
end
end
28 changes: 13 additions & 15 deletions lib/google/ads/google_ads/service_lookup.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require 'google/ads/google_ads/interceptors/logging_interceptor'
require 'google/ads/google_ads/interceptors/error_interceptor'
require 'google/ads/google_ads/interceptors/metadata_interceptor'

module Google
module Ads
Expand All @@ -26,27 +27,36 @@ def call
logging_interceptor = GoogleAds::Interceptors::LoggingInterceptor.new(logger)
end
error_interceptor = GoogleAds::Interceptors::ErrorInterceptor.new
metadata_interceptor = GoogleAds::Interceptors::MetadataInterceptor.new(
config.developer_token,
config.login_customer_id,
config.linked_customer_id,
config.use_cloud_org_for_api_access,
config.gaada
)

version_alternates = {}
Factories::VERSIONS.each do |v|
version_alternates[v] = factory_at_version(v, error_interceptor, logging_interceptor)
version_alternates[v] = factory_at_version(v, error_interceptor, logging_interceptor, metadata_interceptor)
end

highest_factory = factory_at_version(
Factories::HIGHEST_VERSION,
error_interceptor,
logging_interceptor,
metadata_interceptor,
)

VersionAlternate.new(highest_factory, version_alternates)
end

private

def factory_at_version(version, error_interceptor, logging_interceptor)
def factory_at_version(version, error_interceptor, logging_interceptor, metadata_interceptor)
factory = Factories.at_version(version).services.new(**{
logging_interceptor: logging_interceptor,
error_interceptor: error_interceptor,
metadata_interceptor: metadata_interceptor,
deprecation: deprecator
}.merge(gax_service_params))

Expand All @@ -62,27 +72,15 @@ def gax_service_params
end

def headers
headers = {}

# If config.use_cloud_org_for_api_access is not True, add the developer
# token to the request's metadata
if !config.use_cloud_org_for_api_access
headers[:"developer-token"] = config.developer_token
end

if config.login_customer_id
validate_customer_id(:login_customer_id)
# header values must be strings
headers[:"login-customer-id"] = config.login_customer_id.to_s
end

if config.linked_customer_id
validate_customer_id(:linked_customer_id)
# header values must be strings
headers[:"linked-customer-id"] = config.linked_customer_id.to_s
end

headers
{}
end

def validate_customer_id(field)
Expand Down
6 changes: 6 additions & 0 deletions test/test_config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,21 @@ def test_initialize()
client_id_value = 'client id'
client_secret_value = 'client_secret'
developer_token_value = 'developer_token'
gaada_value = 'gaada_value'

config = Google::Ads::GoogleAds::Config.new do |c|
c.refresh_token = refresh_token_value
c.client_id = client_id_value
c.client_secret = client_secret_value
c.developer_token = developer_token_value
c.gaada = gaada_value
end

assert_equal(refresh_token_value, config.refresh_token)
assert_equal(client_id_value, config.client_id)
assert_equal(client_secret_value, config.client_secret)
assert_equal(developer_token_value, config.developer_token)
assert_equal(gaada_value, config.gaada)
end

def test_configure()
Expand All @@ -48,18 +51,21 @@ def test_configure()
client_id_value = 'abcd'
client_secret_value = '!@#$'
developer_token_value = '7x&Z'
gaada_value = 'gaada_value'

config.configure do |c|
c.refresh_token = refresh_token_value
c.client_id = client_id_value
c.client_secret = client_secret_value
c.developer_token = developer_token_value
c.gaada = gaada_value
end

assert_equal(refresh_token_value, config.refresh_token)
assert_equal(client_id_value, config.client_id)
assert_equal(client_secret_value, config.client_secret)
assert_equal(developer_token_value, config.developer_token)
assert_equal(gaada_value, config.gaada)
end

def test_use_cloud_org_for_api_access()
Expand Down
108 changes: 108 additions & 0 deletions test/test_metadata_interceptor.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#!/usr/bin/env ruby
# Encoding: utf-8

require 'minitest/autorun'
require 'google/ads/google_ads/interceptors/metadata_interceptor'
require 'google/protobuf'

class TestMetadataInterceptor < Minitest::Test
attr_reader :mi

def setup
@mi = Google::Ads::GoogleAds::Interceptors::MetadataInterceptor.new(
"dev_token",
"login_id",
"linked_id",
false,
nil
)
end

def test_adds_developer_token_if_not_cloud_org
metadata = {}
mi.request_response(
request: nil,
call: nil,
method: nil,
metadata: metadata
) do
end
assert_equal "dev_token", metadata[:"developer-token"]
end

def test_adds_login_and_linked_customer_id
metadata = {}
mi.request_response(
request: nil,
call: nil,
method: nil,
metadata: metadata
) do
end
assert_equal "login_id", metadata[:"login-customer-id"]
assert_equal "linked_id", metadata[:"linked-customer-id"]
end

def test_appends_pb_version_to_x_goog_api_client
metadata = { :"x-goog-api-client" => "gl-ruby/1.2.3" }
mi.request_response(
request: nil,
call: nil,
method: nil,
metadata: metadata
) do
end
assert_includes metadata[:"x-goog-api-client"], "pb/#{Gem.loaded_specs["google-protobuf"].version}"
end

def test_does_not_duplicate_pb_version
metadata = { :"x-goog-api-client" => "gl-ruby/1.2.3 pb/1.2.3" }
mi.request_response(
request: nil,
call: nil,
method: nil,
metadata: metadata
) do
end
assert_equal "gl-ruby/1.2.3 pb/1.2.3", metadata[:"x-goog-api-client"]
end

def test_skips_developer_token_if_cloud_org
mi_cloud = Google::Ads::GoogleAds::Interceptors::MetadataInterceptor.new(
"dev_token",
"login_id",
"linked_id",
true,
nil
)
metadata = {}
mi_cloud.request_response(
request: nil,
call: nil,
method: nil,
metadata: metadata
) do
end
assert_nil metadata[:"developer-token"]
end

def test_appends_gaada_to_x_goog_api_client
mi_gaada = Google::Ads::GoogleAds::Interceptors::MetadataInterceptor.new(
"dev_token",
"login_id",
"linked_id",
false,
"1.2.3"
)
metadata = { :"x-goog-api-client" => "gl-ruby/1.2.3" }
mi_gaada.request_response(
request: nil,
call: nil,
method: nil,
metadata: metadata
) do
end
assert_includes metadata[:"x-goog-api-client"], "gaada/1.2.3"
assert_includes metadata[:"x-goog-api-client"], "pb/#{Gem.loaded_specs["google-protobuf"].version}"
end
end