em-synchrony 0.3.0.beta.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,50 @@
1
+ require "spec/helper/all"
2
+ require "em-synchrony/activerecord"
3
+
4
+ # create database widgets;
5
+ # use widgets;
6
+ # create table widgets (idx INT);
7
+
8
+ class Widget < ActiveRecord::Base; end;
9
+
10
+ describe "Fiberized ActiveRecord driver for mysql2" do
11
+ DELAY = 0.25
12
+ QUERY = "SELECT sleep(#{DELAY})"
13
+
14
+ it "should establish AR connection" do
15
+ EventMachine.synchrony do
16
+ ActiveRecord::Base.establish_connection(
17
+ :adapter => 'em_mysql2',
18
+ :database => 'widgets',
19
+ :username => 'root'
20
+ )
21
+
22
+ result = Widget.find_by_sql(QUERY)
23
+ result.size.should == 1
24
+
25
+ EventMachine.stop
26
+ end
27
+ end
28
+
29
+ it "should fire sequential, synchronous requests within single fiber" do
30
+ EventMachine.synchrony do
31
+ ActiveRecord::Base.establish_connection(
32
+ :adapter => 'em_mysql2',
33
+ :database => 'widgets',
34
+ :username => 'root'
35
+ )
36
+
37
+ start = now
38
+ res = []
39
+
40
+ res.push Widget.find_by_sql(QUERY)
41
+ res.push Widget.find_by_sql(QUERY)
42
+
43
+ (now - start.to_f).should be_within(DELAY * res.size * 0.15).of(DELAY * res.size)
44
+ res.size.should == 2
45
+
46
+ EventMachine.stop
47
+ end
48
+ end
49
+
50
+ end
@@ -1,7 +1,6 @@
1
1
  require "spec/helper/all"
2
2
 
3
3
  describe EM::Mongo do
4
-
5
4
  it "should yield until connection is ready" do
6
5
  EventMachine.synchrony do
7
6
  connection = EM::Mongo::Connection.new
@@ -14,41 +13,207 @@ describe EM::Mongo do
14
13
  end
15
14
  end
16
15
 
17
- it "should insert a record into db" do
18
- EventMachine.synchrony do
19
- collection = EM::Mongo::Connection.new.db('db').collection('test')
20
- collection.remove({}) # nuke all keys in collection
16
+ describe 'Synchronously (find & first)' do
17
+ it "should insert a record into db" do
18
+ EventMachine.synchrony do
19
+ collection = EM::Mongo::Connection.new.db('db').collection('test')
20
+ collection.remove({}) # nuke all keys in collection
21
21
 
22
- obj = collection.insert('hello' => 'world')
23
- obj.keys.should include '_id'
22
+ obj = collection.insert('hello' => 'world')
23
+ obj.should be_a(BSON::ObjectId)
24
24
 
25
- obj = collection.find
26
- obj.size.should == 1
27
- obj.first['hello'].should == 'world'
25
+ obj = collection.find
26
+ obj.size.should == 1
27
+ obj.first['hello'].should == 'world'
28
28
 
29
- EventMachine.stop
29
+ EventMachine.stop
30
+ end
30
31
  end
31
- end
32
32
 
33
- it "should insert a record into db" do
34
- EventMachine.synchrony do
35
- collection = EM::Mongo::Connection.new.db('db').collection('test')
36
- collection.remove({}) # nuke all keys in collection
33
+ it "should insert a record into db and be able to find it" do
34
+ EventMachine.synchrony do
35
+ collection = EM::Mongo::Connection.new.db('db').collection('test')
36
+ collection.remove({}) # nuke all keys in collection
37
37
 
38
- obj = collection.insert('hello' => 'world')
39
- obj = collection.insert('hello2' => 'world2')
38
+ obj = collection.insert('hello' => 'world')
39
+ obj = collection.insert('hello2' => 'world2')
40
40
 
41
- obj = collection.find({})
42
- obj.size.should == 2
41
+ obj = collection.find({})
42
+ obj.size.should == 2
43
43
 
44
- obj2 = collection.find({}, {:limit => 1})
45
- obj2.size.should == 1
44
+ obj2 = collection.find({}, {:limit => 1})
45
+ obj2.size.should == 1
46
46
 
47
- obj3 = collection.first
48
- obj3.is_a?(Hash).should be_true
47
+ obj3 = collection.first
48
+ obj3.is_a?(Hash).should be_true
49
49
 
