From 5e2b473b478d93d6a1aa627d688b2b2ce05fa9ef Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 25 Jun 2010 13:29:17 -0700 Subject: reorganizing adapter specific tests. [#4974 state:resolved] Signed-off-by: Jeremy Kemper --- .../adapters/postgresql/active_schema_test.rb | 28 +++ .../cases/adapters/postgresql/datatype_test.rb | 243 +++++++++++++++++++++ .../postgresql/schema_authorization_test.rb | 84 +++++++ .../test/cases/adapters/postgresql/schema_test.rb | 193 ++++++++++++++++ 4 files changed, 548 insertions(+) create mode 100644 activerecord/test/cases/adapters/postgresql/active_schema_test.rb create mode 100644 activerecord/test/cases/adapters/postgresql/datatype_test.rb create mode 100644 activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb create mode 100644 activerecord/test/cases/adapters/postgresql/schema_test.rb (limited to 'activerecord/test/cases/adapters/postgresql') diff --git a/activerecord/test/cases/adapters/postgresql/active_schema_test.rb b/activerecord/test/cases/adapters/postgresql/active_schema_test.rb new file mode 100644 index 0000000000..f106e14319 --- /dev/null +++ b/activerecord/test/cases/adapters/postgresql/active_schema_test.rb @@ -0,0 +1,28 @@ +require 'cases/helper' + +class PostgresqlActiveSchemaTest < Test::Unit::TestCase + def setup + ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.class_eval do + alias_method :real_execute, :execute + remove_method :execute + def execute(sql, name = nil) sql end + end + end + + def teardown + ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.class_eval do + remove_method :execute + alias_method :execute, :real_execute + end + end + + def test_create_database_with_encoding + assert_equal %(CREATE DATABASE "matt" ENCODING = 'utf8'), create_database(:matt) + assert_equal %(CREATE DATABASE "aimonetti" ENCODING = 'latin1'), create_database(:aimonetti, :encoding => :latin1) + end + + private + def method_missing(method_symbol, *arguments) + ActiveRecord::Base.connection.send(method_symbol, *arguments) + end +end diff --git a/activerecord/test/cases/adapters/postgresql/datatype_test.rb b/activerecord/test/cases/adapters/postgresql/datatype_test.rb new file mode 100644 index 0000000000..5bb8fa2f93 --- /dev/null +++ b/activerecord/test/cases/adapters/postgresql/datatype_test.rb @@ -0,0 +1,243 @@ +require "cases/helper" + +class PostgresqlArray < ActiveRecord::Base +end + +class PostgresqlMoney < ActiveRecord::Base +end + +class PostgresqlNumber < ActiveRecord::Base +end + +class PostgresqlTime < ActiveRecord::Base +end + +class PostgresqlNetworkAddress < ActiveRecord::Base +end + +class PostgresqlBitString < ActiveRecord::Base +end + +class PostgresqlOid < ActiveRecord::Base +end + +class PostgresqlTimestampWithZone < ActiveRecord::Base +end + +class PostgresqlDataTypeTest < ActiveRecord::TestCase + self.use_transactional_fixtures = false + + def setup + @connection = ActiveRecord::Base.connection + @connection.execute("set lc_monetary = 'C'") + + @connection.execute("INSERT INTO postgresql_arrays (commission_by_quarter, nicknames) VALUES ( '{35000,21000,18000,17000}', '{foo,bar,baz}' )") + @first_array = PostgresqlArray.find(1) + + @connection.execute("INSERT INTO postgresql_moneys (wealth) VALUES ('567.89'::money)") + @connection.execute("INSERT INTO postgresql_moneys (wealth) VALUES ('-567.89'::money)") + @first_money = PostgresqlMoney.find(1) + @second_money = PostgresqlMoney.find(2) + + @connection.execute("INSERT INTO postgresql_numbers (single, double) VALUES (123.456, 123456.789)") + @first_number = PostgresqlNumber.find(1) + + @connection.execute("INSERT INTO postgresql_times (time_interval) VALUES ('1 year 2 days ago')") + @first_time = PostgresqlTime.find(1) + + @connection.execute("INSERT INTO postgresql_network_addresses (cidr_address, inet_address, mac_address) VALUES('192.168.0/24', '172.16.1.254/32', '01:23:45:67:89:0a')") + @first_network_address = PostgresqlNetworkAddress.find(1) + + @connection.execute("INSERT INTO postgresql_bit_strings (bit_string, bit_string_varying) VALUES (B'00010101', X'15')") + @first_bit_string = PostgresqlBitString.find(1) + + @connection.execute("INSERT INTO postgresql_oids (obj_id) VALUES (1234)") + @first_oid = PostgresqlOid.find(1) + + @connection.execute("INSERT INTO postgresql_timestamp_with_zones (time) VALUES ('2010-01-01 10:00:00-1')") + end + + def test_data_type_of_array_types + assert_equal :string, @first_array.column_for_attribute(:commission_by_quarter).type + assert_equal :string, @first_array.column_for_attribute(:nicknames).type + end + + def test_data_type_of_money_types + assert_equal :decimal, @first_money.column_for_attribute(:wealth).type + end + + def test_data_type_of_number_types + assert_equal :float, @first_number.column_for_attribute(:single).type + assert_equal :float, @first_number.column_for_attribute(:double).type + end + + def test_data_type_of_time_types + assert_equal :string, @first_time.column_for_attribute(:time_interval).type + end + + def test_data_type_of_network_address_types + assert_equal :string, @first_network_address.column_for_attribute(:cidr_address).type + assert_equal :string, @first_network_address.column_for_attribute(:inet_address).type + assert_equal :string, @first_network_address.column_for_attribute(:mac_address).type + end + + def test_data_type_of_bit_string_types + assert_equal :string, @first_bit_string.column_for_attribute(:bit_string).type + assert_equal :string, @first_bit_string.column_for_attribute(:bit_string_varying).type + end + + def test_data_type_of_oid_types + assert_equal :integer, @first_oid.column_for_attribute(:obj_id).type + end + + def test_array_values + assert_equal '{35000,21000,18000,17000}', @first_array.commission_by_quarter + assert_equal '{foo,bar,baz}', @first_array.nicknames + end + + def test_money_values + assert_equal 567.89, @first_money.wealth + assert_equal(-567.89, @second_money.wealth) + end + + def test_number_values + assert_equal 123.456, @first_number.single + assert_equal 123456.789, @first_number.double + end + + def test_time_values + assert_equal '-1 years -2 days', @first_time.time_interval + end + + def test_network_address_values + assert_equal '192.168.0.0/24', @first_network_address.cidr_address + assert_equal '172.16.1.254', @first_network_address.inet_address + assert_equal '01:23:45:67:89:0a', @first_network_address.mac_address + end + + def test_bit_string_values + assert_equal '00010101', @first_bit_string.bit_string + assert_equal '00010101', @first_bit_string.bit_string_varying + end + + def test_oid_values + assert_equal 1234, @first_oid.obj_id + end + + def test_update_integer_array + new_value = '{32800,95000,29350,17000}' + assert @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 @first_array.save + assert @first_array.reload + assert_equal @first_array.commission_by_quarter, new_value + end + + def test_update_text_array + new_value = '{robby,robert,rob,robbie}' + assert @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 @first_array.save + assert @first_array.reload + assert_equal @first_array.nicknames, new_value + end + + def test_update_money + new_value = BigDecimal.new('123.45') + assert @first_money.wealth = new_value + assert @first_money.save + assert @first_money.reload + assert_equal new_value, @first_money.wealth + end + + def test_update_number + new_single = 789.012 + new_double = 789012.345 + assert @first_number.single = new_single + assert @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 + end + + def test_update_time + assert @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' + end + + def test_update_network_address + new_cidr_address = '10.1.2.3/32' + new_inet_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 + assert @first_network_address.save + assert @first_network_address.reload + assert_equal @first_network_address.cidr_address, new_cidr_address + assert_equal @first_network_address.inet_address, new_inet_address + assert_equal @first_network_address.mac_address, new_mac_address + end + + def test_update_bit_string + new_bit_string = '11111111' + new_bit_string_varying = 'FF' + assert @first_bit_string.bit_string = new_bit_string + assert @first_bit_string.bit_string_varying = new_bit_string_varying + assert @first_bit_string.save + assert @first_bit_string.reload + assert_equal @first_bit_string.bit_string, new_bit_string + assert_equal @first_bit_string.bit_string, @first_bit_string.bit_string_varying + end + + def test_update_oid + new_value = 567890 + assert @first_oid.obj_id = new_value + assert @first_oid.save + assert @first_oid.reload + assert_equal @first_oid.obj_id, new_value + 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 + + 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 + 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 + 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/schema_authorization_test.rb b/activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb new file mode 100644 index 0000000000..6f372edc38 --- /dev/null +++ b/activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb @@ -0,0 +1,84 @@ +require "cases/helper" + +class SchemaThing < ActiveRecord::Base +end + +class SchemaAuthorizationTest < ActiveRecord::TestCase + self.use_transactional_fixtures = false + + TABLE_NAME = 'schema_things' + COLUMNS = [ + 'id serial primary key', + 'name character varying(50)' + ] + USERS = ['rails_pg_schema_user1', 'rails_pg_schema_user2'] + + def setup + @connection = ActiveRecord::Base.connection + @connection.execute "SET search_path TO '$user',public" + set_session_auth + USERS.each do |u| + @connection.execute "CREATE USER #{u}" rescue nil + @connection.execute "CREATE SCHEMA AUTHORIZATION #{u}" rescue nil + set_session_auth u + @connection.execute "CREATE TABLE #{TABLE_NAME} (#{COLUMNS.join(',')})" + @connection.execute "INSERT INTO #{TABLE_NAME} (name) VALUES ('#{u}')" + set_session_auth + end + end + + def teardown + set_session_auth + @connection.execute "RESET search_path" + USERS.each do |u| + @connection.execute "DROP SCHEMA #{u} CASCADE" + @connection.execute "DROP USER #{u}" + end + end + + def test_schema_invisible + assert_raise(ActiveRecord::StatementInvalid) do + set_session_auth + @connection.execute "SELECT * FROM #{TABLE_NAME}" + end + end + + def test_schema_uniqueness + assert_nothing_raised do + set_session_auth + USERS.each do |u| + set_session_auth u + assert_equal u, @connection.select_value("SELECT name FROM #{TABLE_NAME} WHERE id = 1") + set_session_auth + end + end + end + + def test_sequence_schema_caching + assert_nothing_raised do + USERS.each do |u| + set_session_auth u + st = SchemaThing.new :name => 'TEST1' + st.save! + st = SchemaThing.new :id => 5, :name => 'TEST2' + st.save! + set_session_auth + end + end + end + + def test_tables_in_current_schemas + assert !@connection.tables.include?(TABLE_NAME) + USERS.each do |u| + set_session_auth u + assert @connection.tables.include?(TABLE_NAME) + set_session_auth + end + end + + private + def set_session_auth auth = nil + @connection.execute "SET SESSION AUTHORIZATION #{auth || 'default'}" + end + +end diff --git a/activerecord/test/cases/adapters/postgresql/schema_test.rb b/activerecord/test/cases/adapters/postgresql/schema_test.rb new file mode 100644 index 0000000000..3ed9b1974d --- /dev/null +++ b/activerecord/test/cases/adapters/postgresql/schema_test.rb @@ -0,0 +1,193 @@ +require "cases/helper" + +class SchemaTest < ActiveRecord::TestCase + self.use_transactional_fixtures = false + + SCHEMA_NAME = 'test_schema' + SCHEMA2_NAME = 'test_schema2' + TABLE_NAME = 'things' + CAPITALIZED_TABLE_NAME = 'Things' + INDEX_A_NAME = 'a_index_things_on_name' + INDEX_B_NAME = 'b_index_things_on_different_columns_in_each_schema' + INDEX_A_COLUMN = 'name' + INDEX_B_COLUMN_S1 = 'email' + INDEX_B_COLUMN_S2 = 'moment' + COLUMNS = [ + 'id integer', + 'name character varying(50)', + 'email character varying(50)', + 'moment timestamp without time zone default now()' + ] + + class Thing1 < ActiveRecord::Base + set_table_name "test_schema.things" + end + + class Thing2 < ActiveRecord::Base + set_table_name "test_schema2.things" + end + + class Thing3 < ActiveRecord::Base + set_table_name 'test_schema."things.table"' + end + + class Thing4 < ActiveRecord::Base + set_table_name 'test_schema."Things"' + end + + def setup + @connection = ActiveRecord::Base.connection + @connection.execute "CREATE SCHEMA #{SCHEMA_NAME} CREATE TABLE #{TABLE_NAME} (#{COLUMNS.join(',')})" + @connection.execute "CREATE TABLE #{SCHEMA_NAME}.\"#{TABLE_NAME}.table\" (#{COLUMNS.join(',')})" + @connection.execute "CREATE TABLE #{SCHEMA_NAME}.\"#{CAPITALIZED_TABLE_NAME}\" (#{COLUMNS.join(',')})" + @connection.execute "CREATE SCHEMA #{SCHEMA2_NAME} CREATE TABLE #{TABLE_NAME} (#{COLUMNS.join(',')})" + @connection.execute "CREATE INDEX #{INDEX_A_NAME} ON #{SCHEMA_NAME}.#{TABLE_NAME} USING btree (#{INDEX_A_COLUMN});" + @connection.execute "CREATE INDEX #{INDEX_A_NAME} ON #{SCHEMA2_NAME}.#{TABLE_NAME} USING btree (#{INDEX_A_COLUMN});" + @connection.execute "CREATE INDEX #{INDEX_B_NAME} ON #{SCHEMA_NAME}.#{TABLE_NAME} USING btree (#{INDEX_B_COLUMN_S1});" + @connection.execute "CREATE INDEX #{INDEX_B_NAME} ON #{SCHEMA2_NAME}.#{TABLE_NAME} USING btree (#{INDEX_B_COLUMN_S2});" + end + + def teardown + @connection.execute "DROP SCHEMA #{SCHEMA2_NAME} CASCADE" + @connection.execute "DROP SCHEMA #{SCHEMA_NAME} CASCADE" + end + + def test_table_exists? + [Thing1, Thing2, Thing3, Thing4].each do |klass| + name = klass.table_name + assert @connection.table_exists?(name), "'#{name}' table should exist" + end + end + + def test_table_exists_wrong_schema + assert(!@connection.table_exists?("foo.things"), "table should not exist") + end + + def test_table_exists_quoted_table + assert(@connection.table_exists?('"things.table"'), "table should exist") + end + + def test_with_schema_prefixed_table_name + assert_nothing_raised do + assert_equal COLUMNS, columns("#{SCHEMA_NAME}.#{TABLE_NAME}") + end + end + + def test_with_schema_prefixed_capitalized_table_name + assert_nothing_raised do + assert_equal COLUMNS, columns("#{SCHEMA_NAME}.#{CAPITALIZED_TABLE_NAME}") + end + end + + def test_with_schema_search_path + assert_nothing_raised do + with_schema_search_path(SCHEMA_NAME) do + assert_equal COLUMNS, columns(TABLE_NAME) + end + end + end + + + def test_proper_encoding_of_table_name + assert_equal '"table_name"', @connection.quote_table_name('table_name') + assert_equal '"table.name"', @connection.quote_table_name('"table.name"') + assert_equal '"schema_name"."table_name"', @connection.quote_table_name('schema_name.table_name') + assert_equal '"schema_name"."table.name"', @connection.quote_table_name('schema_name."table.name"') + assert_equal '"schema.name"."table_name"', @connection.quote_table_name('"schema.name".table_name') + assert_equal '"schema.name"."table.name"', @connection.quote_table_name('"schema.name"."table.name"') + end + + def test_classes_with_qualified_schema_name + assert_equal 0, Thing1.count + assert_equal 0, Thing2.count + assert_equal 0, Thing3.count + assert_equal 0, Thing4.count + + Thing1.create(:id => 1, :name => "thing1", :email => "thing1@localhost", :moment => Time.now) + assert_equal 1, Thing1.count + assert_equal 0, Thing2.count + assert_equal 0, Thing3.count + assert_equal 0, Thing4.count + + Thing2.create(:id => 1, :name => "thing1", :email => "thing1@localhost", :moment => Time.now) + assert_equal 1, Thing1.count + assert_equal 1, Thing2.count + assert_equal 0, Thing3.count + assert_equal 0, Thing4.count + + Thing3.create(:id => 1, :name => "thing1", :email => "thing1@localhost", :moment => Time.now) + assert_equal 1, Thing1.count + assert_equal 1, Thing2.count + assert_equal 1, Thing3.count + assert_equal 0, Thing4.count + + Thing4.create(:id => 1, :name => "thing1", :email => "thing1@localhost", :moment => Time.now) + assert_equal 1, Thing1.count + assert_equal 1, Thing2.count + assert_equal 1, Thing3.count + assert_equal 1, Thing4.count + end + + def test_raise_on_unquoted_schema_name + assert_raise(ActiveRecord::StatementInvalid) do + with_schema_search_path '$user,public' + end + end + + def test_without_schema_search_path + assert_raise(ActiveRecord::StatementInvalid) { columns(TABLE_NAME) } + end + + def test_ignore_nil_schema_search_path + assert_nothing_raised { with_schema_search_path nil } + end + + def test_dump_indexes_for_schema_one + do_dump_index_tests_for_schema(SCHEMA_NAME, INDEX_A_COLUMN, INDEX_B_COLUMN_S1) + end + + def test_dump_indexes_for_schema_two + do_dump_index_tests_for_schema(SCHEMA2_NAME, INDEX_A_COLUMN, INDEX_B_COLUMN_S2) + end + + def test_with_uppercase_index_name + ActiveRecord::Base.connection.execute "CREATE INDEX \"things_Index\" ON #{SCHEMA_NAME}.things (name)" + assert_nothing_raised { ActiveRecord::Base.connection.remove_index! "things", "#{SCHEMA_NAME}.things_Index"} + + ActiveRecord::Base.connection.execute "CREATE INDEX \"things_Index\" ON #{SCHEMA_NAME}.things (name)" + ActiveRecord::Base.connection.schema_search_path = SCHEMA_NAME + assert_nothing_raised { ActiveRecord::Base.connection.remove_index! "things", "things_Index"} + ActiveRecord::Base.connection.schema_search_path = "public" + end + + private + def columns(table_name) + @connection.send(:column_definitions, table_name).map do |name, type, default| + "#{name} #{type}" + (default ? " default #{default}" : '') + end + end + + def with_schema_search_path(schema_search_path) + @connection.schema_search_path = schema_search_path + yield if block_given? + ensure + @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) + with_schema_search_path(this_schema_name) do + indexes = @connection.indexes(TABLE_NAME).sort_by {|i| i.name} + assert_equal 2,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) + end + end + + def do_dump_index_assertions_for_one_index(this_index, this_index_name, this_index_column) + assert_equal TABLE_NAME, this_index.table + assert_equal 1, this_index.columns.size + assert_equal this_index_column, this_index.columns[0] + assert_equal this_index_name, this_index.name + end +end -- cgit v1.2.3