Rails 3 + PostgreSQL + RSpec: App works fine but RSpec example fails - ruby-on-rails-3

I am developing this Rails 3.2 application using the Apartment gem as middleware. The application itself works perfectly and all the RSpec examples also work perfectly when ran individually. However, when I run all the tests at the same time using the bundle exec rspec command, there are two examples that fail in two different controller specs and they do exactly the same thing. Here are the two examples in question:
In the issues_controller_spec.rb file:
describe "GET 'new'" do
# ...
context "for authenticated users" do
before(:each) do
controller.log_in(create(:user))
get :new
end
# ...
it "should create a new issue instance and put it in an instance variable" do
assigns(:issue).should be_an_instance_of Issue
end
end
end
In the users_controller_spec.rb file:
describe "GET 'new'" do
# ...
context "for authenticated users" do
# ...
context "for admin users" do
before(:each) do
admin = create(:admin)
admin.add_role :admin
controller.log_in(admin)
get :new
end
# ...
it "should create a new User instance and put it in an instance variable" do
assigns(:user).should be_an_instance_of User
end
end
end
end
These two examples are affected by a before hook:
before(:each) do
client = create(:client)
#request.host = "#{client.account_name}.lvh.me"
end
When creating a new Client, there is an after_create callback:
# Create the client database (Apartment) for multi-tenancy
def create_client_database
begin
Apartment::Database.create(self.account_name)
rescue Apartment::SchemaExists
return
rescue
self.destroy
end
end
And there is where the examples fail. Now if I remove the begin...rescue...end block and keep the line Apartment::Database.create(self.account_name) I get the following exception in the failling examples:
ActiveRecord::StatementInvalid:
PG::Error: ERROR: current transaction is aborted, commands ignored until end of transaction block
: SET search_path TO public
Again, if I run the examples individually, they pass but if I run all the examples, the two examples above fail.
Does anyone know what I am doing wrong please?
Note: The whole application code can be found here.

I solved this problem by wrapping the line client = create(:client) in a begin, rescue, end block like so:
before(:each) do
begin
client = create(:client)
rescue
client = Client.create!(attributes_for(:client))
end
#request.host = "#{client.account_name}.lvh.me"
end
I don't know how or why this works but I know it works.

Related

Intermittent OmniAuth errors authenticating against Google

