describe Appsignal::Transmitter do let(:config) { project_fixture_config } let(:base_uri) { "action" } let(:log) { StringIO.new } let(:instance) { Appsignal::Transmitter.new(base_uri, config) } before do config.config_hash[:hostname] = "app1.local" config.logger = Logger.new(log) end describe "#uri" do let(:uri) { instance.uri } it "returns a URI object with configuration data" do expect(uri.to_s).to start_with(config[:endpoint]) expect(uri.path).to eq("/1/action") expect(CGI.parse(uri.query)).to eq( "api_key" => ["abc"], "hostname" => ["app1.local"], "name" => ["TestApp"], "environment" => ["production"], "gem_version" => [Appsignal::VERSION] ) end context "when base_uri argument is a full URI" do let(:base_uri) { "http://foo.bar/path" } it "uses the full URI" do expect(uri.to_s).to start_with("#{base_uri}?") end end context "when base_uri argument is only a path" do it "uses the config[:endpoint] base" do expect(uri.to_s).to start_with("#{config[:endpoint]}/1/#{base_uri}?") end end end describe "#transmit" do before do stub_request(:post, "https://push.appsignal.com/1/action").with( :query => { :api_key => "abc", :environment => "production", :gem_version => Appsignal::VERSION, :hostname => config[:hostname], :name => "TestApp" }, :body => "{\"the\":\"payload\"}", :headers => { "Content-Type" => "application/json; charset=UTF-8" } ).to_return(:status => 200) end let(:response) { instance.transmit(:the => :payload) } it "returns Net::HTTP response" do expect(response).to be_kind_of(Net::HTTPResponse) expect(response.code).to eq "200" end context "with ca_file_path config option set" do context "when file does not exist" do before do config.config_hash[:ca_file_path] = File.join(resources_dir, "cacert.pem") end it "ignores the config and logs a warning" do expect(response).to be_kind_of(Net::HTTPResponse) expect(response.code).to eq "200" expect(log.string).to_not include "Ignoring non-existing or unreadable " \ "`ca_file_path`: #{config[:ca_file_path]}" end end context "when not existing file" do before do config.config_hash[:ca_file_path] = File.join(tmp_dir, "ca_file_that_does_not_exist") end it "ignores the config and logs a warning" do expect(response).to be_kind_of(Net::HTTPResponse) expect(response.code).to eq "200" expect(log.string).to include "Ignoring non-existing or unreadable " \ "`ca_file_path`: #{config[:ca_file_path]}" end end context "when not readable file" do let(:file) { File.join(tmp_dir, "ca_file") } before do config.config_hash[:ca_file_path] = file File.open(file, "w") { |f| f.chmod 0o000 } end it "ignores the config and logs a warning" do expect(response).to be_kind_of(Net::HTTPResponse) expect(response.code).to eq "200" expect(log.string).to include "Ignoring non-existing or unreadable " \ "`ca_file_path`: #{config[:ca_file_path]}" end after { File.delete file } end end end describe "#http_post" do subject { instance.send(:http_post, "the" => "payload") } it "sets the path" do expect(subject.path).to eq instance.uri.request_uri end it "sets the correct headers" do expect(subject["Content-Type"]).to eq "application/json; charset=UTF-8" end end describe "#http_client" do subject { instance.send(:http_client) } context "with a http uri" do let(:config) { project_fixture_config("test") } it { expect(subject).to be_instance_of(Net::HTTP) } it { expect(subject.proxy?).to be_falsy } it { expect(subject.use_ssl?).to be_falsy } end context "with a https uri" do let(:config) { project_fixture_config("production") } it { expect(subject).to be_instance_of(Net::HTTP) } it { expect(subject.proxy?).to be_falsy } it { expect(subject.use_ssl?).to be_truthy } it { expect(subject.verify_mode).to eq OpenSSL::SSL::VERIFY_PEER } it { expect(subject.ca_file).to eq config[:ca_file_path] } end context "with a proxy" do let(:config) { project_fixture_config("production", :http_proxy => "http://localhost:8080") } it { expect(subject).to be_instance_of(Net::HTTP) } it { expect(subject.proxy?).to be_truthy } it { expect(subject.proxy_address).to eq "localhost" } it { expect(subject.proxy_port).to eq 8080 } end end end