officer 0.8.4 → 0.8.5

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.
data/.autotest ADDED
@@ -0,0 +1,10 @@
1
+ # Override autotest default magic to rerun all tests every time a
2
+ # change is detected on the file system.
3
+ class Autotest
4
+ def get_to_green
5
+ begin
6
+ rerun_all_tests
7
+ wait_for_changes unless all_good
8
+ end until all_good
9
+ end
10
+ end
data/README.markdown CHANGED
@@ -1,11 +1,10 @@
1
- # Officer - Distributed Lock Server and Client
1
+ # Officer - Ruby lock server and client built on EventMachine
2
2
 
3
- It is implemented using Ruby and Eventmachine. Inspiration comes from [elock](http://github.com/dustin/elock).
3
+ Officer is designed to help you coordinate distributed processes and avoid race conditions. Inspiration comes from [elock](http://github.com/dustin/elock).
4
4
 
5
5
  ## Installation
6
6
 
7
- sudo gem install gemcutter
8
- sudo gem install officer
7
+ gem install officer
9
8
 
10
9
  ## Usage
11
10
 
@@ -101,11 +100,6 @@ Options:
101
100
  client.my_locks
102
101
 
103
102
 
104
- ## Planned Features
105
-
106
- - Server: configure the daemons gem to allow multiple server processes to run on one box.
107
- - Tests
108
-
109
103
  ## Copyright
110
104
 
111
105
  Copyright (c) 2010 Chad Remesch. See LICENSE for details.
data/Rakefile CHANGED
@@ -7,8 +7,8 @@ Jeweler::Tasks.new do |gem|
7
7
  gem.name = "officer"
8
8
  gem.homepage = "http://github.com/chadrem/officer"
9
9
  gem.license = "MIT"
10
- gem.summary = %Q{Distributed lock server and client}
11
- gem.description = %Q{Distributed lock server and client written in Ruby and EventMachine}
10
+ gem.summary = %Q{Ruby lock server and client built on EventMachine.}
11
+ gem.description = %Q{Officer is designed to help you coordinate distributed processes and avoid race conditions.}
12
12
  gem.email = "chad@remesch.com"
13
13
  gem.authors = ["Chad Remesch"]
14
14
  # Include your dependencies below. Runtime dependencies are required when using your gem,
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.8.4
1
+ 0.8.5
data/officer.gemspec CHANGED
@@ -5,13 +5,13 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{officer}
8
- s.version = "0.8.4"
8
+ s.version = "0.8.5"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Chad Remesch"]
12
12
  s.date = %q{2011-01-22}
13
13
  s.default_executable = %q{officer}
14
- s.description = %q{Distributed lock server and client written in Ruby and EventMachine}
14
+ s.description = %q{Officer is designed to help you coordinate distributed processes and avoid race conditions.}
15
15
  s.email = %q{chad@remesch.com}
16
16
  s.executables = ["officer"]
17
17
  s.extra_rdoc_files = [
@@ -19,6 +19,7 @@ Gem::Specification.new do |s|
19
19
  "README.markdown"
20
20
  ]
21
21
  s.files = [
22
+ ".autotest",
22
23
  ".document",
23
24
  ".rspec",
24
25
  "LICENSE",
@@ -41,7 +42,7 @@ Gem::Specification.new do |s|
41
42
  s.licenses = ["MIT"]
42
43
  s.require_paths = ["lib"]
43
44
  s.rubygems_version = %q{1.3.7}
44
- s.summary = %q{Distributed lock server and client}
45
+ s.summary = %q{Ruby lock server and client built on EventMachine.}
45
46
  s.test_files = [
46
47
  "spec/integration/officer_spec.rb",
47
48
  "spec/spec_helper.rb"
@@ -1,4 +1,5 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require "benchmark"
2
3
 
3
4
  describe Officer do
4
5
  before do
@@ -11,7 +12,7 @@ describe Officer do
11
12
  @server_thread.terminate
12
13
  end
13
14
 
14
- context "single client tests" do
15
+ describe "COMMAND: with_lock" do
15
16
  before do
16
17
  @client = Officer::Client.new
17
18
  end
@@ -21,22 +22,22 @@ describe Officer do
21
22
  @client = nil
22
23
  end
23
24
 
24
- it "should allow a client to request its locks" do
25
- @client.my_locks.should eq({"value"=>[], "result"=>"locks"})
26
- end
27
-
28
- it "should allow a client to request and release a lock using non-block syntax" do
29
- @client.lock("testlock")
30
- @client.my_locks.should eq({"value"=>["testlock"], "result"=>"locks"})
31
- @client.unlock("testlock")
32
- @client.my_locks.should eq({"value"=>[], "result"=>"locks"})
33
- end
34
-
35
25
  it "should allow a client to request and release a lock using block syntax" do
36
26
  @client.with_lock("testlock") do
37
27
  @client.my_locks.should eq({"value"=>["testlock"], "result"=>"locks"})
38
28
  end
39
29
  end
30
+ end
31
+
32
+ describe "COMMAND: reset" do
33
+ before do
34
+ @client = Officer::Client.new
35
+ end
36
+
37
+ after do
38
+ @client.send("disconnect")
39
+ @client = nil
40
+ end
40
41
 
41
42
  it "should allow a client to reset all of its locks (release them all)" do
42
43
  @client.lock("testlock1")
@@ -47,10 +48,36 @@ describe Officer do
47
48
  end
48
49
  end
49
50
 
50
- context "multi-client tests" do
51
+ describe "COMMAND: reconnect" do
52
+ before do
53
+ @client = Officer::Client.new
54
+ end
55
+
56
+ after do
57
+ @client.send("disconnect")
58
+ @client = nil
59
+ end
60
+
61
+ it "should allow a client to force a reconnect in order to get a new socket" do
62
+ original_socket = @client.instance_variable_get("@socket")
63
+ @client.reconnect
64
+ @client.instance_variable_get("@socket").should_not eq(original_socket)
65
+ @client.my_locks.should eq({"value"=>[], "result"=>"locks"})
66
+ end
67
+ end
68
+
69
+ describe "COMMAND: connections" do
51
70
  before do
52
71
  @client1 = Officer::Client.new
53
72
  @client2 = Officer::Client.new
73
+
74
+ @client1_src_port = @client1.instance_variable_get('@socket').addr[1]
75
+ @client2_src_port = @client2.instance_variable_get('@socket').addr[1]
76
+
77
+ @client1.lock("client1_testlock1")
78
+ @client1.lock("client1_testlock2")
79
+ @client2.lock("client2_testlock1")
80
+ @client2.lock("client2_testlock2")
54
81
  end
55
82
 
56
83
  after do
@@ -60,12 +87,177 @@ describe Officer do
60
87
  @client2 = nil
61
88
  end
62
89
 
63
- it "should allow a client to see all the locks on a server (including those owned by other clients)" do
90
+ it "should allow a client to see all the connections to a server" do
91
+ connections = @client2.connections
92
+
93
+ connections["value"]["127.0.0.1:#{@client1_src_port}"].should eq(["client1_testlock1", "client1_testlock2"])
94
+ connections["value"]["127.0.0.1:#{@client2_src_port}"].should eq(["client2_testlock1", "client2_testlock2"])
95
+ connections["value"].keys.length.should eq(2)
96
+ connections["result"].should eq("connections")
97
+ end
98
+ end
99
+
100
+ describe "COMMAND: locks" do
101
+ before do
102
+ @client1 = Officer::Client.new
103
+ @client2 = Officer::Client.new
104
+
105
+ @client1_src_port = @client1.instance_variable_get('@socket').addr[1]
106
+ @client2_src_port = @client2.instance_variable_get('@socket').addr[1]
107
+
64
108
  @client1.lock("client1_testlock1")
65
109
  @client1.lock("client1_testlock2")
66
110
  @client2.lock("client2_testlock1")
67
111
  @client2.lock("client2_testlock2")
68
- # @client2.locks.should eq(false)
112
+ end
113
+
114
+ after do
115
+ @client1.send("disconnect")
116
+ @client1 = nil
117
+ @client2.send("disconnect")
118
+ @client2 = nil
119
+ end
120
+
121
+ it "should allow a client to see all the locks on a server (including those owned by other clients)" do
122
+ locks = @client2.locks
123
+
124
+ locks["value"]["client1_testlock1"].should eq(["127.0.0.1:#{@client1_src_port}"])
125
+ locks["value"]["client1_testlock2"].should eq(["127.0.0.1:#{@client1_src_port}"])
126
+ locks["value"]["client2_testlock1"].should eq(["127.0.0.1:#{@client2_src_port}"])
127
+ locks["value"]["client2_testlock2"].should eq(["127.0.0.1:#{@client2_src_port}"])
128
+ locks["value"].length.should eq(4)
129
+ locks["result"].should eq("locks")
130
+ end
131
+ end
132
+
133
+ describe "COMMAND: my_locks" do
134
+ before do
135
+ @client = Officer::Client.new
136
+ end
137
+
138
+ after do
139
+ @client.send("disconnect")
140
+ @client = nil
141
+ end
142
+
143
+ it "should allow a client to request its locks" do
144
+ @client.my_locks.should eq({"value"=>[], "result"=>"locks"})
145
+ end
146
+ end
147
+
148
+ describe "COMMAND: lock & unlock" do
149
+ describe "basic functionality" do
150
+ before do
151
+ @client = Officer::Client.new
152
+ end
153
+
154
+ after do
155
+ @client.send("disconnect")
156
+ @client = nil
157
+ end
158
+
159
+ it "should allow a client to request and release a lock" do
160
+ @client.lock("testlock").should eq({"result" => "acquired", "name" => "testlock"})
161
+ @client.my_locks.should eq({"value"=>["testlock"], "result"=>"locks"})
162
+ @client.unlock("testlock")
163
+ @client.my_locks.should eq({"value"=>[], "result"=>"locks"})
164
+ end
165
+ end
166
+
167
+ describe "locking options" do
168
+ describe "OPTION: timeout" do
169
+ before do
170
+ @client1 = Officer::Client.new
171
+ @client2 = Officer::Client.new
172
+
173
+ @client1_src_port = @client1.instance_variable_get('@socket').addr[1]
174
+ @client2_src_port = @client2.instance_variable_get('@socket').addr[1]
175
+
176
+ @client1.lock("testlock")
177
+ end
178
+
179
+ after do
180
+ @client1.send("disconnect")
181
+ @client1 = nil
182
+ @client2.send("disconnect")
183
+ @client2 = nil
184
+ end
185
+
186
+ it "should allow a client to set an instant timeout when obtaining a lock" do
187
+ @client2.lock("testlock", :timeout => 0).should eq(
188
+ {"result"=>"timed_out", "name"=>"testlock", "queue"=>["127.0.0.1:#{@client1_src_port}"]}
189
+ )
190
+ end
191
+
192
+ it "should allow a client to set a positive integer timeout when obtaining a lock" do
193
+ time = Benchmark.realtime do
194
+ @client2.lock("testlock", :timeout => 1).should eq(
195
+ {"result"=>"timed_out", "name"=>"testlock", "queue"=>["127.0.0.1:#{@client1_src_port}"]}
196
+ )
197
+ end
198
+ time.should > 1
199
+ time.should < 1.5
200
+ end
201
+ end
202
+
203
+ describe "OPTION: queue_max" do
204
+ before do
205
+ end
206
+
207
+ after do
208
+ @thread1.terminate
209
+ @thread2.terminate
210
+ end
211
+
212
+ it "should allow a client to abort when obtaining a lock if too many other clients are waiting for the same lock" do
213
+ @client1 = Officer::Client.new
214
+ @client1.lock("testlock")
215
+
216
+ @thread1 = Thread.new {
217
+ @client2 = Officer::Client.new
218
+ @client2.lock("testlock")
219
+ raise "This should never execute since the lock request should block"
220
+ }
221
+
222
+ @thread2 = Thread.new {
223
+ @client3 = Officer::Client.new
224
+ @client3.lock("testlock")
225
+ raise "This should never execute since the lock request should block"
226
+ }
227
+
228
+ sleep(0.25) # Allow thread 1 & 2 time to run.
229
+
230
+ @thread1.status.should eq("sleep")
231
+ @thread2.status.should eq("sleep")
232
+
233
+ client1_src_port = @client1.instance_variable_get('@socket').addr[1]
234
+ client2_src_port = @client2.instance_variable_get('@socket').addr[1]
235
+ client3_src_port = @client3.instance_variable_get('@socket').addr[1]
236
+
237
+ @client4 = Officer::Client.new
238
+ @client4.lock("testlock", :queue_max => 3).should eq(
239
+ {"result" => "queue_maxed", "name" => "testlock", "queue" =>
240
+ ["127.0.0.1:#{client1_src_port}", "127.0.0.1:#{client2_src_port}", "127.0.0.1:#{client3_src_port}"]}
241
+ )
242
+ end
243
+ end
244
+
245
+ describe "OPTION: namespace" do
246
+ before do
247
+ @client = Officer::Client.new(:namespace => "myapp")
248
+ end
249
+
250
+ after do
251
+ @client.send("disconnect")
252
+ @client = nil
253
+ end
254
+
255
+ it "should allow a client to set a namespace when obtaining a lock" do
256
+ @client.with_lock("testlock") do
257
+ @client.locks["value"]["myapp:testlock"].should_not eq(nil)
258
+ end
259
+ end
260
+ end
69
261
  end
70
262
  end
71
263
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: officer
3
3
  version: !ruby/object:Gem::Version
4
- hash: 55
4
+ hash: 53
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 8
9
- - 4
10
- version: 0.8.4
9
+ - 5
10
+ version: 0.8.5
11
11
  platform: ruby
12
12
  authors:
13
13
  - Chad Remesch
@@ -90,7 +90,7 @@ dependencies:
90
90
  version: "0"
91
91
  type: :runtime
92
92
  version_requirements: *id005
93
- description: Distributed lock server and client written in Ruby and EventMachine
93
+ description: Officer is designed to help you coordinate distributed processes and avoid race conditions.
94
94
  email: chad@remesch.com
95
95
  executables:
96
96
  - officer
@@ -100,6 +100,7 @@ extra_rdoc_files:
100
100
  - LICENSE
101
101
  - README.markdown
102
102
  files:
103
+ - .autotest
103
104
  - .document
104
105
  - .rspec
105
106
  - LICENSE
@@ -150,7 +151,7 @@ rubyforge_project:
150
151
  rubygems_version: 1.3.7
151
152
  signing_key:
152
153
  specification_version: 3
153
- summary: Distributed lock server and client
154
+ summary: Ruby lock server and client built on EventMachine.
154
155
  test_files:
155
156
  - spec/integration/officer_spec.rb
156
157
  - spec/spec_helper.rb