diff --git a/lib/unleash/client.rb b/lib/unleash/client.rb index 11d078f2..a05213ae 100644 --- a/lib/unleash/client.rb +++ b/lib/unleash/client.rb @@ -64,7 +64,10 @@ def register http.use_ssl = true if uri.scheme == 'https' http.open_timeout = Unleash.configuration.timeout # in seconds http.read_timeout = Unleash.configuration.timeout # in seconds - headers = {'Content-Type' => 'application/json'} + + headers = (Unleash.configuration.custom_http_headers || {}).dup + headers['Content-Type'] = 'application/json' + request = Net::HTTP::Post.new(uri.request_uri, headers) request.body = info.to_json diff --git a/lib/unleash/configuration.rb b/lib/unleash/configuration.rb index 32067b5d..372d01aa 100644 --- a/lib/unleash/configuration.rb +++ b/lib/unleash/configuration.rb @@ -4,6 +4,7 @@ module Unleash class Configuration attr_accessor :url, :app_name, :instance_id, + :custom_http_headers, :disable_metrics, :timeout, :retry_limit, :refresh_interval, :metrics_interval, :backup_file, :logger, :log_level @@ -13,6 +14,11 @@ def initialize(opts = {}) self.url = opts[:url] || nil self.instance_id = opts[:instance_id] || SecureRandom.uuid + if opts[:custom_http_headers].is_a?(Hash) || opts[:custom_http_headers].nil? + self.custom_http_headers = opts[:custom_http_headers] || {} + else + raise ArgumentError, "custom_http_headers must be a hash." + end self.disable_metrics = opts[:disable_metrics] || false self.refresh_interval = opts[:refresh_interval] || 15 self.metrics_interval = opts[:metrics_interval] || 10 @@ -42,7 +48,11 @@ def metrics_interval_in_millis def validate! if self.app_name.nil? or self.url.nil? - raise ArgumentError, "URL and app_name are required" + raise ArgumentError, "URL and app_name are required parameters." + end + + if ! self.custom_http_headers.is_a?(Hash) + raise ArgumentError, "custom_http_headers must be a hash." end end diff --git a/lib/unleash/metrics_reporter.rb b/lib/unleash/metrics_reporter.rb index 175bebe1..8c3b8b7a 100755 --- a/lib/unleash/metrics_reporter.rb +++ b/lib/unleash/metrics_reporter.rb @@ -43,7 +43,9 @@ def send http.use_ssl = true if uri.scheme == 'https' http.open_timeout = Unleash.configuration.timeout # in seconds http.read_timeout = Unleash.configuration.timeout # in seconds - headers = {'Content-Type' => 'application/json'} + + headers = (Unleash.configuration.custom_http_headers || {}).dup + headers['Content-Type'] = 'application/json' request = Net::HTTP::Post.new(uri.request_uri, headers) request.body = generated_report.to_json diff --git a/lib/unleash/toggle_fetcher.rb b/lib/unleash/toggle_fetcher.rb index f41aab44..ddc40c02 100755 --- a/lib/unleash/toggle_fetcher.rb +++ b/lib/unleash/toggle_fetcher.rb @@ -38,6 +38,7 @@ def toggles end # rename to refresh_from_server! ?? + # TODO: should simplify by moving uri / http initialization to class initialization def fetch Unleash.logger.debug "fetch()" Unleash.logger.debug "ETag: #{self.etag}" unless self.etag.nil? @@ -47,8 +48,12 @@ def fetch http.use_ssl = true if uri.scheme == 'https' http.open_timeout = Unleash.configuration.timeout # in seconds http.read_timeout = Unleash.configuration.timeout # in seconds - request = Net::HTTP::Get.new(uri.request_uri) - request['If-None-Match'] = self.etag unless self.etag.nil? + + headers = (Unleash.configuration.custom_http_headers || {}).dup + headers['Content-Type'] = 'application/json' + headers['If-None-Match'] = self.etag unless self.etag.nil? + + request = Net::HTTP::Get.new(uri.request_uri, headers) response = http.request(request) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 3066dd78..00bf101b 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -2,9 +2,13 @@ require "unleash" require "unleash/client" +require 'webmock/rspec' + require 'coveralls' Coveralls.wear! +WebMock.disable_net_connect!(allow_localhost: false) + RSpec.configure do |config| # Enable flags like --only-failures and --next-failure config.example_status_persistence_file_path = ".rspec_status" diff --git a/spec/unleash/client_spec.rb b/spec/unleash/client_spec.rb index 6fe37f0e..d3398ef7 100644 --- a/spec/unleash/client_spec.rb +++ b/spec/unleash/client_spec.rb @@ -5,6 +5,62 @@ expect(Unleash::VERSION).not_to be nil end + it "Uses custom http headers when initializing client" do + WebMock.stub_request(:post, "http://test-url//client/register") + .with( + headers: { + 'Accept'=>'*/*', + 'Content-Type'=>'application/json', + 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', + 'User-Agent'=>'Ruby', + 'X-Api-Key'=>'123' + }) + .to_return(status: 200, body: "", headers: {}) + WebMock.stub_request(:post, "http://test-url//client/metrics"). + with( + headers: { + 'Accept'=>'*/*', + 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', + 'Content-Type'=>'application/json', + 'User-Agent'=>'Ruby' + }). + to_return(status: 200, body: "", headers: {}) + + + Unleash.configure do |config| + config.url = 'http://test-url/' + config.app_name = 'my-test-app' + config.instance_id = 'rspec/test' + config.custom_http_headers = {'X-API-KEY' => '123'} + end + + unleash_client = Unleash::Client.new( + url: 'http://test-url/', + app_name: 'my-test-app', + instance_id: 'rspec/test', + custom_http_headers: {'X-API-KEY' => '123'} + ) + + expect( + a_request(:post, "http://test-url//client/register") + .with( headers: {'Content-Type': 'application/json'}) + .with( headers: {'X-API-KEY': '123', 'Content-Type': 'application/json'}) + ).to have_been_made.once + + expect( + a_request(:get, "http://test-url//client/features") + .with( headers: {'X-API-KEY': '123'}) + ).to have_been_made.once + + # Test now sending of metrics + Unleash.reporter.send + expect( + a_request(:post, "http://test-url//client/metrics") + .with( headers: {'Content-Type': 'application/json'}) + .with( headers: {'X-API-KEY': '123', 'Content-Type': 'application/json'}) + ).to have_been_made.once + end + it "does something useful" do expect(false).to eq(false) end diff --git a/spec/unleash/configuration_spec.rb b/spec/unleash/configuration_spec.rb index 14f5f509..02ac0fbc 100644 --- a/spec/unleash/configuration_spec.rb +++ b/spec/unleash/configuration_spec.rb @@ -4,12 +4,17 @@ RSpec.describe Unleash do describe 'Configuration' do + before do + Unleash.configuration = nil + end + it "should have the correct defaults" do - config = Unleash::Configuration.new() + config = Unleash::Configuration.new expect(config.app_name).to be_nil expect(config.url).to be_nil expect(config.instance_id).to be_truthy + expect(config.custom_http_headers).to eq({}) expect(config.disable_metrics).to be_falsey expect(config.refresh_interval).to eq(15) @@ -17,12 +22,13 @@ expect(config.timeout).to eq(30) expect(config.retry_limit).to eq(1) - # expect(config.validate!).to raise_error(ArgumentError) expect(config.backup_file).to_not be_nil + + expect{ config.validate! }.to raise_error(ArgumentError) end it "should by default be invalid" do - config = Unleash::Configuration.new() + config = Unleash::Configuration.new expect{ config.validate! }.to raise_error(ArgumentError) end @@ -50,6 +56,53 @@ expect(config.client_register_url).to eq('https://testurl/api/client/register') end - end + it "should allow hashes for custom_http_headers via yield" do + Unleash.configure do |config| + config.url = 'http://test-url/' + config.app_name = 'my-test-app' + config.custom_http_headers = {'X-API-KEY': '123'} + end + expect{ Unleash.configuration.validate! }.not_to raise_error + expect(Unleash.configuration.custom_http_headers).to eq({'X-API-KEY': '123'}) + end + + it "should allow hashes for custom_http_headers via new client" do + config = Unleash::Configuration.new( + url: 'https://testurl/api', + app_name: 'test-app', + custom_http_headers: {'X-API-KEY': '123'}) + + expect{ config.validate! }.not_to raise_error + expect(config.custom_http_headers).to eq({'X-API-KEY': '123'}) + end -end \ No newline at end of file + it "should not accept invalid custom_http_headers via yield" do + expect do + Unleash.configure do |config| + config.url = 'http://test-url/' + config.app_name = 'my-test-app' + config.custom_http_headers = 123.456 + end + end.to raise_error(ArgumentError) + end + + it "should not accept invalid custom_http_headers via new client" do + WebMock.stub_request(:post, "http://test-url//client/register"). + with( + headers: { + 'Accept'=>'*/*', + 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', + 'Content-Type'=>'application/json', + 'User-Agent'=>'Ruby' + }). + to_return(status: 200, body: "", headers: {}) + + expect{ Unleash::Client.new( + url: 'https://testurl/api', + app_name: 'test-app', + custom_http_headers: 123.0, + disable_metrics: true + ) }.to raise_error(ArgumentError) + end + end +end diff --git a/unleash-client.gemspec b/unleash-client.gemspec index cb24275a..cc2a197b 100644 --- a/unleash-client.gemspec +++ b/unleash-client.gemspec @@ -28,6 +28,7 @@ Gem::Specification.new do |spec| spec.add_development_dependency "bundler", "~> 1.14" spec.add_development_dependency "rake", "~> 10.0" spec.add_development_dependency "rspec", "~> 3.0" + spec.add_development_dependency "webmock", "~> 3.0" spec.add_development_dependency "coveralls" end