50
- EventMachine.stop
50
+ EventMachine.stop
51
+ end
52
+ end
53
+
54
+ it "should be able to order results" do
55
+ EventMachine.synchrony do
56
+ collection = EM::Mongo::Connection.new.db('db').collection('test')
57
+ collection.remove({}) # nuke all keys in collection
58
+
59
+ collection.insert(:name => 'one', :position => 0)
60
+ collection.insert(:name => 'three', :position => 2)
61
+ collection.insert(:name => 'two', :position => 1)
62
+
63
+ res = collection.find({}, {:order => 'position'})
64
+ res[0]["name"].should == 'one'
65
+ res[1]["name"].should == 'two'
66
+ res[2]["name"].should == 'three'
67
+
68
+ res1 = collection.find({}, {:order => [:position, :desc]})
69
+ res1[0]["name"].should == 'three'
70
+ res1[1]["name"].should == 'two'
71
+ res1[2]["name"].should == 'one'
72
+
73
+ EventMachine.stop
74
+ end
75
+ end
76
+ end
77
+
78
+
79
+ #
80
+ # em-mongo version > 0.3.6
81
+ #
82
+ if defined?(EM::Mongo::Cursor)
83
+ describe '*A*synchronously (afind & afirst) [Mongo > 0.3.6, using cursor]' do
84
+ it "should insert a record into db" do
85
+ EventMachine.synchrony do
86
+ collection = EM::Mongo::Connection.new.db('db').collection('test')
87
+ collection.remove({}) # nuke all keys in collection
88
+
89
+ obj = collection.insert('hello' => 'world')
90
+ obj.should be_a(BSON::ObjectId)
91
+
92
+ cursor = collection.afind
93
+ cursor.should be_a(EM::Mongo::Cursor)
94
+ cursor.to_a.callback do |obj|
95
+ obj.size.should == 1
96
+ obj.first['hello'].should == 'world'
97
+ EM.next_tick{ EventMachine.stop }
98
+ end
99
+ end
100
+ end
101
+
102
+ it "should insert a record into db and be able to find it" do
103
+ EventMachine.synchrony do
104
+ collection = EM::Mongo::Connection.new.db('db').collection('test')
105
+ collection.remove({}) # nuke all keys in collection
106
+
107
+ obj = collection.insert('hello' => 'world')
108
+ obj = collection.insert('hello2' => 'world2')
109
+
110
+ collection.afind({}).to_a.callback do |obj|
111
+ obj.size.should == 2
112
+ end
113
+ collection.afind({}, {:limit => 1}).to_a.callback do |obj2|
114
+ obj2.size.should == 1
115
+ end
116
+ collection.afirst.callback do |obj3|
117
+ obj3.is_a?(Hash).should be_true
118
+ obj3['hello'].should == 'world'
119
+ EM.next_tick{ EventMachine.stop }
120
+ end
121
+ end
122
+ end
123
+
124
+ it "should be able to order results" do
125
+ EventMachine.synchrony do
126
+ collection = EM::Mongo::Connection.new.db('db').collection('test')
127
+ collection.remove({}) # nuke all keys in collection
128
+
129
+ collection.insert(:name => 'one', :position => 0)
130
+ collection.insert(:name => 'three', :position => 2)
131
+ collection.insert(:name => 'two', :position => 1)
132
+
133
+ collection.afind({}, {:order => 'position'}).to_a.callback do |res|
134
+ res[0]["name"].should == 'one'
135
+ res[1]["name"].should == 'two'
136
+ res[2]["name"].should == 'three'
137
+ end
138
+
139
+ collection.afind({}, {:order => [:position, :desc]}).to_a.callback do |res1|
140
+ res1[0]["name"].should == 'three'
141
+ res1[1]["name"].should == 'two'
142
+ res1[2]["name"].should == 'one'
143
+ EM.next_tick{ EventMachine.stop }
144
+ end
145
+
146
+ end
147
+ end
148
+ end
149
+
150
+ else
151
+ describe '*A*synchronously (afind & afirst) [Mongo <= 0.3.6, using blocks]' do
152
+ it "should insert a record into db" do
153
+ EventMachine.synchrony do
154
+ collection = EM::Mongo::Connection.new.db('db').collection('test')
155
+ collection.remove({}) # nuke all keys in collection
156
+
157
+ obj = collection.insert('hello' => 'world')
158
+ obj.should be_a(BSON::ObjectId)
159
+
160
+ ret_val = collection.afind do |obj|
161
+ obj.size.should == 1
162
+ obj.first['hello'].should == 'world'
163
+ EM.next_tick{ EventMachine.stop }
164
+ end
165
+ ret_val.should be_a(Integer)
166
+ end
167
+ end
168
+
169
+ it "should insert a record into db and be able to find it" do
170
+ EventMachine.synchrony do
171
+ collection = EM::Mongo::Connection.new.db('db').collection('test')
172
+ collection.remove({}) # nuke all keys in collection
173
+
174
+ obj = collection.insert('hello' => 'world')
175
+ obj = collection.insert('hello2' => 'world2')
176
+
177
+ collection.afind({}) do |obj|
178
+ obj.size.should == 2
179
+ end
180
+ collection.afind({}, {:limit => 1}) do |obj2|
181
+ obj2.size.should == 1
182
+ end
183
+ collection.afirst do |obj3|
184
+ obj3.is_a?(Hash).should be_true
185
+ obj3['hello'].should == 'world'
186
+ EM.next_tick{ EventMachine.stop }
187
+ end
188
+ end
189
+ end
190
+
191
+ it "should be able to order results" do
192
+ EventMachine.synchrony do
193
+ collection = EM::Mongo::Connection.new.db('db').collection('test')
194
+ collection.remove({}) # nuke all keys in collection
195
+
196
+ collection.insert(:name => 'one', :position => 0)
197
+ collection.insert(:name => 'three', :position => 2)
198
+ collection.insert(:name => 'two', :position => 1)
199
+
200
+ collection.afind({}, {:order => 'position'}) do |res|
201
+ res[0]["name"].should == 'one'
202
+ res[1]["name"].should == 'two'
203
+ res[2]["name"].should == 'three'
204
+ end
205
+
206
+ collection.afind({}, {:order => [:position, :desc]}) do |res1|
207
+ res1[0]["name"].should == 'three'
208
+ res1[1]["name"].should == 'two'
209
+ res1[2]["name"].should == 'one'
210
+ EM.next_tick{ EventMachine.stop }
211
+ end
212
+
213
+ end
214
+ end
51
215
  end
