test: cover test_revoke_login_session_by_id_signs_out_only_that_device

This commit is contained in:
dualfroz committed 2026-09-09 16:59:24 +02:00
1 parent a04596c925
commit f0803046dd
1 file changed
+122
+122
View File
@@ -476,3 +476,125 @@ class AuthenticatableTest < Minitest::Test
assert_equal 200, status_a
end
def test_revoke_login_session_by_id_signs_out_only_that_device
browser_a_remember = cookie_named(multi_sign_in, 'remember_session_token')
browser_b_remember = cookie_named(multi_sign_in, 'remember_session_token')
browser_b_id = AuthLoginSession.order(:id, :desc).first.id
status, _, body = call('POST', "/multi/revoke/#{browser_b_id}", cookies: browser_a_remember)
assert_equal 200, status
assert_equal 'revoked', body.join
status_b, = call('GET', '/multi/dashboard', cookies: browser_b_remember)
assert_equal 302, status_b
status_a, = call('GET', '/multi/dashboard', cookies: browser_a_remember)
assert_equal 200, status_a
end
def test_revoke_login_session_refuses_a_session_belonging_to_another_user
AuthUser.create!(email: 'other@example.com', password: 'hunter2')
other_login = AuthLoginSession.create!(user_id: AuthUser.find_by(email: 'other@example.com').id)
browser_a_remember = cookie_named(multi_sign_in, 'remember_session_token')
status, _, body = call('POST', "/multi/revoke/#{other_login.id}", cookies: browser_a_remember)
assert_equal 404, status
assert_equal 'not found', body.join
refute_nil AuthLoginSession.find_by(id: other_login.id)
end
def test_revoking_the_current_login_session_signs_that_browser_out_too
browser_a_remember = cookie_named(multi_sign_in, 'remember_session_token')
current_id = AuthLoginSession.first.id
call('POST', "/multi/revoke/#{current_id}", cookies: browser_a_remember)
status, = call('GET', '/multi/dashboard', cookies: browser_a_remember)
assert_equal 302, status
end
def test_signing_in_without_remember_does_not_set_a_remember_session_cookie
headers = multi_sign_in(remember: false)
assert_nil cookie_named(headers, 'remember_session_token')
assert_equal 0, AuthLoginSession.count
end
def capped_sign_in
_, headers, = call('POST', '/capped/sign_in',
headers: { 'Content-Type' => 'application/x-www-form-urlencoded' },
body: 'email=foksiu@example.com&password=hunter2')
headers
end
def test_max_remember_sessions_requires_remember_sessions
error = assert_raises(ArgumentError) do
Class.new(Prism::Controller) do
include Prism::Authenticatable
authenticate_with model: :AuthUser, max_remember_sessions: 2
end
end
assert_match(/max_remember_sessions: requires remember_sessions:/, error.message)
end
def test_under_the_limit_keeps_every_browser
browser_a = cookie_named(capped_sign_in, 'remember_session_token')
browser_b = cookie_named(capped_sign_in, 'remember_session_token')
assert_equal 2, AuthLoginSession.count
status_a, = call('GET', '/capped/dashboard', cookies: browser_a)
status_b, = call('GET', '/capped/dashboard', cookies: browser_b)
assert_equal 200, status_a
assert_equal 200, status_b
end
def test_exceeding_the_limit_signs_out_the_oldest_browser_first
browser_a = cookie_named(capped_sign_in, 'remember_session_token')
browser_b = cookie_named(capped_sign_in, 'remember_session_token')
browser_c = cookie_named(capped_sign_in, 'remember_session_token')
assert_equal 2, AuthLoginSession.count
status_a, = call('GET', '/capped/dashboard', cookies: browser_a)
assert_equal 302, status_a, 'the oldest (first) browser should have been pruned'
status_b, = call('GET', '/capped/dashboard', cookies: browser_b)
status_c, = call('GET', '/capped/dashboard', cookies: browser_c)
assert_equal 200, status_b
assert_equal 200, status_c
end
def test_repeatedly_exceeding_the_limit_keeps_it_pinned_at_the_max
5.times { capped_sign_in }
assert_equal 2, AuthLoginSession.count
end
def zero_capped_sign_in
call('POST', '/zero-capped/sign_in',
headers: { 'Content-Type' => 'application/x-www-form-urlencoded' },
body: 'email=foksiu@example.com&password=hunter2')
end
# `max_remember_sessions: 0` is a deliberately-set "never actually
# remembered" limit (see the comment on prune_oldest_login_sessions) -
# unlike every positive limit above, it must prune the row `sign_in`
# itself just created, not just older ones.
def test_max_remember_sessions_of_zero_prunes_the_row_it_just_created
status, headers, = zero_capped_sign_in
assert_equal 200, status
assert_equal 0, AuthLoginSession.count,
'a limit of 0 must prune the just-created row too, not only rows older than it'
session_cookie = session_cookie_from(headers)
refute_nil session_cookie, 'sign_in always sets the plain session cookie regardless of the remember-row prune'
status, = call('GET', '/zero-capped/dashboard', cookies: session_cookie)
assert_equal 200, status, 'the session cookie set by this very sign_in must still authenticate the request'
end
def test_max_remember_sessions_of_zero_makes_the_remember_cookie_dead_on_arrival
_, headers, = zero_capped_sign_in
remember_cookie = cookie_named(headers, 'remember_session_token')
refute_nil remember_cookie, 'sign_in(remember: true) sets the cookie unconditionally, before the prune runs'
status, = call('GET', '/zero-capped/dashboard', cookies: remember_cookie)
assert_equal 302, status, 'the remember cookie token matches no row once the limit-0 prune destroyed it'
end
end