officer 0.8.4 → 0.8.5

Sign up to get free protection for your applications and to get access to all the features.
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