rack-cache-buster 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.markdown +13 -17
- data/lib/rack/cache_buster.rb +34 -29
- data/lib/rack/cache_buster/cache_control_header.rb +46 -0
- data/recipes/rack_cache_buster_recipes.rb +57 -0
- data/test/cache_busting_test.rb +18 -11
- metadata +5 -4
- data/lib/rack/cache_buster/auto.rb +0 -13
- data/test/auto_test.rb +0 -70
    
        data/README.markdown
    CHANGED
    
    | @@ -1,25 +1,17 @@ | |
| 1 1 | 
             
            # Rack::CacheBuster
         | 
| 2 2 |  | 
| 3 | 
            -
            Place this in your rack stack and all caching will be gone.
         | 
| 4 | 
            -
             | 
| 5 | 
            -
            Add an optional key to salt the ETags in and out of your app.
         | 
| 6 | 
            -
             | 
| 7 | 
            -
            ## Usage:
         | 
| 8 | 
            -
                use Rack::CacheBuster, APP_VERSION
         | 
| 9 | 
            -
             | 
| 10 | 
            -
            # Rack::CacheBuster::Auto
         | 
| 11 | 
            -
             | 
| 12 3 | 
             
            Use to wind down a running app when needed.
         | 
| 13 4 |  | 
| 14 | 
            -
             | 
| 5 | 
            +
            Limits the max-age to the contents of the `WIND_DOWN` file, and salts the ETags to unsure clients see different deployments as having different contents.
         | 
| 15 6 |  | 
| 16 7 | 
             
            ## Usage:
         | 
| 8 | 
            +
                require "rack/cache_buster"
         | 
| 9 | 
            +
                WIND_DOWN_TIME = Time.parse(File.read(File.join(Rails.root, "WIND_DOWN"))) rescue nil
         | 
| 10 | 
            +
                APP_VERSION    = File.read(File.join(Rails.root, "REVISION")) rescue nil
         | 
| 11 | 
            +
                
         | 
| 12 | 
            +
                …
         | 
| 17 13 |  | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
            ensure you have a REVISION file on your production servers, capistrano does this by default.
         | 
| 21 | 
            -
             | 
| 22 | 
            -
                use Rack::CacheBuster::Auto, File.join(Rails.root, "REVISION"), File.join(Rails.root, "WIND_DOWN")
         | 
| 14 | 
            +
                use Rack::CacheBuster, APP_VERSION, WIND_DOWN_TIME
         | 
| 23 15 |  | 
| 24 16 | 
             
            ### Before you deploy:
         | 
| 25 17 |  | 
| @@ -29,6 +21,10 @@ ensure you have a REVISION file on your production servers, capistrano does this | |
| 29 21 |  | 
| 30 22 | 
             
            * Restart all instances (touch tmp/restart.txt will be fine for passenger apps).
         | 
| 31 23 |  | 
| 32 | 
            -
             | 
| 24 | 
            +
            * Once all the caches should have expired you can deploy as normal.
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            ## Notes
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            If you are using Rack::Cache, you can safely put the CacheBuster below it in the stack, but only if you clear Rack::Cache's cache upon deploy.
         | 
| 33 29 |  | 
| 34 | 
            -
             | 
| 30 | 
            +
            This is actually the recommended approach as it will prevent the increased amount of hits between `WIND_DOWN_TIME` and your actual deployment from making it through to your app.
         | 
    
        data/lib/rack/cache_buster.rb
    CHANGED
    
    | @@ -2,53 +2,58 @@ require 'digest/md5' | |
| 2 2 |  | 
| 3 3 | 
             
            module Rack
         | 
| 4 4 | 
             
              class CacheBuster
         | 
| 5 | 
            -
                 | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
                  @ | 
| 9 | 
            -
                  if key
         | 
| 10 | 
            -
                    @key = "-"+Digest::MD5.hexdigest(key).freeze
         | 
| 11 | 
            -
                    @key_regexp = /#{@key}/.freeze
         | 
| 12 | 
            -
                  end
         | 
| 5 | 
            +
                def initialize(app, key, target_time = nil)
         | 
| 6 | 
            +
                  @app, @target_time = app, target_time
         | 
| 7 | 
            +
                  @key = "-"+Digest::MD5.hexdigest(key || "blank-key").freeze
         | 
