From 52b78f13801fe08b4fc951a51d18086649fd4896 Mon Sep 17 00:00:00 2001 From: Tom de Bruijn Date: Mon, 24 Jun 2024 14:53:50 +0200 Subject: [PATCH] Refactor Hanami specs to use Transaction#to_h Don't assert method calls but check what the extension receives for transaction data. Part of #252 [skip changeset] --- lib/appsignal/integrations/hanami.rb | 8 +- .../lib/appsignal/integrations/hanami_spec.rb | 120 +++++++++++------- spec/support/hanami/hanami_app.rb | 4 +- 3 files changed, 80 insertions(+), 52 deletions(-) diff --git a/lib/appsignal/integrations/hanami.rb b/lib/appsignal/integrations/hanami.rb index 8f8e5a2c3..615300752 100644 --- a/lib/appsignal/integrations/hanami.rb +++ b/lib/appsignal/integrations/hanami.rb @@ -17,7 +17,9 @@ def self.init Appsignal.start_logger Appsignal.start - ::Hanami::Action.prepend Appsignal::Integrations::HanamiIntegration if Appsignal.active? + return unless Appsignal.active? + + ::Hanami::Action.prepend Appsignal::Integrations::HanamiIntegration end end end @@ -41,11 +43,15 @@ def call(env) begin Appsignal.instrument("process_action.hanami") do super.tap do |response| + # TODO: update to response_status or remove: + # https://github.com/appsignal/appsignal-ruby/issues/183 transaction.set_metadata("status", response.status.to_s) end end rescue Exception => error # rubocop:disable Lint/RescueException transaction.set_error(error) + # TODO: update to response_status or remove: + # https://github.com/appsignal/appsignal-ruby/issues/183 transaction.set_metadata("status", "500") raise error ensure diff --git a/spec/lib/appsignal/integrations/hanami_spec.rb b/spec/lib/appsignal/integrations/hanami_spec.rb index 8c0357d33..90a99538b 100644 --- a/spec/lib/appsignal/integrations/hanami_spec.rb +++ b/spec/lib/appsignal/integrations/hanami_spec.rb @@ -4,30 +4,25 @@ describe "Hanami integration" do require "appsignal/integrations/hanami" - before do - allow(Appsignal).to receive(:active?).and_return(true) - allow(Appsignal).to receive(:start).and_return(true) - allow(Appsignal).to receive(:start_logger).and_return(true) - end - describe Appsignal::Integrations::HanamiPlugin do it "starts AppSignal on init" do expect(Appsignal).to receive(:start) - end - - it "starts the logger on init" do expect(Appsignal).to receive(:start_logger) + Appsignal::Integrations::HanamiPlugin.init end it "prepends the integration to Hanami" do - expect(::Hanami::Action).to receive(:prepend) - .with(Appsignal::Integrations::HanamiIntegration) + allow(Appsignal).to receive(:active?).and_return(true) + Appsignal::Integrations::HanamiPlugin.init + expect(::Hanami::Action.included_modules) + .to include(Appsignal::Integrations::HanamiIntegration) end context "when not active" do before { allow(Appsignal).to receive(:active?).and_return(false) } it "does not prepend the integration" do + Appsignal::Integrations::HanamiPlugin.init expect(::Hanami::Action).to_not receive(:prepend) .with(Appsignal::Integrations::HanamiIntegration) end @@ -52,8 +47,6 @@ expect(Appsignal.config.env).to eq("test") end end - - after { Appsignal::Integrations::HanamiPlugin.init } end describe "Hanami Actions" do @@ -64,60 +57,91 @@ :method => "GET" ) end + let(:router_params) { { "foo" => "bar", "baz" => "qux" } } + around { |example| keep_transactions { example.run } } + before :context do + start_agent + end + before do + allow(Appsignal).to receive(:active?).and_return(true) + Appsignal::Integrations::HanamiPlugin.init + end - let(:router_params) { { :foo => "bar", :baz => "qux" } } + def make_request(env, app: HanamiApp::Actions::Books::Index) + action = app.new + action.call(env) + end - describe "#call", :error => false do + describe "#call" do it "sets params" do - expect_any_instance_of(Appsignal::Transaction).to receive(:params=).with(router_params) + make_request(env) + + expect(last_transaction.to_h).to include( + "sample_data" => hash_including( + "params" => router_params + ) + ) end - it "sets the action name" do - expect_any_instance_of(Appsignal::Transaction).to receive(:set_action_if_nil) - .with("HanamiApp::Actions::Books::Index") + it "sets the namespace and action name" do + make_request(env) + + expect(last_transaction.to_h).to include( + "namespace" => Appsignal::Transaction::HTTP_REQUEST, + "action" => "HanamiApp::Actions::Books::Index" + ) end it "sets the metadata" do - expect_any_instance_of(Appsignal::Transaction).to receive(:set_metadata) - .with("status", "200") - expect_any_instance_of(Appsignal::Transaction).to receive(:set_metadata) - .with("path", "/books") - expect_any_instance_of(Appsignal::Transaction).to receive(:set_metadata) - .with("method", "GET") + make_request(env) + + expect(last_transaction.to_h).to include( + "metadata" => hash_including( + "status" => "200", + "path" => "/books", + "method" => "GET" + ) + ) end - it "sets the queue start" do - expect_any_instance_of(Appsignal::Transaction) - .to receive(:set_http_or_background_queue_start) + context "with queue start header" do + let(:queue_start_time) { fixed_time * 1_000 } + before do + env["HTTP_X_REQUEST_START"] = "t=#{queue_start_time.to_i}" # in milliseconds + end + + it "sets the queue start" do + make_request(env) + + expect(last_transaction.ext.queue_start).to eq(queue_start_time) + end end - context "with error", :error => true do - let(:error) { HanamiApp::ExampleError } + context "with error" do + before do + expect do + make_request(env, :app => HanamiApp::Actions::Books::Error) + end.to raise_error(ExampleException) + end it "records the exception" do - expect_any_instance_of(Appsignal::Transaction).to receive(:set_error).with(error) + expect(last_transaction.to_h).to include( + "error" => { + "name" => "ExampleException", + "message" => "exception message", + "backtrace" => kind_of(String) + } + ) end it "sets the status to 500" do - expect_any_instance_of(Appsignal::Transaction).to receive(:set_metadata) - .with("status", "500") - expect_any_instance_of(Appsignal::Transaction).to receive(:set_metadata).twice + expect(last_transaction.to_h).to include( + "metadata" => hash_including( + "status" => "500" + ) + ) end end - - after(:error => false) do - Appsignal::Integrations::HanamiPlugin.init - - action = HanamiApp::Actions::Books::Index.new - action.call(env) - end - - after(:error => true) do - Appsignal::Integrations::HanamiPlugin.init - - action = HanamiApp::Actions::Books::Error.new - expect { action.call(env) }.to raise_error(error) - end end end end diff --git a/spec/support/hanami/hanami_app.rb b/spec/support/hanami/hanami_app.rb index ed0f5348d..457997d47 100644 --- a/spec/support/hanami/hanami_app.rb +++ b/spec/support/hanami/hanami_app.rb @@ -21,11 +21,9 @@ def handle(_request, response) class Error < Hanami::Action def handle(_request, _response) - raise ExampleError + raise ExampleException, "exception message" end end end end - - class ExampleError < StandardError; end end