I am having some problems with tests failing, and it seems to be related to the foreign key constraints I have in the database.
Listing A shows what appears in development.log, when I run "rake test", before any output appears in test.log (which I find strange because I would have thought that all output would go to test.log when running in test mode). Lising B shows the corresponding output of the "rake test --trace" command.
IIf I remove the foreign key constraints from the database, the test runs fine, and Listing C appears in the development log instead. The corresponding "rake test --trace" output is shown in Listing D.
So it seems that as part of the testing process, rails is attempting to drop and recreate all of the tables in the database, but it is doing it in the wrong order so that the foreign key constraints get in they way. In fact the ordering is based on the order that the tables are created in schema.rb (LISTING E) (which is different to the order that I programmatically create the tables in the migration file (LISTING F)). So has anyone else had this problem? Is the solution a matter of controlling which order schema.rb creates the table? Or is there something more fundamental wrong with my setup?
Thanks. ============= LISTING A ========================
SQL (0.000450) SELECT * FROM schema_info SQL (0.000502) SHOW TABLES SQL (0.001142) SHOW FIELDS FROM functional_rights SQL (0.001021) SHOW KEYS FROM functional_rights SQL (0.001017) SHOW FIELDS FROM functional_rights_functional_roles SQL (0.000922) SHOW KEYS FROM functional_rights_functional_roles SQL (0.001036) SHOW FIELDS FROM functional_roles SQL (0.000856) SHOW KEYS FROM functional_roles SQL (0.000990) SHOW FIELDS FROM functional_roles_users SQL (0.000903) SHOW KEYS FROM functional_roles_users SQL (0.001211) SHOW FIELDS FROM users SQL (0.001118) SHOW KEYS FROM users SQL (0.000000) Mysql::Error: Cannot delete or update a parent row: a foreign key constraint fails: DROP TABLE functional_rights SQL (0.000000) Mysql::Error: Table 'functional_rights' already exists: CREATE TABLEfunctional_rights (`id` int(11) DEFAULT NULL auto_increment PRIMARY KEY, `name` varchar(255) DEFAULT '' NOT NULL, `controller` varchar(255) DEFAULT '' NOT NULL, `action` varchar(255) DEFAULT '' NOT NULL) ENGINE=InnoDB
============= LISTING B ========================
(in /home/michael/code/rails/work/railsproject) ** Invoke test (first_time) ** Execute test ** Invoke test:units (first_time) ** Invoke db:test:prepare (first_time) ** Invoke environment (first_time) ** Execute environment ** Execute db:test:prepare ** Invoke db:test:clone (first_time) ** Invoke db:schema:dump (first_time) ** Invoke environment ** Execute db:schema:dump ** Execute db:test:clone ** Invoke db:schema:load (first_time) ** Invoke environment ** Execute db:schema:load ** Invoke test:functionals (first_time) ** Invoke db:test:prepare ** Execute test:functionals /usr/bin/ruby18 -Ilib:test "/usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake/rake_test_loader.rb" "test/functional/functional_role_controller_test.rb" "test/functional/user_controller_test.rb" "test/functional/functional_right_controller_test.rb" "test/functional/session_controller_test.rb" Loaded suite /usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake/rake_test_loader Started .............. Finished in 0.181921 seconds.
14 tests, 80 assertions, 0 failures, 0 errors ** Invoke test:integration (first_time) ** Invoke db:test:prepare ** Execute test:integration /usr/bin/ruby18 -Ilib:test "/usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake/rake_test_loader.rb" rake aborted! Test failures /usr/lib/ruby/gems/1.8/gems/rails-1.1.6/lib/tasks/testing.rake:35 /usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake.rb:387:in `execute' /usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake.rb:387:in `execute' /usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake.rb:357:in `invoke' /usr/lib/ruby/1.8/thread.rb:135:in `synchronize' /usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake.rb:350:in `invoke' /usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake.rb:1906:in `run' /usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake.rb:1906:in `run' /usr/lib/ruby/gems/1.8/gems/rake-0.7.1/bin/rake:7 /usr/bin/rake:18
============= LISTING C ========================
SQL (0.000450) SELECT * FROM schema_info SQL (0.000485) SHOW TABLES SQL (0.001146) SHOW FIELDS FROM functional_rights SQL (0.001023) SHOW KEYS FROM functional_rights SQL (0.001011) SHOW FIELDS FROM functional_rights_functional_roles SQL (0.000823) SHOW KEYS FROM functional_rights_functional_roles SQL (0.001001) SHOW FIELDS FROM functional_roles SQL (0.000853) SHOW KEYS FROM functional_roles SQL (0.000991) SHOW FIELDS FROM functional_roles_users SQL (0.000838) SHOW KEYS FROM functional_roles_users SQL (0.001170) SHOW FIELDS FROM users SQL (0.001298) SHOW KEYS FROM users SQL (0.001402) DROP TABLE functional_rights SQL (0.006160) CREATE TABLE functional_rights (`id` int(11) DEFAULT NULL auto_increment PRIMARY KEY, `name` varchar(255) DEFAULT '' NOT NULL, `controller` varchar(255) DEFAULT '' NOT NULL, `action` varchar(255) DEFAULT '' NOT NULL) ENGINE=InnoDB SQL (0.001514) DROP TABLE functional_rights_functional_roles SQL (0.010817) CREATE TABLE functional_rights_functional_roles (`functional_right_id` int(11), `functional_role_id` int(11)) ENGINE=InnoDB SQL (0.001557) DROP TABLE functional_roles SQL (0.004841) CREATE TABLE functional_roles (`id` int(11) DEFAULT NULL auto_increment PRIMARY KEY, `name` varchar(255) DEFAULT '' NOT NULL) ENGINE=InnoDB SQL (0.001718) DROP TABLE functional_roles_users SQL (0.005080) CREATE TABLE functional_roles_users (`functional_role_id` int(11), `user_id` int(11)) ENGINE=InnoDB SQL (0.001777) DROP TABLE users SQL (0.005176) CREATE TABLE users (`id` int(11) DEFAULT NULL auto_increment PRIMARY KEY, `username` varchar(255) DEFAULT '' NOT NULL, `password_salt` varchar(255) DEFAULT '' NOT NULL, `password_hash` varchar(255) DEFAULT '' NOT NULL, `email_address` varchar(255) DEFAULT '' NOT NULL, `created_at` datetime NOT NULL) ENGINE=InnoDB SQL (0.000000) Mysql::Error: Table 'schema_info' already exists: CREATE TABLE schema_info (version int(11)) SQL (0.000974) SHOW FIELDS FROM schema_info SQL (0.000680) UPDATE schema_info SET version = 2
============= LISTING D ========================
(in /home/michael/code/rails/work/railsproject) ** Invoke test (first_time) ** Execute test ** Invoke test:units (first_time) ** Invoke db:test:prepare (first_time) ** Invoke environment (first_time) ** Execute environment ** Execute db:test:prepare ** Invoke db:test:clone (first_time) ** Invoke db:schema:dump (first_time) ** Invoke environment ** Execute db:schema:dump ** Execute db:test:clone ** Invoke db:schema:load (first_time) ** Invoke environment ** Execute db:schema:load ** Execute test:units /usr/bin/ruby18 -Ilib:test "/usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake/rake_test_loader.rb" "test/unit/functional_role_test.rb" "test/unit/overlay_test.rb" "test/unit/password_test.rb" "test/unit/user_test.rb" "test/unit/functional_right_test.rb" Loaded suite /usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake/rake_test_loader Started ............................................... Finished in 1.309497 seconds.
47 tests, 262 assertions, 0 failures, 0 errors ** Invoke test:functionals (first_time) ** Invoke db:test:prepare ** Execute test:functionals /usr/bin/ruby18 -Ilib:test "/usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake/rake_test_loader.rb" "test/functional/functional_role_controller_test.rb" "test/functional/user_controller_test.rb" "test/functional/functional_right_controller_test.rb" "test/functional/session_controller_test.rb" Loaded suite /usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake/rake_test_loader Started .............. Finished in 0.15657 seconds.
14 tests, 80 assertions, 0 failures, 0 errors ** Invoke test:integration (first_time) ** Invoke db:test:prepare ** Execute test:integration /usr/bin/ruby18 -Ilib:test "/usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake/rake_test_loader.rb"
===========================LISTING E ==========================
ActiveRecord::Schema.define(:version => 2) do
create_table "functional_rights", :force => true do |t| t.column "name", :string, :default => "", :null => false t.column "controller", :string, :default => "", :null => false t.column "action", :string, :default => "", :null => false end
create_table "functional_rights_functional_roles", :id => false, :force => true do |t| t.column "functional_right_id", :integer t.column "functional_role_id", :integer end
add_index "functional_rights_functional_roles", ["functional_right_id"], :name => "fk_frfr_functional_right" add_index "functional_rights_functional_roles", ["functional_role_id"], :name => "fk_frfr_functional_role"
create_table "functional_roles", :force => true do |t| t.column "name", :string, :default => "", :null => false end
create_table "functional_roles_users", :id => false, :force => true do |t| t.column "functional_role_id", :integer t.column "user_id", :integer end
add_index "functional_roles_users", ["functional_role_id"], :name => "fk_fru_functional_role" add_index "functional_roles_users", ["user_id"], :name => "fk_fru_user"
create_table "users", :force => true do |t| t.column "username", :string, :default => "", :null => false t.column "password_salt", :string, :default => "", :null => false t.column "password_hash", :string, :default => "", :null => false t.column "email_address", :string, :default => "", :null => false t.column "created_at", :datetime, :null => false end
end
========================== LISTING F ===========================
class AddFunctionalRightsAndFunctionalRolesTables < ActiveRecord::Migration def self.up create_table(:functional_rights, :force => true) { |t| # A table storing the actions on a given controller that a given right allows a user to perform. t.column :name, :string, :null => false t.column :controller, :string, :null => false t.column :action, :string, :null => false } create_table(:functional_roles, :force => true) { |t| # *functional* roles, referring to the fact that we are talking about actions that a user may perform, rather than data they can access. t.column :name, :string, :null => false } # Join create_table(:functional_rights_functional_roles, :id => false, :force => true) { |t| t.column :functional_right_id, :integer t.column :functional_role_id, :integer } # Join create_table(:functional_roles_users, :id => false, :force => true) { |t| t.column :functional_role_id, :integer t.column :user_id, :integer } # Add foreign key constraints. execute 'ALTER TABLE functional_rights_functional_roles ADD CONSTRAINT fk_frfr_functional_right FOREIGN KEY ( functional_right_id ) REFERENCES functional_rights( id ) ' execute 'ALTER TABLE functional_rights_functional_roles ADD CONSTRAINT fk_frfr_functional_role FOREIGN KEY ( functional_role_id ) REFERENCES functional_roles( id ) ' execute 'ALTER TABLE functional_roles_users ADD CONSTRAINT fk_fru_functional_role FOREIGN KEY ( functional_role_id ) REFERENCES functional_roles( id ) ' execute 'ALTER TABLE functional_roles_users ADD CONSTRAINT fk_fru_user FOREIGN KEY ( user_id ) REFERENCES users( id ) ' end
def self.down drop_table :functional_rights_functional_roles drop_table :functional_roles_users drop_table :functional_rights drop_table :functional_roles end end