mongo-lock 1.1.4 → 1.2.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.
Files changed (39) hide show
  1. checksums.yaml +8 -8
  2. data/Gemfile.lock +41 -38
  3. data/README.md +7 -4
  4. data/lib/mongo-lock.rb +22 -37
  5. data/lib/mongo-lock/configuration.rb +38 -4
  6. data/lib/mongo-lock/drivers/base.rb +41 -0
  7. data/lib/mongo-lock/drivers/mongo.rb +99 -0
  8. data/lib/mongo-lock/drivers/moped.rb +62 -0
  9. data/lib/mongo-lock/send_with_raise_methods.rb +28 -0
  10. data/lib/mongo-lock/version.rb +1 -1
  11. data/mongo-lock.gemspec +4 -3
  12. data/spec/configuration_spec.rb +66 -0
  13. data/spec/configure_spec.rb +8 -2
  14. data/spec/examples/acquire_example.rb +219 -0
  15. data/spec/examples/acquired_example.rb +54 -0
  16. data/spec/examples/available_example.rb +70 -0
  17. data/spec/examples/clear_expired_example.rb +100 -0
  18. data/spec/examples/ensure_indexes_example.rb +38 -0
  19. data/spec/examples/expired_example.rb +41 -0
  20. data/spec/examples/extend_by_example.rb +137 -0
  21. data/spec/examples/release_all_example.rb +117 -0
  22. data/spec/examples/release_example.rb +166 -0
  23. data/spec/initialise_spec.rb +2 -0
  24. data/spec/mongo_driver_spec.rb +22 -0
  25. data/spec/moped_driver_spec.rb +22 -0
  26. data/spec/rake_spec.rb +1 -1
  27. data/spec/spec_helper.rb +2 -7
  28. data/spec/support/mongo_helper.rb +41 -0
  29. metadata +58 -23
  30. data/lib/mongo-lock/mongo_queries.rb +0 -97
  31. data/spec/acquire_spec.rb +0 -217
  32. data/spec/acquired_spec.rb +0 -53
  33. data/spec/available_spec.rb +0 -68
  34. data/spec/clear_expired_spec.rb +0 -98
  35. data/spec/ensure_indexes_spec.rb +0 -34
  36. data/spec/expired_spec.rb +0 -39
  37. data/spec/extend_by_spec.rb +0 -135
  38. data/spec/release_all_spec.rb +0 -115
  39. data/spec/release_spec.rb +0 -164
