Skip to content

Commit

Permalink
Add emergency banner support
Browse files Browse the repository at this point in the history
- We remove the odd handling of link_text (where it's blanked
  if the link is blank), because the component can handle this
  already.
- In `static`, the library class handling the banner used a class
  variable to memoize the redis client. Because that's a bit of
  a code smell (and makes testing awkward), we replace that with
  a required config value in Rails.application.config (as mentioned
  in the documentation).
- We use the rails cache to cache the call to redis for one minute,
  which seems like a reasonable compromise between traffic to the
  redis cluster and the banner being available (one minute means
  that we're more responsive than the 5 minute cache, giving us
  a bit of flexibility in cache busting to test when the banner
  comes up).

Audit Trail:
- https://github.com/alphagov/static/blob/bb53325994ebb23476f577f8dbb8bc78d04ceac7/lib/emergency_banner/display.rb
- https://github.com/alphagov/static/blob/bb53325994ebb23476f577f8dbb8bc78d04ceac7/app/views/root/_gem_base.html.erb#L21-L44
  • Loading branch information
KludgeKML committed Dec 10, 2024
1 parent 9482c55 commit a48c950
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 0 deletions.
11 changes: 11 additions & 0 deletions app/views/govuk_web_banners/_emergency_banner.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<% emergency_banner = GovukWebBanners::EmergencyBanner.new(redis_client: Rails.application.config.emergency_banner_redis_client) %>
<% if emergency_banner.active? %>
<%= render "govuk_publishing_components/components/emergency_banner", {
campaign_class: emergency_banner.campaign_class,
heading: emergency_banner.heading,
link: emergency_banner.link,
link_text: emergency_banner.link_text,
short_description: emergency_banner.short_description,
homepage: false,
} %>
<% end %>
1 change: 1 addition & 0 deletions lib/govuk_web_banners.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require "govuk_publishing_components"

require "govuk_web_banners/emergency_banner"
require "govuk_web_banners/engine"
require "govuk_web_banners/recruitment_banner"
require "govuk_web_banners/version"
Expand Down
33 changes: 33 additions & 0 deletions lib/govuk_web_banners/emergency_banner.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
require "govuk_app_config/govuk_error"
require "redis"

module GovukWebBanners
class EmergencyBanner
attr_reader :campaign_class, :heading, :short_description, :link, :link_text

def initialize(redis_client:)
content = content_from_redis(redis_client)

@campaign_class = content[:campaign_class].presence
@heading = content[:heading].presence
@short_description = content[:short_description].presence
@link = content[:link].presence
@link_text = content[:link_text].presence
end

def active?
[campaign_class, heading].all?
end

private

def content_from_redis(client)
Rails.cache.fetch("#emergency_banner/config", expires_in: 1.minute) do
client.hgetall("emergency_banner").try(:symbolize_keys)
end
rescue StandardError => e
GovukError.notify(e, extra: { context: "Emergency Banner Redis" })
{}
end
end
end
30 changes: 30 additions & 0 deletions spec/requests/emergency_banner_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
RSpec.describe "Emergency Banners" do
context "getting a path with the banner partial" do
context "with the emergency banner active" do
before do
allow_any_instance_of(Redis).to receive(:hgetall).with("emergency_banner").and_return(
heading: "Emergency!",
campaign_class: "notable-death",
)
end

it "shows a banner in the page" do
get "/emergency"

expect(response.body).to include("Emergency!")
end
end

context "with the emergency banner inactive" do
before do
allow_any_instance_of(Redis).to receive(:hgetall).with("emergency_banner").and_return({})
end

it "does not show a banner in the page" do
get "/emergency"

expect(response.body).not_to include("Emergency!")
end
end
end
end
55 changes: 55 additions & 0 deletions spec/units/emergency_banner_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
RSpec.describe GovukWebBanners::EmergencyBanner do
let(:redis_client) { double(hgetall: {}) }
subject(:emergency_banner) { GovukWebBanners::EmergencyBanner.new(redis_client:) }

describe "caching" do
context "with a Rails cache" do
it "caches calls to the redis client for one minute" do
allow(Rails).to receive(:cache).and_return(ActiveSupport::Cache.lookup_store(:memory_store))
Rails.cache.clear

GovukWebBanners::EmergencyBanner.new(redis_client:)
GovukWebBanners::EmergencyBanner.new(redis_client:)

expect(redis_client).to have_received(:hgetall).once

travel_to(Time.now + 61.seconds)

GovukWebBanners::EmergencyBanner.new(redis_client:)
expect(redis_client).to have_received(:hgetall).twice

travel_back
end
end
end

context "with the emergency banner inactive" do
describe "#active?" do
it "returns false" do
expect(emergency_banner.active?).to be false
end
end
end

context "with the emergency banner active" do
let(:redis_client) { double(hgetall: { heading: "Emergency!", campaign_class: "notable-death" }) }

describe "#active?" do
it "returns true" do
expect(emergency_banner.active?).to be true
end
end
end

context "if the call to Redis fails" do
before do
allow(redis_client).to receive(:hgetall).with("emergency_banner").and_raise(StandardError)
end

describe "#active?" do
it "returns false" do
expect(emergency_banner.active?).to be false
end
end
end
end

0 comments on commit a48c950

Please sign in to comment.