From 330cd1f35fe09501e268f010ab59beb9b066e5ba Mon Sep 17 00:00:00 2001 From: DualFroz Date: Wed, 9 Sep 2026 22:25:57 +0200 Subject: [PATCH] test: cover ArticlePagesController and show --- test/test_conditional_get.rb | 140 +++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 test/test_conditional_get.rb diff --git a/test/test_conditional_get.rb b/test/test_conditional_get.rb new file mode 100644 index 0000000..395a73f --- /dev/null +++ b/test/test_conditional_get.rb @@ -0,0 +1,140 @@ +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