Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatically maintain test database schema #13528

Merged
merged 1 commit into from Jan 2, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 11 additions & 0 deletions activerecord/CHANGELOG.md
@@ -1,3 +1,12 @@
* Since the `test_help.rb` in Railties now automatically maintains
your test schema, the `rake db:test:*` tasks are deprecated. This
doesn't stop you manually running other tasks on your test database
if needed:

rake db:schema:load RAILS_ENV=test

*Jon Leighton*

* Fix presence validator for association when the associated record responds to `to_a`.

*gmarik*
Expand Down Expand Up @@ -54,6 +63,8 @@
* Deprecated use of string argument as a configuration lookup in
`ActiveRecord::Base.establish_connection`. Instead, a symbol must be given.

* Deprecated use of string argument as a configuration lookup in `ActiveRecord::Base.establish_connection`. Instead, a symbol must be given.

*José Valim*

* Fixed `update_column`, `update_columns`, and `update_all` to correctly serialize
Expand Down
3 changes: 3 additions & 0 deletions activerecord/lib/active_record/core.rb
Expand Up @@ -69,6 +69,9 @@ module Core
mattr_accessor :timestamped_migrations, instance_writer: false
self.timestamped_migrations = true

# :nodoc:
mattr_accessor :maintain_test_schema, instance_accessor: false

def self.disable_implicit_join_references=(value)
ActiveSupport::Deprecation.warn("Implicit join references were removed with Rails 4.1." \
"Make sure to remove this configuration because it does nothing.")
Expand Down
13 changes: 13 additions & 0 deletions activerecord/lib/active_record/migration.rb
Expand Up @@ -389,6 +389,19 @@ def check_pending!
raise ActiveRecord::PendingMigrationError if ActiveRecord::Migrator.needs_migration?
end

def load_schema_if_pending!
if ActiveRecord::Migrator.needs_migration?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems like a ActiveRecord::Tasks::DatabaseTasks.purge is missing here. /cc @jonleighton. See #15787 Is what we were doing under test namespace

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So seems like it's already fixed #15394

ActiveRecord::Tasks::DatabaseTasks.load_schema
check_pending!
end
end

def maintain_test_schema! # :nodoc:
if ActiveRecord::Base.maintain_test_schema
suppress_messages { load_schema_if_pending! }
end
end

def method_missing(name, *args, &block) # :nodoc:
(delegate || superclass.delegate).send(name, *args, &block)
end
Expand Down
9 changes: 1 addition & 8 deletions activerecord/lib/active_record/railtie.rb
Expand Up @@ -31,22 +31,15 @@ class Railtie < Rails::Railtie # :nodoc:


config.active_record.use_schema_cache_dump = true
config.active_record.maintain_test_schema = true

config.eager_load_namespaces << ActiveRecord

rake_tasks do
require "active_record/base"

ActiveRecord::Tasks::DatabaseTasks.seed_loader = Rails.application
ActiveRecord::Tasks::DatabaseTasks.env = Rails.env

namespace :db do
task :load_config do
ActiveRecord::Tasks::DatabaseTasks.db_dir = Rails.application.config.paths["db"].first
ActiveRecord::Tasks::DatabaseTasks.migrations_paths = Rails.application.paths['db/migrate'].to_a
ActiveRecord::Tasks::DatabaseTasks.fixtures_path = File.join Rails.root, 'test', 'fixtures'
ActiveRecord::Tasks::DatabaseTasks.root = Rails.root

configuration = if ENV["DATABASE_URL"]
{ Rails.env => ENV["DATABASE_URL"] }
else
Expand Down
34 changes: 17 additions & 17 deletions activerecord/lib/active_record/railties/databases.rake
Expand Up @@ -234,9 +234,7 @@ db_namespace = namespace :db do

desc 'Load a schema.rb file into the database'
task :load => [:environment, :load_config] do
file = ENV['SCHEMA'] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, 'schema.rb')
ActiveRecord::Tasks::DatabaseTasks.check_schema_file(file)
load(file)
ActiveRecord::Tasks::DatabaseTasks.load_schema(:ruby, ENV['SCHEMA'])
end

task :load_if_ruby => ['db:create', :environment] do
Expand Down Expand Up @@ -281,10 +279,7 @@ db_namespace = namespace :db do

