rake spec - prerequisites seem nonsensical - ruby-on-rails

I'm trying to set up a reliable continuous integration server that runs rspec. I've read this answer, and indeed if I run db:reset that seems to get me in a good state to run the tests. In fact, if I run db:reset and then after it, on the cli, run rake spec - my tests run.
However, if I make one rake task that does both, like this:
desc 'Run all tests, used by Jenkins CI'
task :run => [ 'db:reset' ] do
Rake::Task["spec"].invoke
end
By the time the tests run, the database is empty. That appears to be because rake:spec calls the following:
** Invoke db:test:prepare (first_time)
** Invoke db:abort_if_pending_migrations (first_time)
** Invoke environment
** Execute db:abort_if_pending_migrations
** Execute db:test:prepare
** Invoke db:test:load (first_time)
** Invoke db:test:purge (first_time)
** Invoke environment
** Execute db:test:purge
** Execute db:test:load
** Invoke db:schema:load
** Execute spec
If I'm reading it right, it will (line 2) abort if there are pending migrations. Then, eventually db:schema:load again, which loads the database from schema rb... which I'd already done. And, it makes me particularly unclear why, if it's going to re-wipe the db, it would abort if migrations wouldn't have been applied.
Worse still, in my case the first thing the spec task does is bail because the users table doesn't exist... and that was defined in schema.rb (which at this point has been loaded twice).
Any ideas where I'm misunderstanding?

Related

Executing a rake task after `rake test`

I'm trying to create a rake task for a Rails 4.0.2 (Ruby 2.2.3) project that creates the test database along with seeding, then runs the test suite, and finally cleanups afterwards by dropping the test database. Here's a simple example below:
task better_test: :environment do
Rake::Task["test:setup"].execute
Rake::Task["test"].execute
Rake::Task["test:cleanup"].execute
end
The task above does invoke the test:setup rake task (create/seed the test database), then invokes the test rake task, and finally invokes the test:cleanup rake task. The problem however is that the last test:cleanup is invoked before the test rake task is finished running. Is there anyway to invoke the cleanup rake task after the previous tasks are complete?
Here's the output from running the task with trace:
$ RAILS_ENV=test be rake better_test --trace
/usr/local/rvm/gems/ruby-2.2.3/gems/activesupport-4.0.2/lib/active_support/values/time_zone.rb:282: warning: circular argument reference - now
/usr/local/rvm/gems/ruby-2.2.3/gems/honeybadger-1.16.3/lib/honeybadger/rack/user_feedback.rb:51: warning: circular argument reference - action
** Invoke better_test (first_time)
** Invoke environment (first_time)
** Execute environment
** Execute better_test
** Execute test:setup
Creating test database.
** Execute db:test:setup
** Execute db:test:create
** Execute db:create
** Execute db:test:load
** Execute db:schema:load
** Execute db:test_project:setup
** Execute db:test_project:create
** Invoke db:create (first_time)
** Invoke environment
** Execute db:create
** Execute db:test_project:migrate:down
** Execute db:test_project:migrate:up
** Execute db:test_project:seed
** Execute test
** Invoke test:run (first_time)
** Invoke test:units (first_time)
** Invoke test:prepare (first_time)
** Invoke db:test:prepare (first_time)
** Invoke db:abort_if_pending_migrations (first_time)
** Invoke environment
** Invoke db:migrate:load (first_time)
** Invoke environment
** Execute db:migrate:load
** Execute db:abort_if_pending_migrations
** Execute db:test:prepare
** Execute db:drop
** Execute db:create
** Execute db:load
** Invoke db:schema:load (first_time)
** Invoke environment
** Execute db:schema:load
** Execute test:prepare
** Execute test:units
** Invoke test:functionals (first_time)
** Invoke test:prepare
** Execute test:functionals
** Invoke test:integration (first_time)
** Invoke test:prepare
** Execute test:integration
** Execute test:run
** Invoke test:decorators (first_time)
** Invoke test:prepare
** Execute test:decorators
** Execute test:cleanup
** Execute db:test:drop
** Execute db:drop
** Execute db:test_project:drop
** Invoke db:drop (first_time)
** Invoke environment
** Execute db:drop
Run options: --seed 19360
# Running tests:
EE....
Finished tests in 0.037493s, 160.0278 tests/s, 106.6852 assertions/s.
As you can see the tasks are invoked in order but the cleanup task is executed before the tests have completed. Any ideas to address this?
As it turns out, this was less to do with rake and more to do with the way Minitest executes its tests. I mentioned in the question it appeared that the rake tasks were being invoked in the correct order but the tests were executed later for some reason. The reason is because Minitest utilizes the ruby Kernel method at_exit for execution of the tests. The test files are read in at the time the rake test was invoked but all tests are executed at the end of the ruby program, even after my subsequent rake tasks. Here's a blog article that explains the issue in more detail: http://blog.arkency.com/2013/06/are-we-abusing-at-exit/.
Try to use the rake standard syntax for calling multiple tasks:
task better_test: ["test:setup", "test", "test:cleanup"]
Maybe this will resolve you problem.
Also, it seems that Rake actually builds the list of all tasks it should run before executing them, and run each one only once. For example:
task :a
task :b
task :c
task better_test: ["a", "b", "c", "b"]
results in:
$ rake better_test -t
** Invoke better_test (first_time)
** Invoke a (first_time)
** Execute a
** Invoke b (first_time)
** Execute b
** Invoke c (first_time)
** Execute c
** Execute better_test
As you see, the task b is run only once (the first one). I believe that your test:setup or test somehow depend on test:cleanup task. So it is called earlier than expected.
Rake::Task["test"].enhance do
Rake::Task["test:cleanup"].invoke
end

