transaction_isolation_continued 1.0.5 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.dockerignore +1 -0
- data/.github/workflows/main.yml +35 -20
- data/.gitignore +3 -0
- data/README.md +77 -56
- data/docker/ruby-2.5/Dockerfile +6 -0
- data/docker/ruby-2.7/Dockerfile +6 -0
- data/docker/ruby-3.0/Dockerfile +6 -0
- data/docker/ruby-3.1/Dockerfile +6 -0
- data/docker/test-ruby-2.5.sh +26 -0
- data/docker/test-ruby-2.7.sh +29 -0
- data/docker/test-ruby-3.0.sh +26 -0
- data/docker/test-ruby-3.1.sh +26 -0
- data/docker/test-ruby.sh +8 -0
- data/docker-compose.yml +60 -0
- data/gemfiles/Gemfile.base +4 -0
- data/gemfiles/activerecord-5.2/Gemfile.sqlite3 +1 -1
- data/gemfiles/activerecord-6.0/Gemfile.sqlite3 +1 -1
- data/gemfiles/activerecord-6.1/Gemfile.sqlite3 +1 -1
- data/gemfiles/activerecord-7.0/Gemfile.sqlite3 +1 -1
- data/lib/transaction_isolation/active_record/base.rb +5 -3
- data/lib/transaction_isolation/active_record/connection_adapters/abstract_adapter.rb +10 -9
- data/lib/transaction_isolation/active_record/connection_adapters/mysql2_adapter.rb +29 -27
- data/lib/transaction_isolation/active_record/connection_adapters/postgresql_adapter.rb +26 -24
- data/lib/transaction_isolation/active_record/connection_adapters/sqlite3_adapter.rb +24 -21
- data/lib/transaction_isolation/active_record/errors.rb +2 -0
- data/lib/transaction_isolation/configuration.rb +6 -4
- data/lib/transaction_isolation/version.rb +3 -1
- data/lib/transaction_isolation.rb +9 -9
- data/test/db/all.rb +2 -0
- data/test/db/db.rb +15 -15
- data/test/db/migrations.rb +6 -7
- data/test/db/queued_job.rb +2 -0
- data/test/integration/active_record/base/isolation_level_test.rb +3 -9
- data/test/integration/active_record/connection_adapters/any_adapter/current_isolation_level_test.rb +8 -16
- data/test/integration/active_record/connection_adapters/any_adapter/current_vendor_isolation_level_test.rb +8 -16
- data/test/integration/active_record/connection_adapters/any_adapter/isolation_level_test.rb +18 -29
- data/test/integration/active_record/connection_adapters/any_adapter/supports_isolation_levels_test.rb +2 -10
- data/test/integration/active_record/connection_adapters/any_adapter/translate_exception_test.rb +20 -26
- data/test/library_setup.rb +11 -9
- data/test/test_helper.rb +9 -6
- data/test/test_runner.rb +3 -2
- data/transaction_isolation_continued.gemspec +14 -14
- metadata +25 -19
- data/Gemfile.local +0 -18
- data/d +0 -1
- data/test/test_console.rb +0 -11
@@ -1,11 +1,12 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
if defined?(ActiveRecord::ConnectionAdapters::Mysql2Adapter)
|
2
4
|
|
3
5
|
module TransactionIsolation
|
4
6
|
module ActiveRecord
|
5
7
|
module ConnectionAdapters # :nodoc:
|
6
8
|
module Mysql2Adapter
|
7
|
-
|
8
|
-
def self.included( base )
|
9
|
+
def self.included(base)
|
9
10
|
base.class_eval do
|
10
11
|
alias_method :translate_exception_without_transaction_isolation_conflict, :translate_exception
|
11
12
|
alias_method :translate_exception, :translate_exception_with_transaction_isolation_conflict
|
@@ -17,18 +18,18 @@ if defined?( ActiveRecord::ConnectionAdapters::Mysql2Adapter )
|
|
17
18
|
end
|
18
19
|
|
19
20
|
VENDOR_ISOLATION_LEVEL = {
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
}
|
21
|
+
read_uncommitted: 'READ UNCOMMITTED',
|
22
|
+
read_committed: 'READ COMMITTED',
|
23
|
+
repeatable_read: 'REPEATABLE READ',
|
24
|
+
serializable: 'SERIALIZABLE'
|
25
|
+
}.freeze
|
25
26
|
|
26
27
|
ANSI_ISOLATION_LEVEL = {
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
}
|
28
|
+
'READ UNCOMMITTED' => :read_uncommitted,
|
29
|
+
'READ COMMITTED' => :read_committed,
|
30
|
+
'REPEATABLE READ' => :repeatable_read,
|
31
|
+
'SERIALIZABLE' => :serializable
|
32
|
+
}.freeze
|
32
33
|
|
33
34
|
def current_isolation_level
|
34
35
|
ANSI_ISOLATION_LEVEL[current_vendor_isolation_level]
|
@@ -37,28 +38,30 @@ if defined?( ActiveRecord::ConnectionAdapters::Mysql2Adapter )
|
|
37
38
|
# transaction_isolation was added in MySQL 5.7.20 as an alias for tx_isolation, which is now deprecated and is removed in MySQL 8.0. Applications should be adjusted to use transaction_isolation in preference to tx_isolation.
|
38
39
|
def current_vendor_isolation_level
|
39
40
|
isolation_variable = TransactionIsolation.config.mysql_isolation_variable
|
40
|
-
select_value(
|
41
|
+
select_value("SELECT @@session.#{isolation_variable}").gsub('-', ' ')
|
41
42
|
end
|
42
43
|
|
43
|
-
def isolation_level(
|
44
|
-
validate_isolation_level(
|
44
|
+
def isolation_level(level)
|
45
|
+
validate_isolation_level(level)
|
45
46
|
|
46
47
|
original_vendor_isolation_level = current_vendor_isolation_level if block_given?
|
47
48
|
|
48
|
-
execute(
|
49
|
+
execute("SET SESSION TRANSACTION ISOLATION LEVEL #{VENDOR_ISOLATION_LEVEL[level]}")
|
50
|
+
|
51
|
+
return unless block_given?
|
49
52
|
|
50
53
|
begin
|
51
54
|
yield
|
52
55
|
ensure
|
53
56
|
execute "SET SESSION TRANSACTION ISOLATION LEVEL #{original_vendor_isolation_level}"
|
54
|
-
end
|
57
|
+
end
|
55
58
|
end
|
56
59
|
|
57
60
|
def translate_exception_with_transaction_isolation_conflict(*args)
|
58
61
|
exception = args.first
|
59
62
|
|
60
|
-
if isolation_conflict?(
|
61
|
-
::ActiveRecord::TransactionIsolationConflict.new(
|
63
|
+
if isolation_conflict?(exception)
|
64
|
+
::ActiveRecord::TransactionIsolationConflict.new("Transaction isolation conflict detected: #{exception.message}")
|
62
65
|
else
|
63
66
|
translate_exception_without_transaction_isolation_conflict(*args)
|
64
67
|
end
|
@@ -66,18 +69,17 @@ if defined?( ActiveRecord::ConnectionAdapters::Mysql2Adapter )
|
|
66
69
|
|
67
70
|
ruby2_keywords :translate_exception_with_transaction_isolation_conflict if respond_to?(:ruby2_keywords, true)
|
68
71
|
|
69
|
-
def isolation_conflict?(
|
70
|
-
[
|
71
|
-
|
72
|
-
exception.message =~ /#{Regexp.escape(
|
72
|
+
def isolation_conflict?(exception)
|
73
|
+
['Deadlock found when trying to get lock',
|
74
|
+
'Lock wait timeout exceeded'].any? do |error_message|
|
75
|
+
exception.message =~ /#{Regexp.escape(error_message)}/i
|
73
76
|
end
|
74
77
|
end
|
75
|
-
|
76
78
|
end
|
77
79
|
end
|
78
80
|
end
|
79
81
|
end
|
80
82
|
|
81
|
-
ActiveRecord::ConnectionAdapters::Mysql2Adapter.
|
83
|
+
ActiveRecord::ConnectionAdapters::Mysql2Adapter.include TransactionIsolation::ActiveRecord::ConnectionAdapters::Mysql2Adapter
|
82
84
|
|
83
|
-
end
|
85
|
+
end
|
@@ -1,11 +1,12 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
if defined?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
|
2
4
|
|
3
5
|
module TransactionIsolation
|
4
6
|
module ActiveRecord
|
5
7
|
module ConnectionAdapters # :nodoc:
|
6
8
|
module PostgreSQLAdapter
|
7
|
-
|
8
|
-
def self.included( base )
|
9
|
+
def self.included(base)
|
9
10
|
base.class_eval do
|
10
11
|
alias_method :translate_exception_without_transaction_isolation_conflict, :translate_exception
|
11
12
|
alias_method :translate_exception, :translate_exception_with_transaction_isolation_conflict
|
@@ -17,39 +18,41 @@ if defined?( ActiveRecord::ConnectionAdapters::PostgreSQLAdapter )
|
|
17
18
|
end
|
18
19
|
|
19
20
|
VENDOR_ISOLATION_LEVEL = {
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
}
|
21
|
+
read_uncommitted: 'READ UNCOMMITTED',
|
22
|
+
read_committed: 'READ COMMITTED',
|
23
|
+
repeatable_read: 'REPEATABLE READ',
|
24
|
+
serializable: 'SERIALIZABLE'
|
25
|
+
}.freeze
|
25
26
|
|
26
27
|
ANSI_ISOLATION_LEVEL = {
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
}
|
28
|
+
'READ UNCOMMITTED' => :read_uncommitted,
|
29
|
+
'READ COMMITTED' => :read_committed,
|
30
|
+
'REPEATABLE READ' => :repeatable_read,
|
31
|
+
'SERIALIZABLE' => :serializable
|
32
|
+
}.freeze
|
32
33
|
|
33
34
|
def current_isolation_level
|
34
35
|
ANSI_ISOLATION_LEVEL[current_vendor_isolation_level]
|
35
36
|
end
|
36
37
|
|
37
38
|
def current_vendor_isolation_level
|
38
|
-
select_value(
|
39
|
+
select_value('SHOW TRANSACTION ISOLATION LEVEL').upcase
|
39
40
|
end
|
40
41
|
|
41
|
-
def isolation_level(
|
42
|
-
validate_isolation_level(
|
42
|
+
def isolation_level(level)
|
43
|
+
validate_isolation_level(level)
|
43
44
|
|
44
45
|
original_vendor_isolation_level = current_vendor_isolation_level if block_given?
|
45
46
|
|
46
47
|
execute "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL #{VENDOR_ISOLATION_LEVEL[level]}"
|
47
48
|
|
49
|
+
return unless block_given?
|
50
|
+
|
48
51
|
begin
|
49
52
|
yield
|
50
53
|
ensure
|
51
54
|
execute "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL #{original_vendor_isolation_level}"
|
52
|
-
end
|
55
|
+
end
|
53
56
|
end
|
54
57
|
|
55
58
|
def translate_exception_with_transaction_isolation_conflict(*args)
|
@@ -64,18 +67,17 @@ if defined?( ActiveRecord::ConnectionAdapters::PostgreSQLAdapter )
|
|
64
67
|
|
65
68
|
ruby2_keywords :translate_exception_with_transaction_isolation_conflict if respond_to?(:ruby2_keywords, true)
|
66
69
|
|
67
|
-
def isolation_conflict?(
|
68
|
-
[
|
69
|
-
|
70
|
-
exception.message =~ /#{Regexp.escape(
|
70
|
+
def isolation_conflict?(exception)
|
71
|
+
['deadlock detected',
|
72
|
+
'could not serialize access'].any? do |error_message|
|
73
|
+
exception.message =~ /#{Regexp.escape(error_message)}/i
|
71
74
|
end
|
72
75
|
end
|
73
|
-
|
74
76
|
end
|
75
77
|
end
|
76
78
|
end
|
77
79
|
end
|
78
80
|
|
79
|
-
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.
|
81
|
+
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.include TransactionIsolation::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
|
80
82
|
|
81
|
-
end
|
83
|
+
end
|
@@ -1,11 +1,12 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
if defined?(ActiveRecord::ConnectionAdapters::SQLite3Adapter)
|
2
4
|
|
3
5
|
module TransactionIsolation
|
4
6
|
module ActiveRecord
|
5
7
|
module ConnectionAdapters # :nodoc:
|
6
8
|
module SQLite3Adapter
|
7
|
-
|
8
|
-
def self.included( base )
|
9
|
+
def self.included(base)
|
9
10
|
base.class_eval do
|
10
11
|
alias_method :translate_exception_without_transaction_isolation_conflict, :translate_exception
|
11
12
|
alias_method :translate_exception, :translate_exception_with_transaction_isolation_conflict
|
@@ -17,37 +18,39 @@ if defined?( ActiveRecord::ConnectionAdapters::SQLite3Adapter )
|
|
17
18
|
end
|
18
19
|
|
19
20
|
VENDOR_ISOLATION_LEVEL = {
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
}
|
21
|
+
read_uncommitted: 'read_uncommitted = 1',
|
22
|
+
read_committed: 'read_uncommitted = 0',
|
23
|
+
repeatable_read: 'read_uncommitted = 0',
|
24
|
+
serializable: 'read_uncommitted = 0'
|
25
|
+
}.freeze
|
25
26
|
|
26
27
|
ANSI_ISOLATION_LEVEL = {
|
27
|
-
|
28
|
-
|
29
|
-
}
|
28
|
+
'read_uncommitted = 1' => :read_uncommitted,
|
29
|
+
'read_uncommitted = 0' => :serializable
|
30
|
+
}.freeze
|
30
31
|
|
31
32
|
def current_isolation_level
|
32
33
|
ANSI_ISOLATION_LEVEL[current_vendor_isolation_level]
|
33
34
|
end
|
34
35
|
|
35
36
|
def current_vendor_isolation_level
|
36
|
-
"read_uncommitted = #{select_value(
|
37
|
+
"read_uncommitted = #{select_value('PRAGMA read_uncommitted')}"
|
37
38
|
end
|
38
39
|
|
39
|
-
def isolation_level(
|
40
|
-
validate_isolation_level(
|
40
|
+
def isolation_level(level)
|
41
|
+
validate_isolation_level(level)
|
41
42
|
|
42
43
|
original_vendor_isolation_level = current_vendor_isolation_level if block_given?
|
43
44
|
|
44
45
|
execute "PRAGMA #{VENDOR_ISOLATION_LEVEL[level]}"
|
45
46
|
|
47
|
+
return unless block_given?
|
48
|
+
|
46
49
|
begin
|
47
50
|
yield
|
48
51
|
ensure
|
49
52
|
execute "PRAGMA #{original_vendor_isolation_level}"
|
50
|
-
end
|
53
|
+
end
|
51
54
|
end
|
52
55
|
|
53
56
|
def translate_exception_with_transaction_isolation_conflict(*args)
|
@@ -63,11 +66,11 @@ if defined?( ActiveRecord::ConnectionAdapters::SQLite3Adapter )
|
|
63
66
|
ruby2_keywords :translate_exception_with_transaction_isolation_conflict if respond_to?(:ruby2_keywords, true)
|
64
67
|
|
65
68
|
# http://www.sqlite.org/c3ref/c_abort.html
|
66
|
-
def isolation_conflict?(
|
67
|
-
[
|
68
|
-
|
69
|
-
|
70
|
-
exception.message =~ /#{Regexp.escape(
|
69
|
+
def isolation_conflict?(exception)
|
70
|
+
['The database file is locked',
|
71
|
+
'A table in the database is locked',
|
72
|
+
'Database lock protocol error'].any? do |error_message|
|
73
|
+
exception.message =~ /#{Regexp.escape(error_message)}/i
|
71
74
|
end
|
72
75
|
end
|
73
76
|
end
|
@@ -75,6 +78,6 @@ if defined?( ActiveRecord::ConnectionAdapters::SQLite3Adapter )
|
|
75
78
|
end
|
76
79
|
end
|
77
80
|
|
78
|
-
ActiveRecord::ConnectionAdapters::SQLite3Adapter.
|
81
|
+
ActiveRecord::ConnectionAdapters::SQLite3Adapter.include TransactionIsolation::ActiveRecord::ConnectionAdapters::SQLite3Adapter
|
79
82
|
|
80
83
|
end
|
@@ -1,16 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module TransactionIsolation
|
2
4
|
class Configuration
|
3
|
-
attr_accessor :mysql_isolation_variable
|
4
|
-
attr_accessor :detect_mysql_isolation_variable
|
5
|
+
attr_accessor :mysql_isolation_variable, :detect_mysql_isolation_variable
|
5
6
|
|
6
7
|
def initialize
|
7
8
|
@mysql_isolation_variable = 'tx_isolation'
|
8
9
|
@detect_mysql_isolation_variable = true
|
9
10
|
end
|
10
11
|
|
11
|
-
def mysql_isolation_variable=(
|
12
|
+
def mysql_isolation_variable=(value)
|
12
13
|
unless value.in? %w[transaction_isolation tx_isolation]
|
13
|
-
raise ArgumentError,
|
14
|
+
raise ArgumentError,
|
15
|
+
"Invalid MySQL isolation variable '#{value}'. Supported variables include 'transaction_isolation' and 'tx_isolation'."
|
14
16
|
end
|
15
17
|
|
16
18
|
@mysql_isolation_variable = value
|
@@ -1,9 +1,10 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_record'
|
2
4
|
require_relative 'transaction_isolation/version'
|
3
5
|
require_relative 'transaction_isolation/configuration'
|
4
6
|
|
5
7
|
module TransactionIsolation
|
6
|
-
|
7
8
|
# Must be called after ActiveRecord established a connection.
|
8
9
|
# Only then we know which connection adapter is actually loaded and can be enhanced.
|
9
10
|
# Please note ActiveRecord does not load unused adapters.
|
@@ -31,21 +32,20 @@ module TransactionIsolation
|
|
31
32
|
config
|
32
33
|
end
|
33
34
|
|
34
|
-
if defined?(
|
35
|
+
if defined?(::Rails)
|
35
36
|
# Setup applying the patch after Rails is initialized.
|
36
37
|
class Railtie < ::Rails::Railtie
|
37
38
|
config.after_initialize do
|
38
39
|
if ActiveRecord::Base.connection.adapter_name == 'Mysql2' && TransactionIsolation.config.detect_mysql_isolation_variable
|
39
40
|
mysql_version = ActiveRecord::Base.connection.select_value('SELECT version()')
|
40
|
-
if mysql_version >= '8'
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
41
|
+
TransactionIsolation.config.mysql_isolation_variable = if mysql_version >= '8'
|
42
|
+
'transaction_isolation'
|
43
|
+
else
|
44
|
+
'tx_isolation'
|
45
|
+
end
|
45
46
|
end
|
46
47
|
TransactionIsolation.apply_activerecord_patch
|
47
48
|
end
|
48
49
|
end
|
49
50
|
end
|
50
|
-
|
51
51
|
end
|
data/test/db/all.rb
CHANGED
data/test/db/db.rb
CHANGED
@@ -1,37 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'fileutils'
|
2
4
|
|
3
5
|
module TransactionIsolation
|
4
6
|
module Test
|
5
7
|
module Db
|
6
|
-
|
7
8
|
def self.connect_to_mysql2
|
8
9
|
::ActiveRecord::Base.establish_connection(
|
9
|
-
:
|
10
|
-
:
|
11
|
-
:
|
12
|
-
:
|
13
|
-
:
|
10
|
+
adapter: 'mysql2',
|
11
|
+
database: ENV['MYSQL_DB_NAME'],
|
12
|
+
host: ENV['MYSQL_DB_HOST'],
|
13
|
+
user: 'root',
|
14
|
+
password: ENV['MYSQL_DB_PASS']
|
14
15
|
)
|
15
16
|
end
|
16
17
|
|
17
18
|
def self.connect_to_postgresql
|
18
19
|
::ActiveRecord::Base.establish_connection(
|
19
|
-
:
|
20
|
-
:
|
21
|
-
:
|
22
|
-
:
|
23
|
-
:
|
20
|
+
adapter: 'postgresql',
|
21
|
+
database: ENV['POSTGRESQL_DB_NAME'],
|
22
|
+
host: ENV['POSTGRESQL_DB_HOST'],
|
23
|
+
user: ENV['POSTGRESQL_DB_USER'],
|
24
|
+
password: ENV['POSTGRESQL_DB_PASS']
|
24
25
|
)
|
25
26
|
end
|
26
27
|
|
27
28
|
def self.connect_to_sqlite3
|
28
29
|
ActiveRecord::Base.establish_connection(
|
29
|
-
:
|
30
|
-
:
|
31
|
-
:
|
30
|
+
adapter: 'sqlite3',
|
31
|
+
database: ':memory:',
|
32
|
+
verbosity: 'silent'
|
32
33
|
)
|
33
34
|
end
|
34
|
-
|
35
35
|
end
|
36
36
|
end
|
37
37
|
end
|
data/test/db/migrations.rb
CHANGED
@@ -1,20 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module TransactionIsolation
|
2
4
|
module Test
|
3
5
|
module Migrations
|
4
|
-
|
5
6
|
def self.run!
|
6
7
|
c = ::ActiveRecord::Base.connection
|
7
8
|
|
8
9
|
# Queued Jobs
|
9
|
-
|
10
|
-
c.create_table
|
11
|
-
t.text
|
12
|
-
t.integer
|
10
|
+
|
11
|
+
c.create_table 'queued_jobs', force: true do |t|
|
12
|
+
t.text 'job', null: false
|
13
|
+
t.integer 'status', default: 0, null: false
|
13
14
|
t.timestamps
|
14
15
|
end
|
15
|
-
|
16
16
|
end
|
17
|
-
|
18
17
|
end
|
19
18
|
end
|
20
19
|
end
|
data/test/db/queued_job.rb
CHANGED
@@ -1,23 +1,17 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'test_helper'
|
4
4
|
|
5
5
|
class ActiveRecordTest < Minitest::Test
|
6
|
-
|
7
6
|
class BaseTest < Minitest::Test
|
8
|
-
|
9
7
|
class IsolationLevelTest < Minitest::Test
|
10
|
-
|
11
8
|
def test_wraps_connection_isolation_level
|
12
|
-
ActiveRecord::Base.isolation_level(
|
9
|
+
ActiveRecord::Base.isolation_level(:serializable) do
|
13
10
|
ActiveRecord::Base.transaction do
|
14
|
-
assert_equal(
|
11
|
+
assert_equal(:serializable, ActiveRecord::Base.connection.current_isolation_level)
|
15
12
|
end
|
16
13
|
end
|
17
14
|
end
|
18
|
-
|
19
15
|
end
|
20
|
-
|
21
16
|
end
|
22
|
-
|
23
17
|
end
|
data/test/integration/active_record/connection_adapters/any_adapter/current_isolation_level_test.rb
CHANGED
@@ -1,33 +1,25 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'test_helper'
|
4
4
|
|
5
5
|
class ActiveRecordTest < Minitest::Test
|
6
|
-
|
7
6
|
class ConnectionAdaptersTest < Minitest::Test
|
8
|
-
|
9
7
|
class AnyAdapterTest < Minitest::Test
|
10
|
-
|
11
8
|
class CurrentIsolationLevelTest < Minitest::Test
|
12
|
-
|
13
9
|
def test_returns_correct_default_isolation_level
|
14
|
-
if defined?(
|
15
|
-
assert_equal(
|
10
|
+
if defined?(ActiveRecord::ConnectionAdapters::Mysql2Adapter)
|
11
|
+
assert_equal(:repeatable_read, ActiveRecord::Base.connection.current_isolation_level)
|
16
12
|
end
|
17
13
|
|
18
|
-
if defined?(
|
19
|
-
assert_equal(
|
14
|
+
if defined?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
|
15
|
+
assert_equal(:read_committed, ActiveRecord::Base.connection.current_isolation_level)
|
20
16
|
end
|
21
17
|
|
22
|
-
|
23
|
-
assert_equal( :serializable, ActiveRecord::Base.connection.current_isolation_level )
|
24
|
-
end
|
25
|
-
end
|
18
|
+
return unless defined?(ActiveRecord::ConnectionAdapters::SQLite3Adapter)
|
26
19
|
|
20
|
+
assert_equal(:serializable, ActiveRecord::Base.connection.current_isolation_level)
|
21
|
+
end
|
27
22
|
end
|
28
|
-
|
29
23
|
end
|
30
|
-
|
31
24
|
end
|
32
|
-
|
33
25
|
end
|
@@ -1,33 +1,25 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'test_helper'
|
4
4
|
|
5
5
|
class ActiveRecordTest < Minitest::Test
|
6
|
-
|
7
6
|
class ConnectionAdaptersTest < Minitest::Test
|
8
|
-
|
9
7
|
class AnyAdapterTest < Minitest::Test
|
10
|
-
|
11
8
|
class CurrentVendorIsolationLevelTest < Minitest::Test
|
12
|
-
|
13
9
|
def test_returns_correct_default_vendor_isolation_level
|
14
|
-
if defined?(
|
15
|
-
assert_equal(
|
10
|
+
if defined?(ActiveRecord::ConnectionAdapters::Mysql2Adapter)
|
11
|
+
assert_equal('REPEATABLE READ', ActiveRecord::Base.connection.current_vendor_isolation_level)
|
16
12
|
end
|
17
13
|
|
18
|
-
if defined?(
|
19
|
-
assert_equal(
|
14
|
+
if defined?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
|
15
|
+
assert_equal('READ COMMITTED', ActiveRecord::Base.connection.current_vendor_isolation_level)
|
20
16
|
end
|
21
17
|
|
22
|
-
|
23
|
-
assert_equal( 'read_uncommitted = 0', ActiveRecord::Base.connection.current_vendor_isolation_level )
|
24
|
-
end
|
25
|
-
end
|
18
|
+
return unless defined?(ActiveRecord::ConnectionAdapters::SQLite3Adapter)
|
26
19
|
|
20
|
+
assert_equal('read_uncommitted = 0', ActiveRecord::Base.connection.current_vendor_isolation_level)
|
21
|
+
end
|
27
22
|
end
|
28
|
-
|
29
23
|
end
|
30
|
-
|
31
24
|
end
|
32
|
-
|
33
25
|
end
|