rails--rails/activerecord/test/cases/test_case.rb

143 lines
4.9 KiB
Ruby
Raw Normal View History

# frozen_string_literal: true
require "active_support"
require "active_support/testing/autorun"
require "active_support/testing/method_call_assertions"
require "active_support/testing/stream"
require "active_record/fixtures"
require "cases/validations_repair_helper"
module ActiveRecord
# = Active Record Test Case
#
# Defines some test assertions to test against SQL queries.
class TestCase < ActiveSupport::TestCase #:nodoc:
include ActiveSupport::Testing::MethodCallAssertions
include ActiveSupport::Testing::Stream
include ActiveRecord::TestFixtures
include ActiveRecord::ValidationsRepairHelper
self.fixture_path = FIXTURES_ROOT
self.use_instantiated_fixtures = false
self.use_transactional_tests = true
def create_fixtures(*fixture_set_names, &block)
ActiveRecord::FixtureSet.create_fixtures(ActiveRecord::TestCase.fixture_path, fixture_set_names, fixture_class_names, &block)
end
def teardown
SQLCounter.clear_log
end
def capture_sql
SQLCounter.clear_log
yield
SQLCounter.log_all.dup
end
def assert_sql(*patterns_to_match)
capture_sql { yield }
ensure
failed_patterns = []
patterns_to_match.each do |pattern|
failed_patterns << pattern unless SQLCounter.log_all.any? { |sql| pattern === sql }
end
assert failed_patterns.empty?, "Query pattern(s) #{failed_patterns.map(&:inspect).join(', ')} not found.#{SQLCounter.log.size == 0 ? '' : "\nQueries:\n#{SQLCounter.log.join("\n")}"}"
end
def assert_queries(num = 1, options = {})
ignore_none = options.fetch(:ignore_none) { num == :any }
SQLCounter.clear_log
x = yield
the_log = ignore_none ? SQLCounter.log_all : SQLCounter.log
if num == :any
assert_operator the_log.size, :>=, 1, "1 or more queries expected, but none were executed."
else
mesg = "#{the_log.size} instead of #{num} queries were executed.#{the_log.size == 0 ? '' : "\nQueries:\n#{the_log.join("\n")}"}"
assert_equal num, the_log.size, mesg
end
x
end
def assert_no_queries(options = {}, &block)
options.reverse_merge! ignore_none: true
assert_queries(0, options, &block)
end
def assert_column(model, column_name, msg = nil)
assert has_column?(model, column_name), msg
end
def assert_no_column(model, column_name, msg = nil)
assert_not has_column?(model, column_name), msg
end
def has_column?(model, column_name)
model.reset_column_information
model.column_names.include?(column_name.to_s)
end
def frozen_error_class
Object.const_defined?(:FrozenError) ? FrozenError : RuntimeError
end
end
class PostgreSQLTestCase < TestCase
def self.run(*args)
super if current_adapter?(:PostgreSQLAdapter)
end
end
class Mysql2TestCase < TestCase
def self.run(*args)
super if current_adapter?(:Mysql2Adapter)
end
end
class SQLite3TestCase < TestCase
def self.run(*args)
super if current_adapter?(:SQLite3Adapter)
end
end
class SQLCounter
class << self
attr_accessor :ignored_sql, :log, :log_all
def clear_log; self.log = []; self.log_all = []; end
end
clear_log
self.ignored_sql = [/^PRAGMA/, /^SELECT currval/, /^SELECT CAST/, /^SELECT @@IDENTITY/, /^SELECT @@ROWCOUNT/, /^SAVEPOINT/, /^ROLLBACK TO SAVEPOINT/, /^RELEASE SAVEPOINT/, /^SHOW max_identifier_length/, /^BEGIN/, /^COMMIT/]
# FIXME: this needs to be refactored so specific database can add their own
# ignored SQL, or better yet, use a different notification for the queries
# instead examining the SQL content.
Address incorrect number of queries executed at Oracle enhanced adapter This pull request addresses these 17 failures when tested with Oracle enhanced adapter. All of these failures are due to the incorrect number of queries. Here is the first one. ```ruby $ ARCONN=oracle bin/test test/cases/nested_attributes_test.rb:1086 Using oracle Run options: --seed 27985 F Finished in 0.874514s, 1.1435 runs/s, 1.1435 assertions/s. 1) Failure: TestHasManyAutosaveAssociationWhichItselfHasAutosaveAssociations#test_circular_references_do_not_perform_unnecessary_queries [/home/yahonda/git/rails/activerecord/test/cases/nested_attributes_test.rb:1086]: 6 instead of 3 queries were executed. Queries: select us.sequence_name from all_sequences us where us.sequence_owner = :owner and us.sequence_name = :sequence_name INSERT INTO "SHIPS" ("NAME", "ID") VALUES (:a1, :a2) select us.sequence_name from all_sequences us where us.sequence_owner = :owner and us.sequence_name = :sequence_name INSERT INTO "SHIP_PARTS" ("NAME", "SHIP_ID", "UPDATED_AT", "ID") VALUES (:a1, :a2, :a3, :a4) select us.sequence_name from all_sequences us where us.sequence_owner = :owner and us.sequence_name = :sequence_name INSERT INTO "TREASURES" ("LOOTER_ID", "LOOTER_TYPE", "SHIP_ID", "ID") VALUES (:a1, :a2, :a3, :a4). Expected: 3 Actual: 6 1 runs, 1 assertions, 1 failures, 0 errors, 0 skips $ ``` Since https://github.com/rsim/oracle-enhanced/pull/1490 Oracle enhanced adapter drops its own schema caching called OracleEnhancedAdapter.cache_columns` to use Rails scehema cache generated by `db:schema:cache:dump`. By this change some extra sql statements executed at ActiveRecord unit test, which can be fixed by adding the sql statement to `oracle_ignored`. * All 17 failures fixed by this pull request: ```ruby ARCONN=oracle bin/test test/cases/nested_attributes_test.rb:1086 ARCONN=oracle bin/test test/cases/locking_test.rb:308 ARCONN=oracle bin/test test/cases/locking_test.rb:365 ARCONN=oracle bin/test test/cases/dirty_test.rb:351 ARCONN=oracle bin/test test/cases/dirty_test.rb:334 ARCONN=oracle bin/test test/cases/autosave_association_test.rb:192 ARCONN=oracle bin/test test/cases/associations/has_many_associations_test.rb:950 ARCONN=oracle bin/test test/cases/associations/has_many_associations_test.rb:1059 ARCONN=oracle bin/test test/cases/autosave_association_test.rb:627 ARCONN=oracle bin/test test/cases/autosave_association_test.rb:607 ARCONN=oracle bin/test test/cases/autosave_association_test.rb:617 ARCONN=oracle bin/test test/cases/autosave_association_test.rb:641 ARCONN=oracle bin/test test/cases/associations/has_many_through_associations_test.rb:546 ARCONN=oracle bin/test test/cases/associations/has_many_through_associations_test.rb:297 ARCONN=oracle bin/test test/cases/associations/has_many_through_associations_test.rb:586 ARCONN=oracle bin/test test/cases/associations/has_many_through_associations_test.rb:172 ARCONN=oracle bin/test test/cases/associations/has_many_through_associations_test.rb:269 ```
2017-10-31 18:06:23 +00:00
oracle_ignored = [/^select .*nextval/i, /^SAVEPOINT/, /^ROLLBACK TO/, /^\s*select .* from all_triggers/im, /^\s*select .* from all_constraints/im, /^\s*select .* from all_tab_cols/im, /^\s*select .* from all_sequences/im]
mysql_ignored = [/^SHOW FULL TABLES/i, /^SHOW FULL FIELDS/, /^SHOW CREATE TABLE /i, /^SHOW VARIABLES /, /^\s*SELECT (?:column_name|table_name)\b.*\bFROM information_schema\.(?:key_column_usage|tables)\b/im]
2017-12-06 10:09:24 +00:00
postgresql_ignored = [/^\s*select\b.*\bfrom\b.*pg_namespace\b/im, /^\s*select tablename\b.*from pg_tables\b/im, /^\s*select\b.*\battname\b.*\bfrom\b.*\bpg_attribute\b/im, /^SHOW search_path/i, /^\s*SELECT\b.*::regtype::oid\b/im]
sqlite3_ignored = [/^\s*SELECT name\b.*\bFROM sqlite_master/im, /^\s*SELECT sql\b.*\bFROM sqlite_master/im]
[oracle_ignored, mysql_ignored, postgresql_ignored, sqlite3_ignored].each do |db_ignored_sql|
ignored_sql.concat db_ignored_sql
end
attr_reader :ignore
def initialize(ignore = Regexp.union(self.class.ignored_sql))
@ignore = ignore
end
def call(name, start, finish, message_id, values)
return if values[:cached]
sql = values[:sql]
self.class.log_all << sql
self.class.log << sql unless ignore.match?(sql)
end
end
ActiveSupport::Notifications.subscribe("sql.active_record", SQLCounter.new)
end