216
+
52
217
  end
53
218
 
54
219
  it "should update records in db" do
@@ -56,14 +221,13 @@ describe EM::Mongo do
56
221
  collection = EM::Mongo::Connection.new.db('db').collection('test')
57
222
  collection.remove({}) # nuke all keys in collection
58
223
 
59
- obj = collection.insert('hello' => 'world')
224
+ obj_id = collection.insert('hello' => 'world')
60
225
  collection.update({'hello' => 'world'}, {'hello' => 'newworld'})
61
226
 
62
- new_obj = collection.first({'_id' => obj['_id']})
227
+ new_obj = collection.first({'_id' => obj_id})
63
228
  new_obj['hello'].should == 'newworld'
64
229
 
65
230
  EventMachine.stop
66
231
  end
67
232
  end
68
-
69
233
  end
@@ -0,0 +1,39 @@
1
+ require "spec/helper/all"
2
+ require "em-synchrony/fiber_iterator"
3
+
4
+ describe EventMachine::Synchrony::FiberIterator do
5
+
6
+ it "should wait until the iterator is done and wrap internal block within a fiber" do
7
+ EM.synchrony do
8
+
9
+ results = []
10
+ i = EM::Synchrony::FiberIterator.new(1..5, 2).each do |num|
11
+ EM::Synchrony.sleep(0.1)
12
+ results.push num
13
+ end
14
+
15
+ results.should == (1..5).to_a
16
+ results.size.should == 5
17
+ EventMachine.stop
18
+ end
19
+ end
20
+
21
+ #
22
+ # it "should sum values within the iterator" do
23
+ # EM.synchrony do
24
+ # data = (1..5).to_a
25
+ # res = EM::Synchrony::FiberIterator.new(data, 2).inject(0) do |total, num, iter|
26
+ # EM::Synchrony.sleep(0.1)
27
+ #
28
+ # p [:sync, total, num]
29
+ # iter.return(total += num)
30
+ # end
31
+ #
32
+ # res.should == data.inject(:+)
33
+ # EventMachine.stop
34
+ # end
35
+ # end
36
+
37
+
38
+
39
+ end
data/spec/helper/all.rb CHANGED
@@ -4,11 +4,12 @@ require 'pp'
4
4
 
5
5
  require 'lib/em-synchrony'
6
6
  require 'lib/em-synchrony/em-http'
7
- require 'lib/em-synchrony/em-mysqlplus'
7
+ require 'lib/em-synchrony/mysql2'
8
8
  require 'lib/em-synchrony/em-remcached'
9
9
  require 'lib/em-synchrony/em-memcache'
10
10
  require 'lib/em-synchrony/em-mongo'
11
11
  require 'lib/em-synchrony/em-redis'
