mongo-lock 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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