em-synchrony 1.0.0 → 1.0.1
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/Gemfile +3 -1
- data/README.md +173 -170
- data/Rakefile +3 -5
- data/em-synchrony.gemspec +1 -1
- data/lib/active_record/connection_adapters/em_mysql2_adapter.rb +47 -0
- data/lib/em-synchrony.rb +33 -10
- data/lib/em-synchrony/activerecord.rb +103 -5
- data/lib/em-synchrony/amqp.rb +180 -0
- data/lib/em-synchrony/connection_pool.rb +3 -2
- data/lib/em-synchrony/core_ext.rb +10 -0
- data/lib/em-synchrony/em-hiredis.rb +103 -24
- data/lib/em-synchrony/em-mongo.rb +19 -0
- data/lib/em-synchrony/em-multi.rb +4 -2
- data/lib/em-synchrony/mongo.rb +6 -2
- data/lib/em-synchrony/mysql2.rb +16 -0
- data/lib/em-synchrony/tcpsocket.rb +5 -4
- data/lib/em-synchrony/thread.rb +108 -7
- data/spec/activerecord_spec.rb +108 -49
- data/spec/amqp_spec.rb +146 -0
- data/spec/connection_pool_spec.rb +4 -4
- data/spec/em-mongo_spec.rb +26 -0
- data/spec/helper/all.rb +1 -7
- data/spec/hiredis_spec.rb +24 -1
- data/spec/http_spec.rb +8 -8
- data/spec/multi_spec.rb +13 -0
- data/spec/mysql2_spec.rb +13 -0
- data/spec/synchrony_spec.rb +29 -10
- data/spec/tcpsocket_spec.rb +10 -0
- data/spec/thread_spec.rb +191 -0
- metadata +15 -10
- data/lib/em-synchrony/active_record/connection_adapters/em_mysql2_adapter.rb +0 -18
- data/lib/em-synchrony/active_record/patches.rb +0 -132
@@ -9,7 +9,7 @@ describe EventMachine::Synchrony::ConnectionPool do
|
|
9
9
|
EventMachine.run do
|
10
10
|
|
11
11
|
db = EventMachine::Synchrony::ConnectionPool.new(size: 1) do
|
12
|
-
|
12
|
+
Mysql2::EM::Client.new
|
13
13
|
end
|
14
14
|
|
15
15
|
Fiber.new {
|
@@ -33,7 +33,7 @@ describe EventMachine::Synchrony::ConnectionPool do
|
|
33
33
|
EventMachine.run do
|
34
34
|
|
35
35
|
db = EventMachine::Synchrony::ConnectionPool.new(size: 2) do
|
36
|
-
|
36
|
+
Mysql2::EM::Client.new
|
37
37
|
end
|
38
38
|
|
39
39
|
Fiber.new {
|
@@ -57,7 +57,7 @@ describe EventMachine::Synchrony::ConnectionPool do
|
|
57
57
|
EventMachine.run do
|
58
58
|
|
59
59
|
db = EventMachine::Synchrony::ConnectionPool.new(size: 2) do
|
60
|
-
|
60
|
+
Mysql2::EM::Client.new
|
61
61
|
end
|
62
62
|
|
63
63
|
Fiber.new {
|
@@ -88,7 +88,7 @@ describe EventMachine::Synchrony::ConnectionPool do
|
|
88
88
|
EventMachine.run do
|
89
89
|
|
90
90
|
db = EventMachine::Synchrony::ConnectionPool.new(size: 5) do
|
91
|
-
|
91
|
+
Mysql2::EM::Client.new
|
92
92
|
end
|
93
93
|
|
94
94
|
Fiber.new {
|
data/spec/em-mongo_spec.rb
CHANGED
@@ -230,4 +230,30 @@ describe EM::Mongo do
|
|
230
230
|
EventMachine.stop
|
231
231
|
end
|
232
232
|
end
|
233
|
+
|
234
|
+
context "authentication" do
|
235
|
+
# these specs only get asserted if you run mongod with the --auth flag
|
236
|
+
it "successfully authenticates" do
|
237
|
+
# For this spec you will need to add this user to the database
|
238
|
+
#
|
239
|
+
# From the Mongo shell:
|
240
|
+
# > use db
|
241
|
+
# > db.addUser('test', 'test')
|
242
|
+
EventMachine.synchrony do
|
243
|
+
database = EM::Mongo::Connection.new.db('db')
|
244
|
+
database.authenticate('test', 'test').should == true
|
245
|
+
EventMachine.stop
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
it "raises an AuthenticationError if it cannot authenticate" do
|
250
|
+
EventMachine.synchrony do
|
251
|
+
database = EM::Mongo::Connection.new.db('db')
|
252
|
+
proc {
|
253
|
+
database.authenticate('test', 'wrong_password')
|
254
|
+
}.should raise_error(EventMachine::Mongo::AuthenticationError, "auth fails")
|
255
|
+
EventMachine.stop
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
233
259
|
end
|
data/spec/helper/all.rb
CHANGED
@@ -10,19 +10,13 @@ require 'lib/em-synchrony/em-memcache'
|
|
10
10
|
require 'lib/em-synchrony/em-mongo'
|
11
11
|
require 'lib/em-synchrony/em-redis'
|
12
12
|
require 'lib/em-synchrony/em-hiredis'
|
13
|
+
require 'lib/em-synchrony/amqp'
|
13
14
|
|
14
15
|
require 'helper/tolerance_matcher'
|
15
16
|
require 'helper/stub-http-server'
|
16
17
|
|
17
18
|
def now(); Time.now.to_f; end
|
18
19
|
|
19
|
-
def silence_warnings()
|
20
|
-
old_verbose, $VERBOSE = $VERBOSE, nil
|
21
|
-
yield
|
22
|
-
ensure
|
23
|
-
$VERBOSE = old_verbose
|
24
|
-
end
|
25
|
-
|
26
20
|
RSpec.configure do |config|
|
27
21
|
config.include(Sander6::CustomMatchers)
|
28
22
|
end
|
data/spec/hiredis_spec.rb
CHANGED
@@ -11,6 +11,29 @@ describe EM::Hiredis do
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
+
it "should work with compact connect syntax" do
|
15
|
+
EventMachine.synchrony do
|
16
|
+
redis = EM::Hiredis.connect
|
17
|
+
|
18
|
+
redis.set('a', 'bar')
|
19
|
+
redis.get('a').should == 'bar'
|
20
|
+
|
21
|
+
EM.stop
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should work with manual db select" do
|
26
|
+
EventMachine.synchrony do
|
27
|
+
redis = EM::Hiredis.connect 'redis://127.0.0.1:6379'
|
28
|
+
redis.select(0)
|
29
|
+
|
30
|
+
redis.set('a', 'baz')
|
31
|
+
redis.get('a').should == 'baz'
|
32
|
+
|
33
|
+
EM.stop
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
14
37
|
it "should get/set records synchronously" do
|
15
38
|
EventMachine.synchrony do
|
16
39
|
redis = EM::Hiredis::Client.connect
|
@@ -26,7 +49,7 @@ describe EM::Hiredis do
|
|
26
49
|
it "should incr/decr key synchronously" do
|
27
50
|
EventMachine.synchrony do
|
28
51
|
redis = EM::Hiredis::Client.connect
|
29
|
-
redis.
|
52
|
+
redis.del('key')
|
30
53
|
|
31
54
|
redis.incr('key')
|
32
55
|
redis.get('key').to_i.should == 1
|
data/spec/http_spec.rb
CHANGED
@@ -59,24 +59,24 @@ describe EventMachine::HttpRequest do
|
|
59
59
|
EventMachine.stop
|
60
60
|
end
|
61
61
|
end
|
62
|
-
|
62
|
+
|
63
63
|
it "should terminate immediately in case of connection errors" do
|
64
64
|
EventMachine.synchrony do
|
65
|
-
response = EventMachine::HttpRequest.new(CONNECTION_ERROR_URL).get
|
65
|
+
response = EventMachine::HttpRequest.new(CONNECTION_ERROR_URL, :connection_timeout => 0.1).get
|
66
66
|
response.error.should_not be_nil
|
67
|
-
|
67
|
+
|
68
68
|
EventMachine.stop
|
69
69
|
end
|
70
70
|
end
|
71
|
-
|
71
|
+
|
72
72
|
it "should process inactivity timeout correctly" do
|
73
73
|
EventMachine.synchrony do
|
74
74
|
s = StubServer.new("HTTP/1.0 200 OK\r\nConnection: close\r\n\r\nFoo", 5)
|
75
|
-
|
75
|
+
|
76
76
|
start = now
|
77
|
-
r = EventMachine::HttpRequest.new(URL, :inactivity_timeout => 0.
|
78
|
-
(now - start.to_f).should be_within(0.2).of(0.
|
79
|
-
|
77
|
+
r = EventMachine::HttpRequest.new(URL, :inactivity_timeout => 0.1).get
|
78
|
+
(now - start.to_f).should be_within(0.2).of(0.1)
|
79
|
+
|
80
80
|
s.stop
|
81
81
|
EventMachine.stop
|
82
82
|
end
|
data/spec/multi_spec.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require "helper/all"
|
2
|
+
|
3
|
+
describe EM::Synchrony do
|
4
|
+
describe "Multi" do
|
5
|
+
it "should require unique keys for each deferrable" do
|
6
|
+
lambda do
|
7
|
+
m = EM::Synchrony::Multi.new
|
8
|
+
m.add :df1, EM::DefaultDeferrable.new
|
9
|
+
m.add :df1, EM::DefaultDeferrable.new
|
10
|
+
end.should raise_error("Duplicate Multi key")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/spec/mysql2_spec.rb
CHANGED
@@ -107,4 +107,17 @@ describe Mysql2::EM::Client do
|
|
107
107
|
end
|
108
108
|
end
|
109
109
|
|
110
|
+
it "errback should not catch exception thrown from callback" do
|
111
|
+
class ErrbackShouldNotCatchThis < Exception; end
|
112
|
+
proc {
|
113
|
+
EM.synchrony do
|
114
|
+
db = Mysql2::EM::Client.new
|
115
|
+
res = db.query QUERY
|
116
|
+
raise ErrbackShouldNotCatchThis.new("errback should not catch this")
|
117
|
+
|
118
|
+
EventMachine.stop
|
119
|
+
end
|
120
|
+
}.should raise_error(ErrbackShouldNotCatchThis)
|
121
|
+
end
|
122
|
+
|
110
123
|
end
|
data/spec/synchrony_spec.rb
CHANGED
@@ -1,14 +1,33 @@
|
|
1
1
|
require "helper/all"
|
2
2
|
|
3
|
-
describe EM::Synchrony
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
3
|
+
describe EM::Synchrony do
|
4
|
+
describe "#sync" do
|
5
|
+
it "returns immediately if the syncee already succeeded" do
|
6
|
+
args = stub("args")
|
7
|
+
|
8
|
+
Fiber.new {
|
9
|
+
df = EM::DefaultDeferrable.new
|
10
|
+
df.succeed args
|
11
|
+
EM::Synchrony.sync(df).should == args
|
12
|
+
|
13
|
+
df = EM::DefaultDeferrable.new
|
14
|
+
df.succeed nil
|
15
|
+
EM::Synchrony.sync(df).should == nil
|
16
|
+
}.resume
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "#next_tick" do
|
21
|
+
it "should wrap next_tick into a Fiber context" do
|
22
|
+
Fiber.new {
|
23
|
+
df = EM::DefaultDeferrable.new
|
24
|
+
|
25
|
+
EM::Synchrony.next_tick do
|
26
|
+
df.succeed args
|
27
|
+
EM::Synchrony.sync(df).should == args
|
28
|
+
end
|
29
|
+
}.resume
|
30
|
+
end
|
13
31
|
end
|
32
|
+
|
14
33
|
end
|
data/spec/tcpsocket_spec.rb
CHANGED
@@ -17,4 +17,14 @@ describe EventMachine::Synchrony::TCPSocket do
|
|
17
17
|
EM.stop
|
18
18
|
end
|
19
19
|
end
|
20
|
+
|
21
|
+
it 'should accept "send" when wrapped in a connection pool' do
|
22
|
+
EventMachine.synchrony do
|
23
|
+
@socket = EventMachine::Synchrony::ConnectionPool.new(size: 1) do
|
24
|
+
EventMachine::Synchrony::TCPSocket.new 'eventmachine.rubyforge.org', 80
|
25
|
+
end
|
26
|
+
@socket.send("GET / HTTP1.1\r\n\r\n").class.should be(Fixnum)
|
27
|
+
EM.stop
|
28
|
+
end
|
29
|
+
end
|
20
30
|
end
|
data/spec/thread_spec.rb
ADDED
@@ -0,0 +1,191 @@
|
|
1
|
+
require "spec/helper/all"
|
2
|
+
|
3
|
+
describe EventMachine::Synchrony::Thread::Mutex do
|
4
|
+
let(:m) { EM::Synchrony::Thread::Mutex.new }
|
5
|
+
it "should synchronize" do
|
6
|
+
EM.synchrony do
|
7
|
+
i = 0
|
8
|
+
f1 = Fiber.new do
|
9
|
+
m.synchronize do
|
10
|
+
f = Fiber.current
|
11
|
+
EM.next_tick { f.resume }
|
12
|
+
Fiber.yield
|
13
|
+
i += 1
|
14
|
+
end
|
15
|
+
end.resume
|
16
|
+
f1 = Fiber.new do
|
17
|
+
m.synchronize do
|
18
|
+
i.should eql(1)
|
19
|
+
EM.stop
|
20
|
+
end
|
21
|
+
end.resume
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "lock" do
|
26
|
+
describe "when mutex already locked" do
|
27
|
+
|
28
|
+
it "should raise ThreadError" do
|
29
|
+
f = Fiber.new do
|
30
|
+
m.lock
|
31
|
+
Fiber.yield
|
32
|
+
m.lock
|
33
|
+
end
|
34
|
+
f.resume
|
35
|
+
proc { f.resume }.should raise_error(FiberError)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "sleep" do
|
41
|
+
describe "without timeout" do
|
42
|
+
it "should sleep until resume" do
|
43
|
+
EM.synchrony do
|
44
|
+
m.lock
|
45
|
+
i = 0
|
46
|
+
f = Fiber.current
|
47
|
+
EM.next_tick { i += 1; f.resume }
|
48
|
+
res = m.sleep
|
49
|
+
i.should eql(1)
|
50
|
+
EM.stop
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should release lock" do
|
55
|
+
EM.synchrony do
|
56
|
+
i = 0
|
57
|
+
Fiber.new do
|
58
|
+
m.lock
|
59
|
+
f = Fiber.current
|
60
|
+
EM.next_tick { f.resume }
|
61
|
+
Fiber.yield
|
62
|
+
i += 1
|
63
|
+
m.sleep
|
64
|
+
end.resume
|
65
|
+
Fiber.new do
|
66
|
+
m.lock
|
67
|
+
i.should eql(1)
|
68
|
+
EM.stop
|
69
|
+
end.resume
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should wait unlock after resume" do
|
74
|
+
EM.synchrony do
|
75
|
+
i = 0
|
76
|
+
f1 = Fiber.new do
|
77
|
+
m.lock
|
78
|
+
m.sleep
|
79
|
+
i.should eql(1)
|
80
|
+
EM.stop
|
81
|
+
end
|
82
|
+
f2 = Fiber.new do
|
83
|
+
m.lock
|
84
|
+
f1.resume
|
85
|
+
i += 1
|
86
|
+
m.unlock
|
87
|
+
end
|
88
|
+
f1.resume
|
89
|
+
f2.resume
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "with timeout" do
|
94
|
+
it "should sleep for timeout" do
|
95
|
+
EM.synchrony do
|
96
|
+
m.lock
|
97
|
+
i = 0
|
98
|
+
EM.next_tick { i += 1 }
|
99
|
+
m.sleep(0.05)
|
100
|
+
i.should eql(1)
|
101
|
+
EM.stop
|
102
|
+
end
|
103
|
+
end
|
104
|
+
describe "and resume before timeout" do
|
105
|
+
it "should not raise any execptions" do
|
106
|
+
EM.synchrony do
|
107
|
+
m.lock
|
108
|
+
f = Fiber.current
|
109
|
+
EM.next_tick { f.resume }
|
110
|
+
m.sleep(0.05)
|
111
|
+
EM.add_timer(0.1) { EM.stop }
|
112
|
+
end
|
113
|
+
end
|
114
|
+
it "should resume in nested Fiber" do
|
115
|
+
EM.synchrony do
|
116
|
+
f = Fiber.new do
|
117
|
+
m.synchronize do
|
118
|
+
t = m.sleep(0.05)
|
119
|
+
t.should >= 0.05
|
120
|
+
end
|
121
|
+
EM.stop
|
122
|
+
end
|
123
|
+
f.resume
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
describe EventMachine::Synchrony::Thread::ConditionVariable do
|
131
|
+
let(:c){ EM::Synchrony::Thread::ConditionVariable.new }
|
132
|
+
it "should wakeup waiter" do
|
133
|
+
i = ''
|
134
|
+
EM.synchrony do
|
135
|
+
f1 = Fiber.new do
|
136
|
+
m.synchronize do
|
137
|
+
i << 'a'
|
138
|
+
c.wait(m)
|
139
|
+
i << 'c'
|
140
|
+
end
|
141
|
+
EM.stop
|
142
|
+
end.resume
|
143
|
+
f2 = Fiber.new do
|
144
|
+
i << 'b'
|
145
|
+
c.signal
|
146
|
+
end.resume
|
147
|
+
end
|
148
|
+
i.should == 'abc'
|
149
|
+
end
|
150
|
+
it 'should allow to play ping-pong' do
|
151
|
+
i = ''
|
152
|
+
EM.synchrony do
|
153
|
+
f1 = Fiber.new do
|
154
|
+
m.synchronize do
|
155
|
+
i << 'pi'
|
156
|
+
c.wait(m)
|
157
|
+
i << '-po'
|
158
|
+
c.signal
|
159
|
+
end
|
160
|
+
end.resume
|
161
|
+
f2 = Fiber.new do
|
162
|
+
m.synchronize do
|
163
|
+
i << 'ng'
|
164
|
+
c.signal
|
165
|
+
c.wait(m)
|
166
|
+
i << 'ng'
|
167
|
+
end
|
168
|
+
EM.stop
|
169
|
+
end.resume
|
170
|
+
end
|
171
|
+
i.should == 'ping-pong'
|
172
|
+
end
|
173
|
+
it 'should not raise, when timer wakes up fiber between `signal` and `next_tick`' do
|
174
|
+
proc {
|
175
|
+
EM.synchrony do
|
176
|
+
f = Fiber.new do
|
177
|
+
m.synchronize do
|
178
|
+
c.wait(m, 0.0001)
|
179
|
+
end
|
180
|
+
EM.add_timer(0.001){ EM.stop }
|
181
|
+
end
|
182
|
+
i = 0
|
183
|
+
f.resume
|
184
|
+
EM.next_tick{
|
185
|
+
c.signal
|
186
|
+
}
|
187
|
+
end
|
188
|
+
}.should_not raise_error
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|