How to mock/stub restful_authenticated and acl2-ized actions

Dear all,

I am wondering how to properly mock/stub out the preliminary steps to
actions protected by restful_authentication and acl_system2 (role-based
authorization to execute actions). Here’s my setup:

class User < ActiveRecord::Base
has_and_belongs_to_many :roles
has_many :tasks
[snip]
end

class Task < ActiveRecord::Base
belongs_to :user
end

I also have a Role class that habtm :users

Now, for the controller that I need to spec:

class TasksController < ApplicationController
before_filter :login_required
access_control :DEFAULT => ‘operator’

def index
@tasks = current_user.tasks
end
end

Two interesting things happen here. First, access to the index action is
only granted after checking that the user is logged-in and that she is
an ‘operator’. Second, the tasks method is called on current_user, which
is available to all controllers that include AuthenticatedSystem.

I can easily write a few specs for this controller if I use a
fixture_scenario and login_as (see below). On the other hand, I am
trying to learn to abide to the “hey, dont touch that!” database thing.
As a novice, the task of setting up examples in which authentication &
authorization are satisfied, and where current_user still responds
properly appears daunting. But then again, I am a novice!

Thank you all in advance,
Giuseppe

###############

my current specs

###############
include AuthenticatedTestHelper
describe TasksController, “with a logged-in user having ‘operator’
privileges” do
scenario :users_and_roles
before(:each) do
login_as :giuseppe # based on the fixtures, giuseppe is now a
logged-in operator
end

describe “getting the index” do

before(:each) do
  @tasks = mock_model(Task)
  Task.stub!(:find).and_return([@tasks])
end

it "should render index" do
  get :index
  response.should render_template('index')
end

it "should assign to the @tasks instance variable" do
  get :index
  assigns[:tasks].should ==[@tasks]
end

end
end

While my approach might not be the best, since I don’t
stub :login_required, it still serves me well. I would do something
like this:

user = mock_model(User, :operator => true)
controller.stub!(:current_user).and_return(user)

login_required will find the ‘current_user’ and be happy. I don’t
know if the :operator => true thing will cut it for your other check,
but that should get you on the right track.

I hope that helps!
Glenn

Hi Glenn, thanks for the response.

I would do something like this:

user = mock_model(User, :operator => true)
controller.stub!(:current_user).and_return(user)

OK, so, :operator is not a User attribute. Rather, a user is an
operator, so to speak, if a habtm relationship exists between the user
and the role titled ‘operator’. If I modify your code like this:

role = mock_model(Role, :title => 'operator')
user = mock_model(User, :roles => [role])
controller.stub!(:current_user).and_return(user)

things appear to be working well.
Thank you again for your help!

Giuseppe

Hi Jarkko, I see your point.

However, checking the user’s roles in order to authorize access to the
action is done behind the scenes by the acl_system2 plugin, which would
not know what to do with has_role?, unless I am missing something.

Thanks!
Giuseppe

You might want to take that one step further and create a method such
as has_role?(:operator) for the user class. That way you don’t have to
stub arrays like roles in your specs, you just stub that method to
return true or false and you’re done. That way you make your code more
easily “speccable”:

def has_role?(role)
roles.map(&:title).include?(role.to_s)
end

//jarkko

On 8.4.2008, at 23.17, Giuseppe B. wrote:

role = mock_model(Role, :title => ‘operator’)
user = mock_model(User, :roles => [role])
controller.stub!(:current_user).and_return(user)

things appear to be working well.
Thank you again for your help!

You might want to take that one step further and create a method such
as has_role?(:operator) for the user class. That way you don’t have to
stub arrays like roles in your specs, you just stub that method to
return true or false and you’re done. That way you make your code more
easily “speccable”:

def has_role?(role)
roles.map(&:title).include?(role.to_s)
end

//jarkko

Giuseppe

Posted via http://www.ruby-forum.com/.


rspec-users mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users


Jarkko L.

http://www.railsecommerce.com
http://odesign.fi

On Tue, Apr 8, 2008 at 10:03 AM, Giuseppe B. [email protected]
wrote:

Dear all,

I am wondering how to properly mock/stub out the preliminary steps to
actions protected by restful_authentication and acl_system2 (role-based
authorization to execute actions). Here’s my setup:

I use a different authorization plugin, so you might have to adapt, but
I’ve
got the following in my spec_helper:

def as_role(roles = [])
returning User.new do |user|
# This will become stub_model whenever 1.1.4 comes out …
user.id = 2000
user.stub!(:new_record?).and_return false
user.stub!(:valid?).and_return true

if @controller
  @controller.stub!(:login_required).and_return true
  @controller.stub!(:current_user).and_return true
  @controller.stub!(:logged_in?).and_return true
end

user.stub!(:has_role?).and_return false  # because has_role? hits 

the DB
[*roles].map(&:to_s).each do |role|
user.stub!(“is_#{role}?”).and_return true
user.stub!(:has_role?).with(role).and_return true
end
end
end
alias :logged_in :as_role

This returns a User, and can be used in either the controller or in
model
specs, to deal with various aspects of a roled user. You can call it
with
an array of roles, or a single role; it deals with it either way. The
last
alias is because logged_in looks better than as_role without any
arguments.