@@ -0,0 +1,54 @@
1
+ shared_examples "MongoLock driver that can find if a lock is acquired" do
2
+
3
+ describe Mongo::Lock do
4
+
5
+ describe '#acquired?' 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 been acquired" do
10
+
11
+ it "returns true" do
12
+ lock.acquire
13
+ expect(lock.acquired?).to be_true
14
+ end
15
+
16
+ end
17
+
18
+ context "when the lock hasn't been acquired" do
19
+
20
+ it "returns false" do
21
+ my_collection.insert key: 'my_lock', owner: 'tobie', expires_at: 1.minute.from_now
22
+ lock.acquire
23
+ expect(lock.acquired?).to be_false
24
+ end
25
+
26
+ end
27
+
28
+ context "when the lock was acquired but has since expired" do
29
+
30
+ let(:lock) { Mongo::Lock.new 'my_lock', owner: 'spence', timeout_in: 0.01, frequency: 0.01, expire_in: 0.1 }
31
+
32
+ it "returns false" do
33
+ lock.acquire
34
+ sleep 0.2
35
+ expect(lock.acquired?).to be_false
36
+ end
37
+
38
+ end
39
+
40
+ context "when the lock was acquired but has since been released" do
41
+
42
+ it "returns false" do
43
+ my_collection.insert key: 'my_lock', owner: 'tobie', expires_at: 1.minute.ago
44
+ lock.acquire
45
+ lock.release
46
+ expect(lock.acquired?).to be_false
47
+ end
48
+
49
+ end
50
+
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,70 @@
1
+ shared_examples "MongoLock driver that can find if a lock is available" do
2
+
3
+ describe Mongo::Lock do
4
+
5
+ describe '.available?' do
6
+
7
+ it "creates a new Mongo::Lock instance and returns whether it is available" do
8
+ expect(Mongo::Lock.available? 'my_lock').to be_true
9
+ end
10
+
11
+ it "calls #available?" do
12
+ expect_any_instance_of(Mongo::Lock).to receive(:available?)
13
+ Mongo::Lock.available? 'my_lock'
14
+ end
15
+
16
+ context "when options are provided" do
17
+
18
+ it "passes them to the new lock" do
19
+ Mongo::Lock.acquire 'my_lock', { owner: 'spence' }
20
+ expect(Mongo::Lock.available?('my_lock', { owner: 'spence' })).to be_true
21
+ end
22
+
23
+ end
24
+
25
+ end
26
+
27
+ describe '#available?' do
28
+
29
+ let(:lock) { Mongo::Lock.new 'my_lock', owner: 'spence', timeout_in: 0.01, frequency: 0.01 }
30
+
31
+ context "when the lock is available" do
32
+
33
+ it "returns true" do
34
+ expect(lock.available?).to be_true
35
+ end
36
+
37
+ end
38
+
39
+ context "when the lock is expired" do
40
+
41
+ it "returns true" do
42
+ my_collection.insert key: 'my_lock', owner: 'tobie', expires_at: 1.minute.ago
43
+ expect(lock.available?).to be_true
44
+ end
45
+
46
+ end
47
+
48
+ context "when the lock is already acquired but by this owner" do
49
+
50
+ it "returns true" do
51
+ my_collection.insert key: 'my_lock', owner: 'spence', expires_at: 1.minute.from_now
52
+ expect(lock.available?).to be_true
53
+ end
54
+
55
+ end
56
+
57
+ context "when the lock is already acquired" do
58
+
59
+ it "returns false" do
60
+ my_collection.insert key: 'my_lock', owner: 'tobie', expires_at: 1.minute.from_now
61
+ expect(lock.available?).to be_false
62
+ end
63
+
64
+ end
65
+
66
+ end
67
+
68
+ end
69
+
70
+ end
@@ -0,0 +1,100 @@
1
+ shared_examples "MongoLock driver that can clear expired locks" do
2
+
3
+ describe Mongo::Lock do
4
+
5
+ describe '.clear_expired' do
6
+
7
+ before :each do
8
+ Mongo::Lock.configure collections: { default: collection1, other: collection2 }
9
+ end
10
+
11
+ let!(:locks) do
12
+ my_collection.insert key: 'tobies_lock', owner: 'tobie', expires_at: 1.minute.from_now, ttl: 1.minute.from_now
13
+ my_collection.insert key: 'spences_lock', owner: 'spence', expires_at: 1.minute.ago, ttl: 1.minute.ago
14
+ other_collection.insert key: 'spences_lock', owner: 'spence', expires_at: 1.minute.ago, ttl: 1.minute.ago
15
+ another_collection.insert key: 'spences_lock', owner: 'spence', expires_at: 1.minute.ago, ttl: 1.minute.ago
16
+ end
17
+
18
+ it "deletes expired locks in all reegistered collections" do
19
+ Mongo::Lock.configure collections: { default: collection1, other: collection2 }
20
+ other_collection.insert owner: 'owner', key: 'my_lock', expires_at: 1.minute.from_now
21
+ Mongo::Lock.clear_expired
22
+ expect(my_collection.find().count).to be 1
23
+ expect(other_collection.find().count).to be 1
24
+ end
25
+
26
+ context "when a collection is provided" do
27
+
28
+ before do
29
+ Mongo::Lock.clear_expired collection: collection2
30
+ end
31
+
32
+ it "does release locks in that collection" do
33
+ expect(other_collection.find({ key: 'spences_lock', owner: 'spence'}).count).to eql 0
34
+ end
35
+
36
+ it "doesn't release locks in other collections" do
37
+ expect(my_collection.find({ key: 'spences_lock', owner: 'spence'}).count).to eql 1
38
+ expect(my_collection.find({ key: 'tobies_lock', owner: 'tobie'}).count).to eql 1
39
+ end
40
+
41
+ end
42
+
43
+ context "when a collection symbol is provided" do
44
+
45
+ before do
46
+ Mongo::Lock.clear_expired collection: :other
47
+ end
48
+
49
+ it "does release locks in that collection" do
50
+ expect(other_collection.find({ key: 'spences_lock', owner: 'spence'}).count).to eql 0
51
+ end
52
+
53
+ it "doesn't release locks in other collections" do
54
+ expect(my_collection.find({ key: 'spences_lock', owner: 'spence'}).count).to eql 1
55
+ expect(my_collection.find({ key: 'tobies_lock', owner: 'tobie'}).count).to eql 1
56
+ end
57
+
58
+ end
59
+
60
+ context "when collections are provided" do
61
+
62
+ before do
63
+ Mongo::Lock.clear_expired collections: [collection3, collection2]
64
+ end
65
+
66
+ it "does release locks in those collection" do
67
+ expect(other_collection.find({ key: 'spences_lock', owner: 'spence'}).count).to eql 0
68
+ expect(another_collection.find({ key: 'spences_lock', owner: 'spence'}).count).to eql 0
69
+ end
70
+
71
+ it "doesn't release locks in other collections" do
72
+ expect(my_collection.find({ key: 'spences_lock', owner: 'spence'}).count).to eql 1
73
+ expect(my_collection.find({ key: 'tobies_lock', owner: 'tobie'}).count).to eql 1
74
+ end
75
+
76
+ context "when collections is provided as a hash" do
77
+
78
+ before do
79
+ Mongo::Lock.clear_expired collections: { another_collection: collection3, other_collection: collection2 }
80
+ end
81
+
82
+ it "does release locks in those collection" do
83
+ expect(other_collection.find({ key: 'spences_lock', owner: 'spence'}).count).to eql 0
84
+ expect(another_collection.find({ key: 'spences_lock', owner: 'spence'}).count).to eql 0
85
+ end
86
+
87
+ it "doesn't release locks in other collections" do
88
+ expect(my_collection.find({ key: 'spences_lock', owner: 'spence'}).count).to eql 1
89
+ expect(my_collection.find({ key: 'tobies_lock', owner: 'tobie'}).count).to eql 1
90
+ end
91
+
92
+ end
93
+
94
+ end
95
+
96
+ end
97
+
98
+ end
99
+
100
+ end
@@ -0,0 +1,38 @@
1
+ shared_examples "MongoLock driver that can ensure indexes" do
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
+ sleep 0.1
15
+ expect(my_collection.index_information['ttl_1']).to eql "v"=>1, "key"=> { "ttl"=>1 }, "ns"=>"mongo_lock_tests.locks", "name"=>"ttl_1", "expireAfterSeconds"=>0
16
+ end
17
+
18
+ it "should build an index on key and expires_at for each collection" do
19
+ sleep 0.1
20
+ expect(my_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"
21
+ end
22
+
23
+ it "should mean expired locks are automatically cleaned", :slow do
24
+ Mongo::Lock.acquire 'my_lock', owner: 'spence', expire_in: 0
25
+ Mongo::Lock.acquire 'other_lock', owner: 'spence', expire_in: 500
26
+ while my_collection.find(owner: 'spence').count != 1
27
+ sleep 1
28
+ end
29
+ expect(my_collection.find(owner: 'spence').count).to be 1
30
+ end
31
+
32
+ end
33
+
34
+ end
35
+
36
+ end
37
+
38
+ end
@@ -0,0 +1,41 @@
1
+ shared_examples "MongoLock driver that can find if a lock have expired" do
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 expire_in: 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 expire_in: 0.1
32
+ expect(lock.expired?).to be_false
33
+ end
34
+
35
+ end
36
+
37
+ end
38
+
39
+ end
40
+
41
+ end
@@ -0,0 +1,137 @@
1
+ shared_examples "MongoLock driver that can extend locks" do
2
+
3
+ describe Mongo::Lock do
4
+
5
+ let(:lock) { Mongo::Lock.new 'my_lock', owner: 'spence', timeout_in: 0.01, frequency: 0.01, expire_in: 1 }
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(my_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
+ let(:lock) { Mongo::Lock.new 'my_lock', owner: 'spence', timeout_in: 0.01, frequency: 0.01, expire_in: 0.11 }
27
+
28
+ it "returns false" do
29
+ lock.acquire
30
+ sleep 0.11
31
+ expect(lock.extend_by 10).to be_false
32
+ end
33
+
34
+ end
35
+
36
+ context "when the lock has not been aquired yet" do
37
+
38
+ it "returns false" do
39
+ lock
40
+ expect(lock.extend_by 10).to be_false
41
+ end
42
+
43
+ end
44
+
45
+ context "when the lock has been released" do
46
+
47
+ it "returns false" do
48
+ lock.acquire
49
+ lock.release
50
+ expect(lock.extend_by 10).to be_false
51
+ end
52
+
53
+ end
54
+
55
+ context "when the raise option is set to true" do
56
+
57
+ let(:lock) { Mongo::Lock.new 'my_lock', owner: 'spence', timeout_in: 0.01, frequency: 0.01, expire_in: 0.01, should_raise: true }
58
+
59
+ context "and the lock has expired" do
60
+
61
+ it "raises a Mongo::Lock::NotExtendedError" do
62
+ lock.acquire
63
+ sleep 0.02
64
+ expect{lock.extend_by 10}.to raise_error Mongo::Lock::NotExtendedError
65
+ end
66
+
67
+ end
68
+
69
+ context "and the lock has not been aquired yet" do
70
+
71
+ it "raises a Mongo::Lock::NotExtendedError" do
72
+ lock
73
+ expect{lock.extend_by 10}.to raise_error Mongo::Lock::NotExtendedError
74
+ end
75
+
76
+ end
77
+
78
+ context "and the lock has been released" do
79
+
80
+ it "raises a Mongo::Lock::NotExtendedError" do
81
+ lock.acquire
82
+ lock.release
83
+ expect{lock.extend_by 10}.to raise_error Mongo::Lock::NotExtendedError
84
+ end
85
+
86
+ end
87
+
88
+ end
89
+
90
+ context "when options are provided" do
91
+
92
+ let(:lock) { Mongo::Lock.new 'my_lock', owner: 'spence', timeout_in: 0.01, frequency: 0.01, should_raise: true }
93
+
94
+ it "they override the defaults" do
95
+ lock
96
+ expect(lock.extend_by 10, should_raise: false).to be_false
97
+ end
98
+
99
+ end
100
+
101
+ end
102
+
103
+ describe '#extend' do
104
+
105
+ it "calls #extend_by with the default expire_in config setting" do
106
+ expect(lock).to receive(:extend_by).with(lock.configuration.expire_in, {})
107
+ lock.extend
108
+ end
109
+
110
+ it "also passes options on" do
111
+ expect(lock).to receive(:extend_by).with(lock.configuration.expire_in, { should_raise: true })
112
+ lock.extend should_raise: true
113
+ end
114
+
115
+ end
116
+
117
+ describe '.extend_by!' do
118
+
119
+ it "calls .extend_by with raise errors option set to true" do
120
+ expect(lock).to receive(:extend_by).with( 10, { should_raise: true })
121
+ lock.extend_by! 10
122
+ end
123
+
124
+ end
125
+
126
+ describe '#extend!' do
127
+
128
+ it "calls .extend with raise errors option set to true" do
129
+ expect(lock).to receive(:extend_by).with(lock.configuration.expire_in, { should_raise: true })
130
+ lock.extend!
131
+ end
132
+
133
+ end
134
+
135
+ end
136
+
137
+ end
@@ -0,0 +1,117 @@
1
+ shared_examples "MongoLock driver that can release all locks" do
2
+
3
+ describe Mongo::Lock do
4
+
5
+ describe '.release_all' do
6
+
7
+ before :each do
8
+ Mongo::Lock.configure collections: { default: collection1, other: collection2 }
9
+ end
10
+
11
+ let!(:locks) do
12
+ my_collection.insert key: 'tobies_lock', owner: 'tobie'
13
+ my_collection.insert key: 'spences_lock', owner: 'spence'
14
+ other_collection.insert key: 'spences_lock', owner: 'spence'
15
+ another_collection.insert key: 'spences_lock', owner: 'spence'
16
+ end
17
+
18
+ it "removes all locks from the database" do
19
+ Mongo::Lock.release_all
20
+ expect(my_collection.count({ key: 'spences_lock', owner: 'spence'})).to eql 0
21
+ expect(my_collection.count({ key: 'tobies_lock', owner: 'tobie'})).to eql 0
22
+ expect(other_collection.count({ key: 'spences_lock', owner: 'spence'})).to eql 0
23
+ end
24
+
25
+ context "when an owner is provided" do
26
+
27
+ before do
28
+ Mongo::Lock.release_all owner: 'spence'
29
+ end
30
+
31
+ it "doesn't release locks belonging to other owners" do
32
+ expect(my_collection.find({ key: 'tobies_lock', owner: 'tobie'}).count).to eql 1
33
+ end
34
+
35
+ it "does release locks belonging to that owner" do
36
+ Mongo::Lock.release_all owner: 'spence'
37
+ expect(my_collection.find({ key: 'spences_lock', owner: 'spence'}).count).to eql 0
38
+ expect(other_collection.find({ key: 'spences_lock', owner: 'spence'}).count).to eql 0
39
+ end
40
+
41
+ end
42
+
43
+ context "when a collection symbol is provided" do
44
+
45
+ before do
46
+ Mongo::Lock.release_all collection: :other
47
+ end
48
+
49
+ it "does release locks in that collection" do
50
+ expect(other_collection.find({ key: 'spences_lock', owner: 'spence'}).count).to eql 0
51
+ end
52
+
53
+ it "doesn't release locks in other collections" do
54
+ expect(my_collection.find({ key: 'spences_lock', owner: 'spence'}).count).to eql 1
55
+ expect(my_collection.find({ key: 'tobies_lock', owner: 'tobie'}).count).to eql 1
56
+ end
57
+
58
+ end
59
+
60
+ context "when a collection is provided" do
61
+
62
+ before do
63
+ Mongo::Lock.release_all collection: collection2
64
+ end
65
+
66
+ it "does release locks in that collection" do
67
+ expect(other_collection.find({ key: 'spences_lock', owner: 'spence'}).count).to eql 0
68
+ end
69
+
70
+ it "doesn't release locks in other collections" do
71
+ expect(my_collection.find({ key: 'spences_lock', owner: 'spence'}).count).to eql 1
72
+ expect(my_collection.find({ key: 'tobies_lock', owner: 'tobie'}).count).to eql 1
73
+ end
74
+
75
+ end
76
+
77
+ context "when collections are provided" do
78
+
79
+ before do
80
+ Mongo::Lock.release_all collections: [collection3, collection2]
81
+ end
82
+
83
+ it "does release locks in those collection" do
84
+ expect(other_collection.find({ key: 'spences_lock', owner: 'spence'}).count).to eql 0
85
+ expect(another_collection.find({ key: 'spences_lock', owner: 'spence'}).count).to eql 0
86
+ end
87
+
88
+ it "doesn't release locks in other collections" do
89
+ expect(my_collection.find({ key: 'spences_lock', owner: 'spence'}).count).to eql 1
90
+ expect(my_collection.find({ key: 'tobies_lock', owner: 'tobie'}).count).to eql 1
91
+ end
92
+
93
+ context "when collections is provided as a hash" do
94
+
95
+ before do
96
+ Mongo::Lock.release_all collections: { another_collection: collection3, other_collection: collection2 }
97
+ end
98
+
99
+ it "does release locks in those collection" do
100
+ expect(other_collection.find({ key: 'spences_lock', owner: 'spence'}).count).to eql 0
101
+ expect(another_collection.find({ key: 'spences_lock', owner: 'spence'}).count).to eql 0
102
+ end
103
+
104
+ it "doesn't release locks in other collections" do
105
+ expect(my_collection.find({ key: 'spences_lock', owner: 'spence'}).count).to eql 1
106
+ expect(my_collection.find({ key: 'tobies_lock', owner: 'tobie'}).count).to eql 1
107
+ end
108
+
109
+ end
110
+
111
+ end
112
+
113
+ end
114
+
115
+ end
116
+
117
+ end