From 00b4f861b862d2f8156758f93fa27da3c5ccf761 Mon Sep 17 00:00:00 2001 From: Jacek Dziewonski Date: Wed, 22 Jan 2025 10:30:28 -0800 Subject: [PATCH] Update StripeClient to optionally take app_info in parameter This app_info will take precedence over the globally defined Stripe.app_info --- lib/stripe/api_requestor.rb | 10 +++++-- lib/stripe/stripe_client.rb | 4 ++- test/stripe/api_requestor_test.rb | 39 +++++++++++++++++++++++++ test/stripe/stripe_client_test.rb | 47 +++++++++++++++++++++++++++++++ 4 files changed, 97 insertions(+), 3 deletions(-) diff --git a/lib/stripe/api_requestor.rb b/lib/stripe/api_requestor.rb index 33eef40c5..3e0acad93 100644 --- a/lib/stripe/api_requestor.rb +++ b/lib/stripe/api_requestor.rb @@ -30,6 +30,8 @@ def initialize(config_arg = {}) else raise ArgumentError, "Can't handle argument: #{config_arg}" end + + @app_info = config.app_info end attr_reader :config, :options @@ -918,7 +920,7 @@ def self.maybe_gc_connection_managers private def request_headers(method, api_mode, req_opts) user_agent = "Stripe/#{api_mode} RubyBindings/#{Stripe::VERSION}" - user_agent += " " + format_app_info(Stripe.app_info) unless Stripe.app_info.nil? + user_agent += " " + format_app_info(fetch_app_info) unless fetch_app_info.nil? headers = { "User-Agent" => user_agent, @@ -963,6 +965,10 @@ def self.maybe_gc_connection_managers headers.update(req_opts[:headers]) end + private def fetch_app_info + @app_info || Stripe.app_info + end + private def log_request(context, num_retries) Util.log_info("Request to Stripe API", account: context.account, @@ -1090,7 +1096,7 @@ def user_agent "(#{RUBY_RELEASE_DATE})" { - application: Stripe.app_info, + application: fetch_app_info, bindings_version: Stripe::VERSION, lang: "ruby", lang_version: lang_version, diff --git a/lib/stripe/stripe_client.rb b/lib/stripe/stripe_client.rb index d5eda6739..a2ce9ac57 100644 --- a/lib/stripe/stripe_client.rb +++ b/lib/stripe/stripe_client.rb @@ -23,7 +23,8 @@ def initialize(api_key, # rubocop:todo Metrics/ParameterLists uploads_base: nil, connect_base: nil, meter_events_base: nil, - client_id: nil) + client_id: nil, + app_info: nil,) unless api_key raise AuthenticationError, "No API key provided. " \ 'Set your API key using "client = Stripe::StripeClient.new()". ' \ @@ -42,6 +43,7 @@ def initialize(api_key, # rubocop:todo Metrics/ParameterLists connect_base: connect_base, meter_events_base: meter_events_base, client_id: client_id, + app_info: app_info }.reject { |_k, v| v.nil? } config = StripeConfiguration.client_init(config_opts) diff --git a/test/stripe/api_requestor_test.rb b/test/stripe/api_requestor_test.rb index b4a9c3dcf..14cfa435c 100644 --- a/test/stripe/api_requestor_test.rb +++ b/test/stripe/api_requestor_test.rb @@ -834,6 +834,45 @@ class RequestorTest < Test::Unit::TestCase Stripe.app_info = old end end + + should "send app_info if set on the APIRequestor's config" do + begin + old = Stripe.app_info + Stripe.app_info = nil + + custom_config = Stripe::StripeConfiguration.setup do |c| + c.app_info = { + name: "MyAwesomePluginInConfig", + partner_id: "partner_4567", + url: "https://myawesomeplugininconfig.info", + version: "4.5.6", + } + end + + stub_request(:post, "#{Stripe::DEFAULT_API_BASE}/v1/account") + .with do |req| + expect_user_agent = "Stripe/v1 RubyBindings/#{Stripe::VERSION}" \ + "MyAwesomePluginInConfig/4.5.6 (https://myawesomeplugininconfig.info)" + assert_equal expect_user_agent, req.headers["User-Agent"] + + data = JSON.parse(req.headers["X-Stripe-Client-User-Agent"], symbolize_names: true) + assert_equal({ + name: "MyAwesomePluginInConfig", + partner_id: "partner_4567", + url: "https://myawesomeplugininconfig.info", + version: "4.5.6", + }, data[:application]) + + true + end + .to_return(body: JSON.generate(object: "account")) + + client = APIRequestor.new(custom_config) + client.execute_request(:post, "/v1/account", :api) + ensure + Stripe.app_info = old + end + end end context "error handling" do diff --git a/test/stripe/stripe_client_test.rb b/test/stripe/stripe_client_test.rb index 5ae5963fc..7697e2096 100644 --- a/test/stripe/stripe_client_test.rb +++ b/test/stripe/stripe_client_test.rb @@ -21,10 +21,12 @@ class StripeClientTest < Test::Unit::TestCase @orig_stripe_account = Stripe.stripe_account @orig_open_timeout = Stripe.open_timeout @orig_api_version = Stripe.api_version + @orig_app_info = Stripe.app_info Stripe.api_key = "DONT_USE_THIS_KEY" Stripe.stripe_account = "DONT_USE_THIS_ACCOUNT" Stripe.open_timeout = 30_000 + Stripe.app_info = nil end teardown do @@ -32,6 +34,7 @@ class StripeClientTest < Test::Unit::TestCase Stripe.stripe_account = @orig_stripe_account Stripe.open_timeout = @orig_open_timeout Stripe.api_version = @orig_api_version + Stripe.app_info = @orig_app_info end should "use default config options" do @@ -112,6 +115,50 @@ class StripeClientTest < Test::Unit::TestCase refute_equal APIRequestor.active_requestor, client.instance_variable_get(:@requestor) end + + should "use client app_info over global app_info" do + Stripe.app_info = { name: "global_app", version: "1.2.3" } + client_app_info = { name: "client_app", version: "4.5.6" } + client = StripeClient.new("test_123", app_info: client_app_info) + + req = nil + stub_request(:get, "#{Stripe::DEFAULT_API_BASE}/v1/customers/cus_123") + .with { |request| req = request } + .to_return(body: JSON.generate(object: "customer")) + + client.v1.customers.retrieve("cus_123") + + assert_match(/client_app\/4\.5\.6/, req.headers["User-Agent"]) + assert_no_match(/global_app/, req.headers["User-Agent"]) + end + + should "fall back to global app_info when client app_info not provided" do + Stripe.app_info = { name: "global_app", version: "1.2.3" } + client = StripeClient.new("test_123") + + req = nil + stub_request(:get, "#{Stripe::DEFAULT_API_BASE}/v1/customers/cus_123") + .with { |request| req = request } + .to_return(body: JSON.generate(object: "customer")) + + client.v1.customers.retrieve("cus_123") + + assert_match(%r{global_app/1\.2\.3}, req.headers["User-Agent"]) + end + + should "work with no app_info set" do + Stripe.app_info = nil + client = StripeClient.new("test_123") + + req = nil + stub_request(:get, "#{Stripe::DEFAULT_API_BASE}/v1/customers/cus_123") + .with { |request| req = request } + .to_return(body: JSON.generate(object: "customer")) + + client.v1.customers.retrieve("cus_123") + + assert_no_match(%r{app/}, req.headers["User-Agent"]) + end end context "#request" do