rake db:setup db:test:prepare won’t behave as expected

I have a script/cibuild script, which I run on Semaphore Hosted CI Service), that contains…
time bundle exec rake db:setup db:test:prepare --trace; echo
… to setup the database and check if are there any pending migrations, but for some reason this won’t work not even on my development machine.
Striping down script/cibuild’s contents boils down to this:
export RAILS_ENV=test
export RACK_ENV=test
# options to rake 'spec' task
export SPEC_OPTS='--color --format documentation --backtrace spec'
echo "Installing dependencies..."
time bundle install --deployment; echo
echo "Setting-up database..."
time bundle exec rake db:setup db:test:prepare --trace; echo
echo "Running tests..."
time bundle exec rake spec --trace; echo
Build will eventually fail with the following trace on Semaphore:
Running tests...
** Invoke spec (first_time)
** Invoke test:prepare (first_time)
** Invoke db:test:prepare (first_time)
** Invoke db:abort_if_pending_migrations (first_time)
** Invoke environment (first_time)
** Execute environment
** Invoke db:load_config (first_time)
** Execute db:load_config
** Execute db:abort_if_pending_migrations
You have 10 pending migrations:
20130418144736 CreateUsers
20130424134725 CreateCollections
20130506124127 AddStaffToUsers
20130513115848 CreateResourceTypes
20130513140804 InstallHstore
20130513141924 CreateResources
20130513144332 AddCredentialDataToUsers
20130523155851 RenameSubscriptionDataInResource
20130531110125 AddProfilePictureToUser
20130722101545 AddEmailIndexToUser
Run `rake db:migrate` to update your database then try again.
Now it seems to me that the problem may not be at db:setup db:test:prepare line, but instead when rake spec is run. I am not sure.
In any case if I run in my development machine…
rake db:drop:all
rake db:setup db:test:prepare
… I will end up with an empty test database (“empty” as in no tables, etc.) whereas…
rake db:drop:all
rake db:setup
rake db:test:prepare
… will create also test database, as expected.
One might think as if I didn’t run rake db:migrate at some point (hence 10 pending migrations), but I am pretty confident that this isn’t the case. Although I don’t have a db/schema.rb file, rails should apply all the migrations to get to the final database schema just fine.
Any ideas, please? Thank you.
Update:
I kind of suspect that the issue might be related to setting RACK_ENV and/or RAILS_ENV environment variables to test. This seems to mess things up a bit.

Test database structure is not created when using Factory girl with Rspec (Rails)

I am using FactoryGirl in my rails application instead of Fixtures.
When i try to use factory girl in my test and create some test data, it shows like
PG:Error relation "users" doesn't exists (i have a model named User)
But when i run rake db:test:clone, and then run the test, the test is passed. The rake db:test:clone command clones all the table structure from development db to test db, and this fixes the issue.
But is there any way for me to not to run rake db:test:clone when using FactoryGirl?
or what am i missing?
Update :
I found out one other thing, i have another application which uses Rspec and FactoryGirl. In that application below are executed when running rake spec --trace command
** Invoke spec (first_time)
** Invoke db:test:clone_structure (first_time)
** Invoke db:structure:dump (first_time)
** Invoke environment (first_time)
** Execute environment
** Invoke db:load_config (first_time)
** Execute db:load_config
** Execute db:structure:dump
** Invoke db:test:load_structure (first_time)
** Invoke db:test:purge (first_time)
** Invoke environment
** Invoke db:load_config
** Execute db:test:purge
** Execute db:test:load_structure
** Invoke db:structure:load (first_time)
** Invoke environment
** Invoke db:load_config
** Execute db:structure:load
But in any of the new application i see the below executed when running rake spec --trace
** Invoke spec (first_time)
** Invoke noop (first_time)
** Execute noop
** Execute spec
Please suggest what am i missing?
regards
Balan
Every time you run a db:migrate, run a db:test:prepare as well, so the database changes are mirrored on your test database as well.
I found the solution, we need to create a rake task customrake.rake under /lib/tasks
and add the line task :spec => 'db:test:prepare', this will make sure rake db:test:prepare is executed before running Specs.