| 8 | 
            +
                  @key_regexp = /#{@key}/.freeze
         | 
| 13 9 | 
             
                end
         | 
| 14 10 |  | 
| 15 11 | 
             
                def call(env)
         | 
| 16 | 
            -
                   | 
| 17 | 
            -
                   | 
| 18 | 
            -
             | 
| 19 | 
            -
                  status, headers, body = app.call(env)
         | 
| 20 | 
            -
             | 
| 21 | 
            -
                  headers = headers.dup
         | 
| 22 | 
            -
                  patch_etag!(headers) if key
         | 
| 23 | 
            -
                  bust_cache!(headers)
         | 
| 24 | 
            -
             | 
| 25 | 
            -
                  [status, headers, body]
         | 
| 12 | 
            +
                  status, headers, body = app.call(unpatch_etag(env))
         | 
| 13 | 
            +
                  [status, patch_etag(limit_cache(headers)), body]
         | 
| 26 14 | 
             
                end
         | 
| 27 15 |  | 
| 28 16 | 
             
              protected
         | 
| 29 17 | 
             
                QUOTE_STRIPPER=/^"|"$/.freeze
         | 
| 30 18 | 
             
                ETAGGY_HEADERS = ["HTTP_IF_NONE_MATCH", "HTTP_IF_MATCH", "HTTP_IF_RANGE"].freeze
         | 
| 31 19 | 
             
                ETag = "ETag".freeze
         | 
| 32 | 
            -
                CacheControl = "Cache-Control".freeze
         | 
| 33 20 |  | 
| 34 21 | 
             
                attr_reader :app
         | 
| 35 22 | 
             
                attr_reader :key
         | 
| 36 23 |  | 
| 37 24 |  | 
| 38 | 
            -
                def  | 
| 39 | 
            -
                  headers | 
| 25 | 
            +
                def limit_cache(headers)
         | 
| 26 | 
            +
                  return headers if @target_time.nil?
         | 
| 27 | 
            +
                  cache_control_header = CacheControlHeader.new(headers)
         | 
| 28 | 
            +
                  if cache_control_header.expired?
         | 
| 29 | 
            +
                    headers
         | 
| 30 | 
            +
                  else
         | 
| 31 | 
            +
                    cache_control_header.expire_time = [@target_time, cache_control_header.expire_time].min
         | 
| 32 | 
            +
                    headers.merge(CacheControlHeader::CacheControl => cache_control_header.to_s)
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                def unpatch_etag(headers)
         | 
| 37 | 
            +
                  p headers
         | 
| 38 | 
            +
                  ETAGGY_HEADERS.inject(headers){|memo, k|
         | 
| 39 | 
            +
                    p [k, memo[k], strip_etag(memo[k])] if memo[k]
         | 
| 40 | 
            +
                    memo.has_key?(k) ? memo.merge(k => strip_etag(memo[k])) : memo
         | 
| 41 | 
            +
                  }
         | 
| 40 42 | 
             
                end
         | 
| 41 43 |  | 
| 42 | 
            -
                def  | 
| 43 | 
            -
                   | 
| 44 | 
            -
                    headers[k] = headers[k].gsub(@key_regexp, "") if headers[k]
         | 
| 45 | 
            -
                  end
         | 
| 44 | 
            +
                def strip_etag(s)
         | 
| 45 | 
            +
                  s.gsub(@key_regexp, "")
         | 
| 46 46 | 
             
                end
         | 
| 47 47 |  | 
| 48 | 
            -
                def  | 
| 49 | 
            -
                   | 
| 50 | 
            -
                   | 
| 51 | 
            -
                  headers[ETag] = %Q{"#{stripped_tag}#{key}"}
         | 
| 48 | 
            +
                def modify_etag(s)
         | 
| 49 | 
            +
                  s = s.to_s.gsub(QUOTE_STRIPPER, "")
         | 
| 50 | 
            +
                  s.empty? ? s : %Q{"#{s}#{key}"}
         | 
| 52 51 | 
             
                end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                def patch_etag(headers)
         | 
| 54 | 
            +
                  headers.merge(ETag => modify_etag(headers[ETag]))
         | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                autoload :CacheControlHeader, "rack/cache_buster/cache_control_header"
         | 
| 53 58 | 
             
              end
         | 
