mongo-lock 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,87 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mongo::Lock do
4
+
5
+ describe '.configure' do
6
+
7
+ after :each do
8
+ Mongo::Lock.class_variable_set('@@default_configuration',nil)
9
+ end
10
+
11
+ it "Creates a new configuration" do
12
+ first_configuration = Mongo::Lock.configuration
13
+ Mongo::Lock.configure
14
+ expect(Mongo::Lock.configuration).to_not be first_configuration
15
+ end
16
+
17
+ it "passes on options hash" do
18
+ Mongo::Lock.configure limit: 3
19
+ Mongo::Lock.configure frequency: 4
20
+ expect(Mongo::Lock.configuration.limit).to be 3
21
+ expect(Mongo::Lock.configuration.frequency).to be 4
22
+ end
23
+
24
+ it "passes on block" do
25
+ Mongo::Lock.configure frequency: 4
26
+ Mongo::Lock.configure do |config|
27
+ config.limit = 5
28
+ end
29
+ expect(Mongo::Lock.configuration.limit).to be 5
30
+ expect(Mongo::Lock.configuration.frequency).to be 4
31
+ end
32
+
33
+ context "when provided with nothing" do
34
+
35
+ it "sets default limit" do
36
+ expect(Mongo::Lock.configuration.limit).to be 100
37
+ end
38
+
39
+ it "sets default timeout_in" do
40
+ expect(Mongo::Lock.configuration.timeout_in).to be 10
41
+ end
42
+
43
+ it "sets default frequency" do
44
+ expect(Mongo::Lock.configuration.frequency).to be 1
45
+ end
46
+
47
+ it "sets default expires_after" do
48
+ expect(Mongo::Lock.configuration.expires_after).to be 10
49
+ end
50
+
51
+ it "sets default owner" do
52
+ expect(Mongo::Lock.configuration.owner).to eql "#{`hostname`.strip}:#{Process.pid}:#{Thread.object_id}"
53
+ end
54
+
55
+ it "sets default raise" do
56
+ expect(Mongo::Lock.configuration.raise).to be_false
57
+ end
58
+
59
+ end
60
+
61
+ end
62
+
63
+ describe '#configure' do
64
+
65
+ let(:lock) { Mongo::Lock.new 'my_lock', owner: 'spence' }
66
+
67
+ it "Creates a new configuration" do
68
+ first_configuration = lock.configuration
69
+ lock.configure
70
+ expect(lock.configuration).to_not be first_configuration
71
+ end
72
+
73
+ it "passes on options hash" do
74
+ lock.configure limit: 3
75
+ expect(lock.configuration.limit).to be 3
76
+ end
77
+
78
+ it "passes on block" do
79
+ lock.configure do |config|
80
+ config.limit = 5
81
+ end
82
+ expect(lock.configuration.limit).to be 5
83
+ end
84
+
85
+ end
86
+
87
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mongo::Lock do
4
+
5
+ describe '.ensure_indexes' do
6
+
7
+ context "when provided with a MongoDB collection" do
8
+
9
+ before :each do
10
+ Mongo::Lock.ensure_indexes
11
+ end
12
+
13
+ it "should build ttl index for each collection" do
14
+ expect(collection.index_information['ttl_1']).to eql "v"=>1, "key"=> { "ttl"=>1 }, "ns"=>"mongo_lock_tests.locks", "name"=>"ttl_1", "expireAfterSeconds"=>0
15
+ end
16
+
17
+ it "should build an index on key and expires_at for each collection" do
18
+ expect(collection.index_information['key_1_owner_1_expires_at_1']).to eql "v"=>1, "key"=> { "key"=>1, "owner"=>1, "expires_at"=>1 }, "ns"=>"mongo_lock_tests.locks", "name"=>"key_1_owner_1_expires_at_1"
19
+ end
20
+
21
+ end
22
+
23
+ end
24
+
25
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mongo::Lock do
4
+
5
+ describe '#expired?' do
6
+
7
+ let(:lock) { Mongo::Lock.new 'my_lock', owner: 'spence', timeout_in: 0.01, frequency: 0.01 }
8
+
9
+ context "when the lock has not been acquired" do
10
+
11
+ it "returns false" do
12
+ sleep 0.02
13
+ expect(lock.expired?).to be_false
14
+ end
15
+
16
+ end
17
+
18
+ context "when the lock has expired" do
19
+
20
+ it "returns true" do
21
+ lock.acquire expires_after: 0.01
22
+ sleep 0.02
23
+ expect(lock.expired?).to be_true
24
+ end
25
+
26
+ end
27
+
28
+ context "when the lock hasn't expired" do
29
+
30
+ it "returns false" do
31
+ lock.acquire expires_after: 0.02
32
+ sleep 0.01
33
+ expect(lock.expired?).to be_false
34
+ end
35
+
36
+ end
37
+
38
+ end
39
+
40
+ end
@@ -0,0 +1,133 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mongo::Lock do
4
+
5
+ let(:lock) { Mongo::Lock.new 'my_lock', owner: 'spence', timeout_in: 0.01, frequency: 0.01, expires_after: 0.01 }
6
+
7
+ describe '#extend_by' do
8
+
9
+ context "when a time is provided" do
10
+
11
+ it "extends the lock" do
12
+ lock.acquire
13
+ lock.extend_by 60
14
+ expect(collection.find(owner: 'spence', key: 'my_lock').first['expires_at']).to be_within(1.second).of(60.seconds.from_now)
15
+ end
16
+
17
+ it "returns true" do
18
+ lock.acquire
19
+ expect(lock.extend_by 50).to be_true
20
+ end
21
+
22
+ end
23
+
24
+ context "when the lock has expired" do
25
+
26
+ it "returns false" do
27
+ lock.acquire
28
+ sleep 0.02
29
+ expect(lock.extend_by 10).to be_false
30
+ end
31
+
32
+ end
33
+
34
+ context "when the lock has not been aquired yet" do
35
+
36
+ it "returns false" do
37
+ lock
38
+ expect(lock.extend_by 10).to be_false
39
+ end
40
+
41
+ end
42
+
43
+ context "when the lock has been released" do
44
+
45
+ it "returns false" do
46
+ lock.acquire
47
+ lock.release
48
+ expect(lock.extend_by 10).to be_false
49
+ end
50
+
51
+ end
52
+
53
+ context "when the raise option is set to true" do
54
+
55
+ let(:lock) { Mongo::Lock.new 'my_lock', owner: 'spence', timeout_in: 0.01, frequency: 0.01, expires_after: 0.01, raise: true }
56
+
57
+ context "and the lock has expired" do
58
+
59
+ it "raises a Mongo::Lock::NotExtendedError" do
60
+ lock.acquire
61
+ sleep 0.02
62
+ expect{lock.extend_by 10}.to raise_error Mongo::Lock::NotExtendedError
63
+ end
64
+
65
+ end
66
+
67
+ context "and the lock has not been aquired yet" do
68
+
69
+ it "raises a Mongo::Lock::NotExtendedError" do
70
+ lock
71
+ expect{lock.extend_by 10}.to raise_error Mongo::Lock::NotExtendedError
72
+ end
73
+
74
+ end
75
+
76
+ context "and the lock has been released" do
77
+
78
+ it "raises a Mongo::Lock::NotExtendedError" do
79
+ lock.acquire
80
+ lock.release
81
+ expect{lock.extend_by 10}.to raise_error Mongo::Lock::NotExtendedError
82
+ end
83
+
84
+ end
85
+
86
+ end
87
+
88
+ context "when options are provided" do
89
+
90
+ let(:lock) { Mongo::Lock.new 'my_lock', owner: 'spence', timeout_in: 0.01, frequency: 0.01, raise: true }
91
+
92
+ it "they override the defaults" do
93
+ lock
94
+ expect(lock.extend_by 10, raise: false).to be_false
95
+ end
96
+
97
+ end
98
+
99
+ end
100
+
101
+ describe '#extend' do
102
+
103
+ it "calls #extend_by with the default expires_after config setting" do
104
+ expect(lock).to receive(:extend_by).with(lock.configuration.expires_after, {})
105
+ lock.extend
106
+ end
107
+
108
+ it "also passes options on" do
109
+ expect(lock).to receive(:extend_by).with(lock.configuration.expires_after, { raise: true })
110
+ lock.extend raise: true
111
+ end
112
+
113
+ end
114
+
115
+ describe '.extend_by!' do
116
+
117
+ it "calls .extend_by with raise errors option set to true" do
118
+ expect(lock).to receive(:extend_by).with( 10, { raise: true })
119
+ lock.extend_by! 10
120
+ end
121
+
122
+ end
123
+
124
+ describe '#extend!' do
125
+
126
+ it "calls .extend with raise errors option set to true" do
127
+ expect(lock).to receive(:extend_by).with(lock.configuration.expires_after, { raise: true })
128
+ lock.extend!
129
+ end
130
+
131
+ end
132
+
133
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mongo::Lock do
4
+
5
+ describe '#initialise' do
6
+
7
+ let(:lock) { Mongo::Lock.new 'my_lock', owner: 'spence', timeout_in: 0.01, frequency: 0.01 }
8
+
9
+ it "creates a new configuration object" do
10
+ expect(lock.configuration).to be_a Mongo::Lock::Configuration
11
+ end
12
+
13
+ it "passes it the class configuration" do
14
+ Mongo::Lock.configure limit: 3
15
+ expect(lock.configuration.limit).to be 3
16
+ end
17
+
18
+ it "allows override of the class configuration" do
19
+ Mongo::Lock.configure limit: 3
20
+ lock = Mongo::Lock.new 'my_lock', limit: 4
21
+ expect(lock.configuration.limit).to be 4
22
+
23
+ end
24
+
25
+ context "when the key is already acquired by this owner" do
26
+
27
+ it "acquires that lock" do
28
+ collection.insert key: 'my_lock', owner: 'spence', expires_at: 1.minute.from_now
29
+ expect(lock.acquired?).to be_true
30
+ end
31
+
32
+ end
33
+
34
+ end
35
+
36
+ end
@@ -0,0 +1,78 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mongo::Lock do
4
+
5
+ describe '.release_all' do
6
+
7
+ before :each do
8
+ Mongo::Lock.configure collections: { default: collection, other: other_collection }
9
+ end
10
+
11
+ let!(:locks) do
12
+ collection.insert key: 'tobies_lock', owner: 'tobie'
13
+ collection.insert key: 'spences_lock', owner: 'spence'
14
+ other_collection.insert key: 'spences_lock', owner: 'spence'
15
+ end
16
+
17
+ it "removes all locks from the database" do
18
+ Mongo::Lock.release_all
19
+ expect(collection.count({ key: 'spences_lock', owner: 'spence'})).to eql 0
20
+ expect(collection.count({ key: 'tobies_lock', owner: 'tobie'})).to eql 0
21
+ expect(other_collection.count({ key: 'spences_lock', owner: 'spence'})).to eql 0
22
+ end
23
+
24
+ context "when an owner is provided" do
25
+
26
+ before do
27
+ Mongo::Lock.release_all owner: 'spence'
28
+ end
29
+
30
+ it "doesn't release locks belonging to other owners" do
31
+ expect(collection.find({ key: 'tobies_lock', owner: 'tobie'}).count).to eql 1
32
+ end
33
+
34
+ it "does release locks belonging to that owner" do
35
+ Mongo::Lock.release_all owner: 'spence'
36
+ expect(collection.find({ key: 'spences_lock', owner: 'spence'}).count).to eql 0
37
+ expect(other_collection.find({ key: 'spences_lock', owner: 'spence'}).count).to eql 0
38
+ end
39
+
40
+ end
41
+
42
+ context "when a collection symbol is provided" do
43
+
44
+ before do
45
+ Mongo::Lock.release_all collection: :other
46
+ end
47
+
48
+ it "does release locks in that collection" do
49
+ expect(other_collection.find({ key: 'spences_lock', owner: 'spence'}).count).to eql 0
50
+ end
51
+
52
+ it "doesn't release locks in other collections" do
53
+ expect(collection.find({ key: 'spences_lock', owner: 'spence'}).count).to eql 1
54
+ expect(collection.find({ key: 'tobies_lock', owner: 'tobie'}).count).to eql 1
55
+ end
56
+
57
+ end
58
+
59
+ context "when a collection is provided" do
60
+
61
+ before do
62
+ Mongo::Lock.release_all collection: other_collection
63
+ end
64
+
65
+ it "does release locks in that collection" do
66
+ expect(other_collection.find({ key: 'spences_lock', owner: 'spence'}).count).to eql 0
67
+ end
68
+
69
+ it "doesn't release locks in other collections" do
70
+ expect(collection.find({ key: 'spences_lock', owner: 'spence'}).count).to eql 1
71
+ expect(collection.find({ key: 'tobies_lock', owner: 'tobie'}).count).to eql 1
72
+ end
73
+
74
+ end
75
+
76
+ end
77
+
78
+ end
@@ -0,0 +1,164 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mongo::Lock do
4
+
5
+ let(:lock) { Mongo::Lock.acquire('my_lock', owner: 'spence', expires_after: 0.1.seconds, timeout_in: 0.01, frequency: 0.01) }
6
+
7
+ describe '.release' do
8
+
9
+ it "creates a new Mongo::Lock instance" do
10
+ lock
11
+ expect(Mongo::Lock.release 'my_lock', owner: 'spence').to be_a Mongo::Lock
12
+ end
13
+
14
+ it "calls #release to release the lock" do
15
+ expect_any_instance_of(Mongo::Lock).to receive(:release)
16
+ Mongo::Lock.release 'my_lock', owner: 'spence'
17
+ end
18
+
19
+ context "when options are provided" do
20
+
21
+ it "passes them to the new lock" do
22
+ l = Mongo::Lock.release 'my_lock', owner: 'spence'
23
+ # expect(l.configuration.owner).to eql 'spence'
24
+ end
25
+
26
+ end
27
+
28
+ end
29
+
30
+ describe '#release' do
31
+
32
+ context "when lock is acquired" do
33
+
34
+ before :each do
35
+ collection.insert key: 'my_lock', owner: 'spence'
36
+ end
37
+
38
+ let(:lock) { Mongo::Lock.acquire 'my_lock', owner: 'spence' }
39
+
40
+ it "releases the lock" do
41
+ lock.release
42
+ expect(collection.find(key: 'my_lock', owner: 'spence').count).to be 0
43
+ end
44
+
45
+ it "returns true" do
46
+ expect(lock.release).to be_true
47
+ end
48
+
49
+ end
50
+
51
+ context "when the lock isn't acquired" do
52
+
53
+ let(:lock) { Mongo::Lock.new 'my_lock', timeout_in: 0.01, frequency: 0.01 }
54
+
55
+ it "acquires the lock first" do
56
+ expect(lock).to receive(:acquire).and_call_original
57
+ lock.release
58
+ end
59
+
60
+ it "returns true" do
61
+ expect(lock.release).to be_true
62
+ end
63
+
64
+ end
65
+
66
+ context "when the lock isn't acquired and cant be" do
67
+
68
+ let(:lock) { Mongo::Lock.new 'my_lock', timeout_in: 1, frequency: 0.01 }
69
+
70
+ it "returns false" do
71
+ collection.insert key: 'my_lock', owner: 'tobie', expires_at: 1.seconds.from_now
72
+ expect(lock.release timeout_in: 0.01).to be_false
73
+ end
74
+
75
+ it "doesn't release the lock" do
76
+ collection.insert key: 'my_lock', owner: 'tobie', expires_at: 1.seconds.from_now
77
+ lock.release timeout_in: 0.01
78
+ expect(collection.find(key: 'my_lock', owner: 'tobie').count).to be 1
79
+ end
80
+
81
+ end
82
+
83
+ context "when the lock was acquired but has since expired" do
84
+
85
+ it "returns true" do
86
+ lock
87
+ sleep 0.2
88
+ expect(lock.release).to be_true
89
+ end
90
+
91
+ end
92
+
93
+ context "when the lock was acquired but has already been released" do
94
+
95
+ it "returns true" do
96
+ lock.release
97
+ expect(lock.release).to be_true
98
+ end
99
+
100
+ end
101
+
102
+ context "when the lock is already acquired but by the same owner in a different instance" do
103
+
104
+ let (:different_instance) { Mongo::Lock.release 'my_lock', owner: 'spence' }
105
+
106
+ it "releases the lock" do
107
+ lock
108
+ different_instance.release
109
+ expect(collection.find(key: 'my_lock', owner: 'spence').count).to be 0
110
+ end
111
+
112
+ it "returns true" do
113
+ lock
114
+ expect(different_instance.release).to be_true
115
+ end
116
+
117
+ end
118
+
119
+ context "when the raise option is set to true" do
120
+
121
+ let(:lock) { Mongo::Lock.new 'my_lock', raise: true, timeout_in: 0.1, frequency: 0.01 }
122
+
123
+ context "when the lock isn't acquired and cant be" do
124
+
125
+ it "raises Mongo::Lock::NotReleasedError" do
126
+ collection.insert key: 'my_lock', owner: 'tobie', expires_at: 1.seconds.from_now
127
+ expect{ lock.release }.to raise_error Mongo::Lock::NotReleasedError
128
+ end
129
+
130
+ end
131
+
132
+ end
133
+
134
+ context "when options are provided" do
135
+
136
+ it "they override the defaults" do
137
+ collection.insert key: 'my_lock', owner: 'tobie', expires_at: 1.seconds.from_now
138
+ expect(lock.release owner: 'tobie').to be_true
139
+ expect(collection.find(key: 'my_lock', owner: 'tobie').count).to be 0
140
+ end
141
+
142
+ end
143
+
144
+ end
145
+
146
+ describe '.release!' do
147
+
148
+ it "calls .release with raise errors option set to true" do
149
+ expect(Mongo::Lock).to receive(:init_and_send).with('my_lock', { owner: 'tobie' }, :release!)
150
+ Mongo::Lock.release! 'my_lock', owner: 'tobie'
151
+ end
152
+
153
+ end
154
+
155
+ describe '#release!' do
156
+
157
+ it "calls .release with raise errors option set to true" do
158
+ expect(lock).to receive(:release).with({ limit: 3, raise: true })
159
+ lock.release! limit: 3
160
+ end
161
+
162
+ end
163
+
164
+ end