rake db:migrate doesn't work and brings me back to the command line rails 3.1.1

Using rails 3.1.1 for windows with railsinstaller
>rake db:migrate
after a pause, brings me right back to the command line. No errors, no messages, just right back to the command line.
I tried
>rake --trace db:migrate
** Invoke db:migrate (first_time)
** Invoke environment (first_time)
** Execute environment
** Invoke db:load_config (first_time)
** Invoke rails_env (first_time)
** Execute rails_env
** Execute db:load_config
** Execute db:migrate
** Invoke db:schema:dump (first_time)
** Invoke environment
** Invoke db:load_config
** Execute db:schema:dump
Doesn't look like anything is wrong, but obviously something isn't working right.
Can anyone help?
If there are no migrations to be run, there will be no output. The --trace command outputs the various steps that rake goes through to prepare, execute, and clean up after the migration. However, when it sees that there is no migration to be run, then it doesn't actually make any DB changes. Only DB changes cause additional output.
The only difference between this and a migration is that the changes to the DB will be output to the command line. No changes => no output.
Make sure you are in the right folder (maybe in the right branch, when using git) and make sure that you have created a migration file.
rails generate migration MigrationName
Edit the generated file as you wish.

Run Rails Tests without Dropping Test Database

Just wondering if there's a way to run Rails tests without dropping the database. I'm currently only executing unit tests and am using the following rake command to do so: rake test:units.
Thanks for the help in advance!
Just in case this is relevant:
Rails 3
Ruby 1.8.7 (MRI)
Oracle 11g Database
activerecord-oracle_enhanced-adapter
In Rails 5 (and possibly earlier versions), just comment-out the following line in spec/rails_helper.rb:
ActiveRecord::Migration.maintain_test_schema!
This will prevent rake test or rspec from attempting to drop your test DB. You'll need to run migrations manually as well.
For Rails 5.2 this behaviour can be modified setting maintain_test_schema to false in test/test_helper.rb before importing rails/test_help:
ActiveRecord::Base.maintain_test_schema = false
require "rails/test_help"
rails/test_help will check the value of maintain_test_schema to decide if it has to drop/create/migrate the test database or not.
After doing some research, I have found that there isn't a way to do this. The test rake tasks will always drop the database, even when providing the TEST= option as Bohdan suggests.
By using the --trace option, this can be proven. Here is the output:
$ rake test:units TEST=test/unit/post_test.rb --trace
(in /Users/johnnyicon/Development/ror/test-app)
** Invoke test:units (first_time)
** Invoke test:prepare (first_time)
** Invoke db:test:prepare (first_time)
** Invoke db:abort_if_pending_migrations (first_time)
** Invoke environment (first_time)
** Execute environment
** Execute db:abort_if_pending_migrations
** Execute db:test:prepare
** Invoke db:test:load (first_time)
** Invoke db:test:purge (first_time)
** Invoke environment
** Execute db:test:purge
** Execute db:test:load
** Invoke db:schema:load (first_time)
** Invoke environment
** Execute db:schema:load
** Execute test:prepare
** Execute test:units
Reading through the Ruby on Rails Guides for Testing, it describes what some of these rake tasks mean. The one to pay particular attention to is the db:test:load task, which you see on the 7th line from the bottom of the output as ** Execute db:test:load. The guides say the following about this task:
Recreate the test database from the
current schema.rb
So even if I were to execute the unit tests one by one as Bohdan suggests, the rake task would still recreate the database. Not the answer I was hoping for, but it isn't a problem anymore.
The reason I was asking to begin with was because I did not have access to another database to use for testing, so I was using my development database for testing as well. But since then, I've been able to get another database dedicated for testing.
Thanks anyway Bohdan! I appreciate the help!
This is a rather old post that does the monkey patching of overriding purge/load tasks:
http://www.pervasivecode.com/blog/2007/09/22/making-rails-raketest-not-drop-your-pgsql-database/
For those looking for a way to skip Rails' default behavior, try adding this to your Rakefile:
Rake::Task["db:test:prepare"].clear
Rake::Task["db:test:load"].clear
Rake::Task["db:test:purge"].clear
Could you not write a custom Rake task that monkey patched the Rake db:test:load task to do nothing?

Resources