| 54 59 | 
             
            end
         | 
| @@ -0,0 +1,46 @@ | |
| 1 | 
            +
            require "rack/cache_buster"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class Rack::CacheBuster::CacheControlHeader < Rack::CacheBuster
         | 
| 4 | 
            +
              CacheControl = "Cache-Control".freeze
         | 
| 5 | 
            +
              Age = "Age".freeze
         | 
| 6 | 
            +
              MaxAge = "max-age".freeze
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              def initialize(env)
         | 
| 9 | 
            +
                @age = env[Age].to_i
         | 
| 10 | 
            +
                @max_age = 0
         | 
| 11 | 
            +
                if env[CacheControl]
         | 
| 12 | 
            +
                  parts = env[CacheControl].split(/ *, */)
         | 
| 13 | 
            +
                  settings, options = parts.partition{|part| part =~ /=/ }
         | 
| 14 | 
            +
                  settings = settings.inject({}){|acc, part|
         | 
| 15 | 
            +
                    k, v = part.split(/ *= */, 2)
         | 
| 16 | 
            +
                    acc.merge(k => v)
         | 
| 17 | 
            +
                  }
         | 
| 18 | 
            +
                  @max_age = settings.delete(MaxAge).to_i
         | 
| 19 | 
            +
                  @other_parts = options + settings.map{|k,v| "#{k}=#{v}"}
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              def expires_in
         | 
| 24 | 
            +
                @max_age - @age
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
              def expired?
         | 
| 28 | 
            +
                expires_in <= 0
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
              def expire_time
         | 
| 32 | 
            +
                Time.now + expires_in
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
              def expire_time=(t)
         | 
| 36 | 
            +
                @max_age = [t.to_i - Time.now.to_i + @age, @age].max
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
              def update_env(env)
         | 
| 40 | 
            +
                env[CacheControl] = to_s
         | 
| 41 | 
            +
              end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
              def to_s
         | 
| 44 | 
            +
                ["max-age=#{@max_age}", *@other_parts].join(", ")
         | 
| 45 | 
            +
              end
         | 
| 46 | 
            +
            end
         | 
| @@ -0,0 +1,57 @@ | |
| 1 | 
            +
            def get_wind_down_time
         | 
| 2 | 
            +
              target_time_string = capture("[ -f #{current_path}/WIND_DOWN ] && cat #{current_path}/WIND_DOWN || echo -n ")
         | 
| 3 | 
            +
              if target_time_string.empty?
         | 
| 4 | 
            +
                nil
         | 
| 5 | 
            +
              else
         | 
| 6 | 
            +
                Time.parse(target_time_string)
         | 
| 7 | 
            +
              end
         | 
| 8 | 
            +
            end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            Capistrano::Configuration.instance(:must_exist).load do
         | 
| 11 | 
            +
              unless exists? :wind_down_time
         | 
| 12 | 
            +
                set :wind_down_time, 60*60 # 1.hour
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              namespace :cache do
         | 
| 16 | 
            +
                desc "Start winding down the current deployment."
         | 
| 17 | 
            +
                task :winddown do
         | 
| 18 | 
            +
                  run "echo '#{Time.now + wind_down_time}' > #{current_path}/WIND_DOWN"
         | 
| 19 | 
            +
                  deploy.restart
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                desc "Cancel an in progress wind down."
         | 
| 23 | 
            +
                task :cancel_winddown do
         | 
| 24 | 
            +
                  run "rm -f #{current_path}/WIND_DOWN"
         | 
| 25 | 
            +
                  deploy.restart
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                desc "Check that wind down has completed (or was never started)."
         | 
| 29 | 
            +
                task :check_ready_to_deploy do
         | 
| 30 | 
            +
                  if target_time = get_wind_down_time
         | 
| 31 | 
            +
                    if target_time > Time.now
         | 
| 32 | 
            +
                      puts "Servers are still winding down the cache.\nThey will be done at #{target_time} #{((target_time.to_i - Time.now.to_i)/60.0).ceil} mins from now.\nContinue with deploy?"
         | 
| 33 | 
            +
                      raise "Servers still winding down." if STDIN.gets !~ /^y/i
         | 
| 34 | 
            +
                    else
         | 
| 35 | 
            +
                      puts "Wind Down completed at #{target_time}"
         | 
