1

I have a Ruby on Rails app that I'm working on and I'm having some problems with my functional tests. In particular, I keep getting denied access during my tests to pages that are possible to access in the browser when logged in through a user with similar credentials (same roles, etc.). For example, here's code from a test for a controller:

include Devise::TestHelpers
include Authorization::TestHelper
...
setup do
  @user = Factory(:user)
  @user.roles << Factory(:refinery_role)
  @user.roles << Factory(:agency_role)
  @user.save
  sign_in @user

  @agency = AgencyOrganization.create :name => "Test Agency"

  @adv1 = AdvertiserOrganization.create :name => "Test Advertiser", :parent => @agency

  UserOrganization.create :user_id => @user.id, :organization_id => @agency.id
end

test "agency user can edit advertiser" do
  assert @user.has_role? :agency #passes
  should_be_allowed_to :update, :advertiser_organizations #passes

  get :edit, {:id => @adv1.id}, {:agency_id => @agency.id}

  assert_equal "/unauthorized", request.env['PATH_INFO'] #passes :'(
  assert_template :edit #fails
  # and more tests we never get to
end

(Obviously those aren't all assertions I really want to check, but they demonstrate what's going on.)

For what it's worth, the above test fails with the follow exception raised:

4) Failure:
test_agency_user_can_edit_advertiser(AdvertiserOrganizationsControllerTest [/Users/gworley/.rvm/gems/ruby-1.9.2-p180@portal/gems/declarative_authorization-0.5.1/lib/declarative_authorization/maintenance.rb:170]:
Exception raised:
<#<Authorization::NotAuthorized: No matching rules found for update for #<Authorization::GuestUser:0x00000101cda2b0 @role_symbols=[:guest]> (roles [:guest], privileges [:update, :manage], context :advertiser_organizations).>>.

Again, as I said, everything works when you're actually running the app, it's just getting tests to work (although maybe the app is only working by accident, who knows?).

Gordon Seidoh Worley
  • 7,839
  • 6
  • 45
  • 82
  • how do you check if user is logged in? why do you send an `:agency_id` as a session variable? – Bohdan Jul 06 '11 at 06:26
  • I guess I don't check because they should have been signed in by setup before each test, and it works on other tests, and I have a test with an assertion that passes only if I do a `signout @user` before it. As for `:agency_id`, users may have multiple agencies, but they should only be interacting with one at a time, so it just seemed like a good way to pass the information around. Still learning rails so maybe that's not the best way to do it. – Gordon Seidoh Worley Jul 06 '11 at 11:02
  • may we see the sign_in method definition? – Jakobinsky Jul 12 '11 at 20:07
  • sign_in is defined in Devise::TestHelpers – Gordon Seidoh Worley Jul 12 '11 at 20:29

4 Answers4

1

You are missing in the setup request.env["devise.mapping"] = Devise.mappings[:user]

Have a look at the Devise wiki for more information. Personally I would extract this login functionality into a separate module and include it on request. i.e, login_user / login_agency_user

Jakobinsky
  • 1,294
  • 8
  • 11
  • I tried this but it doesn't seem to make any difference (even after adjusting to use `@request...` as the wiki suggested). – Gordon Seidoh Worley Jul 12 '11 at 21:12
  • Are you still getting the same error? `/Authorization::GuestUser/` – Jakobinsky Jul 12 '11 at 21:17
  • No, now it's just that I'm still getting redirected to `/unauthorized`. That was actually fixed by something else before I tried your suggestion, but I forgot to update the part of the past showing the failure. – Gordon Seidoh Worley Jul 12 '11 at 22:54
  • I should add that I'm not the only developer, so the previous failure may have been resolved by something someone else did, but I'm still not able to access the page even though I do have the right roles and authorization rules to do it. – Gordon Seidoh Worley Jul 12 '11 at 22:57
  • Are you also using CanCan, or authorisation gem of some sort? can you print out the `current_user`? – Jakobinsky Jul 13 '11 at 06:22
  • Using declarative_authorization. `current_user` is undefined, but `@user` is just an ActiveRecord subclass object with email, password, etc.. – Gordon Seidoh Worley Jul 13 '11 at 12:46
1

This is a shot in the dark because I'm not using Devise in my app, but the authentication system we use has this idiosyncrasy that it's just setting up the :user_id in the session, which gets clobbered by the session hash in the test.

I noticed your test method is setting :agency_id in the session.

Try removing the session hash entirely and seeing if the error you get is replaced by one about the absence of :agency_id rather than an authentication error, or else add whatever session variable that Devise uses for authentication to the hash.

gtd
  • 16,956
  • 6
  • 49
  • 65
  • Based on this, I looked at the session and see that there are several things in it during normal use, including `'warden.user.user.key' => ["User", "3"]` or something similar. Putting that in the session makes the test fail in a new and interesting way that suggest it's actually trying to access the desired controller method. There are also authentication tokens not being set in the tests and exist in the user session. – Gordon Seidoh Worley Jul 20 '11 at 12:45
  • After some more testing, you did help me find the answer: I needed to manual set the value of `'warden.user.user.key'` in the session to make authentication work. Thanks a million! – Gordon Seidoh Worley Jul 20 '11 at 21:01
1

Don't forget to set Authorization.current_user or DA won't know who's signed in

  def current_user
    @controller.current_user
  end
  def with_sign_in(u)
    sign_in u
    Authorization.current_user = current_user 
    yield
    sign_out u
    Authorization.current_user = nil
  end
pixelearth
  • 13,674
  • 10
  • 62
  • 110
0

Is it authentication (who are you) or authorization (what are you allowed to do) which fails? If authorization fails, then it is maybe a problem with the declarative_authorization gem you use. If it is an authentication problem, then it is probably a problem with the Devise gem or the Devise TestHelpers. This similar question may be helpful. If nothing works, then it should also be possible to stub out authentication like this

  before :each do
    @current_user = Factory(:user)
    controller.stub!(:current_user).and_return(@current_user)
    controller.stub!(:user_signed_in?).and_return(:true)
    controller.stub!(:authenticate_user!).and_return(:true)
  end
Community
  • 1
  • 1
0x4a6f4672
  • 27,297
  • 17
  • 103
  • 140