Files
prism/test/test_conditional_get.rb
T

141 lines
4.7 KiB
Ruby

require 'minitest/autorun'
require 'prism'
require 'support'
class ArticlePagesController < Prism::Controller
CURRENT_ETAG = 'article-42-v3'
CURRENT_MODIFIED = Time.utc(2026, 1, 1, 12, 0, 0)
def show
fresh_when(etag: CURRENT_ETAG, last_modified: CURRENT_MODIFIED)
html('full article body')
end
def show_strong
fresh_when(etag: CURRENT_ETAG, weak: false)
html('full article body')
end
def edit
if stale?(etag: CURRENT_ETAG)
html('editable article body')
else
raise 'should not reach render when not stale'
end
end
def update
fresh_when(etag: CURRENT_ETAG, last_modified: CURRENT_MODIFIED)
html('updated')
end
end
class ConditionalGetApp < Prism::Application
get '/article', to: 'article_pages#show'
get '/article/strong', to: 'article_pages#show_strong'
get '/article/edit', to: 'article_pages#edit'
patch '/article', to: 'article_pages#update'
end
class ConditionalGetTest < Minitest::Test
include TestSupport
def call(method, path, **opts)
ConditionalGetApp.call(env_for(method, path, **opts))
end
def test_first_request_renders_and_sets_etag_and_last_modified
status, headers, body = call('GET', '/article')
assert_equal 200, status
assert_equal 'full article body', body.join
refute_nil headers['ETag']
assert_equal 'W/"' + Digest::SHA1.hexdigest('article-42-v3') + '"', headers['ETag']
assert_equal ArticlePagesController::CURRENT_MODIFIED.httpdate, headers['Last-Modified']
end
def test_matching_if_none_match_returns_304_with_empty_body
etag = 'W/"' + Digest::SHA1.hexdigest('article-42-v3') + '"'
status, _, body = call('GET', '/article', headers: { 'If-None-Match' => etag })
assert_equal 304, status
assert_equal '', body.join
end
def test_stale_if_none_match_still_renders_with_200
status, _, body = call('GET', '/article', headers: { 'If-None-Match' => 'W/"stale-value"' })
assert_equal 200, status
assert_equal 'full article body', body.join
end
def test_wildcard_if_none_match_is_always_fresh
status, = call('GET', '/article', headers: { 'If-None-Match' => '*' })
assert_equal 304, status
end
def test_if_modified_since_after_last_modified_is_fresh
status, = call('GET', '/article', headers: { 'If-Modified-Since' => (ArticlePagesController::CURRENT_MODIFIED + 3600).httpdate })
assert_equal 304, status
end
def test_if_modified_since_before_last_modified_is_stale
status, _, body = call('GET', '/article', headers: { 'If-Modified-Since' => (ArticlePagesController::CURRENT_MODIFIED - 3600).httpdate })
assert_equal 200, status
assert_equal 'full article body', body.join
end
def test_strong_etag_has_no_weak_prefix
status, headers, = call('GET', '/article/strong')
assert_equal 200, status
assert_equal '"' + Digest::SHA1.hexdigest('article-42-v3') + '"', headers['ETag']
end
def test_stale_predicate_renders_when_no_conditional_headers_sent
status, _, body = call('GET', '/article/edit')
assert_equal 200, status
assert_equal 'editable article body', body.join
end
def test_stale_predicate_halts_with_304_and_skips_render_when_fresh
etag = 'W/"' + Digest::SHA1.hexdigest('article-42-v3') + '"'
status, _, body = call('GET', '/article/edit', headers: { 'If-None-Match' => etag })
assert_equal 304, status
assert_equal '', body.join
end
def test_matching_if_match_lets_the_write_through
etag = 'W/"' + Digest::SHA1.hexdigest('article-42-v3') + '"'
status, _, body = call('PATCH', '/article', headers: { 'If-Match' => etag })
assert_equal 200, status
assert_equal 'updated', body.join
end
def test_stale_if_match_returns_412_and_skips_the_write
status, _, body = call('PATCH', '/article', headers: { 'If-Match' => 'W/"someone-elses-version"' })
assert_equal 412, status
assert_equal '', body.join
end
def test_wildcard_if_match_always_passes_the_precondition
status, = call('PATCH', '/article', headers: { 'If-Match' => '*' })
assert_equal 200, status
end
def test_if_unmodified_since_before_last_modified_returns_412
header = (ArticlePagesController::CURRENT_MODIFIED - 3600).httpdate
status, _, body = call('PATCH', '/article', headers: { 'If-Unmodified-Since' => header })
assert_equal 412, status
assert_equal '', body.join
end
def test_if_unmodified_since_at_or_after_last_modified_lets_the_write_through
header = ArticlePagesController::CURRENT_MODIFIED.httpdate
status, _, body = call('PATCH', '/article', headers: { 'If-Unmodified-Since' => header })
assert_equal 200, status
assert_equal 'updated', body.join
end
def test_no_precondition_headers_lets_the_write_through
status, = call('PATCH', '/article')
assert_equal 200, status
end
end