| 36 | 
            +
                    end
         | 
| 37 | 
            +
                  else
         | 
| 38 | 
            +
                    puts "No wind down in progress."
         | 
| 39 | 
            +
                  end
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                desc "Get info about the current state of the wind down."
         | 
| 43 | 
            +
                task :info do
         | 
| 44 | 
            +
                  if target_time = get_wind_down_time
         | 
| 45 | 
            +
                    if target_time > Time.now
         | 
| 46 | 
            +
                      puts "Servers are winding down the cache.\nThey will be done at #{target_time} #{((target_time.to_i - Time.now.to_i)/60.0).ceil} mins from now."
         | 
| 47 | 
            +
                    else
         | 
| 48 | 
            +
                      puts "Wind Down completed at #{target_time}"
         | 
| 49 | 
            +
                    end
         | 
| 50 | 
            +
                  else
         | 
| 51 | 
            +
                    puts "No wind down in progress."
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
              end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
              before "deploy:update_code", "cache:check_ready_to_deploy"
         | 
| 57 | 
            +
            end
         | 
    
        data/test/cache_busting_test.rb
    CHANGED
    
    | @@ -5,7 +5,7 @@ class CacheBustingTest < IntegrationTest | |
| 5 5 |  | 
| 6 6 | 
             
              should "forward the request to the app" do
         | 
| 7 7 | 
             
                given_env = nil
         | 
| 8 | 
            -
                @app = Rack::CacheBuster.new(lambda { |env| given_env = env; [200, {}, []]  })
         | 
| 8 | 
            +
                @app = Rack::CacheBuster.new(lambda { |env| given_env = env; [200, {}, []]  }, nil, Time.now)
         | 
| 9 9 | 
             
                get "/foooo"
         | 
| 10 10 | 
             
                assert_not_nil given_env
         | 
| 11 11 | 
             
                assert_equal given_env["PATH_INFO"], "/foooo"
         | 
| @@ -14,7 +14,7 @@ class CacheBustingTest < IntegrationTest | |
| 14 14 | 
             
              should "forward the request to the app with digests removed" do
         | 
| 15 15 | 
             
                given_env = nil
         | 
| 16 16 |  | 
| 17 | 
            -
                @app = Rack::CacheBuster.new(lambda { |env| given_env = env; [200, {}, []]  }, "foo")
         | 
| 17 | 
            +
                @app = Rack::CacheBuster.new(lambda { |env| given_env = env; [200, {}, []]  }, "foo", Time.now)
         | 
| 18 18 |  | 
| 19 19 | 
             
                ["If-None-Match", "If-Match", "If-Range"].each do |k|
         | 
| 20 20 | 
             
                  header(k, "foo-#{DIGEST_OF_FOO}")
         | 
| @@ -27,21 +27,28 @@ class CacheBustingTest < IntegrationTest | |
| 27 27 | 
             
                end
         | 
| 28 28 | 
             
              end
         | 
| 29 29 |  | 
| 30 | 
            -
              should "set  | 
| 31 | 
            -
                @app = Rack::CacheBuster.new(CACHEY_APP)
         | 
| 30 | 
            +
              should "set max-age to 0 if we should already have expired" do
         | 
| 31 | 
            +
                @app = Rack::CacheBuster.new(CACHEY_APP, nil, Time.now - 100)
         | 
| 32 32 | 
             
                get "/foooo"
         | 
| 33 | 
            -
                assert_equal " | 
| 33 | 
            +
                assert_equal "max-age=0, public", last_response["Cache-Control"]
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
              should "set max-age to 0 if we are at expirey time" do
         | 
| 37 | 
            +
                @app = Rack::CacheBuster.new(CACHEY_APP, nil, Time.now)
         | 
| 38 | 
            +
                get "/foooo"
         | 
| 39 | 
            +
                assert_equal "max-age=0, public", last_response["Cache-Control"]
         | 
| 40 | 
            +
              end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
              should "set max-age to 10 if we have 10s left" do
         | 
| 43 | 
            +
                @app = Rack::CacheBuster.new(CACHEY_APP, nil, Time.now + 10)
         | 
| 44 | 
            +
                get "/foooo"
         | 
| 45 | 
            +
                assert_equal "max-age=10, public", last_response["Cache-Control"]
         | 
| 34 46 | 
             
              end
         | 
