diff options
Diffstat (limited to 'activerecord/test/cases/adapters')
29 files changed, 888 insertions, 292 deletions
diff --git a/activerecord/test/cases/adapters/mysql/active_schema_test.rb b/activerecord/test/cases/adapters/mysql/active_schema_test.rb index 8812cf1b7d..0878925a6c 100644 --- a/activerecord/test/cases/adapters/mysql/active_schema_test.rb +++ b/activerecord/test/cases/adapters/mysql/active_schema_test.rb @@ -2,40 +2,61 @@ require "cases/helper" class ActiveSchemaTest < ActiveRecord::TestCase def setup - ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter.class_eval do + @connection = ActiveRecord::Base.remove_connection + ActiveRecord::Base.establish_connection(@connection) + + ActiveRecord::Base.connection.singleton_class.class_eval do alias_method :execute_without_stub, :execute - remove_method :execute def execute(sql, name = nil) return sql end end end def teardown - ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter.class_eval do - remove_method :execute - alias_method :execute, :execute_without_stub - end + ActiveRecord::Base.remove_connection + ActiveRecord::Base.establish_connection(@connection) end def test_add_index # add_index calls index_name_exists? which can't work since execute is stubbed - ActiveRecord::ConnectionAdapters::MysqlAdapter.send(:define_method, :index_name_exists?) do |*| - false - end - expected = "CREATE INDEX `index_people_on_last_name` ON `people` (`last_name`)" + def (ActiveRecord::Base.connection).index_name_exists?(*); false; end + + expected = "CREATE INDEX `index_people_on_last_name` ON `people` (`last_name`) " assert_equal expected, add_index(:people, :last_name, :length => nil) - expected = "CREATE INDEX `index_people_on_last_name` ON `people` (`last_name`(10))" + expected = "CREATE INDEX `index_people_on_last_name` ON `people` (`last_name`(10)) " assert_equal expected, add_index(:people, :last_name, :length => 10) - expected = "CREATE INDEX `index_people_on_last_name_and_first_name` ON `people` (`last_name`(15), `first_name`(15))" + expected = "CREATE INDEX `index_people_on_last_name_and_first_name` ON `people` (`last_name`(15), `first_name`(15)) " assert_equal expected, add_index(:people, [:last_name, :first_name], :length => 15) - expected = "CREATE INDEX `index_people_on_last_name_and_first_name` ON `people` (`last_name`(15), `first_name`)" + expected = "CREATE INDEX `index_people_on_last_name_and_first_name` ON `people` (`last_name`(15), `first_name`) " assert_equal expected, add_index(:people, [:last_name, :first_name], :length => {:last_name => 15}) - expected = "CREATE INDEX `index_people_on_last_name_and_first_name` ON `people` (`last_name`(15), `first_name`(10))" + expected = "CREATE INDEX `index_people_on_last_name_and_first_name` ON `people` (`last_name`(15), `first_name`(10)) " assert_equal expected, add_index(:people, [:last_name, :first_name], :length => {:last_name => 15, :first_name => 10}) - ActiveRecord::ConnectionAdapters::MysqlAdapter.send(:remove_method, :index_name_exists?) + + %w(SPATIAL FULLTEXT UNIQUE).each do |type| + expected = "CREATE #{type} INDEX `index_people_on_last_name` ON `people` (`last_name`) " + assert_equal expected, add_index(:people, :last_name, :type => type) + end + + %w(btree hash).each do |using| + expected = "CREATE INDEX `index_people_on_last_name` USING #{using} ON `people` (`last_name`) " + assert_equal expected, add_index(:people, :last_name, :using => using) + end + + expected = "CREATE INDEX `index_people_on_last_name` USING btree ON `people` (`last_name`(10)) " + assert_equal expected, add_index(:people, :last_name, :length => 10, :using => :btree) + + expected = "CREATE INDEX `index_people_on_last_name` USING btree ON `people` (`last_name`(10)) ALGORITHM = COPY" + assert_equal expected, add_index(:people, :last_name, :length => 10, using: :btree, algorithm: :copy) + + assert_raise ArgumentError do + add_index(:people, :last_name, algorithm: :coyp) + end + + expected = "CREATE INDEX `index_people_on_last_name_and_first_name` USING btree ON `people` (`last_name`(15), `first_name`(15)) " + assert_equal expected, add_index(:people, [:last_name, :first_name], :length => 15, :using => :btree) end def test_drop_table @@ -70,8 +91,7 @@ class ActiveSchemaTest < ActiveRecord::TestCase def test_add_timestamps with_real_execute do begin - ActiveRecord::Base.connection.create_table :delete_me do |t| - end + ActiveRecord::Base.connection.create_table :delete_me ActiveRecord::Base.connection.add_timestamps :delete_me assert column_present?('delete_me', 'updated_at', 'datetime') assert column_present?('delete_me', 'created_at', 'datetime') @@ -98,22 +118,20 @@ class ActiveSchemaTest < ActiveRecord::TestCase private def with_real_execute - #we need to actually modify some data, so we make execute point to the original method - ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter.class_eval do + ActiveRecord::Base.connection.singleton_class.class_eval do alias_method :execute_with_stub, :execute remove_method :execute alias_method :execute, :execute_without_stub end + yield ensure - #before finishing, we restore the alias to the mock-up method - ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter.class_eval do + ActiveRecord::Base.connection.singleton_class.class_eval do remove_method :execute alias_method :execute, :execute_with_stub end end - def method_missing(method_symbol, *arguments) ActiveRecord::Base.connection.send(method_symbol, *arguments) end diff --git a/activerecord/test/cases/adapters/mysql/connection_test.rb b/activerecord/test/cases/adapters/mysql/connection_test.rb index b965983fec..1844a2e0dc 100644 --- a/activerecord/test/cases/adapters/mysql/connection_test.rb +++ b/activerecord/test/cases/adapters/mysql/connection_test.rb @@ -17,7 +17,7 @@ class MysqlConnectionTest < ActiveRecord::TestCase end def test_connect_with_url - run_without_connection do |orig| + run_without_connection do ar_config = ARTest.connection_config['arunit'] skip "This test doesn't work with custom socket location" if ar_config['socket'] diff --git a/activerecord/test/cases/adapters/mysql/enum_test.rb b/activerecord/test/cases/adapters/mysql/enum_test.rb index 40af317ad1..f4e7a3ef0a 100644 --- a/activerecord/test/cases/adapters/mysql/enum_test.rb +++ b/activerecord/test/cases/adapters/mysql/enum_test.rb @@ -5,6 +5,6 @@ class MysqlEnumTest < ActiveRecord::TestCase end def test_enum_limit - assert_equal 5, EnumTest.columns.first.limit + assert_equal 6, EnumTest.columns.first.limit end end diff --git a/activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb b/activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb index 0eb1cc511e..9ad0744aee 100644 --- a/activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb +++ b/activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb @@ -16,6 +16,15 @@ module ActiveRecord eosql end + def test_valid_column + column = @conn.columns('ex').find { |col| col.name == 'id' } + assert @conn.valid_type?(column.type) + end + + def test_invalid_column + assert_not @conn.valid_type?(:foobar) + end + def test_client_encoding assert_equal Encoding::UTF_8, @conn.client_encoding end @@ -86,14 +95,39 @@ module ActiveRecord assert_equal @conn.default_sequence_name('ex_with_custom_index_type_pk', 'id'), seq end + def test_tinyint_integer_typecasting + @conn.exec_query('drop table if exists ex_with_non_boolean_tinyint_column') + @conn.exec_query(<<-eosql) + CREATE TABLE `ex_with_non_boolean_tinyint_column` ( + `status` TINYINT(4)) + eosql + insert(@conn, { 'status' => 2 }, 'ex_with_non_boolean_tinyint_column') + + result = @conn.exec_query('SELECT status FROM ex_with_non_boolean_tinyint_column') + + assert_equal 2, result.column_types['status'].type_cast(result.last['status']) + end + + def test_supports_extensions + assert_not @conn.supports_extensions?, 'does not support extensions' + end + + def test_respond_to_enable_extension + assert @conn.respond_to?(:enable_extension) + end + + def test_respond_to_disable_extension + assert @conn.respond_to?(:disable_extension) + end + private - def insert(ctx, data) + def insert(ctx, data, table='ex') binds = data.map { |name, value| - [ctx.columns('ex').find { |x| x.name == name }, value] + [ctx.columns(table).find { |x| x.name == name }, value] } columns = binds.map(&:first).map(&:name) - sql = "INSERT INTO ex (#{columns.join(", ")}) + sql = "INSERT INTO #{table} (#{columns.join(", ")}) VALUES (#{(['?'] * columns.length).join(', ')})" ctx.exec_insert(sql, 'SQL', binds) diff --git a/activerecord/test/cases/adapters/mysql/reserved_word_test.rb b/activerecord/test/cases/adapters/mysql/reserved_word_test.rb index 4cf4bc4c61..8eb9565963 100644 --- a/activerecord/test/cases/adapters/mysql/reserved_word_test.rb +++ b/activerecord/test/cases/adapters/mysql/reserved_word_test.rb @@ -2,7 +2,7 @@ require "cases/helper" class Group < ActiveRecord::Base Group.table_name = 'group' - belongs_to :select, :class_name => 'Select' + belongs_to :select has_one :values end diff --git a/activerecord/test/cases/adapters/mysql/schema_test.rb b/activerecord/test/cases/adapters/mysql/schema_test.rb index d94bb629a7..807a7a155e 100644 --- a/activerecord/test/cases/adapters/mysql/schema_test.rb +++ b/activerecord/test/cases/adapters/mysql/schema_test.rb @@ -35,6 +35,28 @@ module ActiveRecord def test_table_exists_wrong_schema assert(!@connection.table_exists?("#{@db_name}.zomg"), "table should not exist") end + + def test_dump_indexes + index_a_name = 'index_key_tests_on_snack' + index_b_name = 'index_key_tests_on_pizza' + index_c_name = 'index_key_tests_on_awesome' + + table = 'key_tests' + + indexes = @connection.indexes(table).sort_by {|i| i.name} + assert_equal 3,indexes.size + + index_a = indexes.select{|i| i.name == index_a_name}[0] + index_b = indexes.select{|i| i.name == index_b_name}[0] + index_c = indexes.select{|i| i.name == index_c_name}[0] + assert_equal :btree, index_a.using + assert_nil index_a.type + assert_equal :btree, index_b.using + assert_nil index_b.type + + assert_nil index_c.using + assert_equal :fulltext, index_c.type + end end end end diff --git a/activerecord/test/cases/adapters/mysql2/active_schema_test.rb b/activerecord/test/cases/adapters/mysql2/active_schema_test.rb index a83399d0cd..4ccf568406 100644 --- a/activerecord/test/cases/adapters/mysql2/active_schema_test.rb +++ b/activerecord/test/cases/adapters/mysql2/active_schema_test.rb @@ -2,40 +2,61 @@ require "cases/helper" class ActiveSchemaTest < ActiveRecord::TestCase def setup - ActiveRecord::ConnectionAdapters::Mysql2Adapter.class_eval do + @connection = ActiveRecord::Base.remove_connection + ActiveRecord::Base.establish_connection(@connection) + + ActiveRecord::Base.connection.singleton_class.class_eval do alias_method :execute_without_stub, :execute - remove_method :execute def execute(sql, name = nil) return sql end end end def teardown - ActiveRecord::ConnectionAdapters::Mysql2Adapter.class_eval do - remove_method :execute - alias_method :execute, :execute_without_stub - end + ActiveRecord::Base.remove_connection + ActiveRecord::Base.establish_connection(@connection) end def test_add_index # add_index calls index_name_exists? which can't work since execute is stubbed - ActiveRecord::ConnectionAdapters::Mysql2Adapter.send(:define_method, :index_name_exists?) do |*| - false - end - expected = "CREATE INDEX `index_people_on_last_name` ON `people` (`last_name`)" + def (ActiveRecord::Base.connection).index_name_exists?(*); false; end + + expected = "CREATE INDEX `index_people_on_last_name` ON `people` (`last_name`) " assert_equal expected, add_index(:people, :last_name, :length => nil) - expected = "CREATE INDEX `index_people_on_last_name` ON `people` (`last_name`(10))" + expected = "CREATE INDEX `index_people_on_last_name` ON `people` (`last_name`(10)) " assert_equal expected, add_index(:people, :last_name, :length => 10) - expected = "CREATE INDEX `index_people_on_last_name_and_first_name` ON `people` (`last_name`(15), `first_name`(15))" + expected = "CREATE INDEX `index_people_on_last_name_and_first_name` ON `people` (`last_name`(15), `first_name`(15)) " assert_equal expected, add_index(:people, [:last_name, :first_name], :length => 15) - expected = "CREATE INDEX `index_people_on_last_name_and_first_name` ON `people` (`last_name`(15), `first_name`)" + expected = "CREATE INDEX `index_people_on_last_name_and_first_name` ON `people` (`last_name`(15), `first_name`) " assert_equal expected, add_index(:people, [:last_name, :first_name], :length => {:last_name => 15}) - expected = "CREATE INDEX `index_people_on_last_name_and_first_name` ON `people` (`last_name`(15), `first_name`(10))" + expected = "CREATE INDEX `index_people_on_last_name_and_first_name` ON `people` (`last_name`(15), `first_name`(10)) " assert_equal expected, add_index(:people, [:last_name, :first_name], :length => {:last_name => 15, :first_name => 10}) - ActiveRecord::ConnectionAdapters::Mysql2Adapter.send(:remove_method, :index_name_exists?) + + %w(SPATIAL FULLTEXT UNIQUE).each do |type| + expected = "CREATE #{type} INDEX `index_people_on_last_name` ON `people` (`last_name`) " + assert_equal expected, add_index(:people, :last_name, :type => type) + end + + %w(btree hash).each do |using| + expected = "CREATE INDEX `index_people_on_last_name` USING #{using} ON `people` (`last_name`) " + assert_equal expected, add_index(:people, :last_name, :using => using) + end + + expected = "CREATE INDEX `index_people_on_last_name` USING btree ON `people` (`last_name`(10)) " + assert_equal expected, add_index(:people, :last_name, :length => 10, :using => :btree) + + expected = "CREATE INDEX `index_people_on_last_name` USING btree ON `people` (`last_name`(10)) ALGORITHM = COPY" + assert_equal expected, add_index(:people, :last_name, :length => 10, using: :btree, algorithm: :copy) + + assert_raise ArgumentError do + add_index(:people, :last_name, algorithm: :coyp) + end + + expected = "CREATE INDEX `index_people_on_last_name_and_first_name` USING btree ON `people` (`last_name`(15), `first_name`(15)) " + assert_equal expected, add_index(:people, [:last_name, :first_name], :length => 15, :using => :btree) end def test_drop_table @@ -70,8 +91,7 @@ class ActiveSchemaTest < ActiveRecord::TestCase def test_add_timestamps with_real_execute do begin - ActiveRecord::Base.connection.create_table :delete_me do |t| - end + ActiveRecord::Base.connection.create_table :delete_me ActiveRecord::Base.connection.add_timestamps :delete_me assert column_present?('delete_me', 'updated_at', 'datetime') assert column_present?('delete_me', 'created_at', 'datetime') @@ -98,22 +118,20 @@ class ActiveSchemaTest < ActiveRecord::TestCase private def with_real_execute - #we need to actually modify some data, so we make execute point to the original method - ActiveRecord::ConnectionAdapters::Mysql2Adapter.class_eval do + ActiveRecord::Base.connection.singleton_class.class_eval do alias_method :execute_with_stub, :execute remove_method :execute alias_method :execute, :execute_without_stub end + yield ensure - #before finishing, we restore the alias to the mock-up method - ActiveRecord::ConnectionAdapters::Mysql2Adapter.class_eval do + ActiveRecord::Base.connection.singleton_class.class_eval do remove_method :execute alias_method :execute, :execute_with_stub end end - def method_missing(method_symbol, *arguments) ActiveRecord::Base.connection.send(method_symbol, *arguments) end diff --git a/activerecord/test/cases/adapters/mysql2/connection_test.rb b/activerecord/test/cases/adapters/mysql2/connection_test.rb index fedd9f603c..679c515e8c 100644 --- a/activerecord/test/cases/adapters/mysql2/connection_test.rb +++ b/activerecord/test/cases/adapters/mysql2/connection_test.rb @@ -3,14 +3,14 @@ require "cases/helper" class MysqlConnectionTest < ActiveRecord::TestCase def setup super + @subscriber = SQLSubscriber.new + ActiveSupport::Notifications.subscribe('sql.active_record', @subscriber) @connection = ActiveRecord::Base.connection - @connection.extend(LogIntercepter) - @connection.intercepted = true end def teardown - @connection.intercepted = false - @connection.logged = [] + ActiveSupport::Notifications.unsubscribe(@subscriber) + super end def test_no_automatic_reconnection_after_timeout @@ -72,14 +72,14 @@ class MysqlConnectionTest < ActiveRecord::TestCase def test_logs_name_show_variable @connection.show_variable 'foo' - assert_equal "SCHEMA", @connection.logged[0][1] + assert_equal "SCHEMA", @subscriber.logged[0][1] end def test_logs_name_rename_column_sql @connection.execute "CREATE TABLE `bar_baz` (`foo` varchar(255))" - @connection.logged = [] + @subscriber.logged.clear @connection.send(:rename_column_sql, 'bar_baz', 'foo', 'foo2') - assert_equal "SCHEMA", @connection.logged[0][1] + assert_equal "SCHEMA", @subscriber.logged[0][1] ensure @connection.execute "DROP TABLE `bar_baz`" end diff --git a/activerecord/test/cases/adapters/mysql2/enum_test.rb b/activerecord/test/cases/adapters/mysql2/enum_test.rb index f3a05e48ad..6dd9a5ec87 100644 --- a/activerecord/test/cases/adapters/mysql2/enum_test.rb +++ b/activerecord/test/cases/adapters/mysql2/enum_test.rb @@ -5,6 +5,6 @@ class Mysql2EnumTest < ActiveRecord::TestCase end def test_enum_limit - assert_equal 5, EnumTest.columns.first.limit + assert_equal 6, EnumTest.columns.first.limit end end diff --git a/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb b/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb index 98596a7f62..1a82308176 100644 --- a/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb +++ b/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb @@ -2,7 +2,7 @@ require "cases/helper" class Group < ActiveRecord::Base Group.table_name = 'group' - belongs_to :select, :class_name => 'Select' + belongs_to :select has_one :values end @@ -84,7 +84,6 @@ class MysqlReservedWordTest < ActiveRecord::TestCase assert_nothing_raised { x.save } assert_nothing_raised { Group.find_by_order('y') } assert_nothing_raised { Group.find(1) } - x = Group.find(1) end # has_one association with reserved-word table name diff --git a/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb b/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb new file mode 100644 index 0000000000..9ecd901eac --- /dev/null +++ b/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb @@ -0,0 +1,26 @@ +require "cases/helper" + +module ActiveRecord + module ConnectionAdapters + class Mysql2Adapter + class SchemaMigrationsTest < ActiveRecord::TestCase + def test_initializes_schema_migrations_for_encoding_utf8mb4 + conn = ActiveRecord::Base.connection + + smtn = ActiveRecord::Migrator.schema_migrations_table_name + conn.drop_table(smtn) if conn.table_exists?(smtn) + + config = conn.instance_variable_get(:@config) + original_encoding = config[:encoding] + + config[:encoding] = 'utf8mb4' + conn.initialize_schema_migrations_table + + assert conn.column_exists?(smtn, :version, :string, limit: Mysql2Adapter::MAX_INDEX_LENGTH_FOR_UTF8MB4) + ensure + config[:encoding] = original_encoding + end + end + end + end +end diff --git a/activerecord/test/cases/adapters/mysql2/schema_test.rb b/activerecord/test/cases/adapters/mysql2/schema_test.rb index 94429e772f..5db60ff8a0 100644 --- a/activerecord/test/cases/adapters/mysql2/schema_test.rb +++ b/activerecord/test/cases/adapters/mysql2/schema_test.rb @@ -44,6 +44,27 @@ module ActiveRecord assert_match(/database 'foo-bar'/, e.inspect) end + def test_dump_indexes + index_a_name = 'index_key_tests_on_snack' + index_b_name = 'index_key_tests_on_pizza' + index_c_name = 'index_key_tests_on_awesome' + + table = 'key_tests' + + indexes = @connection.indexes(table).sort_by {|i| i.name} + assert_equal 3,indexes.size + + index_a = indexes.select{|i| i.name == index_a_name}[0] + index_b = indexes.select{|i| i.name == index_b_name}[0] + index_c = indexes.select{|i| i.name == index_c_name}[0] + assert_equal :btree, index_a.using + assert_nil index_a.type + assert_equal :btree, index_b.using + assert_nil index_b.type + + assert_nil index_c.using + assert_equal :fulltext, index_c.type + end end end end diff --git a/activerecord/test/cases/adapters/postgresql/active_schema_test.rb b/activerecord/test/cases/adapters/postgresql/active_schema_test.rb index 01c3e6b49b..22dd48e113 100644 --- a/activerecord/test/cases/adapters/postgresql/active_schema_test.rb +++ b/activerecord/test/cases/adapters/postgresql/active_schema_test.rb @@ -25,14 +25,30 @@ class PostgresqlActiveSchemaTest < ActiveRecord::TestCase def test_add_index # add_index calls index_name_exists? which can't work since execute is stubbed - ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.send(:define_method, :index_name_exists?) do |*| - false - end + ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.stubs(:index_name_exists?).returns(false) - expected = %(CREATE UNIQUE INDEX "index_people_on_last_name" ON "people" ("last_name") WHERE state = 'active') + expected = %(CREATE UNIQUE INDEX "index_people_on_last_name" ON "people" ("last_name") WHERE state = 'active') assert_equal expected, add_index(:people, :last_name, :unique => true, :where => "state = 'active'") - ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.send(:remove_method, :index_name_exists?) + expected = %(CREATE INDEX CONCURRENTLY "index_people_on_last_name" ON "people" ("last_name")) + assert_equal expected, add_index(:people, :last_name, algorithm: :concurrently) + + %w(gin gist hash btree).each do |type| + expected = %(CREATE INDEX "index_people_on_last_name" ON "people" USING #{type} ("last_name")) + assert_equal expected, add_index(:people, :last_name, using: type) + + expected = %(CREATE INDEX CONCURRENTLY "index_people_on_last_name" ON "people" USING #{type} ("last_name")) + assert_equal expected, add_index(:people, :last_name, using: type, algorithm: :concurrently) + end + + assert_raise ArgumentError do + add_index(:people, :last_name, algorithm: :copy) + end + expected = %(CREATE UNIQUE INDEX "index_people_on_last_name" ON "people" USING gist ("last_name")) + assert_equal expected, add_index(:people, :last_name, :unique => true, :using => :gist) + + expected = %(CREATE UNIQUE INDEX "index_people_on_last_name" ON "people" USING gist ("last_name") WHERE state = 'active') + assert_equal expected, add_index(:people, :last_name, :unique => true, :where => "state = 'active'", :using => :gist) end private diff --git a/activerecord/test/cases/adapters/postgresql/array_test.rb b/activerecord/test/cases/adapters/postgresql/array_test.rb index 8774bf626f..9536cceb1d 100644 --- a/activerecord/test/cases/adapters/postgresql/array_test.rb +++ b/activerecord/test/cases/adapters/postgresql/array_test.rb @@ -12,7 +12,8 @@ class PostgresqlArrayTest < ActiveRecord::TestCase @connection = ActiveRecord::Base.connection @connection.transaction do @connection.create_table('pg_arrays') do |t| - t.string 'tags', :array => true + t.string 'tags', array: true + t.integer 'ratings', array: true end end @column = PgArray.columns.find { |c| c.name == 'tags' } @@ -27,6 +28,27 @@ class PostgresqlArrayTest < ActiveRecord::TestCase assert @column.array end + def test_change_column_with_array + @connection.add_column :pg_arrays, :snippets, :string, array: true, default: [] + @connection.change_column :pg_arrays, :snippets, :text, array: true, default: "{}" + + PgArray.reset_column_information + column = PgArray.columns.find { |c| c.name == 'snippets' } + + assert_equal :text, column.type + assert_equal [], column.default + assert column.array + end + + def test_change_column_cant_make_non_array_column_to_array + @connection.add_column :pg_arrays, :a_string, :string + assert_raises ActiveRecord::StatementInvalid do + @connection.transaction do + @connection.change_column :pg_arrays, :a_string, :string, array: true + end + end + end + def test_type_cast_array assert @column @@ -57,42 +79,57 @@ class PostgresqlArrayTest < ActiveRecord::TestCase assert_equal(['1','2','3'], x.tags) end - def test_multi_dimensional - assert_cycle([['1','2'],['2','3']]) + def test_multi_dimensional_with_strings + assert_cycle(:tags, [[['1'], ['2']], [['2'], ['3']]]) + end + + def test_multi_dimensional_with_integers + assert_cycle(:ratings, [[[1], [7]], [[8], [10]]]) end def test_strings_with_quotes - assert_cycle(['this has','some "s that need to be escaped"']) + assert_cycle(:tags, ['this has','some "s that need to be escaped"']) end def test_strings_with_commas - assert_cycle(['this,has','many,values']) + assert_cycle(:tags, ['this,has','many,values']) end def test_strings_with_array_delimiters - assert_cycle(['{','}']) + assert_cycle(:tags, ['{','}']) end def test_strings_with_null_strings - assert_cycle(['NULL','NULL']) + assert_cycle(:tags, ['NULL','NULL']) end def test_contains_nils - assert_cycle(['1',nil,nil]) + assert_cycle(:tags, ['1',nil,nil]) + end + + def test_insert_fixture + tag_values = ["val1", "val2", "val3_with_'_multiple_quote_'_chars"] + @connection.insert_fixture({"tags" => tag_values}, "pg_arrays" ) + assert_equal(PgArray.last.tags, tag_values) + end + + def test_attribute_for_inspect_for_array_field + record = PgArray.new { |a| a.ratings = (1..11).to_a } + assert_equal("[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...]", record.attribute_for_inspect(:ratings)) end private - def assert_cycle array + def assert_cycle field, array # test creation - x = PgArray.create!(:tags => array) + x = PgArray.create!(field => array) x.reload - assert_equal(array, x.tags) + assert_equal(array, x.public_send(field)) # test updating - x = PgArray.create!(:tags => []) - x.tags = array + x = PgArray.create!(field => []) + x.public_send("#{field}=", array) x.save! x.reload - assert_equal(array, x.tags) + assert_equal(array, x.public_send(field)) end end diff --git a/activerecord/test/cases/adapters/postgresql/bytea_test.rb b/activerecord/test/cases/adapters/postgresql/bytea_test.rb new file mode 100644 index 0000000000..b8dd35c4c5 --- /dev/null +++ b/activerecord/test/cases/adapters/postgresql/bytea_test.rb @@ -0,0 +1,104 @@ +# encoding: utf-8 + +require "cases/helper" +require 'active_record/base' +require 'active_record/connection_adapters/postgresql_adapter' + +class PostgresqlByteaTest < ActiveRecord::TestCase + class ByteaDataType < ActiveRecord::Base + self.table_name = 'bytea_data_type' + end + + def setup + @connection = ActiveRecord::Base.connection + begin + @connection.transaction do + @connection.create_table('bytea_data_type') do |t| + t.binary 'payload' + t.binary 'serialized' + end + end + end + @column = ByteaDataType.columns.find { |c| c.name == 'payload' } + assert(@column.is_a?(ActiveRecord::ConnectionAdapters::PostgreSQLColumn)) + end + + def teardown + @connection.execute 'drop table if exists bytea_data_type' + end + + def test_column + assert_equal :binary, @column.type + end + + def test_type_cast_binary_converts_the_encoding + assert @column + + data = "\u001F\x8B" + assert_equal('UTF-8', data.encoding.name) + assert_equal('ASCII-8BIT', @column.type_cast(data).encoding.name) + end + + def test_type_cast_binary_value + data = "\u001F\x8B".force_encoding("BINARY") + assert_equal(data, @column.type_cast(data)) + end + + def test_type_case_nil + assert_equal(nil, @column.type_cast(nil)) + end + + def test_read_value + data = "\u001F" + @connection.execute "insert into bytea_data_type (payload) VALUES ('#{data}')" + record = ByteaDataType.first + assert_equal(data, record.payload) + record.delete + end + + def test_read_nil_value + @connection.execute "insert into bytea_data_type (payload) VALUES (null)" + record = ByteaDataType.first + assert_equal(nil, record.payload) + record.delete + end + + def test_write_value + data = "\u001F" + record = ByteaDataType.create(payload: data) + assert_not record.new_record? + assert_equal(data, record.payload) + end + + def test_write_binary + data = File.read(File.join(File.dirname(__FILE__), '..', '..', '..', 'assets', 'example.log')) + assert(data.size > 1) + record = ByteaDataType.create(payload: data) + assert_not record.new_record? + assert_equal(data, record.payload) + assert_equal(data, ByteaDataType.where(id: record.id).first.payload) + end + + def test_write_nil + record = ByteaDataType.create(payload: nil) + assert_not record.new_record? + assert_equal(nil, record.payload) + assert_equal(nil, ByteaDataType.where(id: record.id).first.payload) + end + + class Serializer + def load(str); str; end + def dump(str); str; end + end + + def test_serialize + klass = Class.new(ByteaDataType) { + serialize :serialized, Serializer.new + } + obj = klass.new + obj.serialized = "hello world" + obj.save! + obj.reload + assert_equal "hello world", obj.serialized + end +end diff --git a/activerecord/test/cases/adapters/postgresql/connection_test.rb b/activerecord/test/cases/adapters/postgresql/connection_test.rb index c03660957e..81aa977c59 100644 --- a/activerecord/test/cases/adapters/postgresql/connection_test.rb +++ b/activerecord/test/cases/adapters/postgresql/connection_test.rb @@ -7,14 +7,14 @@ module ActiveRecord def setup super + @subscriber = SQLSubscriber.new + ActiveSupport::Notifications.subscribe('sql.active_record', @subscriber) @connection = ActiveRecord::Base.connection - @connection.extend(LogIntercepter) - @connection.intercepted = true end def teardown - @connection.intercepted = false - @connection.logged = [] + ActiveSupport::Notifications.unsubscribe(@subscriber) + super end def test_encoding @@ -47,74 +47,48 @@ module ActiveRecord def test_tables_logs_name @connection.tables('hello') - assert_equal 'SCHEMA', @connection.logged[0][1] + assert_equal 'SCHEMA', @subscriber.logged[0][1] end def test_indexes_logs_name @connection.indexes('items', 'hello') - assert_equal 'SCHEMA', @connection.logged[0][1] + assert_equal 'SCHEMA', @subscriber.logged[0][1] end def test_table_exists_logs_name @connection.table_exists?('items') - assert_equal 'SCHEMA', @connection.logged[0][1] + assert_equal 'SCHEMA', @subscriber.logged[0][1] end def test_table_alias_length_logs_name @connection.instance_variable_set("@table_alias_length", nil) @connection.table_alias_length - assert_equal 'SCHEMA', @connection.logged[0][1] + assert_equal 'SCHEMA', @subscriber.logged[0][1] end def test_current_database_logs_name @connection.current_database - assert_equal 'SCHEMA', @connection.logged[0][1] + assert_equal 'SCHEMA', @subscriber.logged[0][1] end def test_encoding_logs_name @connection.encoding - assert_equal 'SCHEMA', @connection.logged[0][1] + assert_equal 'SCHEMA', @subscriber.logged[0][1] end def test_schema_names_logs_name @connection.schema_names - assert_equal 'SCHEMA', @connection.logged[0][1] + assert_equal 'SCHEMA', @subscriber.logged[0][1] end - def test_reconnection_after_simulated_disconnection_with_verify - assert @connection.active? - original_connection_pid = @connection.query('select pg_backend_pid()') - - # Fail with bad connection on next query attempt. - raw_connection = @connection.raw_connection - raw_connection_class = class << raw_connection ; self ; end - raw_connection_class.class_eval <<-CODE, __FILE__, __LINE__ + 1 - def query_fake(*args) - if !( @called ||= false ) - self.stubs(:status).returns(PGconn::CONNECTION_BAD) - @called = true - raise PGError - else - self.unstub(:status) - query_unfake(*args) - end - end - - alias query_unfake query - alias query query_fake - CODE - - begin - @connection.verify! - new_connection_pid = @connection.query('select pg_backend_pid()') - ensure - raw_connection_class.class_eval <<-CODE, __FILE__, __LINE__ + 1 - alias query query_unfake - undef query_fake - CODE - end - - assert_not_equal original_connection_pid, new_connection_pid, "Should have a new underlying connection pid" + def test_statement_key_is_logged + bindval = 1 + @connection.exec_query('SELECT $1::integer', 'SQL', [[nil, bindval]]) + name = @subscriber.payloads.last[:statement_name] + assert name + res = @connection.exec_query("EXPLAIN (FORMAT JSON) EXECUTE #{name}(#{bindval})") + plan = res.column_types['QUERY PLAN'].type_cast res.rows.first.first + assert_operator plan.length, :>, 0 end # Must have with_manual_interventions set to true for this diff --git a/activerecord/test/cases/adapters/postgresql/datatype_test.rb b/activerecord/test/cases/adapters/postgresql/datatype_test.rb index 1e6ae85a25..c5ff8cb609 100644 --- a/activerecord/test/cases/adapters/postgresql/datatype_test.rb +++ b/activerecord/test/cases/adapters/postgresql/datatype_test.rb @@ -246,7 +246,7 @@ _SQL assert_equal 2...10, @second_range.int4_range assert_equal 2...Float::INFINITY, @third_range.int4_range assert_equal(-Float::INFINITY...Float::INFINITY, @fourth_range.int4_range) - assert_equal nil, @empty_range.int4_range + assert_nil @empty_range.int4_range end def test_int8range_values @@ -255,7 +255,7 @@ _SQL assert_equal 11...100, @second_range.int8_range assert_equal 11...Float::INFINITY, @third_range.int8_range assert_equal(-Float::INFINITY...Float::INFINITY, @fourth_range.int8_range) - assert_equal nil, @empty_range.int8_range + assert_nil @empty_range.int8_range end def test_daterange_values @@ -264,7 +264,7 @@ _SQL assert_equal Date.new(2012, 1, 3)...Date.new(2012, 1, 4), @second_range.date_range assert_equal Date.new(2012, 1, 3)...Float::INFINITY, @third_range.date_range assert_equal(-Float::INFINITY...Float::INFINITY, @fourth_range.date_range) - assert_equal nil, @empty_range.date_range + assert_nil @empty_range.date_range end def test_numrange_values @@ -273,7 +273,7 @@ _SQL assert_equal BigDecimal.new('0.1')...BigDecimal.new('0.2'), @second_range.num_range assert_equal BigDecimal.new('0.1')...BigDecimal.new('Infinity'), @third_range.num_range assert_equal BigDecimal.new('-Infinity')...BigDecimal.new('Infinity'), @fourth_range.num_range - assert_equal nil, @empty_range.num_range + assert_nil @empty_range.num_range end def test_tsrange_values @@ -281,18 +281,16 @@ _SQL tz = ::ActiveRecord::Base.default_timezone assert_equal Time.send(tz, 2010, 1, 1, 14, 30, 0)..Time.send(tz, 2011, 1, 1, 14, 30, 0), @first_range.ts_range assert_equal Time.send(tz, 2010, 1, 1, 14, 30, 0)...Time.send(tz, 2011, 1, 1, 14, 30, 0), @second_range.ts_range - assert_equal Time.send(tz, 2010, 1, 1, 14, 30, 0)...Float::INFINITY, @third_range.ts_range assert_equal(-Float::INFINITY...Float::INFINITY, @fourth_range.ts_range) - assert_equal nil, @empty_range.ts_range + assert_nil @empty_range.ts_range end def test_tstzrange_values skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges? assert_equal Time.parse('2010-01-01 09:30:00 UTC')..Time.parse('2011-01-01 17:30:00 UTC'), @first_range.tstz_range assert_equal Time.parse('2010-01-01 09:30:00 UTC')...Time.parse('2011-01-01 17:30:00 UTC'), @second_range.tstz_range - assert_equal Time.parse('2010-01-01 09:30:00 UTC')...Float::INFINITY, @third_range.tstz_range assert_equal(-Float::INFINITY...Float::INFINITY, @fourth_range.tstz_range) - assert_equal nil, @empty_range.tstz_range + assert_nil @empty_range.tstz_range end def test_money_values @@ -300,6 +298,14 @@ _SQL assert_equal(-567.89, @second_money.wealth) end + def test_money_type_cast + column = PostgresqlMoney.columns.find { |c| c.name == 'wealth' } + assert_equal(12345678.12, column.type_cast("$12,345,678.12")) + assert_equal(12345678.12, column.type_cast("$12.345.678,12")) + assert_equal(-1.15, column.type_cast("-$1.15")) + assert_equal(-2.25, column.type_cast("($2.25)")) + end + def test_create_tstzrange skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges? tstzrange = Time.parse('2010-01-01 14:30:00 +0100')...Time.parse('2011-02-02 14:30:00 CDT') @@ -313,14 +319,14 @@ _SQL def test_update_tstzrange skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges? new_tstzrange = Time.parse('2010-01-01 14:30:00 CDT')...Time.parse('2011-02-02 14:30:00 CET') - assert @first_range.tstz_range = new_tstzrange + @first_range.tstz_range = new_tstzrange assert @first_range.save assert @first_range.reload - assert_equal @first_range.tstz_range, new_tstzrange - assert @first_range.tstz_range = Time.parse('2010-01-01 14:30:00 +0100')...Time.parse('2010-01-01 13:30:00 +0000') + assert_equal new_tstzrange, @first_range.tstz_range + @first_range.tstz_range = Time.parse('2010-01-01 14:30:00 +0100')...Time.parse('2010-01-01 13:30:00 +0000') assert @first_range.save assert @first_range.reload - assert_equal @first_range.tstz_range, nil + assert_nil @first_range.tstz_range end def test_create_tsrange @@ -337,14 +343,14 @@ _SQL skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges? tz = ::ActiveRecord::Base.default_timezone new_tsrange = Time.send(tz, 2010, 1, 1, 14, 30, 0)...Time.send(tz, 2011, 2, 2, 14, 30, 0) - assert @first_range.ts_range = new_tsrange + @first_range.ts_range = new_tsrange assert @first_range.save assert @first_range.reload - assert_equal @first_range.ts_range, new_tsrange - assert @first_range.ts_range = Time.send(tz, 2010, 1, 1, 14, 30, 0)...Time.send(tz, 2010, 1, 1, 14, 30, 0) + assert_equal new_tsrange, @first_range.ts_range + @first_range.ts_range = Time.send(tz, 2010, 1, 1, 14, 30, 0)...Time.send(tz, 2010, 1, 1, 14, 30, 0) assert @first_range.save assert @first_range.reload - assert_equal @first_range.ts_range, nil + assert_nil @first_range.ts_range end def test_create_numrange @@ -359,14 +365,14 @@ _SQL def test_update_numrange skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges? new_numrange = BigDecimal.new('0.5')...BigDecimal.new('1') - assert @first_range.num_range = new_numrange + @first_range.num_range = new_numrange assert @first_range.save assert @first_range.reload - assert_equal @first_range.num_range, new_numrange - assert @first_range.num_range = BigDecimal.new('0.5')...BigDecimal.new('0.5') + assert_equal new_numrange, @first_range.num_range + @first_range.num_range = BigDecimal.new('0.5')...BigDecimal.new('0.5') assert @first_range.save assert @first_range.reload - assert_equal @first_range.num_range, nil + assert_nil @first_range.num_range end def test_create_daterange @@ -381,14 +387,14 @@ _SQL def test_update_daterange skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges? new_daterange = Date.new(2012, 2, 3)...Date.new(2012, 2, 10) - assert @first_range.date_range = new_daterange + @first_range.date_range = new_daterange assert @first_range.save assert @first_range.reload - assert_equal @first_range.date_range, new_daterange - assert @first_range.date_range = Date.new(2012, 2, 3)...Date.new(2012, 2, 3) + assert_equal new_daterange, @first_range.date_range + @first_range.date_range = Date.new(2012, 2, 3)...Date.new(2012, 2, 3) assert @first_range.save assert @first_range.reload - assert_equal @first_range.date_range, nil + assert_nil @first_range.date_range end def test_create_int4range @@ -403,14 +409,14 @@ _SQL def test_update_int4range skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges? new_int4range = 6...10 - assert @first_range.int4_range = new_int4range + @first_range.int4_range = new_int4range assert @first_range.save assert @first_range.reload - assert_equal @first_range.int4_range, new_int4range - assert @first_range.int4_range = 3...3 + assert_equal new_int4range, @first_range.int4_range + @first_range.int4_range = 3...3 assert @first_range.save assert @first_range.reload - assert_equal @first_range.int4_range, nil + assert_nil @first_range.int4_range end def test_create_int8range @@ -425,25 +431,25 @@ _SQL def test_update_int8range skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges? new_int8range = 60000...10000000 - assert @first_range.int8_range = new_int8range + @first_range.int8_range = new_int8range assert @first_range.save assert @first_range.reload - assert_equal @first_range.int8_range, new_int8range - assert @first_range.int8_range = 39999...39999 + assert_equal new_int8range, @first_range.int8_range + @first_range.int8_range = 39999...39999 assert @first_range.save assert @first_range.reload - assert_equal @first_range.int8_range, nil + assert_nil @first_range.int8_range end def test_update_tsvector new_text_vector = "'new' 'text' 'vector'" - assert @first_tsvector.text_vector = new_text_vector + @first_tsvector.text_vector = new_text_vector assert @first_tsvector.save assert @first_tsvector.reload - assert @first_tsvector.text_vector = new_text_vector + @first_tsvector.text_vector = new_text_vector assert @first_tsvector.save assert @first_tsvector.reload - assert_equal @first_tsvector.text_vector, new_text_vector + assert_equal new_text_vector, @first_tsvector.text_vector end def test_number_values @@ -481,31 +487,31 @@ _SQL def test_update_integer_array new_value = [32800,95000,29350,17000] - assert @first_array.commission_by_quarter = new_value + @first_array.commission_by_quarter = new_value assert @first_array.save assert @first_array.reload - assert_equal @first_array.commission_by_quarter, new_value - assert @first_array.commission_by_quarter = new_value + assert_equal new_value, @first_array.commission_by_quarter + @first_array.commission_by_quarter = new_value assert @first_array.save assert @first_array.reload - assert_equal @first_array.commission_by_quarter, new_value + assert_equal new_value, @first_array.commission_by_quarter end def test_update_text_array new_value = ['robby','robert','rob','robbie'] - assert @first_array.nicknames = new_value + @first_array.nicknames = new_value assert @first_array.save assert @first_array.reload - assert_equal @first_array.nicknames, new_value - assert @first_array.nicknames = new_value + assert_equal new_value, @first_array.nicknames + @first_array.nicknames = new_value assert @first_array.save assert @first_array.reload - assert_equal @first_array.nicknames, new_value + assert_equal new_value, @first_array.nicknames end def test_update_money new_value = BigDecimal.new('123.45') - assert @first_money.wealth = new_value + @first_money.wealth = new_value assert @first_money.save assert @first_money.reload assert_equal new_value, @first_money.wealth @@ -514,28 +520,28 @@ _SQL def test_update_number new_single = 789.012 new_double = 789012.345 - assert @first_number.single = new_single - assert @first_number.double = new_double + @first_number.single = new_single + @first_number.double = new_double assert @first_number.save assert @first_number.reload - assert_equal @first_number.single, new_single - assert_equal @first_number.double, new_double + assert_equal new_single, @first_number.single + assert_equal new_double, @first_number.double end def test_update_time - assert @first_time.time_interval = '2 years 3 minutes' + @first_time.time_interval = '2 years 3 minutes' assert @first_time.save assert @first_time.reload - assert_equal @first_time.time_interval, '2 years 00:03:00' + assert_equal '2 years 00:03:00', @first_time.time_interval end def test_update_network_address new_inet_address = '10.1.2.3/32' new_cidr_address = '10.0.0.0/8' new_mac_address = 'bc:de:f0:12:34:56' - assert @first_network_address.cidr_address = new_cidr_address - assert @first_network_address.inet_address = new_inet_address - assert @first_network_address.mac_address = new_mac_address + @first_network_address.cidr_address = new_cidr_address + @first_network_address.inet_address = new_inet_address + @first_network_address.mac_address = new_mac_address assert @first_network_address.save assert @first_network_address.reload assert_equal @first_network_address.cidr_address, new_cidr_address @@ -545,56 +551,66 @@ _SQL def test_update_bit_string new_bit_string = '11111111' - new_bit_string_varying = '11111110' - assert @first_bit_string.bit_string = new_bit_string - assert @first_bit_string.bit_string_varying = new_bit_string_varying + new_bit_string_varying = '0xFF' + @first_bit_string.bit_string = new_bit_string + @first_bit_string.bit_string_varying = new_bit_string_varying assert @first_bit_string.save assert @first_bit_string.reload assert_equal new_bit_string, @first_bit_string.bit_string - assert_equal new_bit_string_varying, @first_bit_string.bit_string_varying + assert_equal @first_bit_string.bit_string, @first_bit_string.bit_string_varying + end + + def test_invalid_hex_string + new_bit_string = 'FF' + @first_bit_string.bit_string = new_bit_string + assert_raise(ActiveRecord::StatementInvalid) { assert @first_bit_string.save } + end + + def test_invalid_network_address + @first_network_address.cidr_address = 'invalid addr' + assert_nil @first_network_address.cidr_address + assert_equal 'invalid addr', @first_network_address.cidr_address_before_type_cast + assert @first_network_address.save + + @first_network_address.reload + + @first_network_address.inet_address = 'invalid addr' + assert_nil @first_network_address.inet_address + assert_equal 'invalid addr', @first_network_address.inet_address_before_type_cast + assert @first_network_address.save end def test_update_oid new_value = 567890 - assert @first_oid.obj_id = new_value + @first_oid.obj_id = new_value assert @first_oid.save assert @first_oid.reload - assert_equal @first_oid.obj_id, new_value + assert_equal new_value, @first_oid.obj_id end def test_timestamp_with_zone_values_with_rails_time_zone_support - old_tz = ActiveRecord::Base.time_zone_aware_attributes - old_default_tz = ActiveRecord::Base.default_timezone + with_timezone_config default: :utc, aware_attributes: true do + @connection.reconnect! - ActiveRecord::Base.time_zone_aware_attributes = true - ActiveRecord::Base.default_timezone = :utc - - @connection.reconnect! - - @first_timestamp_with_zone = PostgresqlTimestampWithZone.find(1) - assert_equal Time.utc(2010,1,1, 11,0,0), @first_timestamp_with_zone.time - assert_instance_of Time, @first_timestamp_with_zone.time + @first_timestamp_with_zone = PostgresqlTimestampWithZone.find(1) + assert_equal Time.utc(2010,1,1, 11,0,0), @first_timestamp_with_zone.time + assert_instance_of Time, @first_timestamp_with_zone.time + end ensure - ActiveRecord::Base.default_timezone = old_default_tz - ActiveRecord::Base.time_zone_aware_attributes = old_tz @connection.reconnect! end def test_timestamp_with_zone_values_without_rails_time_zone_support - old_tz = ActiveRecord::Base.time_zone_aware_attributes - old_default_tz = ActiveRecord::Base.default_timezone - - ActiveRecord::Base.time_zone_aware_attributes = false - ActiveRecord::Base.default_timezone = :local - - @connection.reconnect! - - @first_timestamp_with_zone = PostgresqlTimestampWithZone.find(1) - assert_equal Time.utc(2010,1,1, 11,0,0), @first_timestamp_with_zone.time - assert_instance_of Time, @first_timestamp_with_zone.time + with_timezone_config default: :local, aware_attributes: false do + @connection.reconnect! + # make sure to use a non-UTC time zone + @connection.execute("SET time zone 'America/Jamaica'", 'SCHEMA') + + @first_timestamp_with_zone = PostgresqlTimestampWithZone.find(1) + assert_equal Time.utc(2010,1,1, 11,0,0), @first_timestamp_with_zone.time + assert_instance_of Time, @first_timestamp_with_zone.time + end ensure - ActiveRecord::Base.default_timezone = old_default_tz - ActiveRecord::Base.time_zone_aware_attributes = old_tz @connection.reconnect! end end diff --git a/activerecord/test/cases/adapters/postgresql/explain_test.rb b/activerecord/test/cases/adapters/postgresql/explain_test.rb index 619d581d5f..0b61f61572 100644 --- a/activerecord/test/cases/adapters/postgresql/explain_test.rb +++ b/activerecord/test/cases/adapters/postgresql/explain_test.rb @@ -22,13 +22,6 @@ module ActiveRecord assert_match %(EXPLAIN for: SELECT "audit_logs".* FROM "audit_logs" WHERE "audit_logs"."developer_id" IN (1)), explain assert_match %(Seq Scan on audit_logs), explain end - - def test_dont_explain_for_set_search_path - queries = Thread.current[:available_queries_for_explain] = [] - ActiveRecord::Base.connection.schema_search_path = "public" - assert queries.empty? - end - end end end diff --git a/activerecord/test/cases/adapters/postgresql/hstore_test.rb b/activerecord/test/cases/adapters/postgresql/hstore_test.rb index ad98d7c8ce..de724486c2 100644 --- a/activerecord/test/cases/adapters/postgresql/hstore_test.rb +++ b/activerecord/test/cases/adapters/postgresql/hstore_test.rb @@ -7,6 +7,8 @@ require 'active_record/connection_adapters/postgresql_adapter' class PostgresqlHstoreTest < ActiveRecord::TestCase class Hstore < ActiveRecord::Base self.table_name = 'hstores' + + store_accessor :settings, :language, :timezone end def setup @@ -26,6 +28,7 @@ class PostgresqlHstoreTest < ActiveRecord::TestCase @connection.transaction do @connection.create_table('hstores') do |t| t.hstore 'tags', :default => '' + t.hstore 'settings' end end @column = Hstore.columns.find { |c| c.name == 'tags' } @@ -40,25 +43,15 @@ class PostgresqlHstoreTest < ActiveRecord::TestCase assert @connection.extensions.include?('hstore'), "extension list should include hstore" end - def test_hstore_enabled + def test_disable_enable_hstore assert @connection.extension_enabled?('hstore') - end - - def test_disable_hstore - if @connection.extension_enabled?('hstore') - @connection.disable_extension 'hstore' - assert_not @connection.extension_enabled?('hstore') - end - end - - def test_enable_hstore - if @connection.extension_enabled?('hstore') - @connection.disable_extension 'hstore' - end - + @connection.disable_extension 'hstore' assert_not @connection.extension_enabled?('hstore') @connection.enable_extension 'hstore' assert @connection.extension_enabled?('hstore') + ensure + # Restore column(s) dropped by `drop extension hstore cascade;` + load_schema end def test_column @@ -80,6 +73,13 @@ class PostgresqlHstoreTest < ActiveRecord::TestCase Hstore.reset_column_information end + def test_cast_value_on_write + x = Hstore.new tags: {"bool" => true, "number" => 5} + assert_equal({"bool" => "true", "number" => "5"}, x.tags) + x.save + assert_equal({"bool" => "true", "number" => "5"}, x.reload.tags) + end + def test_type_cast_hstore assert @column @@ -93,6 +93,24 @@ class PostgresqlHstoreTest < ActiveRecord::TestCase assert_equal({'c'=>'}','"a"'=>'b "a b'}, @column.type_cast(%q(c=>"}", "\"a\""=>"b \"a b"))) end + def test_with_store_accessors + x = Hstore.new(language: "fr", timezone: "GMT") + assert_equal "fr", x.language + assert_equal "GMT", x.timezone + + x.save! + x = Hstore.first + assert_equal "fr", x.language + assert_equal "GMT", x.timezone + + x.language = "de" + x.save! + + x = Hstore.first + assert_equal "de", x.language + assert_equal "GMT", x.timezone + end + def test_gen1 assert_equal(%q(" "=>""), @column.class.hstore_to_string({' '=>''})) end @@ -189,6 +207,10 @@ class PostgresqlHstoreTest < ActiveRecord::TestCase assert_cycle('ca' => 'cà', 'ac' => 'àc') end + def test_multiline + assert_cycle("a\nb" => "c\nd") + end + private def assert_cycle hash # test creation diff --git a/activerecord/test/cases/adapters/postgresql/json_test.rb b/activerecord/test/cases/adapters/postgresql/json_test.rb index 6fc08ae4f0..c33c7ef968 100644 --- a/activerecord/test/cases/adapters/postgresql/json_test.rb +++ b/activerecord/test/cases/adapters/postgresql/json_test.rb @@ -7,6 +7,8 @@ require 'active_record/connection_adapters/postgresql_adapter' class PostgresqlJSONTest < ActiveRecord::TestCase class JsonDataType < ActiveRecord::Base self.table_name = 'json_data_type' + + store_accessor :settings, :resolution end def setup @@ -15,6 +17,7 @@ class PostgresqlJSONTest < ActiveRecord::TestCase @connection.transaction do @connection.create_table('json_data_type') do |t| t.json 'payload', :default => {} + t.json 'settings' end end rescue ActiveRecord::StatementInvalid @@ -46,6 +49,13 @@ class PostgresqlJSONTest < ActiveRecord::TestCase JsonDataType.reset_column_information end + def test_cast_value_on_write + x = JsonDataType.new payload: {"string" => "foo", :symbol => :bar} + assert_equal({"string" => "foo", "symbol" => "bar"}, x.payload) + x.save + assert_equal({"string" => "foo", "symbol" => "bar"}, x.reload.payload) + end + def test_type_cast_json assert @column @@ -83,4 +93,32 @@ class PostgresqlJSONTest < ActiveRecord::TestCase x = JsonDataType.first assert_equal(nil, x.payload) end + + def test_select_array_json_value + @connection.execute %q|insert into json_data_type (payload) VALUES ('["v0",{"k1":"v1"}]')| + x = JsonDataType.first + assert_equal(['v0', {'k1' => 'v1'}], x.payload) + end + + def test_rewrite_array_json_value + @connection.execute %q|insert into json_data_type (payload) VALUES ('["v0",{"k1":"v1"}]')| + x = JsonDataType.first + x.payload = ['v1', {'k2' => 'v2'}, 'v3'] + assert x.save! + end + + def test_with_store_accessors + x = JsonDataType.new(resolution: "320×480") + assert_equal "320×480", x.resolution + + x.save! + x = JsonDataType.first + assert_equal "320×480", x.resolution + + x.resolution = "640×1136" + x.save! + + x = JsonDataType.first + assert_equal "640×1136", x.resolution + end end diff --git a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb index 05e0f0e192..8b017760b1 100644 --- a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb +++ b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb @@ -10,6 +10,15 @@ module ActiveRecord @connection.exec_query('create table ex(id serial primary key, number integer, data character varying(255))') end + def test_valid_column + column = @connection.columns('ex').find { |col| col.name == 'id' } + assert @connection.valid_type?(column.type) + end + + def test_invalid_column + assert_not @connection.valid_type?(:foobar) + end + def test_primary_key assert_equal 'id', @connection.primary_key('ex') end @@ -216,38 +225,38 @@ module ActiveRecord assert_equal "(number > 100)", index.where end - def test_distinct_zero_orders - assert_equal "DISTINCT posts.id", - @connection.distinct("posts.id", []) + def test_columns_for_distinct_zero_orders + assert_equal "posts.id", + @connection.columns_for_distinct("posts.id", []) end - def test_distinct_one_order - assert_equal "DISTINCT posts.id, posts.created_at AS alias_0", - @connection.distinct("posts.id", ["posts.created_at desc"]) + def test_columns_for_distinct_one_order + assert_equal "posts.id, posts.created_at AS alias_0", + @connection.columns_for_distinct("posts.id", ["posts.created_at desc"]) end - def test_distinct_few_orders - assert_equal "DISTINCT posts.id, posts.created_at AS alias_0, posts.position AS alias_1", - @connection.distinct("posts.id", ["posts.created_at desc", "posts.position asc"]) + def test_columns_for_distinct_few_orders + assert_equal "posts.id, posts.created_at AS alias_0, posts.position AS alias_1", + @connection.columns_for_distinct("posts.id", ["posts.created_at desc", "posts.position asc"]) end - def test_distinct_blank_not_nil_orders - assert_equal "DISTINCT posts.id, posts.created_at AS alias_0", - @connection.distinct("posts.id", ["posts.created_at desc", "", " "]) + def test_columns_for_distinct_blank_not_nil_orders + assert_equal "posts.id, posts.created_at AS alias_0", + @connection.columns_for_distinct("posts.id", ["posts.created_at desc", "", " "]) end - def test_distinct_with_arel_order + def test_columns_for_distinct_with_arel_order order = Object.new def order.to_sql "posts.created_at desc" end - assert_equal "DISTINCT posts.id, posts.created_at AS alias_0", - @connection.distinct("posts.id", [order]) + assert_equal "posts.id, posts.created_at AS alias_0", + @connection.columns_for_distinct("posts.id", [order]) end - def test_distinct_with_nulls - assert_equal "DISTINCT posts.title, posts.updater_id AS alias_0", @connection.distinct("posts.title", ["posts.updater_id desc nulls first"]) - assert_equal "DISTINCT posts.title, posts.updater_id AS alias_0", @connection.distinct("posts.title", ["posts.updater_id desc nulls last"]) + def test_columns_for_distinct_with_nulls + assert_equal "posts.title, posts.updater_id AS alias_0", @connection.columns_for_distinct("posts.title", ["posts.updater_id desc nulls first"]) + assert_equal "posts.title, posts.updater_id AS alias_0", @connection.columns_for_distinct("posts.title", ["posts.updater_id desc nulls last"]) end def test_raise_error_when_cannot_translate_exception diff --git a/activerecord/test/cases/adapters/postgresql/quoting_test.rb b/activerecord/test/cases/adapters/postgresql/quoting_test.rb index 685f0ea74f..1122f8b9a1 100644 --- a/activerecord/test/cases/adapters/postgresql/quoting_test.rb +++ b/activerecord/test/cases/adapters/postgresql/quoting_test.rb @@ -44,6 +44,19 @@ module ActiveRecord c = Column.new(nil, 1, 'float') assert_equal "'Infinity'", @conn.quote(infinity, c) end + + def test_quote_cast_numeric + fixnum = 666 + c = Column.new(nil, nil, 'varchar') + assert_equal "'666'", @conn.quote(fixnum, c) + c = Column.new(nil, nil, 'text') + assert_equal "'666'", @conn.quote(fixnum, c) + end + + def test_quote_time_usec + assert_equal "'1970-01-01 00:00:00.000000'", @conn.quote(Time.at(0)) + assert_equal "'1970-01-01 00:00:00.000000'", @conn.quote(Time.at(0).to_datetime) + end end end end diff --git a/activerecord/test/cases/adapters/postgresql/schema_test.rb b/activerecord/test/cases/adapters/postgresql/schema_test.rb index cd31900d4e..e8dd188ec8 100644 --- a/activerecord/test/cases/adapters/postgresql/schema_test.rb +++ b/activerecord/test/cases/adapters/postgresql/schema_test.rb @@ -11,16 +11,19 @@ class SchemaTest < ActiveRecord::TestCase INDEX_B_NAME = 'b_index_things_on_different_columns_in_each_schema' INDEX_C_NAME = 'c_index_full_text_search' INDEX_D_NAME = 'd_index_things_on_description_desc' + INDEX_E_NAME = 'e_index_things_on_name_vector' INDEX_A_COLUMN = 'name' INDEX_B_COLUMN_S1 = 'email' INDEX_B_COLUMN_S2 = 'moment' INDEX_C_COLUMN = %q{(to_tsvector('english', coalesce(things.name, '')))} INDEX_D_COLUMN = 'description' + INDEX_E_COLUMN = 'name_vector' COLUMNS = [ 'id integer', 'name character varying(50)', 'email character varying(50)', 'description character varying(100)', + 'name_vector tsvector', 'moment timestamp without time zone default now()' ] PK_TABLE_NAME = 'table_with_pk' @@ -61,6 +64,8 @@ class SchemaTest < ActiveRecord::TestCase @connection.execute "CREATE INDEX #{INDEX_C_NAME} ON #{SCHEMA2_NAME}.#{TABLE_NAME} USING gin (#{INDEX_C_COLUMN});" @connection.execute "CREATE INDEX #{INDEX_D_NAME} ON #{SCHEMA_NAME}.#{TABLE_NAME} USING btree (#{INDEX_D_COLUMN} DESC);" @connection.execute "CREATE INDEX #{INDEX_D_NAME} ON #{SCHEMA2_NAME}.#{TABLE_NAME} USING btree (#{INDEX_D_COLUMN} DESC);" + @connection.execute "CREATE INDEX #{INDEX_E_NAME} ON #{SCHEMA_NAME}.#{TABLE_NAME} USING gin (#{INDEX_E_COLUMN});" + @connection.execute "CREATE INDEX #{INDEX_E_NAME} ON #{SCHEMA2_NAME}.#{TABLE_NAME} USING gin (#{INDEX_E_COLUMN});" @connection.execute "CREATE TABLE #{SCHEMA_NAME}.#{PK_TABLE_NAME} (id serial primary key)" @connection.execute "CREATE SEQUENCE #{SCHEMA_NAME}.#{UNMATCHED_SEQUENCE_NAME}" @connection.execute "CREATE TABLE #{SCHEMA_NAME}.#{UNMATCHED_PK_TABLE_NAME} (id integer NOT NULL DEFAULT nextval('#{SCHEMA_NAME}.#{UNMATCHED_SEQUENCE_NAME}'::regclass), CONSTRAINT unmatched_pkey PRIMARY KEY (id))" @@ -236,15 +241,15 @@ class SchemaTest < ActiveRecord::TestCase end def test_dump_indexes_for_schema_one - do_dump_index_tests_for_schema(SCHEMA_NAME, INDEX_A_COLUMN, INDEX_B_COLUMN_S1, INDEX_D_COLUMN) + do_dump_index_tests_for_schema(SCHEMA_NAME, INDEX_A_COLUMN, INDEX_B_COLUMN_S1, INDEX_D_COLUMN, INDEX_E_COLUMN) end def test_dump_indexes_for_schema_two - do_dump_index_tests_for_schema(SCHEMA2_NAME, INDEX_A_COLUMN, INDEX_B_COLUMN_S2, INDEX_D_COLUMN) + do_dump_index_tests_for_schema(SCHEMA2_NAME, INDEX_A_COLUMN, INDEX_B_COLUMN_S2, INDEX_D_COLUMN, INDEX_E_COLUMN) end def test_dump_indexes_for_schema_multiple_schemas_in_search_path - do_dump_index_tests_for_schema("public, #{SCHEMA_NAME}", INDEX_A_COLUMN, INDEX_B_COLUMN_S1, INDEX_D_COLUMN) + do_dump_index_tests_for_schema("public, #{SCHEMA_NAME}", INDEX_A_COLUMN, INDEX_B_COLUMN_S1, INDEX_D_COLUMN, INDEX_E_COLUMN) end def test_with_uppercase_index_name @@ -344,15 +349,20 @@ class SchemaTest < ActiveRecord::TestCase @connection.schema_search_path = "'$user', public" end - def do_dump_index_tests_for_schema(this_schema_name, first_index_column_name, second_index_column_name, third_index_column_name) + def do_dump_index_tests_for_schema(this_schema_name, first_index_column_name, second_index_column_name, third_index_column_name, fourth_index_column_name) with_schema_search_path(this_schema_name) do indexes = @connection.indexes(TABLE_NAME).sort_by {|i| i.name} - assert_equal 3,indexes.size + assert_equal 4,indexes.size do_dump_index_assertions_for_one_index(indexes[0], INDEX_A_NAME, first_index_column_name) do_dump_index_assertions_for_one_index(indexes[1], INDEX_B_NAME, second_index_column_name) do_dump_index_assertions_for_one_index(indexes[2], INDEX_D_NAME, third_index_column_name) + do_dump_index_assertions_for_one_index(indexes[3], INDEX_E_NAME, fourth_index_column_name) + indexes.select{|i| i.name != INDEX_E_NAME}.each do |index| + assert_equal :btree, index.using + end + assert_equal :gin, indexes.select{|i| i.name == INDEX_E_NAME}[0].using assert_equal :desc, indexes.select{|i| i.name == INDEX_D_NAME}[0].orders[INDEX_D_COLUMN] end end diff --git a/activerecord/test/cases/adapters/postgresql/statement_pool_test.rb b/activerecord/test/cases/adapters/postgresql/statement_pool_test.rb index f1c4b85126..c5fd40accc 100644 --- a/activerecord/test/cases/adapters/postgresql/statement_pool_test.rb +++ b/activerecord/test/cases/adapters/postgresql/statement_pool_test.rb @@ -1,38 +1,40 @@ require 'cases/helper' -module ActiveRecord::ConnectionAdapters - class PostgreSQLAdapter < AbstractAdapter - class InactivePGconn - def query(*args) - raise PGError - end +module ActiveRecord + module ConnectionAdapters + class PostgreSQLAdapter < AbstractAdapter + class InactivePGconn + def query(*args) + raise PGError + end - def status - PGconn::CONNECTION_BAD + def status + PGconn::CONNECTION_BAD + end end - end - class StatementPoolTest < ActiveRecord::TestCase - def test_cache_is_per_pid - return skip('must support fork') unless Process.respond_to?(:fork) + class StatementPoolTest < ActiveRecord::TestCase + def test_cache_is_per_pid + return skip('must support fork') unless Process.respond_to?(:fork) - cache = StatementPool.new nil, 10 - cache['foo'] = 'bar' - assert_equal 'bar', cache['foo'] + cache = StatementPool.new nil, 10 + cache['foo'] = 'bar' + assert_equal 'bar', cache['foo'] - pid = fork { - lookup = cache['foo']; - exit!(!lookup) - } + pid = fork { + lookup = cache['foo']; + exit!(!lookup) + } - Process.waitpid pid - assert $?.success?, 'process should exit successfully' - end + Process.waitpid pid + assert $?.success?, 'process should exit successfully' + end - def test_dealloc_does_not_raise_on_inactive_connection - cache = StatementPool.new InactivePGconn.new, 10 - cache['foo'] = 'bar' - assert_nothing_raised { cache.clear } + def test_dealloc_does_not_raise_on_inactive_connection + cache = StatementPool.new InactivePGconn.new, 10 + cache['foo'] = 'bar' + assert_nothing_raised { cache.clear } + end end end end diff --git a/activerecord/test/cases/adapters/postgresql/uuid_test.rb b/activerecord/test/cases/adapters/postgresql/uuid_test.rb new file mode 100644 index 0000000000..a753a23c09 --- /dev/null +++ b/activerecord/test/cases/adapters/postgresql/uuid_test.rb @@ -0,0 +1,136 @@ +# encoding: utf-8 + +require "cases/helper" +require 'active_record/base' +require 'active_record/connection_adapters/postgresql_adapter' + +class PostgresqlUUIDTest < ActiveRecord::TestCase + class UUID < ActiveRecord::Base + self.table_name = 'pg_uuids' + end + + def setup + @connection = ActiveRecord::Base.connection + + unless @connection.supports_extensions? + return skip "do not test on PG without uuid-ossp" + end + + unless @connection.extension_enabled?('uuid-ossp') + @connection.enable_extension 'uuid-ossp' + @connection.commit_db_transaction + end + + @connection.reconnect! + + @connection.transaction do + @connection.create_table('pg_uuids', id: :uuid, default: 'uuid_generate_v1()') do |t| + t.string 'name' + t.uuid 'other_uuid', default: 'uuid_generate_v4()' + end + end + end + + def teardown + @connection.execute 'drop table if exists pg_uuids' + end + + def test_id_is_uuid + assert_equal :uuid, UUID.columns_hash['id'].type + assert UUID.primary_key + end + + def test_id_has_a_default + u = UUID.create + assert_not_nil u.id + end + + def test_auto_create_uuid + u = UUID.create + u.reload + assert_not_nil u.other_uuid + end + + def test_pk_and_sequence_for_uuid_primary_key + pk, seq = @connection.pk_and_sequence_for('pg_uuids') + assert_equal 'id', pk + assert_equal nil, seq + end + + def test_schema_dumper_for_uuid_primary_key + schema = StringIO.new + ActiveRecord::SchemaDumper.dump(@connection, schema) + assert_match(/\bcreate_table "pg_uuids", id: :uuid, default: "uuid_generate_v1\(\)"/, schema.string) + assert_match(/t\.uuid "other_uuid", default: "uuid_generate_v4\(\)"/, schema.string) + end +end + +class PostgresqlUUIDTestNilDefault < ActiveRecord::TestCase + class UUID < ActiveRecord::Base + self.table_name = 'pg_uuids' + end + + def setup + @connection = ActiveRecord::Base.connection + @connection.reconnect! + + @connection.transaction do + @connection.create_table('pg_uuids', id: false) do |t| + t.primary_key :id, :uuid, default: nil + t.string 'name' + end + end + end + + def teardown + @connection.execute 'drop table if exists pg_uuids' + end + + def test_id_allows_default_override_via_nil + col_desc = @connection.execute("SELECT pg_get_expr(d.adbin, d.adrelid) as default + FROM pg_attribute a + LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum + WHERE a.attname='id' AND a.attrelid = 'pg_uuids'::regclass").first + assert_nil col_desc["default"] + end +end + +class PostgresqlUUIDTestInverseOf < ActiveRecord::TestCase + class UuidPost < ActiveRecord::Base + self.table_name = 'pg_uuid_posts' + has_many :uuid_comments, inverse_of: :uuid_post + end + + class UuidComment < ActiveRecord::Base + self.table_name = 'pg_uuid_comments' + belongs_to :uuid_post + end + + def setup + @connection = ActiveRecord::Base.connection + @connection.reconnect! + + @connection.transaction do + @connection.create_table('pg_uuid_posts', id: :uuid) do |t| + t.string 'title' + end + @connection.create_table('pg_uuid_comments', id: :uuid) do |t| + t.uuid :uuid_post_id, default: 'uuid_generate_v4()' + t.string 'content' + end + end + end + + def teardown + @connection.transaction do + @connection.execute 'drop table if exists pg_uuid_comments' + @connection.execute 'drop table if exists pg_uuid_posts' + end + end + + def test_collection_association_with_uuid + post = UuidPost.create! + comment = post.uuid_comments.create! + assert post.uuid_comments.find(comment.id) + end +end diff --git a/activerecord/test/cases/adapters/postgresql/xml_test.rb b/activerecord/test/cases/adapters/postgresql/xml_test.rb new file mode 100644 index 0000000000..bf14b378d8 --- /dev/null +++ b/activerecord/test/cases/adapters/postgresql/xml_test.rb @@ -0,0 +1,38 @@ +# encoding: utf-8 + +require 'cases/helper' +require 'active_record/base' +require 'active_record/connection_adapters/postgresql_adapter' + +class PostgresqlXMLTest < ActiveRecord::TestCase + class XmlDataType < ActiveRecord::Base + self.table_name = 'xml_data_type' + end + + def setup + @connection = ActiveRecord::Base.connection + begin + @connection.transaction do + @connection.create_table('xml_data_type') do |t| + t.xml 'payload', default: {} + end + end + rescue ActiveRecord::StatementInvalid + return skip "do not test on PG without xml" + end + @column = XmlDataType.columns.find { |c| c.name == 'payload' } + end + + def teardown + @connection.execute 'drop table if exists xml_data_type' + end + + def test_column + assert_equal :xml, @column.type + end + + def test_null_xml + @connection.execute %q|insert into xml_data_type (payload) VALUES(null)| + assert_nil XmlDataType.first.payload + end +end diff --git a/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb b/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb index d03d1dd94c..e78cb88562 100644 --- a/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb @@ -1,7 +1,7 @@ require "cases/helper" class CopyTableTest < ActiveRecord::TestCase - fixtures :customers, :companies, :comments + fixtures :customers, :companies, :comments, :binaries def setup @connection = ActiveRecord::Base.connection @@ -54,7 +54,7 @@ class CopyTableTest < ActiveRecord::TestCase end def test_copy_table_with_id_col_that_is_not_primary_key - test_copy_table('goofy_string_id', 'goofy_string_id2') do |from, to, options| + test_copy_table('goofy_string_id', 'goofy_string_id2') do original_id = @connection.columns('goofy_string_id').detect{|col| col.name == 'id' } copied_id = @connection.columns('goofy_string_id2').detect{|col| col.name == 'id' } assert_equal original_id.type, copied_id.type @@ -65,13 +65,17 @@ class CopyTableTest < ActiveRecord::TestCase end def test_copy_table_with_unconventional_primary_key - test_copy_table('owners', 'owners_unconventional') do |from, to, options| + test_copy_table('owners', 'owners_unconventional') do original_pk = @connection.primary_key('owners') copied_pk = @connection.primary_key('owners_unconventional') assert_equal original_pk, copied_pk end end + def test_copy_table_with_binary_column + test_copy_table 'binaries', 'binaries2' + end + protected def copy_table(from, to, options = {}) @connection.copy_table(from, to, {:temporary => true}.merge(options)) @@ -86,7 +90,7 @@ protected end def table_indexes_without_name(table) - @connection.indexes('comments_with_index').delete(:name) + @connection.indexes(table).delete(:name) end def row_count(table) diff --git a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb index 003052bac4..ce7c869eec 100644 --- a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb @@ -21,13 +21,26 @@ module ActiveRecord ) eosql - @conn.extend(LogIntercepter) - @conn.intercepted = true + @subscriber = SQLSubscriber.new + ActiveSupport::Notifications.subscribe('sql.active_record', @subscriber) + end + + def test_valid_column + column = @conn.columns('items').find { |col| col.name == 'id' } + assert @conn.valid_type?(column.type) + end + + # sqlite databases should be able to support any type and not + # just the ones mentioned in the native_database_types. + # Therefore test_invalid column should always return true + # even if the type is not valid. + def test_invalid_column + assert @conn.valid_type?(:foobar) end def teardown - @conn.intercepted = false - @conn.logged = [] + ActiveSupport::Notifications.unsubscribe(@subscriber) + super end def test_column_types @@ -243,7 +256,7 @@ module ActiveRecord def test_tables_logs_name assert_logged [['SCHEMA', []]] do @conn.tables('hello') - assert_not_nil @conn.logged.first.shift + assert_not_nil @subscriber.logged.first.shift end end @@ -255,7 +268,7 @@ module ActiveRecord def test_table_exists_logs_name assert @conn.table_exists?('items') - assert_equal 'SCHEMA', @conn.logged[0][1] + assert_equal 'SCHEMA', @subscriber.logged[0][1] end def test_columns @@ -293,10 +306,10 @@ module ActiveRecord end def test_indexes_logs - assert_difference('@conn.logged.length') do + assert_difference('@subscriber.logged.length') do @conn.indexes('items') end - assert_match(/items/, @conn.logged.last.first) + assert_match(/items/, @subscriber.logged.last.first) end def test_no_indexes @@ -341,11 +354,23 @@ module ActiveRecord assert_nil @conn.primary_key('failboat') end + def test_supports_extensions + assert_not @conn.supports_extensions?, 'does not support extensions' + end + + def test_respond_to_enable_extension + assert @conn.respond_to?(:enable_extension) + end + + def test_respond_to_disable_extension + assert @conn.respond_to?(:disable_extension) + end + private def assert_logged logs yield - assert_equal logs, @conn.logged + assert_equal logs, @subscriber.logged end end diff --git a/activerecord/test/cases/adapters/sqlite3/sqlite3_create_folder_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_create_folder_test.rb new file mode 100644 index 0000000000..5a4fe63580 --- /dev/null +++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_create_folder_test.rb @@ -0,0 +1,21 @@ +# encoding: utf-8 +require "cases/helper" +require 'models/owner' + +module ActiveRecord + module ConnectionAdapters + class SQLite3CreateFolder < ActiveRecord::TestCase + def test_sqlite_creates_directory + Dir.mktmpdir do |dir| + dir = Pathname.new(dir) + @conn = Base.sqlite3_connection :database => dir.join("db/foo.sqlite3"), + :adapter => 'sqlite3', + :timeout => 100 + + assert Dir.exists? dir.join('db') + assert File.exist? dir.join('db/foo.sqlite3') + end + end + end + end +end |