aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Leighton <j@jonathanleighton.com>2012-06-17 13:38:25 -0700
committerJon Leighton <j@jonathanleighton.com>2012-06-17 13:38:25 -0700
commit757140823b2217301911efd531396bfb8f5c9a42 (patch)
tree2ecf81d21e5810b8459536f12ddb509cb35e16d2
parent69881ecdaf204a8e864cdda6af33cc258df544ae (diff)
parent55f8dfd99e20d991dee2d948120ce8955054acbf (diff)
downloadrails-757140823b2217301911efd531396bfb8f5c9a42.tar.gz
rails-757140823b2217301911efd531396bfb8f5c9a42.tar.bz2
rails-757140823b2217301911efd531396bfb8f5c9a42.zip
Merge pull request #6761 from freelancing-god/db-rake
Get logic out of db rake tasks, and into classes and objects
-rw-r--r--activerecord/lib/active_record.rb10
-rw-r--r--activerecord/lib/active_record/railties/databases.rake162
-rw-r--r--activerecord/lib/active_record/tasks/database_tasks.rb82
-rw-r--r--activerecord/lib/active_record/tasks/mysql_database_tasks.rb88
-rw-r--r--activerecord/lib/active_record/tasks/postgresql_database_tasks.rb45
-rw-r--r--activerecord/lib/active_record/tasks/sqlite_database_tasks.rb37
-rw-r--r--activerecord/test/cases/database_tasks_test.rb297
-rw-r--r--activerecord/test/cases/mysql_rake_test.rb179
-rw-r--r--activerecord/test/cases/postgresql_rake_test.rb135
-rw-r--r--activerecord/test/cases/sqlite_rake_test.rb104
10 files changed, 983 insertions, 156 deletions
diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb
index f8526bb691..8526e224da 100644
--- a/activerecord/lib/active_record.rb
+++ b/activerecord/lib/active_record.rb
@@ -137,6 +137,16 @@ module ActiveRecord
end
end
+ module Tasks
+ extend ActiveSupport::Autoload
+
+ autoload :DatabaseTasks
+ autoload :SQLiteDatabaseTasks, 'active_record/tasks/sqlite_database_tasks'
+ autoload :MySQLDatabaseTasks, 'active_record/tasks/mysql_database_tasks'
+ autoload :PostgreSQLDatabaseTasks,
+ 'active_record/tasks/postgresql_database_tasks'
+ end
+
autoload :TestCase
autoload :TestFixtures, 'active_record/fixtures'
end
diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake
index 7dad50bd7f..539836e9ed 100644
--- a/activerecord/lib/active_record/railties/databases.rake
+++ b/activerecord/lib/active_record/railties/databases.rake
@@ -14,138 +14,27 @@ db_namespace = namespace :db do
end
namespace :create do
- # desc 'Create all the local databases defined in config/database.yml'
task :all => :load_config do
- ActiveRecord::Base.configurations.each_value do |config|
- # Skip entries that don't have a database key, such as the first entry here:
- #
- # defaults: &defaults
- # adapter: mysql
- # username: root
- # password:
- # host: localhost
- #
- # development:
- # database: blog_development
- # *defaults
- next unless config['database']
- # Only connect to local databases
- local_database?(config) { create_database(config) }
- end
+ ActiveRecord::Tasks::DatabaseTasks.create_all
end
end
desc 'Create the database from config/database.yml for the current Rails.env (use db:create:all to create all dbs in the config)'
task :create => :load_config do
- configs_for_environment.each { |config| create_database(config) }
- ActiveRecord::Base.establish_connection(configs_for_environment.first)
- end
-
- def mysql_creation_options(config)
- @charset = ENV['CHARSET'] || 'utf8'
- @collation = ENV['COLLATION'] || 'utf8_unicode_ci'
- {:charset => (config['charset'] || @charset), :collation => (config['collation'] || @collation)}
- end
-
- def create_database(config)
- begin
- if config['adapter'] =~ /sqlite/
- if File.exist?(config['database'])
- $stderr.puts "#{config['database']} already exists"
- else
- begin
- # Create the SQLite database
- ActiveRecord::Base.establish_connection(config)
- ActiveRecord::Base.connection
- rescue Exception => e
- $stderr.puts e, *(e.backtrace)
- $stderr.puts "Couldn't create database for #{config.inspect}"
- end
- end
- return # Skip the else clause of begin/rescue
- else
- ActiveRecord::Base.establish_connection(config)
- ActiveRecord::Base.connection
- end
- rescue
- case config['adapter']
- when /mysql/
- if config['adapter'] =~ /jdbc/
- #FIXME After Jdbcmysql gives this class
- require 'active_record/railties/jdbcmysql_error'
- error_class = ArJdbcMySQL::Error
- else
- error_class = config['adapter'] =~ /mysql2/ ? Mysql2::Error : Mysql::Error
- end
- access_denied_error = 1045
- begin
- ActiveRecord::Base.establish_connection(config.merge('database' => nil))
- ActiveRecord::Base.connection.create_database(config['database'], mysql_creation_options(config))
- ActiveRecord::Base.establish_connection(config)
- rescue error_class => sqlerr
- if sqlerr.errno == access_denied_error
- print "#{sqlerr.error}. \nPlease provide the root password for your mysql installation\n>"
- root_password = $stdin.gets.strip
- grant_statement = "GRANT ALL PRIVILEGES ON #{config['database']}.* " \
- "TO '#{config['username']}'@'localhost' " \
- "IDENTIFIED BY '#{config['password']}' WITH GRANT OPTION;"
- ActiveRecord::Base.establish_connection(config.merge(
- 'database' => nil, 'username' => 'root', 'password' => root_password))
- ActiveRecord::Base.connection.create_database(config['database'], mysql_creation_options(config))
- ActiveRecord::Base.connection.execute grant_statement
- ActiveRecord::Base.establish_connection(config)
- else
- $stderr.puts sqlerr.error
- $stderr.puts "Couldn't create database for #{config.inspect}, charset: #{config['charset'] || @charset}, collation: #{config['collation'] || @collation}"
- $stderr.puts "(if you set the charset manually, make sure you have a matching collation)" if config['charset']
- end
- end
- when /postgresql/
- @encoding = config['encoding'] || ENV['CHARSET'] || 'utf8'
- begin
- ActiveRecord::Base.establish_connection(config.merge('database' => 'postgres', 'schema_search_path' => 'public'))
- ActiveRecord::Base.connection.create_database(config['database'], config.merge('encoding' => @encoding))
- ActiveRecord::Base.establish_connection(config)
- rescue Exception => e
- $stderr.puts e, *(e.backtrace)
- $stderr.puts "Couldn't create database for #{config.inspect}"
- end
- end
- else
- $stderr.puts "#{config['database']} already exists"
- end
+ ActiveRecord::Tasks::DatabaseTasks.create_current
end
namespace :drop do
- # desc 'Drops all the local databases defined in config/database.yml'
task :all => :load_config do
- ActiveRecord::Base.configurations.each_value do |config|
- # Skip entries that don't have a database key
- next unless config['database']
- begin
- # Only connect to local databases
- local_database?(config) { drop_database(config) }
- rescue Exception => e
- $stderr.puts "Couldn't drop #{config['database']} : #{e.inspect}"
- end
- end
+ ActiveRecord::Tasks::DatabaseTasks.drop_all
end
end
desc 'Drops the database for the current Rails.env (use db:drop:all to drop all databases)'
task :drop => :load_config do
- configs_for_environment.each { |config| drop_database_and_rescue(config) }
- end
-
- def local_database?(config, &block)
- if config['host'].in?(['127.0.0.1', 'localhost']) || config['host'].blank?
- yield
- else
- $stderr.puts "This task only modifies local databases. #{config['database']} is on a remote host."
- end
+ ActiveRecord::Tasks::DatabaseTasks.drop_current
end
-
desc "Migrate the database (options: VERSION=x, VERBOSE=false)."
task :migrate => [:environment, :load_config] do
ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
@@ -509,16 +398,8 @@ db_namespace = namespace :db do
task :purge => [:environment, :load_config] do
abcs = ActiveRecord::Base.configurations
case abcs['test']['adapter']
- when /mysql/
- ActiveRecord::Base.establish_connection(:test)
- ActiveRecord::Base.connection.recreate_database(abcs['test']['database'], mysql_creation_options(abcs['test']))
- when /postgresql/
- ActiveRecord::Base.clear_active_connections!
- drop_database(abcs['test'])
- create_database(abcs['test'])
- when /sqlite/
- dbfile = abcs['test']['database']
- File.delete(dbfile) if File.exist?(dbfile)
+ when /mysql/, /postgresql/, /sqlite/
+ ActiveRecord::Tasks::DatabaseTasks.purge abcs['test']
when 'sqlserver'
test = abcs.deep_dup['test']
test_database = test['database']
@@ -592,37 +473,6 @@ end
task 'test:prepare' => 'db:test:prepare'
-def drop_database(config)
- case config['adapter']
- when /mysql/
- ActiveRecord::Base.establish_connection(config)
- ActiveRecord::Base.connection.drop_database config['database']
- when /sqlite/
- require 'pathname'
- path = Pathname.new(config['database'])
- file = path.absolute? ? path.to_s : File.join(Rails.root, path)
-
- FileUtils.rm(file)
- when /postgresql/
- ActiveRecord::Base.establish_connection(config.merge('database' => 'postgres', 'schema_search_path' => 'public'))
- ActiveRecord::Base.connection.drop_database config['database']
- end
-end
-
-def drop_database_and_rescue(config)
- begin
- drop_database(config)
- rescue Exception => e
- $stderr.puts "Couldn't drop #{config['database']} : #{e.inspect}"
- end
-end
-
-def configs_for_environment
- environments = [Rails.env]
- environments << 'test' if Rails.env.development?
- ActiveRecord::Base.configurations.values_at(*environments).compact.reject { |config| config['database'].blank? }
-end
-
def session_table_name
ActiveRecord::SessionStore::Session.table_name
end
diff --git a/activerecord/lib/active_record/tasks/database_tasks.rb b/activerecord/lib/active_record/tasks/database_tasks.rb
new file mode 100644
index 0000000000..10cc679a05
--- /dev/null
+++ b/activerecord/lib/active_record/tasks/database_tasks.rb
@@ -0,0 +1,82 @@
+class ActiveRecord::Tasks::DatabaseTasks
+ TASKS_PATTERNS = {
+ /mysql/ => ActiveRecord::Tasks::MySQLDatabaseTasks,
+ /postgresql/ => ActiveRecord::Tasks::PostgreSQLDatabaseTasks,
+ /sqlite/ => ActiveRecord::Tasks::SQLiteDatabaseTasks
+ }
+ LOCAL_HOSTS = ['127.0.0.1', 'localhost']
+
+ def self.create(*arguments)
+ configuration = arguments.first
+ class_for_adapter(configuration['adapter']).new(*arguments).create
+ rescue Exception => error
+ $stderr.puts error, *(error.backtrace)
+ $stderr.puts "Couldn't create database for #{configuration.inspect}"
+ end
+
+ def self.create_all
+ each_local_configuration { |configuration| create configuration }
+ end
+
+ def self.create_current(environment = Rails.env)
+ each_current_configuration(environment) { |configuration|
+ create configuration
+ }
+ ActiveRecord::Base.establish_connection environment
+ end
+
+ def self.drop(*arguments)
+ configuration = arguments.first
+ class_for_adapter(configuration['adapter']).new(*arguments).drop
+ rescue Exception => error
+ $stderr.puts error, *(error.backtrace)
+ $stderr.puts "Couldn't drop #{configuration['database']}"
+ end
+
+ def self.drop_all
+ each_local_configuration { |configuration| drop configuration }
+ end
+
+ def self.drop_current(environment = Rails.env)
+ each_current_configuration(environment) { |configuration|
+ drop configuration
+ }
+ end
+
+ def self.purge(configuration)
+ class_for_adapter(configuration['adapter']).new(configuration).purge
+ end
+
+ private
+
+ def self.class_for_adapter(adapter)
+ key = TASKS_PATTERNS.keys.detect { |pattern| adapter[pattern] }
+ TASKS_PATTERNS[key]
+ end
+
+ def self.each_current_configuration(environment)
+ environments = [environment]
+ environments << 'test' if environment.development?
+
+ configurations = ActiveRecord::Base.configurations.values_at(*environments)
+ configurations.compact.each do |configuration|
+ yield configuration unless configuration['database'].blank?
+ end
+ end
+
+ def self.each_local_configuration
+ ActiveRecord::Base.configurations.each_value do |configuration|
+ next unless configuration['database']
+
+ if local_database?(configuration)
+ yield configuration
+ else
+ $stderr.puts "This task only modifies local databases. #{configuration['database']} is on a remote host."
+ end
+ end
+ end
+
+ def self.local_database?(configuration)
+ configuration['host'].in?(LOCAL_HOSTS) || configuration['host'].blank?
+ end
+end
diff --git a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb
new file mode 100644
index 0000000000..eb598629fa
--- /dev/null
+++ b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb
@@ -0,0 +1,88 @@
+class ActiveRecord::Tasks::MySQLDatabaseTasks
+ DEFAULT_CHARSET = ENV['CHARSET'] || 'utf8'
+ DEFAULT_COLLATION = ENV['COLLATION'] || 'utf8_unicode_ci'
+ ACCESS_DENIED_ERROR = 1045
+
+ delegate :connection, :establish_connection, :to => ActiveRecord::Base
+
+ def initialize(configuration)
+ @configuration = configuration
+ end
+
+ def create
+ establish_connection configuration_without_database
+ connection.create_database configuration['database'], creation_options
+ establish_connection configuration
+ rescue error_class => error
+ raise error unless error.errno == ACCESS_DENIED_ERROR
+
+ $stdout.print error.error
+ establish_connection root_configuration_without_database
+ connection.create_database configuration['database'], creation_options
+ connection.execute grant_statement.gsub(/\s+/, ' ').strip
+ establish_connection configuration
+ rescue error_class => error
+ $stderr.puts error.error
+ $stderr.puts "Couldn't create database for #{configuration.inspect}, #{creation_options.inspect}"
+ $stderr.puts "(If you set the charset manually, make sure you have a matching collation)" if configuration['charset']
+ end
+
+ def drop
+ establish_connection configuration
+ connection.drop_database configuration['database']
+ end
+
+ def purge
+ establish_connection :test
+ connection.recreate_database configuration['database'], creation_options
+ end
+
+ private
+
+ def configuration
+ @configuration
+ end
+
+ def configuration_without_database
+ configuration.merge('database' => nil)
+ end
+
+ def creation_options
+ {
+ :charset => (configuration['charset'] || DEFAULT_CHARSET),
+ :collation => (configuration['collation'] || DEFAULT_COLLATION)
+ }
+ end
+
+ def error_class
+ case configuration['adapter']
+ when /jdbc/
+ require 'active_record/railties/jdbcmysql_error'
+ ArJdbcMySQL::Error
+ when /mysql2/
+ Mysql2::Error
+ else
+ Mysql::Error
+ end
+ end
+
+ def grant_statement
+ <<-SQL
+GRANT ALL PRIVILEGES ON #{configuration['database']}.*
+ TO '#{configuration['username']}'@'localhost'
+IDENTIFIED BY '#{configuration['password']}' WITH GRANT OPTION;
+ SQL
+ end
+
+ def root_configuration_without_database
+ configuration_without_database.merge(
+ 'username' => 'root',
+ 'password' => root_password
+ )
+ end
+
+ def root_password
+ $stdout.print "Please provide the root password for your mysql installation\n>"
+ $stdin.gets.strip
+ end
+end
diff --git a/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb b/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb
new file mode 100644
index 0000000000..331825d3ec
--- /dev/null
+++ b/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb
@@ -0,0 +1,45 @@
+class ActiveRecord::Tasks::PostgreSQLDatabaseTasks
+ DEFAULT_ENCODING = ENV['CHARSET'] || 'utf8'
+
+ delegate :connection, :establish_connection, :clear_active_connections!,
+ :to => ActiveRecord::Base
+
+ def initialize(configuration)
+ @configuration = configuration
+ end
+
+ def create(master_established = false)
+ establish_master_connection unless master_established
+ connection.create_database configuration['database'],
+ configuration.merge('encoding' => encoding)
+ establish_connection configuration
+ end
+
+ def drop
+ establish_master_connection
+ connection.drop_database configuration['database']
+ end
+
+ def purge
+ clear_active_connections!
+ drop
+ create true
+ end
+
+ private
+
+ def configuration
+ @configuration
+ end
+
+ def encoding
+ configuration['encoding'] || DEFAULT_ENCODING
+ end
+
+ def establish_master_connection
+ establish_connection configuration.merge(
+ 'database' => 'postgres',
+ 'schema_search_path' => 'public'
+ )
+ end
+end
diff --git a/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb b/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb
new file mode 100644
index 0000000000..4d3cba8a50
--- /dev/null
+++ b/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb
@@ -0,0 +1,37 @@
+class ActiveRecord::Tasks::SQLiteDatabaseTasks
+ delegate :connection, :establish_connection, :to => ActiveRecord::Base
+
+ def initialize(configuration, root = Rails.root)
+ @configuration, @root = configuration, root
+ end
+
+ def create
+ if File.exist? configuration['database']
+ $stderr.puts "#{configuration['database']} already exists"
+ return
+ end
+
+ establish_connection configuration
+ connection
+ end
+
+ def drop
+ require 'pathname'
+ path = Pathname.new configuration['database']
+ file = path.absolute? ? path.to_s : File.join(root, path)
+
+ FileUtils.rm(file)
+ end
+
+ alias :purge :drop
+
+ private
+
+ def configuration
+ @configuration
+ end
+
+ def root
+ @root
+ end
+end
diff --git a/activerecord/test/cases/database_tasks_test.rb b/activerecord/test/cases/database_tasks_test.rb
new file mode 100644
index 0000000000..503e26f549
--- /dev/null
+++ b/activerecord/test/cases/database_tasks_test.rb
@@ -0,0 +1,297 @@
+require 'cases/helper'
+
+module ActiveRecord
+ class DatabaseTasksCreateTest < ActiveRecord::TestCase
+ def setup
+ @mysql_tasks, @postgresql_tasks, @sqlite_tasks = stub, stub, stub
+
+ ActiveRecord::Tasks::MySQLDatabaseTasks.stubs(:new).returns @mysql_tasks
+ ActiveRecord::Tasks::PostgreSQLDatabaseTasks.stubs(:new).
+ returns @postgresql_tasks
+ ActiveRecord::Tasks::SQLiteDatabaseTasks.stubs(:new).returns @sqlite_tasks
+ end
+
+ def test_mysql_create
+ @mysql_tasks.expects(:create)
+
+ ActiveRecord::Tasks::DatabaseTasks.create 'adapter' => 'mysql'
+ end
+
+ def test_mysql2_create
+ @mysql_tasks.expects(:create)
+
+ ActiveRecord::Tasks::DatabaseTasks.create 'adapter' => 'mysql2'
+ end
+
+ def test_postgresql_create
+ @postgresql_tasks.expects(:create)
+
+ ActiveRecord::Tasks::DatabaseTasks.create 'adapter' => 'postgresql'
+ end
+
+ def test_sqlite_create
+ @sqlite_tasks.expects(:create)
+
+ ActiveRecord::Tasks::DatabaseTasks.create 'adapter' => 'sqlite3'
+ end
+ end
+
+ class DatabaseTasksCreateAllTest < ActiveRecord::TestCase
+ def setup
+ @configurations = {'development' => {'database' => 'my-db'}}
+
+ ActiveRecord::Base.stubs(:configurations).returns(@configurations)
+ end
+
+ def test_ignores_configurations_without_databases
+ @configurations['development'].merge!('database' => nil)
+
+ ActiveRecord::Tasks::DatabaseTasks.expects(:create).never
+
+ ActiveRecord::Tasks::DatabaseTasks.create_all
+ end
+
+ def test_ignores_remote_databases
+ @configurations['development'].merge!('host' => 'my.server.tld')
+ $stderr.stubs(:puts).returns(nil)
+
+ ActiveRecord::Tasks::DatabaseTasks.expects(:create).never
+
+ ActiveRecord::Tasks::DatabaseTasks.create_all
+ end
+
+ def test_warning_for_remote_databases
+ @configurations['development'].merge!('host' => 'my.server.tld')
+
+ $stderr.expects(:puts).with('This task only modifies local databases. my-db is on a remote host.')
+
+ ActiveRecord::Tasks::DatabaseTasks.create_all
+ end
+
+ def test_creates_configurations_with_local_ip
+ @configurations['development'].merge!('host' => '127.0.0.1')
+
+ ActiveRecord::Tasks::DatabaseTasks.expects(:create)
+
+ ActiveRecord::Tasks::DatabaseTasks.create_all
+ end
+
+ def test_creates_configurations_with_local_host
+ @configurations['development'].merge!('host' => 'localhost')
+
+ ActiveRecord::Tasks::DatabaseTasks.expects(:create)
+
+ ActiveRecord::Tasks::DatabaseTasks.create_all
+ end
+
+ def test_creates_configurations_with_blank_hosts
+ @configurations['development'].merge!('host' => nil)
+
+ ActiveRecord::Tasks::DatabaseTasks.expects(:create)
+
+ ActiveRecord::Tasks::DatabaseTasks.create_all
+ end
+ end
+
+ class DatabaseTasksCreateCurrentTest < ActiveRecord::TestCase
+ def setup
+ @configurations = {
+ 'development' => {'database' => 'dev-db'},
+ 'test' => {'database' => 'test-db'},
+ 'production' => {'database' => 'prod-db'}
+ }
+
+ ActiveRecord::Base.stubs(:configurations).returns(@configurations)
+ ActiveRecord::Base.stubs(:establish_connection).returns(true)
+ end
+
+ def test_creates_current_environment_database
+ ActiveRecord::Tasks::DatabaseTasks.expects(:create).
+ with('database' => 'prod-db')
+
+ ActiveRecord::Tasks::DatabaseTasks.create_current(
+ ActiveSupport::StringInquirer.new('production')
+ )
+ end
+
+ def test_creates_test_database_when_environment_is_database
+ ActiveRecord::Tasks::DatabaseTasks.expects(:create).
+ with('database' => 'dev-db')
+ ActiveRecord::Tasks::DatabaseTasks.expects(:create).
+ with('database' => 'test-db')
+
+ ActiveRecord::Tasks::DatabaseTasks.create_current(
+ ActiveSupport::StringInquirer.new('development')
+ )
+ end
+
+ def test_establishes_connection_for_the_given_environment
+ ActiveRecord::Tasks::DatabaseTasks.stubs(:create).returns true
+
+ ActiveRecord::Base.expects(:establish_connection).with('development')
+
+ ActiveRecord::Tasks::DatabaseTasks.create_current(
+ ActiveSupport::StringInquirer.new('development')
+ )
+ end
+ end
+
+ class DatabaseTasksDropTest < ActiveRecord::TestCase
+ def setup
+ @mysql_tasks, @postgresql_tasks, @sqlite_tasks = stub, stub, stub
+
+ ActiveRecord::Tasks::MySQLDatabaseTasks.stubs(:new).returns @mysql_tasks
+ ActiveRecord::Tasks::PostgreSQLDatabaseTasks.stubs(:new).
+ returns @postgresql_tasks
+ ActiveRecord::Tasks::SQLiteDatabaseTasks.stubs(:new).returns @sqlite_tasks
+ end
+
+ def test_mysql_create
+ @mysql_tasks.expects(:drop)
+
+ ActiveRecord::Tasks::DatabaseTasks.drop 'adapter' => 'mysql'
+ end
+
+ def test_mysql2_create
+ @mysql_tasks.expects(:drop)
+
+ ActiveRecord::Tasks::DatabaseTasks.drop 'adapter' => 'mysql2'
+ end
+
+ def test_postgresql_create
+ @postgresql_tasks.expects(:drop)
+
+ ActiveRecord::Tasks::DatabaseTasks.drop 'adapter' => 'postgresql'
+ end
+
+ def test_sqlite_create
+ @sqlite_tasks.expects(:drop)
+
+ ActiveRecord::Tasks::DatabaseTasks.drop 'adapter' => 'sqlite3'
+ end
+ end
+
+ class DatabaseTasksDropAllTest < ActiveRecord::TestCase
+ def setup
+ @configurations = {:development => {'database' => 'my-db'}}
+
+ ActiveRecord::Base.stubs(:configurations).returns(@configurations)
+ end
+
+ def test_ignores_configurations_without_databases
+ @configurations[:development].merge!('database' => nil)
+
+ ActiveRecord::Tasks::DatabaseTasks.expects(:drop).never
+
+ ActiveRecord::Tasks::DatabaseTasks.drop_all
+ end
+
+ def test_ignores_remote_databases
+ @configurations[:development].merge!('host' => 'my.server.tld')
+ $stderr.stubs(:puts).returns(nil)
+
+ ActiveRecord::Tasks::DatabaseTasks.expects(:drop).never
+
+ ActiveRecord::Tasks::DatabaseTasks.drop_all
+ end
+
+ def test_warning_for_remote_databases
+ @configurations[:development].merge!('host' => 'my.server.tld')
+
+ $stderr.expects(:puts).with('This task only modifies local databases. my-db is on a remote host.')
+
+ ActiveRecord::Tasks::DatabaseTasks.drop_all
+ end
+
+ def test_creates_configurations_with_local_ip
+ @configurations[:development].merge!('host' => '127.0.0.1')
+
+ ActiveRecord::Tasks::DatabaseTasks.expects(:drop)
+
+ ActiveRecord::Tasks::DatabaseTasks.drop_all
+ end
+
+ def test_creates_configurations_with_local_host
+ @configurations[:development].merge!('host' => 'localhost')
+
+ ActiveRecord::Tasks::DatabaseTasks.expects(:drop)
+
+ ActiveRecord::Tasks::DatabaseTasks.drop_all
+ end
+
+ def test_creates_configurations_with_blank_hosts
+ @configurations[:development].merge!('host' => nil)
+
+ ActiveRecord::Tasks::DatabaseTasks.expects(:drop)
+
+ ActiveRecord::Tasks::DatabaseTasks.drop_all
+ end
+ end
+
+ class DatabaseTasksDropCurrentTest < ActiveRecord::TestCase
+ def setup
+ @configurations = {
+ 'development' => {'database' => 'dev-db'},
+ 'test' => {'database' => 'test-db'},
+ 'production' => {'database' => 'prod-db'}
+ }
+
+ ActiveRecord::Base.stubs(:configurations).returns(@configurations)
+ end
+
+ def test_creates_current_environment_database
+ ActiveRecord::Tasks::DatabaseTasks.expects(:drop).
+ with('database' => 'prod-db')
+
+ ActiveRecord::Tasks::DatabaseTasks.drop_current(
+ ActiveSupport::StringInquirer.new('production')
+ )
+ end
+
+ def test_creates_test_database_when_environment_is_database
+ ActiveRecord::Tasks::DatabaseTasks.expects(:drop).
+ with('database' => 'dev-db')
+ ActiveRecord::Tasks::DatabaseTasks.expects(:drop).
+ with('database' => 'test-db')
+
+ ActiveRecord::Tasks::DatabaseTasks.drop_current(
+ ActiveSupport::StringInquirer.new('development')
+ )
+ end
+ end
+
+ class DatabaseTasksPurgeTest < ActiveRecord::TestCase
+ def setup
+ @mysql_tasks, @postgresql_tasks, @sqlite_tasks = stub, stub, stub
+
+ ActiveRecord::Tasks::MySQLDatabaseTasks.stubs(:new).returns @mysql_tasks
+ ActiveRecord::Tasks::PostgreSQLDatabaseTasks.stubs(:new).
+ returns @postgresql_tasks
+ ActiveRecord::Tasks::SQLiteDatabaseTasks.stubs(:new).returns @sqlite_tasks
+ end
+
+ def test_mysql_create
+ @mysql_tasks.expects(:purge)
+
+ ActiveRecord::Tasks::DatabaseTasks.purge 'adapter' => 'mysql'
+ end
+
+ def test_mysql2_create
+ @mysql_tasks.expects(:purge)
+
+ ActiveRecord::Tasks::DatabaseTasks.purge 'adapter' => 'mysql2'
+ end
+
+ def test_postgresql_create
+ @postgresql_tasks.expects(:purge)
+
+ ActiveRecord::Tasks::DatabaseTasks.purge 'adapter' => 'postgresql'
+ end
+
+ def test_sqlite_create
+ @sqlite_tasks.expects(:purge)
+
+ ActiveRecord::Tasks::DatabaseTasks.purge 'adapter' => 'sqlite3'
+ end
+ end
+end
diff --git a/activerecord/test/cases/mysql_rake_test.rb b/activerecord/test/cases/mysql_rake_test.rb
new file mode 100644
index 0000000000..cdb0968bb6
--- /dev/null
+++ b/activerecord/test/cases/mysql_rake_test.rb
@@ -0,0 +1,179 @@
+require 'cases/helper'
+require 'mysql'
+
+module ActiveRecord
+ class MysqlDBCreateTest < ActiveRecord::TestCase
+ def setup
+ @connection = stub(:create_database => true)
+ @configuration = {
+ 'adapter' => 'mysql',
+ 'database' => 'my-app-db'
+ }
+
+ ActiveRecord::Base.stubs(:connection).returns(@connection)
+ ActiveRecord::Base.stubs(:establish_connection).returns(true)
+ end
+
+ def test_establishes_connection_without_database
+ ActiveRecord::Base.expects(:establish_connection).
+ with('adapter' => 'mysql', 'database' => nil)
+
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration
+ end
+
+ def test_creates_database_with_default_options
+ @connection.expects(:create_database).
+ with('my-app-db', {:charset => 'utf8', :collation => 'utf8_unicode_ci'})
+
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration
+ end
+
+ def test_creates_database_with_given_options
+ @connection.expects(:create_database).
+ with('my-app-db', {:charset => 'latin', :collation => 'latin_ci'})
+
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration.merge(
+ 'charset' => 'latin', 'collation' => 'latin_ci'
+ )
+ end
+
+ def test_establishes_connection_to_database
+ ActiveRecord::Base.expects(:establish_connection).with(@configuration)
+
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration
+ end
+ end
+
+ class MysqlDBCreateAsRootTest < ActiveRecord::TestCase
+ def setup
+ @connection = stub(:create_database => true, :execute => true)
+ @error = Mysql::Error.new "Invalid permissions"
+ @configuration = {
+ 'adapter' => 'mysql',
+ 'database' => 'my-app-db',
+ 'username' => 'pat',
+ 'password' => 'wossname'
+ }
+
+ $stdin.stubs(:gets).returns("secret\n")
+ $stdout.stubs(:print).returns(nil)
+ @error.stubs(:errno).returns(1045)
+ ActiveRecord::Base.stubs(:connection).returns(@connection)
+ ActiveRecord::Base.stubs(:establish_connection).raises(@error).then.
+ returns(true)
+ end
+
+ def test_root_password_is_requested
+ $stdin.expects(:gets).returns("secret\n")
+
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration
+ end
+
+ def test_connection_established_as_root
+ ActiveRecord::Base.expects(:establish_connection).with({
+ 'adapter' => 'mysql',
+ 'database' => nil,
+ 'username' => 'root',
+ 'password' => 'secret'
+ })
+
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration
+ end
+
+ def test_database_created_by_root
+ @connection.expects(:create_database).
+ with('my-app-db', :charset => 'utf8', :collation => 'utf8_unicode_ci')
+
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration
+ end
+
+ def test_grant_privileges_for_normal_user
+ @connection.expects(:execute).with("GRANT ALL PRIVILEGES ON my-app-db.* TO 'pat'@'localhost' IDENTIFIED BY 'wossname' WITH GRANT OPTION;")
+
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration
+ end
+
+ def test_connection_established_as_normal_user
+ ActiveRecord::Base.expects(:establish_connection).returns do
+ ActiveRecord::Base.expects(:establish_connection).with({
+ 'adapter' => 'mysql',
+ 'database' => 'my-app-db',
+ 'username' => 'pat',
+ 'password' => 'secret'
+ })
+
+ raise @error
+ end
+
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration
+ end
+
+ def test_sends_output_to_stderr_when_other_errors
+ @error.stubs(:errno).returns(42)
+
+ $stderr.expects(:puts).at_least_once.returns(nil)
+
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration
+ end
+ end
+
+ class MySQLDBDropTest < ActiveRecord::TestCase
+ def setup
+ @connection = stub(:drop_database => true)
+ @configuration = {
+ 'adapter' => 'mysql',
+ 'database' => 'my-app-db'
+ }
+
+ ActiveRecord::Base.stubs(:connection).returns(@connection)
+ ActiveRecord::Base.stubs(:establish_connection).returns(true)
+ end
+
+ def test_establishes_connection_to_postgresql_database
+ ActiveRecord::Base.expects(:establish_connection).with @configuration
+
+ ActiveRecord::Tasks::DatabaseTasks.drop @configuration
+ end
+
+ def test_drops_database
+ @connection.expects(:drop_database).with('my-app-db')
+
+ ActiveRecord::Tasks::DatabaseTasks.drop @configuration
+ end
+ end
+
+ class MySQLTestPurge < ActiveRecord::TestCase
+ def setup
+ @connection = stub(:recreate_database => true)
+ @configuration = {
+ 'adapter' => 'mysql',
+ 'database' => 'test-db'
+ }
+
+ ActiveRecord::Base.stubs(:connection).returns(@connection)
+ ActiveRecord::Base.stubs(:establish_connection).returns(true)
+ end
+
+ def test_establishes_connection_to_test_database
+ ActiveRecord::Base.expects(:establish_connection).with(:test)
+
+ ActiveRecord::Tasks::DatabaseTasks.purge @configuration
+ end
+
+ def test_recreates_database_with_the_default_options
+ @connection.expects(:recreate_database).
+ with('test-db', {:charset => 'utf8', :collation => 'utf8_unicode_ci'})
+
+ ActiveRecord::Tasks::DatabaseTasks.purge @configuration
+ end
+
+ def test_recreates_database_with_the_given_options
+ @connection.expects(:recreate_database).
+ with('test-db', {:charset => 'latin', :collation => 'latin_ci'})
+
+ ActiveRecord::Tasks::DatabaseTasks.purge @configuration.merge(
+ 'charset' => 'latin', 'collation' => 'latin_ci'
+ )
+ end
+ end
+end
diff --git a/activerecord/test/cases/postgresql_rake_test.rb b/activerecord/test/cases/postgresql_rake_test.rb
new file mode 100644
index 0000000000..6d6ede354d
--- /dev/null
+++ b/activerecord/test/cases/postgresql_rake_test.rb
@@ -0,0 +1,135 @@
+require 'cases/helper'
+
+module ActiveRecord
+ class PostgreSQLDBCreateTest < ActiveRecord::TestCase
+ def setup
+ @connection = stub(:create_database => true)
+ @configuration = {
+ 'adapter' => 'postgresql',
+ 'database' => 'my-app-db'
+ }
+
+ ActiveRecord::Base.stubs(:connection).returns(@connection)
+ ActiveRecord::Base.stubs(:establish_connection).returns(true)
+ end
+
+ def test_establishes_connection_to_postgresql_database
+ ActiveRecord::Base.expects(:establish_connection).with(
+ 'adapter' => 'postgresql',
+ 'database' => 'postgres',
+ 'schema_search_path' => 'public'
+ )
+
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration
+ end
+
+ def test_creates_database_with_default_encoding
+ @connection.expects(:create_database).
+ with('my-app-db', @configuration.merge('encoding' => 'utf8'))
+
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration
+ end
+
+ def test_creates_database_with_given_encoding
+ @connection.expects(:create_database).
+ with('my-app-db', @configuration.merge('encoding' => 'latin'))
+
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration.
+ merge('encoding' => 'latin')
+ end
+
+ def test_establishes_connection_to_new_database
+ ActiveRecord::Base.expects(:establish_connection).with(@configuration)
+
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration
+ end
+
+ def test_db_create_with_error_prints_message
+ ActiveRecord::Base.stubs(:establish_connection).raises(Exception)
+
+ $stderr.stubs(:puts).returns(true)
+ $stderr.expects(:puts).
+ with("Couldn't create database for #{@configuration.inspect}")
+
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration
+ end
+ end
+
+ class PostgreSQLDBDropTest < ActiveRecord::TestCase
+ def setup
+ @connection = stub(:drop_database => true)
+ @configuration = {
+ 'adapter' => 'postgresql',
+ 'database' => 'my-app-db'
+ }
+
+ ActiveRecord::Base.stubs(:connection).returns(@connection)
+ ActiveRecord::Base.stubs(:establish_connection).returns(true)
+ end
+
+ def test_establishes_connection_to_postgresql_database
+ ActiveRecord::Base.expects(:establish_connection).with(
+ 'adapter' => 'postgresql',
+ 'database' => 'postgres',
+ 'schema_search_path' => 'public'
+ )
+
+ ActiveRecord::Tasks::DatabaseTasks.drop @configuration
+ end
+
+ def test_drops_database
+ @connection.expects(:drop_database).with('my-app-db')
+
+ ActiveRecord::Tasks::DatabaseTasks.drop @configuration
+ end
+ end
+
+ class PostgreSQLPurgeTest < ActiveRecord::TestCase
+ def setup
+ @connection = stub(:create_database => true, :drop_database => true)
+ @configuration = {
+ 'adapter' => 'postgresql',
+ 'database' => 'my-app-db'
+ }
+
+ ActiveRecord::Base.stubs(:connection).returns(@connection)
+ ActiveRecord::Base.stubs(:clear_active_connections!).returns(true)
+ ActiveRecord::Base.stubs(:establish_connection).returns(true)
+ end
+
+ def test_clears_active_connections
+ ActiveRecord::Base.expects(:clear_active_connections!)
+
+ ActiveRecord::Tasks::DatabaseTasks.purge @configuration
+ end
+
+ def test_establishes_connection_to_postgresql_database
+ ActiveRecord::Base.expects(:establish_connection).with(
+ 'adapter' => 'postgresql',
+ 'database' => 'postgres',
+ 'schema_search_path' => 'public'
+ )
+
+ ActiveRecord::Tasks::DatabaseTasks.purge @configuration
+ end
+
+ def test_drops_database
+ @connection.expects(:drop_database).with('my-app-db')
+
+ ActiveRecord::Tasks::DatabaseTasks.purge @configuration
+ end
+
+ def test_creates_database
+ @connection.expects(:create_database).
+ with('my-app-db', @configuration.merge('encoding' => 'utf8'))
+
+ ActiveRecord::Tasks::DatabaseTasks.purge @configuration
+ end
+
+ def test_establishes_connection
+ ActiveRecord::Base.expects(:establish_connection).with(@configuration)
+
+ ActiveRecord::Tasks::DatabaseTasks.purge @configuration
+ end
+ end
+end
diff --git a/activerecord/test/cases/sqlite_rake_test.rb b/activerecord/test/cases/sqlite_rake_test.rb
new file mode 100644
index 0000000000..f96a161df1
--- /dev/null
+++ b/activerecord/test/cases/sqlite_rake_test.rb
@@ -0,0 +1,104 @@
+require 'cases/helper'
+require 'pathname'
+
+module ActiveRecord
+ class SqliteDBCreateTest < ActiveRecord::TestCase
+ def setup
+ @database = "db_create.sqlite3"
+ @connection = stub :connection
+ @configuration = {
+ 'adapter' => 'sqlite3',
+ 'database' => @database
+ }
+
+ File.stubs(:exist?).returns(false)
+ ActiveRecord::Base.stubs(:connection).returns(@connection)
+ ActiveRecord::Base.stubs(:establish_connection).returns(true)
+ end
+
+ def test_db_checks_database_exists
+ File.expects(:exist?).with(@database).returns(false)
+
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration, '/rails/root'
+ end
+
+ def test_db_create_when_file_exists
+ File.stubs(:exist?).returns(true)
+
+ $stderr.expects(:puts).with("#{@database} already exists")
+
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration, '/rails/root'
+ end
+
+ def test_db_create_with_file_does_nothing
+ File.stubs(:exist?).returns(true)
+ $stderr.stubs(:puts).returns(nil)
+
+ ActiveRecord::Base.expects(:establish_connection).never
+
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration, '/rails/root'
+ end
+
+ def test_db_create_establishes_a_connection
+ ActiveRecord::Base.expects(:establish_connection).with(@configuration)
+
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration, '/rails/root'
+ end
+
+ def test_db_create_with_error_prints_message
+ ActiveRecord::Base.stubs(:establish_connection).raises(Exception)
+
+ $stderr.stubs(:puts).returns(true)
+ $stderr.expects(:puts).
+ with("Couldn't create database for #{@configuration.inspect}")
+
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration, '/rails/root'
+ end
+ end
+
+ class SqliteDBDropTest < ActiveRecord::TestCase
+ def setup
+ @database = "db_create.sqlite3"
+ @path = stub(:to_s => '/absolute/path', :absolute? => true)
+ @configuration = {
+ 'adapter' => 'sqlite3',
+ 'database' => @database
+ }
+
+ Pathname.stubs(:new).returns(@path)
+ File.stubs(:join).returns('/former/relative/path')
+ FileUtils.stubs(:rm).returns(true)
+ end
+
+ def test_creates_path_from_database
+ Pathname.expects(:new).with(@database).returns(@path)
+
+ ActiveRecord::Tasks::DatabaseTasks.drop @configuration, '/rails/root'
+ end
+
+ def test_removes_file_with_absolute_path
+ @path.stubs(:absolute?).returns(true)
+
+ FileUtils.expects(:rm).with('/absolute/path')
+
+ ActiveRecord::Tasks::DatabaseTasks.drop @configuration, '/rails/root'
+ end
+
+ def test_generates_absolute_path_with_given_root
+ @path.stubs(:absolute?).returns(false)
+
+ File.expects(:join).with('/rails/root', @path).
+ returns('/former/relative/path')
+
+ ActiveRecord::Tasks::DatabaseTasks.drop @configuration, '/rails/root'
+ end
+
+ def test_removes_file_with_relative_path
+ @path.stubs(:absolute?).returns(false)
+
+ FileUtils.expects(:rm).with('/former/relative/path')
+
+ ActiveRecord::Tasks::DatabaseTasks.drop @configuration, '/rails/root'
+ end
+ end
+end