| 35 47 |  | 
| 36 48 | 
             
              should 'append version to etag of response' do
         | 
| 37 | 
            -
                @app = Rack::CacheBuster.new(CACHEY_APP, "foo")
         | 
| 49 | 
            +
                @app = Rack::CacheBuster.new(CACHEY_APP, "foo", Time.now)
         | 
| 38 50 | 
             
                get "/"
         | 
| 39 51 | 
             
                assert_equal %Q{"an-etag-#{DIGEST_OF_FOO}"}, last_response["ETag"]
         | 
| 40 52 | 
             
              end
         | 
| 41 53 |  | 
| 42 | 
            -
              should "leave the ETag alone if no key is given" do
         | 
| 43 | 
            -
                @app = Rack::CacheBuster.new(CACHEY_APP)
         | 
| 44 | 
            -
                get "/foooo"
         | 
| 45 | 
            -
                assert_equal %Q{"an-etag"}, last_response["ETag"]
         | 
| 46 | 
            -
              end
         | 
| 47 54 | 
             
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification 
         | 
| 2 2 | 
             
            name: rack-cache-buster
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.2.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors: 
         | 
| 7 7 | 
             
            - Tom Lea
         | 
| @@ -9,7 +9,7 @@ autorequire: | |
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 11 |  | 
| 12 | 
            -
            date: 2009-10- | 
| 12 | 
            +
            date: 2009-10-23 00:00:00 +01:00
         | 
| 13 13 | 
             
            default_executable: 
         | 
| 14 14 | 
             
            dependencies: []
         | 
| 15 15 |  | 
| @@ -23,10 +23,10 @@ extra_rdoc_files: | |
| 23 23 | 
             
            - README.markdown
         | 
| 24 24 | 
             
            files: 
         | 
| 25 25 | 
             
            - README.markdown
         | 
| 26 | 
            -
            -  | 
| 26 | 
            +
            - recipes/rack_cache_buster_recipes.rb
         | 
| 27 27 | 
             
            - test/cache_busting_test.rb
         | 
| 28 28 | 
             
            - test/test_helper.rb
         | 
| 29 | 
            -
            - lib/rack/cache_buster/ | 
| 29 | 
            +
            - lib/rack/cache_buster/cache_control_header.rb
         | 
| 30 30 | 
             
            - lib/rack/cache_buster.rb
         | 
| 31 31 | 
             
            has_rdoc: true
         | 
| 32 32 | 
             
            homepage: http://tomlea.co.uk/
         | 
| @@ -37,6 +37,7 @@ rdoc_options: | |
| 37 37 | 
             
            - --main
         | 
| 38 38 | 
             
            - README.markdown
         | 
| 39 39 | 
             
            require_paths: 
         | 
| 40 | 
            +
            - recipes
         | 
| 40 41 | 
             
            - lib
         | 
| 41 42 | 
             
            required_ruby_version: !ruby/object:Gem::Requirement 
         | 
| 42 43 | 
             
              requirements: 
         | 
| @@ -1,13 +0,0 @@ | |
| 1 | 
            -
            require "rack/cache_buster"
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            class Rack::CacheBuster::Auto < Rack::CacheBuster
         | 
| 4 | 
            -
              def initialize(app, key_filename, enabled_filename)
         | 
| 5 | 
            -
                @enabled = File.exists?(enabled_filename)
         | 
| 6 | 
            -
                key = File.exists?(key_filename) && File.open(key_filename).gets.chomp
         | 
| 7 | 
            -
                super(app, key)
         | 
| 8 | 
            -
              end
         | 
| 9 | 
            -
             | 
| 10 | 
            -
              def bust_cache!(headers)
         | 
| 11 | 
            -
                @enabled ? super(headers) : headers
         | 
| 12 | 
            -
              end
         | 
| 13 | 
            -
            end
         | 
    
        data/test/auto_test.rb
    DELETED
    
    | @@ -1,70 +0,0 @@ | |
| 1 | 
            -
            #FOO
         | 
| 2 | 
            -
            require "test_helper"
         | 
| 3 | 
            -
             | 
| 4 | 
            -
            class CacheBusterAutoTest < IntegrationTest
         | 
| 5 | 
            -
              DIGEST_OF_HASH_FOO=Digest::MD5.hexdigest("#FOO")
         | 
