Skip to content

Commit

Permalink
Add Govuk-Use-Recommended-Links Vary response header and value header
Browse files Browse the repository at this point in the history
This commit adds the `Govuk-Use-Recommended-Links` Vary response header and value header to responses generated by the `ContentItemsController`. This is to enable cache invalidation of previous responses if the incoming `Govuk-Use-Recommended-Links` request header changes state.
  • Loading branch information
Karl Baker committed Jun 26, 2019
1 parent f876571 commit 5ae92a0
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 0 deletions.
6 changes: 6 additions & 0 deletions app/controllers/content_items_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ def show
load_content_item

set_expiry
set_use_recommended_related_links_header
set_access_control_allow_origin_header if request.format.atom?
set_guide_draft_access_token if @content_item.is_a?(GuidePresenter)
render_template
Expand Down Expand Up @@ -112,6 +113,11 @@ def set_access_control_allow_origin_header
response.headers["Access-Control-Allow-Origin"] = "*"
end

def set_use_recommended_related_links_header
response.headers['Vary'] = [response.headers['Vary'], FeatureFlagNames.recommended_related_links].compact.join(', ')
response.headers[FeatureFlagNames.recommended_related_links] = Services.feature_toggler.feature_flags.get_feature_flag(FeatureFlagNames.recommended_related_links)
end

def set_expiry
expires_in(@content_item.cache_control_max_age(request.format),
public: @content_item.cache_control_public?)
Expand Down
2 changes: 2 additions & 0 deletions app/models/feature_toggler.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
class FeatureToggler
attr_reader :feature_flags

def initialize(feature_flags)
@feature_flags = feature_flags
end
Expand Down
4 changes: 4 additions & 0 deletions app/models/http_feature_flags.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ def add_http_feature_flag(header_name, val)
@feature_flags[header_name] = val
end

def get_feature_flag(header_name)
@feature_flags[header_name]
end

def feature_enabled?(header_name, request_headers)
@feature_flags.has_key?(header_name) && @feature_flags[header_name] == request_headers[header_name]
end
Expand Down
36 changes: 36 additions & 0 deletions test/controllers/content_items_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ class ContentItemsControllerTest < ActionController::TestCase
end

test "gets item from content store and keeps existing ordered_related_items when feature flag header not specified" do
HttpFeatureFlags.instance.add_http_feature_flag(FeatureFlagNames.recommended_related_links, 'true')
content_item = content_store_has_schema_example('case_study', 'case_study')

get :show, params: { path: path_for(content_item) }
Expand All @@ -139,6 +140,7 @@ class ContentItemsControllerTest < ActionController::TestCase
end

test "gets item from content store and keep existing ordered_related_items when feature flag header is specified but links already exist" do
HttpFeatureFlags.instance.add_http_feature_flag(FeatureFlagNames.recommended_related_links, 'true')
request.headers[FeatureFlagNames.recommended_related_links] = 'true'

content_item = content_store_has_schema_example('guide', 'guide')
Expand All @@ -150,7 +152,21 @@ class ContentItemsControllerTest < ActionController::TestCase
assert_equal content_item['links']['ordered_related_items'], assigns[:content_item].content_item['links']['ordered_related_items']
end

test "gets item from content store and keeps ordered_related_items when feature flag header is specified but recommended links turned off" do
HttpFeatureFlags.instance.add_http_feature_flag(FeatureFlagNames.recommended_related_links, 'false')
request.headers[FeatureFlagNames.recommended_related_links] = 'true'

content_item = content_store_has_schema_example('case_study', 'case_study')

get :show, params: { path: path_for(content_item) }
assert_response :success
assert_empty content_item['links']['ordered_related_items'], 'Content item should have existing related links'
refute_empty content_item['links']['suggested_ordered_related_items'], 'Content item should have existing suggested related links'
assert_equal [], assigns[:content_item].content_item['links']['ordered_related_items']
end

test "gets item from content store and replaces ordered_related_items when feature flag header is specified and there are no existing links" do
HttpFeatureFlags.instance.add_http_feature_flag(FeatureFlagNames.recommended_related_links, 'true')
request.headers[FeatureFlagNames.recommended_related_links] = 'true'

content_item = content_store_has_schema_example('case_study', 'case_study')
Expand All @@ -162,6 +178,26 @@ class ContentItemsControllerTest < ActionController::TestCase
assert_equal assigns[:content_item].content_item['links']['ordered_related_items'], content_item['links']['suggested_ordered_related_items']
end

test "sets the Govuk-Use-Recommended-Links header to true when using recommended links" do
HttpFeatureFlags.instance.add_http_feature_flag(FeatureFlagNames.recommended_related_links, 'true')
content_item = content_store_has_schema_example('case_study', 'case_study')

get :show, params: { path: path_for(content_item) }

assert_includes response.headers['Vary'], FeatureFlagNames.recommended_related_links
assert_equal 'true', response.headers[FeatureFlagNames.recommended_related_links]
end

test "sets the Govuk-Use-Recommended-Links header to false when not using recommended links" do
HttpFeatureFlags.instance.add_http_feature_flag(FeatureFlagNames.recommended_related_links, 'false')
content_item = content_store_has_schema_example('case_study', 'case_study')

get :show, params: { path: path_for(content_item) }

assert_includes response.headers['Vary'], FeatureFlagNames.recommended_related_links
assert_equal 'false', response.headers[FeatureFlagNames.recommended_related_links]
end

test "sets the expiry as sent by content-store" do
content_item = content_store_has_schema_example('coming_soon', 'coming_soon')
content_store_has_item(content_item['base_path'], content_item, max_age: 20)
Expand Down
7 changes: 7 additions & 0 deletions test/models/feature_toggler_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ class FeatureTogglerTest < ActiveSupport::TestCase
assert_equal(true, use_recommended_links)
end

test 'feature_flags attr_reader delegates to instance of feature_flags' do
feature_flags = HttpFeatureFlags.new
feature_toggler = FeatureToggler.new(feature_flags)

assert_equal feature_flags, feature_toggler.feature_flags
end

def setup
@request_headers = { 'HTTP_GOVUK_USE_RECOMMENDED_RELATED_LINKS': 'true' }
end
Expand Down
17 changes: 17 additions & 0 deletions test/models/http_feature_flags_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,21 @@ class HttpFeatureFlagsTest < ActiveSupport::TestCase
feature_enabled = instance.feature_enabled?('USE_MAGIC', 'USE_MAGIC' => 'only_at_weekends')
assert_equal(true, feature_enabled)
end

test 'get_feature_flag returns nil when feature flag does not exist' do
instance = HttpFeatureFlags.new

feature_flag_value = instance.get_feature_flag('USE_MAGIC')

assert_equal nil, feature_flag_value
end

test 'get_feature_flag returns feature flag value when feature flag exists' do
instance = HttpFeatureFlags.new

instance.add_http_feature_flag('USE_MAGIC', 'only_at_weekends')
feature_flag_value = instance.get_feature_flag('USE_MAGIC')

assert_equal 'only_at_weekends', feature_flag_value
end
end

0 comments on commit 5ae92a0

Please sign in to comment.