# desc "Recreate the databases from the structure.sql file"
task :load => [:environment, :load_config] do
filename = ENV['DB_STRUCTURE'] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "structure.sql")
ActiveRecord::Tasks::DatabaseTasks.check_schema_file(filename)
current_config = ActiveRecord::Tasks::DatabaseTasks.current_config
ActiveRecord::Tasks::DatabaseTasks.structure_load(current_config, filename)
ActiveRecord::Tasks::DatabaseTasks.load_schema(:sql, ENV['DB_STRUCTURE'])
end

task :load_if_sql => ['db:create', :environment] do
Expand All @@ -294,8 +289,15 @@ db_namespace = namespace :db do

namespace :test do

task :deprecated do
Rake.application.top_level_tasks.grep(/^db:test:/).each do |task|
$stderr.puts "WARNING: #{task} is deprecated. The Rails test helper now maintains " \
"your test schema automatically, see the release notes for details."
end
end

# desc "Recreate the test database from the current schema"
task :load => 'db:test:purge' do
task :load => %w(db:test:deprecated db:test:purge) do
case ActiveRecord::Base.schema_format
when :ruby
db_namespace["test:load_schema"].invoke
Expand All @@ -305,7 +307,7 @@ db_namespace = namespace :db do
end

# desc "Recreate the test database from an existent schema.rb file"
task :load_schema => 'db:test:purge' do
task :load_schema => %w(db:test:deprecated db:test:purge) do
begin
should_reconnect = ActiveRecord::Base.connection_pool.active_connection?
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test'])
Expand All @@ -319,7 +321,7 @@ db_namespace = namespace :db do
end

# desc "Recreate the test database from an existent structure.sql file"
task :load_structure => 'db:test:purge' do
task :load_structure => %w(db:test:deprecated db:test:purge) do
begin
ActiveRecord::Tasks::DatabaseTasks.current_config(:config => ActiveRecord::Base.configurations['test'])
db_namespace["structure:load"].invoke
Expand All @@ -329,7 +331,7 @@ db_namespace = namespace :db do
end

# desc "Recreate the test database from a fresh schema"
task :clone => :environment do
task :clone => %w(db:test:deprecated environment) do
case ActiveRecord::Base.schema_format
when :ruby
db_namespace["test:clone_schema"].invoke
Expand All @@ -339,18 +341,18 @@ db_namespace = namespace :db do
end

# desc "Recreate the test database from a fresh schema.rb file"
task :clone_schema => ["db:schema:dump", "db:test:load_schema"]
task :clone_schema => %w(db:test:deprecated db:schema:dump db:test:load_schema)

# desc "Recreate the test database from a fresh structure.sql file"
task :clone_structure => [ "db:structure:dump", "db:test:load_structure" ]
task :clone_structure => %w(db:structure:dump db:test:load_structure)

# desc "Empty the test database"
task :purge => [:environment, :load_config] do
task :purge => %w(db:test:deprecated environment load_config) do
ActiveRecord::Tasks::DatabaseTasks.purge ActiveRecord::Base.configurations['test']
end

# desc 'Check for pending migrations and load the test schema'
task :prepare => [:environment, :load_config] do
task :prepare => %w(db:test:deprecated environment load_config) do
unless ActiveRecord::Base.configurations.blank?
db_namespace['test:load'].invoke
end
Expand Down Expand Up @@ -385,5 +387,3 @@ namespace :railties do
end
end
end

task 'test:prepare' => ['db:test:prepare', 'db:test:load', 'db:abort_if_pending_migrations']
44 changes: 41 additions & 3 deletions activerecord/lib/active_record/tasks/database_tasks.rb
Expand Up @@ -36,9 +36,8 @@ class DatabaseNotSupported < StandardError; end # :nodoc:
module DatabaseTasks
extend self

attr_writer :current_config
attr_accessor :database_configuration, :migrations_paths, :seed_loader, :db_dir,
:fixtures_path, :env, :root
attr_writer :current_config, :db_dir, :migrations_paths, :fixtures_path, :root, :env, :seed_loader
attr_accessor :database_configuration

LOCAL_HOSTS = ['127.0.0.1', 'localhost']

Expand All @@ -51,6 +50,30 @@ def register_task(pattern, task)
register_task(/postgresql/, ActiveRecord::Tasks::PostgreSQLDatabaseTasks)
register_task(/sqlite/, ActiveRecord::Tasks::SQLiteDatabaseTasks)