| 6 | 
            -
             | 
| 7 | 
            -
              context "with no key files" do
         | 
| 8 | 
            -
                setup do
         | 
| 9 | 
            -
                  @app = Rack::CacheBuster::Auto.new(CACHEY_APP, "/no-file-here.txt", "/no-file-here.txt")
         | 
| 10 | 
            -
                end
         | 
| 11 | 
            -
             | 
| 12 | 
            -
                should "not set cache-control to no-cache" do
         | 
| 13 | 
            -
                  get "/foooo"
         | 
| 14 | 
            -
                  assert_not_equal "no-cache", last_response["Cache-Control"]
         | 
| 15 | 
            -
                end
         | 
| 16 | 
            -
             | 
| 17 | 
            -
                should "leave the ETag alone" do
         | 
| 18 | 
            -
                  get "/foooo"
         | 
| 19 | 
            -
                  assert_equal %Q{"an-etag"}, last_response["ETag"]
         | 
| 20 | 
            -
                end
         | 
| 21 | 
            -
              end
         | 
| 22 | 
            -
             | 
| 23 | 
            -
              context "with a key file" do
         | 
| 24 | 
            -
                setup do
         | 
| 25 | 
            -
                  @app = Rack::CacheBuster::Auto.new(CACHEY_APP, __FILE__, "/no-file-here.txt")
         | 
| 26 | 
            -
                end
         | 
| 27 | 
            -
             | 
| 28 | 
            -
                should "still not set cache-control to no-cache" do
         | 
| 29 | 
            -
                  get "/foooo"
         | 
| 30 | 
            -
                  assert_not_equal "no-cache", last_response["Cache-Control"]
         | 
| 31 | 
            -
                end
         | 
| 32 | 
            -
             | 
| 33 | 
            -
                should "fiddle with the ETag" do
         | 
| 34 | 
            -
                  get "/foooo"
         | 
| 35 | 
            -
                  assert_equal %Q{"an-etag-#{DIGEST_OF_HASH_FOO}"}, last_response["ETag"]
         | 
| 36 | 
            -
                end
         | 
| 37 | 
            -
              end
         | 
| 38 | 
            -
             | 
| 39 | 
            -
              context "with an enabled file" do
         | 
| 40 | 
            -
                setup do
         | 
| 41 | 
            -
                  @app = Rack::CacheBuster::Auto.new(CACHEY_APP, "/no-file-here.txt", __FILE__)
         | 
| 42 | 
            -
                end
         | 
| 43 | 
            -
             | 
| 44 | 
            -
                should "set cache-control to no-cache" do
         | 
| 45 | 
            -
                  get "/foooo"
         | 
| 46 | 
            -
                  assert_equal "no-cache", last_response["Cache-Control"]
         | 
| 47 | 
            -
                end
         | 
| 48 | 
            -
             | 
| 49 | 
            -
                should "leave the ETag alone" do
         | 
| 50 | 
            -
                  get "/foooo"
         | 
| 51 | 
            -
                  assert_equal %Q{"an-etag"}, last_response["ETag"]
         | 
| 52 | 
            -
                end
         | 
| 53 | 
            -
              end
         | 
| 54 | 
            -
             | 
| 55 | 
            -
              context "with an enabled file and a key file" do
         | 
| 56 | 
            -
                setup do
         | 
| 57 | 
            -
                  @app = Rack::CacheBuster::Auto.new(CACHEY_APP, __FILE__, __FILE__)
         | 
| 58 | 
            -
                end
         | 
| 59 | 
            -
             | 
| 60 | 
            -
                should "set cache-control to no-cache" do
         | 
| 61 | 
            -
                  get "/foooo"
         | 
| 62 | 
            -
                  assert_equal "no-cache", last_response["Cache-Control"]
         | 
| 63 | 
            -
                end
         | 
| 64 | 
            -
             | 
| 65 | 
            -
                should "fiddle with the ETag" do
         | 
| 66 | 
            -
                  get "/foooo"
         | 
| 67 | 
            -
                  assert_equal %Q{"an-etag-#{DIGEST_OF_HASH_FOO}"}, last_response["ETag"]
         | 
| 68 | 
            -
                end
         | 
| 69 | 
            -
              end
         | 
| 70 | 
            -
            end
         |