Skip to content

Instantly share code, notes, and snippets.

@brettfishman
Created October 10, 2012 20:39
Show Gist options
  • Save brettfishman/3868277 to your computer and use it in GitHub Desktop.
Save brettfishman/3868277 to your computer and use it in GitHub Desktop.
Testing HTTP caching using RSpec and CanCan
# Given a controller that looks like this
class ModelsController < ApplicationController
load_and_authorize_resource #CanCan
def show
if stale? @model
respond_to do |format|
format.json do
@model
end
end
end
end
end
# The spec looks like this
context "http caching" do
context "given a model" do
before do
@model = Factory :model, :user => @brett
end
context "on the first request" do
it "returns a 200" do
get :show, :id => @model.id, :format => :json
response.code.should == "200"
end
end
context "on a subsequent request" do
before do
get :show, :id => @model.id, :format => :json
response.code.should == "200"
response.headers['ETag'].should be_present
response.headers['Last-Modified'].should be_present
@etag = response.headers['ETag']
@last_modified = response.headers['Last-Modified']
end
context "if it is not stale" do
before do
request.env['HTTP_IF_NONE_MATCH'] = @etag
request.env['HTTP_IF_MODIFIED_SINCE'] = @last_modified
end
it "returns a 304" do
get :show, :id => @model.id, :format => :json
response.code.should == "304"
end
end
context "if it has been updated" do
before do
sleep 1 # To ensure the model.updated_at has a delta of at least 1 sec
@model.touch
request.env['HTTP_IF_NONE_MATCH'] = @etag
request.env['HTTP_IF_MODIFIED_SINCE'] = @last_modified
end
it "returns a 200" do
# Initialize account_item instance in the controller so CanCan
# will load up the resource from the db again
controller.instance_variable_set(:@model, nil)
get :show, :id => @model.id, :format => :json
response.code.should == "200"
end
end
end
end
end
@brettfishman
Copy link
Author

Line 58 is necessary because CanCan "caches" the resource instance internally (see #load_resource in lib/cancan/controller_resource.rb) if it has already been loaded. This is an issue when testing a controller instance, as the next time a request is made to the same instance, the resource will be set to the cached one, which we don't want.

@maxcal
Copy link

maxcal commented May 11, 2014

Is there a reason that the expectation on the first request are in the before block instead of in the "on the first request" context?

context "on the first request" do
  it "returns a 200" do
    get :show, :id => @model.id, :format => :json
    response.code.should == "200"       
  end
  it "set an ETag header" do
    response.headers['ETag'].should be_present
  end
  it "sets 'Last-Modified'" do
    response.headers['Last-Modified'].should be_present
  end 
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment