test: cover AuthzArticlePolicy, destroy? and CacheHelpersTest
This commit is contained in:
1 parent
f0803046dd
commit
730c66caf0
2 files changed
+180
No files matched your search
@@ -0,0 +1,113 @@
|
||||
require 'minitest/autorun'
|
||||
require 'prism'
|
||||
require 'support'
|
||||
require 'tmpdir'
|
||||
|
||||
class AuthzArticlePolicy < Prism::Policy
|
||||
def destroy?
|
||||
user && record.user_id == user.id
|
||||
end
|
||||
end
|
||||
|
||||
class AuthzSessionsController < Prism::Controller
|
||||
include Prism::Authenticatable
|
||||
authenticate_with model: :AuthzUser
|
||||
|
||||
def create
|
||||
user = AuthzUser.find_by(email: params['email'])
|
||||
if user
|
||||
sign_in(user)
|
||||
halt(200, 'signed in')
|
||||
else
|
||||
halt(401, 'invalid credentials')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class ArticlesController < Prism::Controller
|
||||
include Prism::Authenticatable
|
||||
include Prism::Authorizable
|
||||
authenticate_with model: :AuthzUser
|
||||
before_action :require_authentication, only: %i[destroy]
|
||||
rescue_from Prism::Policy::NotAuthorizedError, with: :forbidden
|
||||
|
||||
def destroy
|
||||
article = AuthzArticle.find(params['id'])
|
||||
authorize(article)
|
||||
article.destroy
|
||||
halt(200, 'deleted')
|
||||
rescue Prism::Orm::RecordNotFound
|
||||
halt(404, 'not found')
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def forbidden(_exception)
|
||||
halt(403, 'forbidden')
|
||||
end
|
||||
end
|
||||
|
||||
class AuthorizableApp < Prism::Application
|
||||
enable_sessions(secret: 'authz-secret')
|
||||
post '/sign_in', to: 'authz_sessions#create'
|
||||
delete '/articles/:id', to: 'articles#destroy'
|
||||
end
|
||||
|
||||
class AuthorizableTest < Minitest::Test
|
||||
include TestSupport
|
||||
|
||||
def setup
|
||||
@dir = Dir.mktmpdir('prism-authorizable')
|
||||
@store = Prism::Orm::Store.new(File.join(@dir, 'test.pstore'))
|
||||
@store.create_table(:authz_users, %w[id email])
|
||||
@store.create_table(:authz_articles, %w[id title user_id])
|
||||
|
||||
user_class = Class.new(Prism::Orm::Model) { table_name :authz_users }
|
||||
user_class.store = @store
|
||||
Object.const_set(:AuthzUser, user_class)
|
||||
|
||||
article_class = Class.new(Prism::Orm::Model) { table_name :authz_articles }
|
||||
article_class.store = @store
|
||||
Object.const_set(:AuthzArticle, article_class)
|
||||
|
||||
@owner = AuthzUser.create!(email: 'owner@example.com')
|
||||
@stranger = AuthzUser.create!(email: 'stranger@example.com')
|
||||
@article = AuthzArticle.create!(title: 'mine', user_id: @owner.id)
|
||||
end
|
||||
|
||||
def teardown
|
||||
FileUtils.remove_entry(@dir)
|
||||
Object.send(:remove_const, :AuthzUser) if Object.const_defined?(:AuthzUser)
|
||||
Object.send(:remove_const, :AuthzArticle) if Object.const_defined?(:AuthzArticle)
|
||||
end
|
||||
|
||||
def call(method, path, **opts)
|
||||
AuthorizableApp.call(env_for(method, path, **opts))
|
||||
end
|
||||
|
||||
def cookie_for(email)
|
||||
_, headers, = call('POST', '/sign_in',
|
||||
headers: { 'Content-Type' => 'application/x-www-form-urlencoded' },
|
||||
body: URI.encode_www_form('email' => email))
|
||||
lines = headers['Set-Cookie'].split("\n")
|
||||
lines.find { |line| line.start_with?('prism.session=') }.split(';').first
|
||||
end
|
||||
|
||||
def test_owner_may_destroy_their_own_article
|
||||
status, _, body = call('DELETE', "/articles/#{@article.id}", cookies: cookie_for('owner@example.com'))
|
||||
assert_equal 200, status
|
||||
assert_equal 'deleted', body.join
|
||||
end
|
||||
|
||||
def test_stranger_gets_403_instead_of_destroying_someone_elses_article
|
||||
status, _, body = call('DELETE', "/articles/#{@article.id}", cookies: cookie_for('stranger@example.com'))
|
||||
assert_equal 403, status
|
||||
assert_equal 'forbidden', body.join
|
||||
assert AuthzArticle.find_by(id: @article.id), 'the article must survive a denied authorization'
|
||||
end
|
||||
|
||||
def test_signed_out_request_never_reaches_the_policy_at_all
|
||||
status, = call('DELETE', "/articles/#{@article.id}")
|
||||
assert_equal 401, status
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,67 @@
|
||||
require 'minitest/autorun'
|
||||
require 'prism'
|
||||
require 'tmpdir'
|
||||
require 'fileutils'
|
||||
|
||||
class CacheHelpersTest < Minitest::Test
|
||||
def setup
|
||||
Prism::Cache.store.clear
|
||||
@dir = Dir.mktmpdir('prism-cache-helpers')
|
||||
FileUtils.mkdir_p(File.join(@dir, 'pages'))
|
||||
@view = Prism::View.new(@dir)
|
||||
end
|
||||
|
||||
def teardown
|
||||
FileUtils.remove_entry(@dir)
|
||||
Prism::Cache.store.clear
|
||||
end
|
||||
|
||||
def write(relative, source)
|
||||
File.write(File.join(@dir, relative), source)
|
||||
end
|
||||
|
||||
def test_cache_block_renders_and_stores_the_fragment
|
||||
write('pages/show.erb', '<% cache("greeting") do %><%= greeting %><% end %>')
|
||||
result = @view.render('pages/show', locals: { greeting: 'hi' })
|
||||
assert_equal 'hi', result
|
||||
assert_equal 'hi', Prism::Cache.store.read('greeting')
|
||||
end
|
||||
|
||||
def test_cache_block_is_not_reevaluated_on_a_hit
|
||||
calls = []
|
||||
write('pages/show.erb', '<% cache("counter") do %><%= track! %><% end %>')
|
||||
@view = Prism::View.new(@dir, helpers: CounterHelper.new(calls))
|
||||
|
||||
first = @view.render('pages/show')
|
||||
second = @view.render('pages/show')
|
||||
|
||||
assert_equal first, second
|
||||
assert_equal 1, calls.size
|
||||
end
|
||||
|
||||
def test_cache_key_can_be_an_array_mixing_scope_and_a_model
|
||||
model = Struct.new(:cache_key).new('posts/7-42')
|
||||
write('pages/show.erb', '<% cache([:sidebar, model]) do %>rendered<% end %>')
|
||||
@view.render('pages/show', locals: { model: model })
|
||||
assert @view.expand_cache_key([:sidebar, model]) == 'sidebar/posts/7-42'
|
||||
assert_equal 'rendered', Prism::Cache.store.read('sidebar/posts/7-42')
|
||||
end
|
||||
|
||||
def test_expires_in_evicts_the_entry_after_the_given_time
|
||||
write('pages/show.erb', '<% cache("temp", expires_in: 0) do %>value<% end %>')
|
||||
@view.render('pages/show')
|
||||
sleep 0.01
|
||||
assert_nil Prism::Cache.store.read('temp')
|
||||
end
|
||||
|
||||
class CounterHelper
|
||||
def initialize(calls)
|
||||
@calls = calls
|
||||
end
|
||||
|
||||
def track!
|
||||
@calls << true
|
||||
'x'
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in new issue
Block a user