When trying to authenticate using Omniauth, it works flawlessly in my development environment (Mac OSX Mavericks), but fails most of the time in production (on Heroku). The errors vary between "Invalid Credentials" and "Connection failed". In all cases, I'm already logged in to my Google account. I may get one or another of these errors anywhere between 4 and 8 times before the process succeeds.
Has anyone see this and can you shed some light on why this might be happening?
Gem: oa_openid (0.3.2)
config/routes.rb:
...
resource :admin_session, only: %w(show create destroy)
match '/auth/googleapps/callback' => 'admin_sessions#create'
...
config/omniauth.rb:
require 'openid/store/filesystem'
Rails.application.config.middleware.use OmniAuth::Strategies::GoogleApps,
OpenID::Store::Filesystem.new('./tmp'),
name: 'googleapps', domain: 'booktrakr.com'
admin_sessions_controller:
class AdminSessionsController < ApplicationController
# GET /admin_sessions
def show
redirect_to "/auth/googleapps?origin=#{params[:origin] || request.fullpath}" and return unless is_admin?
#session = authenticated_admin
end
# POST /admin_sessions
def create
authinfo = request.env['omniauth.auth']
uid = authinfo['uid']
unless uid =~ %r(^https?://(groundbreakingsoftware|booktrakr).com/openid)
raise "Bad hacker, no cookie"
end
self.authenticated_admin = authinfo
redirect_to request.env['omniauth.origin'], notice: 'Session was successfully created.'
end
# DELETE /admin_sessions
def destroy
self.authenticated_admin = nil
redirect_to root_url
end
end
It appears that switching to OAuth2 (https://github.com/zquestz/omniauth-google-oauth2) resolved the problem, at least at first blush. Thanks, #Ashitaka!

Why has shoulda controller test assign_to no access to instance variable?

For my Rails 3 application I use FactoryGirl together with shoulda context (1.0.0.beta1) and matchers (1.0.0.beta3) for my functional tests.
My problem: in the code example below, the assign_to test fails because #user - to my surprise - turns out to be nil. In the outer setup block, #user is assigned a valid model instance, but from within the should assign_to statement the instance variable is not accessible. Why is that and what is the correct way to write that test?
class UsersControllerTest < ActionController::TestCase
context "as admin" do
setup do
#user = Factory.create(:user)
end
context "getting index" do
setup do
get :index
end
should assign_to(:users).with([#user])
end
end
I discovered that passing the value as a black miraculously works. However, after digging into the actual AssignToMatcher code, it doesn't seem to make sense why the parameter method wouldn't work while the block method would.
For the sake of the +250 rep I'm investing in this, I'd still like an answer that explains why the param method isn't working (and how to fix it), but until then, at least I have a workaround.
#dblp1, hopefully this works for you too. Here's an example specific to your code:
class UsersControllerTest < ActionController::TestCase
context "as admin" do
setup do
#user = Factory.create(:user)
end
context "getting index" do
setup do
get :index
end
should assign_to(:users).with { [#user] }
end
end
end
(I am pasting as an answer as it is fairly long)
I mocked a bit your test and checked what was the results passed.
Interestingly enough, when I call the matcher #post=null (as I believe in your case). The issues I think (after a while of investigation), it coming from the the order the setup do block is called and the fact that the variables defined in one context are not visible in the nested context.
modified class
context "as admin" do
setup do
#post = Post.new
puts "Step 1 - inside setup do"
puts #post.class
end
puts "Step 2 - outside setup do 1"
puts #post.class
context "getting index" do
setup do
get :index
end
puts "Step 3 - calling shoulda"
puts #post.class
should assign_to(:posts).with([#post])
#should assign_to(:posts).with { [#post] }
end
end
And the results in the console
ruby -I test test/functional/posts_controller_test.rb
Step 2 - outside setup do 1
NilClass
Step 3 - calling shoulda
NilClass
Loaded suite test/functional/posts_controller_test
Started
Step 1 - inside setup do
Post
So the setup cycle is called at the end (and not at the beginning) and then your is Nil when passed to the matcher.
Even if I remove the first setup do does not work pretty well.
Step 1 - inside setup do
Post
Step 2 - outside setup do 1
Post
Step 3 - calling shoulda
NilClass
Finally, putting the post in the inner context
Step 3 - calling shoulda
Post
If you call #user = Factory.create(:user) directly inside the "getting index" context, I believe it will work.
When you are working with indexes you should use the plural of the instance variable.
#users rather than #user
You should also populate it as an array.
Finally, Shoulda matchers should start with "it" and be contained in braces, at least in the RSpec world, which is what I use. Not sure if this is the case with Test::Unit or whether your formatting above will work.
Try something like this.
class UsersControllerTest < ActionController::TestCase
context "as admin" do
setup do
#user = Factory.create(:user)
end
context "getting index" do
setup do
#users = Array.new(3) { Factory(:user) }
get :index
end
it { should assign_to(:users).with(#users) }
end
end

Wrong model stub when testing controllers which using inherited_resources

I'm new to RSpec and my controllers're using inherited_resources, I have this mock/stub setup like:
describe MarketsController do
def mock_market(stubs={})
#mock_market ||= mock_model(Market, stubs).as_null_object
end
describe "GET index" do
it "assigns all markets as #markets" do
Market.stub(:all){ [mock_market] }
get :index
assigns(:markets).should eql([mock_market])
end
end
end
And this spec fails because there's nothing in the assigns(:markets). After I added:
class MarketsController
def index
#markets = Market.all
end
end
it'll pass so I guess that's because the inherited_resources doesn't call Market.all to get all of the Market instance and thus bypass the stub for Market.stub(:all). The index method I added above is obviously redundant and shouldn't exist at all, so the question is, without call Market.all explicitly, what should I do in my spec to complete the tests? Thanks in advance!
If I am reading the code correctly, inherited_resources first tries to use Market.scoped if it exists. So do you have a scoped scope?

Failing to test Devise with Capybara

I'm building a Rails 3 app using Devise, with Capybara for UI testing. The following test is failing:
class AuthenticationTest < ActionController::IntegrationTest
def setup
#user = User.create!(:email => 'test#example.com',
:password => 'testtest',
:password_confirmation => 'testtest')
#user.save!
Capybara.reset_sessions!
end
test "sign_in" do
# this proves the user exists in the database ...
assert_equal 1, User.count
assert_equal 'test#example.com', User.first.email
# ... but we still can't log in ...
visit '/users/sign_in'
assert page.has_content?('Sign in')
fill_in :user_email, :with => 'test#example.com'
fill_in :user_password, :with => 'testtest'
click_button('user_submit')
# ... because this test fails
assert page.has_content?('Signed in successfully.')
end
end
... but I have no idea why. As you can see from the code, the user is being created in the database; I'm using the same approach to create the user as I did in seeds.rb.
If I run the test through the debugger, I can see the user in the database and verify that the page is loading. But still the authentication fails; I can verify this because if I change the assertion to test for the failure case, the test passes:
# verify that the authentication actually failed
assert page.has_content?('Invalid email or password.')
I'm used to Rails 2, & using Selenium for this sort of testing, so I suspect I'm doing something daft. Could someone please point me in the right direction here?
I was having the same issue and found a thread with a solution:
RSpec.configure do |config|
config.use_transactional_fixtures = false
config.before(:suite) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
For the DatabaseCleaner stuff to work you'll need to include the database_cleaner gem. If you haven't used it before, you may need to rake db:test:prepare before rerunning your tests. I hope this works for you, too!
I've run into a similar problem before. Setting the password directly has some weird effects because it's supposed to be encrypted and stored with a salt--sometimes it works for me and other times it doesn't. I have a hard time remembering which specific cases were problematic. I'd recommend the following, in this order (for simplicity)
Verify that the password field is getting filled in properly and passed as the right param (not necessary if you're using Devise's autogenerated view and haven't touched it)
if your site can run in development mode (i.e. no log in bugs), then just boot it up and log in manually
If not, insert debugger as the first line in your sessions_controller. Then check params and make sure the password is correct and in params[:user][:password].
If you didn't override Devise's sessions_controller, then you can find your Devise path with bundle show devise. Then look for the create action within (devise path)/app/controllers/devise/sessions_controller.rb
Change your test setup to create a user through the web interface, to ensure the password gets set properly, then try running your test again
I had the same issue with a setup fairly similar to yours. In my case, switching to ActiveRecord sessions in the initializer solved the problem.
Additionally, make sure you call #user.skip_confirmation! if you are using the "confirmable" module in devise.

How to log exceptions automatically in Rails?

If there is an exception in a controller action and rescue is used, Rails does not show the exception either in the browser (which is O.K), nor does it write the exception to the log file.
Is there a way to get Rails to write the exception to the log file in this case?
Example:
def some_action
2/0
rescue
#this code is called, but Rails does not write the exception to the log
end
You're rescuing the exception, so it won't log it because nothing bad actually happened since it was, in fact, "rescued".
You can put the following code within your rescue block to put an entry in the log:
logger.warn "Exception rescued!"
You can read more about using the logger in the Rails Guides.
I ended up using rescue_from in the ApplicationController, logging the exception message and backtrace, and then using params[:controller] and params[:action] to determine what controller/action to redirect to.
For example, if PostsController#show exception'ed out, I would redirect to PostsController#index from within rescue_from. It's been working so far, so it doesn't seem to be a bad thing to do redirect_to from within rescue_from. Time will let me know, I'm sure! (Just need to make sure that my redirects don't cause some infinite loops!)
And just in someone is interested in this hack (try at your own risk!):
class ApplicationController < ActionController::Base
def determine_redirect_to_path(controller,action)
...
end
rescue_from StandardError do |exception|
backtrace_size = exception.backtrace.size
if backtrace_size >= 2 then max_range = 2
elsif backtrace_size >= 1 then max_range = 1
end
if max_range > 0
s = "rescued_from:: #{params[:controller]}##{params[:action]}: #{exception.inspect}\n#{exception.backtrace[0..max_range].to_s}\n"
logger.error s
end
redirect_to determine_redirect_to_path(params[:controller],params[:action])
end
end