From 9faf031a1077e8d151264be613b09418d24c1486 Mon Sep 17 00:00:00 2001 From: Al Davidson Date: Fri, 24 Nov 2023 14:10:02 +0000 Subject: [PATCH] Test the adding of custom fields via LogStasher The way LogStasher hooks into Rails makes it difficult to test that configured custom fields actually get added. It was tricky to find an approach to worked, wasn't too awkward and wasn't too tightly coupled to LogStasher. _Notes on some of the esoteric details of these new tests_ `append_info_to_payload`: This is a Rails instrumentation hook (intended for use by third parties). It's run during request handling and LogStasher uses it to "append" its default fields and any custom fields defined by our app. The visible effect in the context of this method and its caller is that those LogStasher fields are set on the `payload` hash that was supplied to the method. So, invoking this method is enough to simulate a controller action running for LogStasher's purposes. And, if the payload hash contains our custom field key (and value, when there is one), we've defined it successfully. `logstasher_add_custom_fields_to_payload`: If a Rails app has defined custom LogStasher fields (with `LogStasher.add_custom_fields`), LogStasher registers a listener with Rails that fires whenever a controller is loaded and that listener adds this method to the loaded controller. Therefore, if a newly-loaded controller has this method, one or more LogStasher custom fields have been defined successfully. --- spec/lib/govuk_json_logging_spec.rb | 65 +++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/spec/lib/govuk_json_logging_spec.rb b/spec/lib/govuk_json_logging_spec.rb index d25d18a..ac8da16 100644 --- a/spec/lib/govuk_json_logging_spec.rb +++ b/spec/lib/govuk_json_logging_spec.rb @@ -3,6 +3,11 @@ require "govuk_app_config/govuk_json_logging" require "rack/test" +class TestController < ActionController::Base + include LogStasher::ActionController::Instrumentation + def index; end +end + RSpec.describe GovukJsonLogging do let(:govuk_headers_class) do Class.new do @@ -78,6 +83,66 @@ def self.headers expect(fake_stdout.read).to match(/test default log entry/) end + context "given a block" do + it "evals the block" do + done = false + expect { + GovukJsonLogging.configure do + done = true + end + }.to change { done }.to(true) + end + + context "and the block configures custom fields" do + describe "any subsequently-created ActionController" do + let(:headers) { { "REMOTE_ADDR" => "10.10.10.10" } } + let(:mock_request) { ActionDispatch::TestRequest.new(Rack::MockRequest.env_for("http://example.com:8080/", headers)) } + let(:mock_response) { ActionDispatch::TestResponse.new } + + before do + GovukJsonLogging.configure do + add_custom_fields do |fields| + fields[:govuk_custom_field] = request.headers["GOVUK-Custom-Header"] + end + end + + @controller = TestController.new + allow(@controller).to receive(:request).and_return(mock_request) + allow(@controller).to receive(:response).and_return(mock_response) + end + + it "has a logstasher_add_custom_fields_to_payload method" do + expect(@controller.methods).to include(:logstasher_add_custom_fields_to_payload) + end + + describe "calling the logstasher_add_custom_fields_to_payload" do + let(:payload) { {} } + + it "executes the block" do + expect(@controller).to receive(:logstasher_add_custom_fields_to_payload) + @controller.send(:append_info_to_payload, payload) + end + + it "adds the custom fields to the payload" do + @controller.send(:append_info_to_payload, payload) + expect(payload.keys).to include(:govuk_custom_field) + end + + context "when the custom field has a value" do + before do + mock_request.headers["GOVUK-Custom-header"] = "My header value" + end + + it "sets the custom field value in the payload" do + @controller.send(:append_info_to_payload, payload) + expect(payload[:govuk_custom_field]).to eq("My header value") + end + end + end + end + end + end + describe "when making requests to the application" do include Rack::Test::Methods