if DependencyHelper.rails_present?
  describe Appsignal::Rack::RailsInstrumentation do
    class MockController; end

    let(:transaction) { new_transaction }
    let(:app) { DummyApp.new }
    let(:params) do
      {
        "controller" => "blog_posts",
        "action" => "show",
        "id" => "1",
        "my_custom_param" => "my custom secret",
        "password" => "super secret"
      }
    end
    let(:env) do
      http_request_env_with_data(
        :params => params,
        :with_queue_start => true,
        "action_dispatch.request_id" => "request_id123",
        "action_dispatch.parameter_filter" => [:my_custom_param, :password],
        "action_controller.instance" => double(
          :class => MockController,
          :action_name => "index"
        )
      )
    end
    let(:middleware) { Appsignal::Rack::RailsInstrumentation.new(app, {}) }
    around { |example| keep_transactions { example.run } }
    before do
      start_agent
      env[Appsignal::Rack::APPSIGNAL_TRANSACTION] = transaction
    end

    def make_request
      middleware.call(env)
      last_transaction&._sample
    end

    def make_request_with_error(error_class, error_message)
      expect { make_request }.to raise_error(error_class, error_message)
    end

    context "with a request that doesn't raise an error" do
      before { make_request }

      it "calls the next middleware in the stack" do
        expect(app).to be_called
      end

      it "does not instrument an event" do
        expect(last_transaction).to_not include_events
      end
    end

    context "with a request that raises an error" do
      let(:app) do
        DummyApp.new { |_env| raise ExampleException, "error message" }
      end
      before do
        make_request_with_error(ExampleException, "error message")
      end

      it "calls the next middleware in the stack" do
        expect(app).to be_called
      end

      it "reports the error on the transaction" do
        expect(last_transaction).to have_error("ExampleException", "error message")
      end
    end

    it "sets the controller action as the action name" do
      make_request

      expect(last_transaction).to have_namespace(Appsignal::Transaction::HTTP_REQUEST)
      expect(last_transaction).to have_action("MockController#index")
    end

    it "sets request metadata on the transaction" do
      make_request

      expect(last_transaction).to include_metadata(
        "method" => "GET",
        "path" => "/blog"
      )
      expect(last_transaction).to include_tags("request_id" => "request_id123")
    end

    it "reports Rails filter parameters" do
      make_request

      expect(last_transaction).to include_params(
        "controller" => "blog_posts",
        "action" => "show",
        "id" => "1",
        "my_custom_param" => "[FILTERED]",
        "password" => "[FILTERED]"
      )
    end

    context "with an invalid HTTP request method" do
      it "does not store the invalid HTTP request method" do
        env[:request_method] = "FOO"
        env["REQUEST_METHOD"] = "FOO"
        logs = capture_logs { make_request }

        expect(last_transaction).to_not include_metadata("method" => anything)
        expect(logs).to contains_log(
          :error,
          "Exception while fetching the HTTP request method: "
        )
      end
    end

    context "with a request path that's not a route" do
      it "doesn't set an action name" do
        env[:path] = "/unknown-route"
        env["action_controller.instance"] = nil
        make_request

        expect(last_transaction).to_not have_action
      end
    end
  end
end
