forked from rails/deadlock_retry
-
Notifications
You must be signed in to change notification settings - Fork 28
/
deadlock_retry_test.rb
108 lines (85 loc) · 2.6 KB
/
deadlock_retry_test.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
require 'rubygems'
# Change the version if you want to test a different version of ActiveRecord
gem 'activerecord', '3.0.7'
require 'active_record'
require 'active_record/version'
puts "Testing ActiveRecord #{ActiveRecord::VERSION::STRING}"
require 'test/unit'
require 'logger'
require "deadlock_retry"
class MockModel
@@open_transactions = 0
def self.transaction(*objects)
@@open_transactions += 1
yield
ensure
@@open_transactions -= 1
end
def self.open_transactions
@@open_transactions
end
def self.connection
self
end
def self.logger
@logger ||= Logger.new(nil)
end
def self.show_innodb_status
[]
end
def self.reset_innodb_status_availability
DeadlockRetry.innodb_status_availability = nil
end
include DeadlockRetry
end
class DeadlockRetryTest < Test::Unit::TestCase
DEADLOCK_ERROR = "MySQL::Error: Deadlock found when trying to get lock"
TIMEOUT_ERROR = "MySQL::Error: Lock wait timeout exceeded"
def setup
end
def test_no_errors
assert_equal :success, MockModel.transaction { :success }
end
def test_no_errors_with_deadlock
errors = [ DEADLOCK_ERROR ] * 3
assert_equal :success, MockModel.transaction { raise ActiveRecord::StatementInvalid, errors.shift unless errors.empty?; :success }
assert errors.empty?
end
def test_no_errors_with_lock_timeout
errors = [ TIMEOUT_ERROR ] * 3
assert_equal :success, MockModel.transaction { raise ActiveRecord::StatementInvalid, errors.shift unless errors.empty?; :success }
assert errors.empty?
end
def test_error_if_limit_exceeded
assert_raise(ActiveRecord::StatementInvalid) do
MockModel.transaction { raise ActiveRecord::StatementInvalid, DEADLOCK_ERROR }
end
end
def test_error_if_unrecognized_error
assert_raise(ActiveRecord::StatementInvalid) do
MockModel.transaction { raise ActiveRecord::StatementInvalid, "Something else" }
end
end
def test_included_by_default
assert ActiveRecord::Base.respond_to?(:transaction_with_deadlock_handling)
end
def test_innodb_status_availability
DeadlockRetry.innodb_status_available = nil
MockModel.transaction {}
assert_equal true, DeadlockRetry.innodb_status_available?
end
def test_error_in_nested_transaction_should_retry_outermost_transaction
tries = 0
errors = 0
MockModel.transaction do
tries += 1
MockModel.transaction do
MockModel.transaction do
errors += 1
raise ActiveRecord::StatementInvalid, "MySQL::Error: Lock wait timeout exceeded" unless errors > 3
end
end
end
assert_equal 4, tries
end
end