12
+ require 'lib/em-synchrony/em-hiredis'
12
13
 
13
14
  require 'helper/tolerance_matcher'
14
15
  require 'helper/stub-http-server'
@@ -0,0 +1,40 @@
1
+ require "spec/helper/all"
2
+
3
+ describe EM::Hiredis do
4
+
5
+ it "should yield until connection is ready" do
6
+ EventMachine.synchrony do
7
+ connection = EM::Hiredis::Client.connect
8
+ connection.connected.should be_true
9
+
10
+ EventMachine.stop
11
+ end
12
+ end
13
+
14
+ it "should get/set records synchronously" do
15
+ EventMachine.synchrony do
16
+ redis = EM::Hiredis::Client.connect
17
+
18
+ redis.set('a', 'foo')
19
+ redis.get('a').should == 'foo'
20
+ redis.get('c').should == nil
21
+
22
+ EM.stop
23
+ end
24
+ end
25
+
26
+ it "should incr/decr key synchronously" do
27
+ EventMachine.synchrony do
28
+ redis = EM::Hiredis::Client.connect
29
+ redis.delete('key')
30
+
31
+ redis.incr('key')
32
+ redis.get('key').to_i.should == 1
33
+
34
+ redis.decr('key')
35
+ redis.get('key').to_i.should == 0
36
+
37
+ EM.stop
38
+ end
39
+ end
40
+ end
data/spec/http_spec.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require "spec/helper/all"
2
2
 
3
3
  URL = "http://localhost:8081/"
4
+ CONNECTION_ERROR_URL = "http://random-domain-blah.com/"
4
5
  DELAY = 0.25
5
6
 
6
7
  describe EventMachine::HttpRequest do
@@ -58,4 +59,26 @@ describe EventMachine::HttpRequest do
58
59
  EventMachine.stop
59
60
  end
60
61
  end
62
+
63
+ it "should terminate immediately in case of connection errors" do
64
+ EventMachine.synchrony do
65
+ response = EventMachine::HttpRequest.new(CONNECTION_ERROR_URL).get
66
+ response.error.should_not be_nil
67
+
68
+ EventMachine.stop
69
+ end
70
+ end
71
+
72
+ it "should process inactivity timeout correctly" do
73
+ EventMachine.synchrony do
74
+ s = StubServer.new("HTTP/1.0 200 OK\r\nConnection: close\r\n\r\nFoo", 5)
75
+
76
+ start = now
77
+ r = EventMachine::HttpRequest.new(URL, :inactivity_timeout => 0.5).get
78
+ (now - start.to_f).should be_within(0.2).of(0.5)
79
+
80
+ s.stop
81
+ EventMachine.stop
82
+ end
83
+ end
61
84
  end
@@ -0,0 +1,59 @@
1
+ require "spec/helper/all"
2
+ require "tempfile"
3
+
4
+ DELAY = 0.1
5
+
6
+ describe EventMachine::Synchrony do
7
+ before(:each) { @temp_file = Tempfile.new("stdout") }
8
+ after(:each) { @temp_file.unlink }
9
+
10
+ def with_input(string = "", &block)
11
+ string = "#{string}\n"
12
+
13
+ @temp_file.write string
14
+ @temp_file.flush
15
+
16
+ EM::Synchrony.add_timer(DELAY) do
17
+ original_stdin = STDIN
18
+ STDIN.reopen(@temp_file.path)
19
+
20
+ block.call if block_given?
21
+
22
+ STDIN.reopen(original_stdin)
23
+ end
24
+ end
25
+
26
+ it "waits for input" do
27
+ EM.synchrony do
28
+ start = now
29
+
30
+ with_input do
31
+ EM::Synchrony.gets
32
+
33
+ (now - start.to_f).should be_within(DELAY * 0.15).of(DELAY)
34
+ end
35
+
36
+ EM.add_timer(DELAY * 2) { EM.stop }
37
+ end
38
+ end
39
+
40
+ it "trails input with a newline to emulate gets" do
41
+ EM.synchrony do
42
+ with_input("Hello") do
43
+ EM::Synchrony.gets.should == "Hello\n"
44
+ end
45
+
46
+ EM.add_timer(DELAY * 2) { EM.stop }
47
+ end
48
+ end
49
+
50
+ it "should stop after the first line" do
51
+ EM.synchrony do
52
+ with_input("Hello\nWorld!") do
53
+ EM::Synchrony.gets.should == "Hello\n"
54
+ end
55
+
56
+ EM.add_timer(DELAY * 2) { EM.stop }
57
+ end
58
+ end
59
+ end