test: cover PolicyTestArticlePolicy, edit? and RateLimiterDslTest

This commit is contained in:
dualfroz committed 2026-09-13 19:03:43 +02:00
1 parent d23fb5fec3
commit c81a6bee5f
3 files changed
+191

No files matched your search

+74
View File
@@ -0,0 +1,74 @@
require 'minitest/autorun'
require 'prism'
PolicyTestUser = Struct.new(:id)
PolicyTestArticle = Struct.new(:id, :owner_id)
class PolicyTestArticlePolicy < Prism::Policy
def edit?
user && record.owner_id == user.id
end
alias_method :destroy?, :edit?
end
class PolicyTestArticlePolicy::Scope < Prism::Policy::Scope
def resolve
scope.select { |article| user && article.owner_id == user.id }
end
end
class PolicyEmptyPolicy < Prism::Policy
end
class PolicyTest < Minitest::Test
def setup
@owner = PolicyTestUser.new(1)
@stranger = PolicyTestUser.new(2)
@article = PolicyTestArticle.new(10, 1)
end
def test_owner_may_edit_and_destroy
policy = PolicyTestArticlePolicy.new(@owner, @article)
assert policy.edit?
assert policy.destroy?
end
def test_stranger_may_not_edit_or_destroy
policy = PolicyTestArticlePolicy.new(@stranger, @article)
refute policy.edit?
refute policy.destroy?
end
def test_undeclared_query_default_denies
policy = PolicyEmptyPolicy.new(@owner, @article)
refute policy.publish?
refute policy.archive?
end
def test_non_predicate_missing_method_still_raises
policy = PolicyEmptyPolicy.new(@owner, @article)
assert_raises(NoMethodError) { policy.some_method }
end
def test_for_record_resolves_the_conventional_policy_class
assert_equal PolicyTestArticlePolicy, Prism::Policy.for_record(@article)
assert_equal PolicyTestArticlePolicy, Prism::Policy.for_record(PolicyTestArticle)
end
def test_scope_resolves_to_only_the_users_own_records
articles = [@article, PolicyTestArticle.new(11, 2)]
resolved = PolicyTestArticlePolicy::Scope.new(@owner, articles).resolve
assert_equal [@article], resolved
end
def test_scope_base_class_requires_resolve_to_be_implemented
assert_raises(NotImplementedError) { Prism::Policy::Scope.new(@owner, []).resolve }
end
def test_not_authorized_error_carries_record_and_query
error = Prism::Policy::NotAuthorizedError.new(@article, 'destroy?')
assert_equal @article, error.record
assert_equal 'destroy?', error.query
assert_includes error.message, 'destroy?'
end
end
+64
View File
@@ -0,0 +1,64 @@
require 'minitest/autorun'
require 'prism'
class RateLimiterDslTest < Minitest::Test
def setup
Prism::RateLimiter.reset!
end
def teardown
Prism::RateLimiter.reset!
end
def test_throttle_registers_a_named_rule
Prism::RateLimiter.throttle('logins/ip', limit: 5, period: 60) { |req| req }
rule = Prism::RateLimiter.throttles.fetch('logins/ip')
assert_equal 5, rule.limit
assert_equal 60, rule.period
end
def test_blocklist_safelist_and_track_registries_are_independent
Prism::RateLimiter.blocklist('bad-actors') { |_req| true }
Prism::RateLimiter.safelist('internal') { |_req| false }
Prism::RateLimiter.track('all-requests') { |_req| true }
assert_equal %w[bad-actors], Prism::RateLimiter.blocklists.keys
assert_equal %w[internal], Prism::RateLimiter.safelists.keys
assert_equal %w[all-requests], Prism::RateLimiter.tracks.keys
end
def test_reset_clears_every_registry_and_the_store
Prism::RateLimiter.throttle('t', limit: 1, period: 60) { |_req| 'k' }
Prism::RateLimiter.store.count('t:k', 60)
Prism::RateLimiter.reset!
assert_empty Prism::RateLimiter.throttles
assert_equal 1, Prism::RateLimiter.store.count('t:k', 60)
end
def test_on_notify_receives_type_name_request_and_payload
seen = []
Prism::RateLimiter.on_notify { |type, name, _request, payload| seen << [type, name, payload] }
Prism::RateLimiter.notify(:throttle, 'logins/ip', :fake_request, '1.2.3.4')
assert_equal [[:throttle, 'logins/ip', '1.2.3.4']], seen
end
def test_fail2ban_filter_allows_offenses_below_the_threshold
3.times.each do |i|
blocked = Prism::RateLimiter.fail2ban_filter('1.2.3.4', maxretry: 3, findtime: 60, bantime: 300) { true }
assert_equal(i == 2, blocked)
end
end
def test_fail2ban_filter_ignores_non_offenses
5.times do
refute Prism::RateLimiter.fail2ban_filter('1.2.3.4', maxretry: 3, findtime: 60, bantime: 300) { false }
end
end
def test_fail2ban_filter_keeps_blocking_once_banned_even_without_a_new_offense
3.times { Prism::RateLimiter.fail2ban_filter('1.2.3.4', maxretry: 3, findtime: 60, bantime: 300) { true } }
assert Prism::RateLimiter.fail2ban_filter('1.2.3.4', maxretry: 3, findtime: 60, bantime: 300) { false }
end
end
+53
View File
@@ -0,0 +1,53 @@
require 'minitest/autorun'
require 'prism'
class RateLimiterMemoryStoreTest < Minitest::Test
def setup
@store = Prism::RateLimiter::MemoryStore.new
end
def test_count_increments_within_the_same_window
assert_equal 1, @store.count('ip:1', 60)
assert_equal 2, @store.count('ip:1', 60)
assert_equal 3, @store.count('ip:1', 60)
end
def test_count_is_independent_per_key
assert_equal 1, @store.count('ip:1', 60)
assert_equal 1, @store.count('ip:2', 60)
end
def test_count_resets_after_the_window_elapses
assert_equal 1, @store.count('ip:1', 0.05)
assert_equal 2, @store.count('ip:1', 0.05)
sleep 0.08
assert_equal 1, @store.count('ip:1', 0.05)
end
def test_banned_is_false_when_never_banned
refute @store.banned?('ip:1')
end
def test_ban_makes_banned_true_until_it_expires
@store.ban!('ip:1', 0.05)
assert @store.banned?('ip:1')
sleep 0.08
refute @store.banned?('ip:1')
end
def test_reset_clears_windows_and_bans
@store.count('ip:1', 60)
@store.ban!('ip:2', 60)
@store.reset!
assert_equal 1, @store.count('ip:1', 60)
refute @store.banned?('ip:2')
end
def test_concurrent_increments_do_not_lose_updates
threads = Array.new(20) do
Thread.new { 100.times { @store.count('shared', 60) } }
end
threads.each(&:join)
assert_equal 2001, @store.count('shared', 60)
end
end