class MockPresentHook < Appsignal::Hooks::Hook def dependencies_present? true end def install MockPresentHook.call_something end def self.call_something end end class MockNotPresentHook < Appsignal::Hooks::Hook def dependencies_present? false end def install MockNotPresentHook.call_something end end class MockErrorHook < Appsignal::Hooks::Hook def dependencies_present? true end def install raise "error" end end describe Appsignal::Hooks do it "should register and install a hook once" do Appsignal::Hooks::Hook.register(:mock_present_hook, MockPresentHook) expect(Appsignal::Hooks.hooks[:mock_present_hook]).to be_instance_of(MockPresentHook) expect(Appsignal::Hooks.hooks[:mock_present_hook].installed?).to be_falsy expect(MockPresentHook).to receive(:call_something).once Appsignal::Hooks.load_hooks Appsignal::Hooks.load_hooks Appsignal::Hooks.load_hooks expect(Appsignal::Hooks.hooks[:mock_present_hook].installed?).to be_truthy Appsignal::Hooks.hooks.delete(:mock_present_hook) end it "should not install if depencies are not present" do Appsignal::Hooks::Hook.register(:mock_not_present_hook, MockNotPresentHook) expect(Appsignal::Hooks.hooks[:mock_not_present_hook]).to be_instance_of(MockNotPresentHook) expect(Appsignal::Hooks.hooks[:mock_not_present_hook].installed?).to be_falsy expect(MockPresentHook).to_not receive(:call_something) Appsignal::Hooks.load_hooks expect(Appsignal::Hooks.hooks[:mock_not_present_hook].installed?).to be_falsy Appsignal::Hooks.hooks.delete(:mock_not_present_hook) end it "should not install if there is an error while installing" do Appsignal::Hooks::Hook.register(:mock_error_hook, MockErrorHook) expect(Appsignal::Hooks.hooks[:mock_error_hook]).to be_instance_of(MockErrorHook) expect(Appsignal::Hooks.hooks[:mock_error_hook].installed?).to be_falsy expect(Appsignal.logger).to receive(:error).with("Error while installing mock_error_hook hook: error").once Appsignal::Hooks.load_hooks expect(Appsignal::Hooks.hooks[:mock_error_hook].installed?).to be_falsy Appsignal::Hooks.hooks.delete(:mock_error_hook) end end describe Appsignal::Hooks::Helpers do class ClassWithHelpers include Appsignal::Hooks::Helpers end let(:with_helpers) { ClassWithHelpers.new } describe "#truncate" do let(:very_long_text) do "a" * 400 end it "should truncate the text to 200 chars max" do expect(with_helpers.truncate(very_long_text)).to eq "#{"a" * 197}..." end end describe "#string_or_inspect" do context "when string" do it "should return the string" do expect(with_helpers.string_or_inspect("foo")).to eq "foo" end end context "when integer" do it "should return the string" do expect(with_helpers.string_or_inspect(1)).to eq "1" end end context "when object" do let(:object) { Object.new } it "should return the string" do expect(with_helpers.string_or_inspect(object)).to eq object.inspect end end end describe "#extract_value" do context "for a hash" do let(:hash) { { :key => "value" } } context "when the key exists" do subject { with_helpers.extract_value(hash, :key) } it { is_expected.to eq "value" } end context "when the key does not exist" do subject { with_helpers.extract_value(hash, :nonexistent_key) } it { is_expected.to be_nil } context "with a default value" do subject { with_helpers.extract_value(hash, :nonexistent_key, 1) } it { is_expected.to eq 1 } end end end context "for a struct" do before :context do TestStruct = Struct.new(:key) end let(:struct) { TestStruct.new("value") } context "when the key exists" do subject { with_helpers.extract_value(struct, :key) } it { is_expected.to eq "value" } end context "when the key does not exist" do subject { with_helpers.extract_value(struct, :nonexistent_key) } it { is_expected.to be_nil } context "with a default value" do subject { with_helpers.extract_value(struct, :nonexistent_key, 1) } it { is_expected.to eq 1 } end end end context "for an object" do let(:object) { double(:existing_method => "value") } context "when the method exists" do subject { with_helpers.extract_value(object, :existing_method) } it { is_expected.to eq "value" } end context "when the method does not exist" do subject { with_helpers.extract_value(object, :nonexistent_method) } it { is_expected.to be_nil } context "and there is a default value" do subject { with_helpers.extract_value(object, :nonexistent_method, 1) } it { is_expected.to eq 1 } end end end context "when we need to call to_s on the value" do let(:object) { double(:existing_method => 1) } subject { with_helpers.extract_value(object, :existing_method, nil, true) } it { is_expected.to eq "1" } end end describe "#format_args" do let(:object) { Object.new } let(:args) do [ "Model", 1, object, "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." ] end it "should format the arguments" do expect(with_helpers.format_args(args)).to eq([ "Model", "1", object.inspect, "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ..." ]) end end end