def db_dir
@db_dir ||= Rails.application.config.paths["db"].first
end

def migrations_paths
@migrations_paths ||= Rails.application.paths['db/migrate'].to_a
end

def fixtures_path
@fixtures_path ||= File.join(root, 'test', 'fixtures')
end

def root
@root ||= Rails.root
end

def env
@env ||= Rails.env
end

def seed_loader
@seed_loader ||= Rails.application
end

def current_config(options = {})
options.reverse_merge! :env => env
if options.has_key?(:config)
Expand Down Expand Up @@ -133,6 +156,21 @@ def structure_load(*arguments)
class_for_adapter(configuration['adapter']).new(*arguments).structure_load(filename)
end

def load_schema(format = ActiveRecord::Base.schema_format, file = nil)
case format
when :ruby
file ||= File.join(db_dir, "schema.rb")
check_schema_file(file)
load(file)
when :sql
file ||= File.join(db_dir, "structure.sql")
check_schema_file(file)
structure_load(current_config, file)
else
raise ArgumentError, "unknown format #{format.inspect}"
end
end

def check_schema_file(filename)
unless File.exist?(filename)
message = %{#{filename} doesn't exist yet. Run `rake db:migrate` to create it, then try again.}
Expand Down
11 changes: 11 additions & 0 deletions guides/source/4_1_release_notes.md
Expand Up @@ -281,6 +281,13 @@ for detailed changes.
* Add `Application#message_verifier` method to return a message
verifier. ([Pull Request](https://github.com/rails/rails/pull/12995))

* The `test_help.rb` file which is required by the default generated test
helper will automatically keep your test database up-to-date with
`db/schema.rb` (or `db/structure.sql`). It raises an error if
reloading the schema does not resolve all pending migrations. Opt out
with `config.active_record.maintain_test_schema = false`. ([Pull
Request](https://github.com/rails/rails/pull/13528))

Action Pack
-----------

Expand Down Expand Up @@ -421,6 +428,10 @@ for detailed changes.
* Deprecated `ConnectionAdapters::SchemaStatements#distinct`,
as it is no longer used by internals. ([Pull Request](https://github.com/rails/rails/pull/10556))

* Deprecated `rake db:test:*` tasks as the test database is now
automatically maintained. See railties release notes. ([Pull
Request](https://github.com/rails/rails/pull/13528))

### Notable changes

* Added `ActiveRecord::Base.to_param` for convenient "pretty" URLs derived from
Expand Down
2 changes: 2 additions & 0 deletions guides/source/configuring.md
Expand Up @@ -290,6 +290,8 @@ All these configuration options are delegated to the `I18n` library.

* `config.active_record.attribute_types_cached_by_default` sets the attribute types that `ActiveRecord::AttributeMethods` will cache by default on reads. The default is `[:datetime, :timestamp, :time, :date]`.

* `config.active_record.maintain_test_schema` is a boolean value which controls whether Active Record should try to keep your test database schema up-to-date with `db/schema.rb` (or `db/structure.sql`) when you run your tests. The default is true.

The MySQL adapter adds one additional configuration option:

* `ActiveRecord::ConnectionAdapters::MysqlAdapter.emulate_booleans` controls whether Active Record will consider all `tinyint(1)` columns in a MySQL database to be booleans and is true by default.
Expand Down
1 change: 0 additions & 1 deletion guides/source/plugins.md
Expand Up @@ -224,7 +224,6 @@ and migrating the database. First, run:
```bash
$ cd test/dummy
$ rake db:migrate
$ rake db:test:prepare
```

While you are here, change the Hickwall and Wickwall models so that they know that they are supposed to act
Expand Down
26 changes: 2 additions & 24 deletions guides/source/testing.md
Expand Up @@ -211,31 +211,9 @@ This line of code is called an _assertion_. An assertion is a line of code that

Every test contains one or more assertions. Only when all the assertions are successful will the test pass.

### Preparing your Application for Testing
### Maintaining the test database schema

Before you can run your tests, you need to ensure that the test database structure is current. For this you can use the following rake commands:

```bash
$ rake db:migrate
...
$ rake db:test:load
```

The `rake db:migrate` above runs any pending migrations on the _development_ environment and updates `db/schema.rb`. The `rake db:test:load` recreates the test database from the current `db/schema.rb`. On subsequent attempts, it is a good idea to first run `db:test:prepare`, as it first checks for pending migrations and warns you appropriately.

NOTE: `db:test:prepare` will fail with an error if `db/schema.rb` doesn't exist.

#### Rake Tasks for Preparing your Application for Testing

| Tasks | Description |
| ------------------------------ | ------------------------------------------------------------------------- |
| `rake db:test:clone` | Recreate the test database from the current environment's database schema |
| `rake db:test:clone_structure` | Recreate the test database from the development structure |
| `rake db:test:load` | Recreate the test database from the current `schema.rb` |
| `rake db:test:prepare` | Check for pending migrations and load the test schema |
| `rake db:test:purge` | Empty the test database. |

TIP: You can see all these rake tasks and their descriptions by running `rake --tasks --describe`
In order to run your tests, your test database will need to have the current structure. The test helper checks whether your test database has any pending migrations. If so, it will try to load your `db/schema.rb` or `db/structure.sql` into the test database. If migrations are still pending, an error will be raised.

### Running Tests

Expand Down
7 changes: 7 additions & 0 deletions guides/source/upgrading_ruby_on_rails.md
Expand Up @@ -91,6 +91,13 @@ secrets, you need to:

5. Restart your server.

### Changes to test helper

If your test helper contains a call to
`ActiveRecord::Migration.check_pending!` this can be removed. The check
is now done automatically when you `require 'test_help'`, although
leaving this line in your helper is not harmful in any way.

### Changes in JSON handling

There are a few major changes related to JSON handling in Rails 4.1.
Expand Down
6 changes: 6 additions & 0 deletions railties/CHANGELOG.md
@@ -1,3 +1,9 @@
* `test_help.rb` now automatically checks/maintains your test datbase
schema. (Use `config.active_record.maintain_test_schema = false` to
disable.)

*Jon Leighton*

* Configure `secrets.yml` and `database.yml` to read configuration
from the system environment by default for production.

Expand Down
Expand Up @@ -4,8 +4,6 @@

class ActiveSupport::TestCase
<% unless options[:skip_active_record] -%>
ActiveRecord::Migration.check_pending!

# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
#
# Note: You'll currently still have to declare fixtures explicitly in integration tests
Expand Down
2 changes: 2 additions & 0 deletions railties/lib/rails/test_help.rb
Expand Up @@ -15,6 +15,8 @@
end

if defined?(ActiveRecord::Base)
ActiveRecord::Migration.maintain_test_schema!

class ActiveSupport::TestCase
include ActiveRecord::TestFixtures
self.fixture_path = "#{Rails.root}/test/fixtures/"
Expand Down
9 changes: 9 additions & 0 deletions railties/test/application/rake/dbs_test.rb
Expand Up @@ -174,6 +174,15 @@ def db_test_load_structure
require "#{app_path}/config/environment"
db_test_load_structure
end

test 'db:test deprecation' do
require "#{app_path}/config/environment"
Dir.chdir(app_path) do
output = `bundle exec rake db:migrate db:test:prepare 2>&1`
assert_equal "WARNING: db:test:prepare is deprecated. The Rails test helper now maintains " \
"your test schema automatically, see the release notes for details.\n", output
end
end
end
end
end
4 changes: 2 additions & 2 deletions railties/test/application/rake_test.rb
Expand Up @@ -187,7 +187,7 @@ def test_loading_only_yml_fixtures
def test_scaffold_tests_pass_by_default
output = Dir.chdir(app_path) do
`rails generate scaffold user username:string password:string;
bundle exec rake db:migrate db:test:clone test`
bundle exec rake db:migrate test`
end

assert_match(/7 runs, 13 assertions, 0 failures, 0 errors/, output)
Expand All @@ -197,7 +197,7 @@ def test_scaffold_tests_pass_by_default
def test_scaffold_with_references_columns_tests_pass_by_default
output = Dir.chdir(app_path) do
`rails generate scaffold LineItems product:references cart:belongs_to;
bundle exec rake db:migrate db:test:clone test`
bundle exec rake db:migrate test`
end

assert_match(/7 runs, 13 assertions, 0 failures, 0 errors/, output)
Expand Down