/
optimistic_locking_spec.rb
114 lines (105 loc) · 3.39 KB
/
optimistic_locking_spec.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
109
110
111
112
113
114
require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
describe "optimistic_locking plugin" do
before do
@c = Class.new(Sequel::Model(:people)) do
end
h = {1=>{:id=>1, :name=>'John', :lock_version=>2}}
lv = @lv = "lock_version"
@c.instance_dataset.numrows = @c.dataset.numrows = proc do |sql|
case sql
when /UPDATE people SET (name|#{lv}) = ('Jim'|'Bob'|\d+), (?:name|#{lv}) = ('Jim'|'Bob'|\d+) WHERE \(\(id = (\d+)\) AND \(#{lv} = (\d+)\)\)/
name, nlv = $1 == 'name' ? [$2, $3] : [$3, $2]
m = h[$4.to_i]
if m && m[:lock_version] == $5.to_i
m.merge!(:name=>name.gsub("'", ''), :lock_version=>nlv.to_i)
1
else
0
end
when /UPDATE people SET #{lv} = (\d+) WHERE \(\(id = (\d+)\) AND \(#{lv} = (\d+)\)\)/
m = h[$2.to_i]
if m && m[:lock_version] == $3.to_i
m.merge!(:lock_version=>$1.to_i)
1
else
0
end
when /DELETE FROM people WHERE \(\(id = (\d+)\) AND \(#{lv} = (\d+)\)\)/
m = h[$1.to_i]
if m && m[lv.to_sym] == $2.to_i
h.delete[$1.to_i]
1
else
0
end
else
puts sql
end
end
@c.dataset._fetch = proc do |sql|
m = h[1].dup
v = m.delete(:lock_version)
m[lv.to_sym] = v
m
end
@c.columns :id, :name, :lock_version
@c.plugin :optimistic_locking
end
specify "should raise an error when updating a stale record" do
p1 = @c[1]
p2 = @c[1]
p1.update(:name=>'Jim')
proc{p2.update(:name=>'Bob')}.should raise_error(Sequel::Plugins::OptimisticLocking::Error)
end
specify "should raise an error when destroying a stale record" do
p1 = @c[1]
p2 = @c[1]
p1.update(:name=>'Jim')
proc{p2.destroy}.should raise_error(Sequel::Plugins::OptimisticLocking::Error)
end
specify "should not raise an error when updating the same record twice" do
p1 = @c[1]
p1.update(:name=>'Jim')
proc{p1.update(:name=>'Bob')}.should_not raise_error
end
specify "should allow changing the lock column via model.lock_column=" do
@lv.replace('lv')
@c.columns :id, :name, :lv
@c.lock_column = :lv
p1 = @c[1]
p2 = @c[1]
p1.update(:name=>'Jim')
proc{p2.update(:name=>'Bob')}.should raise_error(Sequel::Plugins::OptimisticLocking::Error)
end
specify "should allow changing the lock column via plugin option" do
@lv.replace('lv')
@c.columns :id, :name, :lv
@c.plugin :optimistic_locking, :lock_column=>:lv
p1 = @c[1]
p2 = @c[1]
p1.update(:name=>'Jim')
proc{p2.destroy}.should raise_error(Sequel::Plugins::OptimisticLocking::Error)
end
specify "should work when subclassing" do
c = Class.new(@c)
p1 = c[1]
p2 = c[1]
p1.update(:name=>'Jim')
proc{p2.update(:name=>'Bob')}.should raise_error(Sequel::Plugins::OptimisticLocking::Error)
end
specify "should increment the lock column when #modified! even if no columns are changed" do
p1 = @c[1]
p1.modified!
lv = p1.lock_version
p1.save_changes
p1.lock_version.should == lv + 1
end
specify "should not increment the lock column when the update fails" do
@c.instance_dataset.meta_def(:update) { raise Exception }
p1 = @c[1]
p1.modified!
lv = p1.lock_version
proc{p1.save_changes}.should raise_error(Exception)
p1.lock_version.should == lv
end
end