alondra 0.0.3
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/.gitignore +9 -0
- data/Gemfile +22 -0
- data/Gemfile.lock +166 -0
- data/MIT-LICENSE +20 -0
- data/README.md +177 -0
- data/Rakefile +34 -0
- data/alondra.gemspec +23 -0
- data/app/assets/javascripts/alondra-client.js.coffee.erb +71 -0
- data/app/assets/javascripts/moz_websocket.js +5 -0
- data/app/assets/javascripts/vendor/jquery.json-2.2.js +178 -0
- data/app/assets/javascripts/vendor/json2.js +480 -0
- data/app/assets/javascripts/vendor/swfobject.js +4 -0
- data/app/assets/javascripts/vendor/web_socket.js +379 -0
- data/app/assets/swf/WebSocketMain.swf +0 -0
- data/app/helpers/alondra_helper.rb +24 -0
- data/lib/alondra/changes_callbacks.rb +52 -0
- data/lib/alondra/changes_push.rb +23 -0
- data/lib/alondra/channel.rb +84 -0
- data/lib/alondra/command.rb +38 -0
- data/lib/alondra/command_dispatcher.rb +22 -0
- data/lib/alondra/connection.rb +52 -0
- data/lib/alondra/event.rb +74 -0
- data/lib/alondra/event_listener.rb +86 -0
- data/lib/alondra/event_router.rb +27 -0
- data/lib/alondra/listener_callback.rb +37 -0
- data/lib/alondra/message.rb +35 -0
- data/lib/alondra/message_queue.rb +70 -0
- data/lib/alondra/message_queue_client.rb +71 -0
- data/lib/alondra/push_controller.rb +53 -0
- data/lib/alondra/pushing.rb +14 -0
- data/lib/alondra/server.rb +44 -0
- data/lib/alondra/session_parser.rb +57 -0
- data/lib/alondra.rb +80 -0
- data/lib/generators/alondra/USAGE +8 -0
- data/lib/generators/alondra/alondra_generator.rb +7 -0
- data/lib/generators/alondra/templates/alondra +33 -0
- data/lib/tasks/alondra_tasks.rake +4 -0
- data/script/rails +6 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/assets/javascripts/application.js +9 -0
- data/test/dummy/app/assets/stylesheets/application.css +7 -0
- data/test/dummy/app/controllers/application_controller.rb +14 -0
- data/test/dummy/app/controllers/chats_controller.rb +85 -0
- data/test/dummy/app/controllers/messages_controller.rb +12 -0
- data/test/dummy/app/controllers/sessions_controller.rb +20 -0
- data/test/dummy/app/controllers/users_controller.rb +30 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/helpers/chats_helper.rb +6 -0
- data/test/dummy/app/helpers/error_messages_helper.rb +23 -0
- data/test/dummy/app/helpers/layout_helper.rb +22 -0
- data/test/dummy/app/mailers/.gitkeep +0 -0
- data/test/dummy/app/models/.gitkeep +0 -0
- data/test/dummy/app/models/chat.rb +5 -0
- data/test/dummy/app/models/message.rb +4 -0
- data/test/dummy/app/models/user.rb +37 -0
- data/test/dummy/app/views/chats/_form.html.erb +21 -0
- data/test/dummy/app/views/chats/edit.html.erb +6 -0
- data/test/dummy/app/views/chats/index.html.erb +23 -0
- data/test/dummy/app/views/chats/new.html.erb +5 -0
- data/test/dummy/app/views/chats/show.html.erb +49 -0
- data/test/dummy/app/views/layouts/application.html.erb +19 -0
- data/test/dummy/app/views/sessions/new.html.erb +15 -0
- data/test/dummy/app/views/shared/_message.js.erb +1 -0
- data/test/dummy/app/views/users/_form.html.erb +20 -0
- data/test/dummy/app/views/users/edit.html.erb +3 -0
- data/test/dummy/app/views/users/index.html.erb +25 -0
- data/test/dummy/app/views/users/new.html.erb +5 -0
- data/test/dummy/app/views/users/show.html.erb +15 -0
- data/test/dummy/config/application.rb +42 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/database.yml +31 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +27 -0
- data/test/dummy/config/environments/production.rb +54 -0
- data/test/dummy/config/environments/test.rb +39 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +10 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +9 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +12 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +19 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/db/migrate/20110719090458_create_chats.rb +9 -0
- data/test/dummy/db/migrate/20110719090538_create_messages.rb +10 -0
- data/test/dummy/db/migrate/20110720193249_create_users.rb +16 -0
- data/test/dummy/db/schema.rb +38 -0
- data/test/dummy/lib/controller_authentication.rb +48 -0
- data/test/dummy/log/.gitkeep +0 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +26 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/public/stylesheets/application.css +75 -0
- data/test/dummy/script/rails +6 -0
- data/test/integration/push_changes_test.rb +41 -0
- data/test/integration/push_messages_test.rb +40 -0
- data/test/models/channel_test.rb +49 -0
- data/test/models/command_test.rb +29 -0
- data/test/models/configuration_test.rb +22 -0
- data/test/models/connection_test.rb +18 -0
- data/test/models/event_listener_test.rb +217 -0
- data/test/models/event_router_test.rb +7 -0
- data/test/models/message_queue_client_test.rb +26 -0
- data/test/models/message_queue_test.rb +70 -0
- data/test/models/pushing_test.rb +34 -0
- data/test/performance/message_queue_performance.rb +66 -0
- data/test/support/factories.rb +19 -0
- data/test/support/integration_helper.rb +18 -0
- data/test/support/integration_test.rb +6 -0
- data/test/support/mocks/bogus_event.rb +15 -0
- data/test/support/mocks/mock_connection.rb +24 -0
- data/test/support/mocks/mock_event_router.rb +12 -0
- data/test/support/mocks/mock_listener.rb +9 -0
- data/test/test_helper.rb +14 -0
- metadata +316 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
module Alondra
|
|
4
|
+
|
|
5
|
+
class ChannelTest < ActiveSupport::TestCase
|
|
6
|
+
|
|
7
|
+
def setup
|
|
8
|
+
@connection = MockConnection.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
test "it has a name" do
|
|
12
|
+
channel = Channel.new('test name channel')
|
|
13
|
+
assert_equal 'test name channel', channel.name
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
test "can fetch channel by name" do
|
|
17
|
+
channel = Channel['dummy channel']
|
|
18
|
+
assert_equal 'dummy channel', channel.name
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
test "allow clients to subscribe" do
|
|
22
|
+
channel = Channel.new('test subscriptions channel')
|
|
23
|
+
assert_equal 0, channel.connections.size
|
|
24
|
+
|
|
25
|
+
channel.subscribe @connection
|
|
26
|
+
|
|
27
|
+
assert_equal 1, channel.connections.size
|
|
28
|
+
assert channel.connections.keys.include? @connection
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
test "deliver events to all subscribed connections" do
|
|
32
|
+
channel = Channel.new('test deliver events channel')
|
|
33
|
+
channel.subscribe @connection
|
|
34
|
+
|
|
35
|
+
assert @connection.channels.include?(channel)
|
|
36
|
+
|
|
37
|
+
event = Event.new :event => :created, :resource => Chat.new, :channel => 'test deliver events channel'
|
|
38
|
+
|
|
39
|
+
channel.receive event
|
|
40
|
+
|
|
41
|
+
assert EM.reactor_running?
|
|
42
|
+
|
|
43
|
+
sleep(0.5) # Leave event machine to catch up
|
|
44
|
+
|
|
45
|
+
last_message = @connection.messages.last
|
|
46
|
+
assert_equal event.to_json, last_message
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
module Alondra
|
|
4
|
+
|
|
5
|
+
class CommandTest < ActiveSupport::TestCase
|
|
6
|
+
|
|
7
|
+
def setup
|
|
8
|
+
@connection = MockConnection.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
test "it is created with a connection and a hash" do
|
|
12
|
+
command = Command.new @connection, :command => 'subscribe', :channel => 'test'
|
|
13
|
+
|
|
14
|
+
assert_equal :subscribe, command.name
|
|
15
|
+
assert_equal 'test', command.channel.name
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
test "subscribe to channel when subscribe command is executed" do
|
|
19
|
+
channel = Channel['test']
|
|
20
|
+
assert_equal 0, channel.connections.size
|
|
21
|
+
|
|
22
|
+
command = Command.new @connection, :command => 'subscribe', :channel => 'test'
|
|
23
|
+
command.execute!
|
|
24
|
+
|
|
25
|
+
assert_equal 1, channel.connections.size
|
|
26
|
+
assert channel.connections.keys.include? @connection
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
module Alondra
|
|
4
|
+
|
|
5
|
+
class ConfigurationTest < ActiveSupport::TestCase
|
|
6
|
+
|
|
7
|
+
test "it has default values" do
|
|
8
|
+
assert_equal 12346, Alondra.config.port
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
test "it allows to override default values" do
|
|
12
|
+
assert_equal 'localhost', Alondra.config.host
|
|
13
|
+
Alondra.config.host = 'www.example.com'
|
|
14
|
+
assert_equal 'www.example.com', Alondra.config.host
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
test "it allows to define new variables" do
|
|
18
|
+
Alondra.config.test_variable = 'something'
|
|
19
|
+
assert_equal 'something', Alondra.config.test_variable
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
module Alondra
|
|
4
|
+
|
|
5
|
+
class ConnectionTest < ActiveSupport::TestCase
|
|
6
|
+
|
|
7
|
+
test "it is assigned an UUI on creation" do
|
|
8
|
+
assert MockConnection.new.uuid.present?
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
test "can find if there is a session" do
|
|
12
|
+
session = {:user_id => 10}
|
|
13
|
+
connection = MockConnection.new(session)
|
|
14
|
+
|
|
15
|
+
assert_equal session, connection.session
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
module Alondra
|
|
4
|
+
|
|
5
|
+
class ChatListener < EventListener
|
|
6
|
+
|
|
7
|
+
def self.created_chat_ids
|
|
8
|
+
@created_chat_ids ||= []
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.subscribed_user_ids
|
|
12
|
+
@subscribed_user_ids ||= []
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.subscribed_to_collection
|
|
16
|
+
@subscribed_to_collection ||= []
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.subscribed_to_member
|
|
20
|
+
@subscribed_to_member ||= []
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def self.custom_events
|
|
24
|
+
@custom_events ||= []
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
on :created do |event|
|
|
28
|
+
ChatListener.created_chat_ids << event.resource.id
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
on :destroyed do |event|
|
|
32
|
+
chat = event.resource
|
|
33
|
+
ChatListener.created_chat_ids.delete(chat.id)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
on :subscribed do |event|
|
|
37
|
+
ChatListener.subscribed_user_ids << session[:user_id]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
on :unsubscribed do |event|
|
|
41
|
+
ChatListener.subscribed_user_ids.delete(session[:user_id])
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
on :subscribed, :to => :collection do |event|
|
|
45
|
+
ChatListener.subscribed_to_collection << session[:user_id]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
on :unsubscribed, :to => :collection do |event|
|
|
49
|
+
ChatListener.subscribed_to_collection.delete(session[:user_id])
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
on :subscribed, :to => :member do |event|
|
|
53
|
+
ChatListener.subscribed_to_member << session[:user_id]
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
on :unsubscribed, :to => :member do |event|
|
|
57
|
+
ChatListener.subscribed_to_member.delete(session[:user_id])
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
on :custom do |event|
|
|
61
|
+
ChatListener.custom_events << event
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
on :boom do |event|
|
|
65
|
+
event.boom!
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class EventListenerTest < ActiveSupport::TestCase
|
|
72
|
+
|
|
73
|
+
test "can listen to a specific channel providing a string pattern" do
|
|
74
|
+
class TextPatternListener < EventListener
|
|
75
|
+
listen_to 'string pattern'
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
assert TextPatternListener.listen_to?('string pattern')
|
|
79
|
+
assert TextPatternListener.listen_to?('string pattern and more')
|
|
80
|
+
assert !TextPatternListener.listen_to?('other string pattern')
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
test "can listen to specific channel providing a regexp as pattern" do
|
|
84
|
+
class RegexpPatternListener < EventListener
|
|
85
|
+
listen_to /man$/
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
assert RegexpPatternListener.listen_to?('Superman')
|
|
89
|
+
assert !RegexpPatternListener.listen_to?('Lex Luthor')
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
test "it has a default channel pattern" do
|
|
93
|
+
class DefaultPatternsListener < EventListener; end
|
|
94
|
+
|
|
95
|
+
assert DefaultPatternsListener.listen_to?('/default/patterns/')
|
|
96
|
+
assert DefaultPatternsListener.listen_to?('/default/patterns/1')
|
|
97
|
+
|
|
98
|
+
assert !DefaultPatternsListener.listen_to?('/default/other/')
|
|
99
|
+
assert !DefaultPatternsListener.listen_to?('/other/patterns/')
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
test "default channel pattern is ignored if explicit listen_to pattern is called" do
|
|
103
|
+
class OverwrittenDefaultPatternsListener < EventListener
|
|
104
|
+
listen_to '/others'
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
assert OverwrittenDefaultPatternsListener.listen_to?('/others')
|
|
108
|
+
assert OverwrittenDefaultPatternsListener.listen_to?('/others/1/')
|
|
109
|
+
assert !OverwrittenDefaultPatternsListener.listen_to?('/overwritten/default/patterns')
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
test 'receive created and destroyes events' do
|
|
114
|
+
ChatListener.listen_to '/chats/'
|
|
115
|
+
|
|
116
|
+
chat = Chat.create(:name => 'Observed chat')
|
|
117
|
+
|
|
118
|
+
sleep(0.1)
|
|
119
|
+
|
|
120
|
+
assert ChatListener.created_chat_ids.include?(chat.id)
|
|
121
|
+
|
|
122
|
+
chat.destroy
|
|
123
|
+
|
|
124
|
+
sleep(0.1)
|
|
125
|
+
|
|
126
|
+
assert !ChatListener.created_chat_ids.include?(chat.id)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
test 'react to subscribed and unsubscribed events' do
|
|
130
|
+
session = {:user_id => 28 }
|
|
131
|
+
connection = MockConnection.new(session)
|
|
132
|
+
|
|
133
|
+
assert !ChatListener.subscribed_user_ids.include?(28)
|
|
134
|
+
|
|
135
|
+
Command.new(connection, :command => 'subscribe', :channel => '/chats/').execute!
|
|
136
|
+
|
|
137
|
+
sleep(0.1)
|
|
138
|
+
|
|
139
|
+
assert ChatListener.subscribed_user_ids.include?(28)
|
|
140
|
+
|
|
141
|
+
Command.new(connection, :command => 'unsubscribe', :channel => '/chats/').execute!
|
|
142
|
+
|
|
143
|
+
sleep(0.1)
|
|
144
|
+
|
|
145
|
+
assert !ChatListener.subscribed_user_ids.include?(28)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
test 'react to subscribed and unsubscribed events on collection' do
|
|
149
|
+
session = {:user_id => 29 }
|
|
150
|
+
connection = MockConnection.new(session)
|
|
151
|
+
|
|
152
|
+
assert !ChatListener.subscribed_to_collection.include?(29)
|
|
153
|
+
assert !ChatListener.subscribed_to_member.include?(29)
|
|
154
|
+
|
|
155
|
+
Command.new(connection, :command => 'subscribe', :channel => '/chats/').execute!
|
|
156
|
+
|
|
157
|
+
sleep(0.1)
|
|
158
|
+
|
|
159
|
+
assert ChatListener.subscribed_to_collection.include?(29)
|
|
160
|
+
assert !ChatListener.subscribed_to_member.include?(29)
|
|
161
|
+
|
|
162
|
+
Command.new(connection, :command => 'unsubscribe', :channel => '/chats/').execute!
|
|
163
|
+
|
|
164
|
+
sleep(0.1)
|
|
165
|
+
|
|
166
|
+
assert !ChatListener.subscribed_to_collection.include?(29)
|
|
167
|
+
assert !ChatListener.subscribed_to_member.include?(29)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
test 'react to subscribed and unsubscribed events on member' do
|
|
171
|
+
session = {:user_id => 30 }
|
|
172
|
+
connection = MockConnection.new(session)
|
|
173
|
+
|
|
174
|
+
chat = Factory.create :chat
|
|
175
|
+
|
|
176
|
+
chat_channel = "/chats/#{chat.id}"
|
|
177
|
+
|
|
178
|
+
assert !ChatListener.subscribed_to_collection.include?(30)
|
|
179
|
+
assert !ChatListener.subscribed_to_member.include?(30)
|
|
180
|
+
|
|
181
|
+
Command.new(connection, :command => 'subscribe', :channel => chat_channel).execute!
|
|
182
|
+
|
|
183
|
+
sleep(0.1)
|
|
184
|
+
|
|
185
|
+
assert !ChatListener.subscribed_to_collection.include?(30)
|
|
186
|
+
assert ChatListener.subscribed_to_member.include?(30)
|
|
187
|
+
|
|
188
|
+
Command.new(connection, :command => 'unsubscribe', :channel => chat_channel).execute!
|
|
189
|
+
|
|
190
|
+
sleep(0.1)
|
|
191
|
+
|
|
192
|
+
assert !ChatListener.subscribed_to_collection.include?(30)
|
|
193
|
+
assert !ChatListener.subscribed_to_member.include?(30)
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
test 'receive customs events' do
|
|
197
|
+
event = Event.new :event => :custom, :resource => Chat.new, :channel => '/chats/'
|
|
198
|
+
EventRouter.new.process(event)
|
|
199
|
+
|
|
200
|
+
sleep(0.1)
|
|
201
|
+
|
|
202
|
+
assert_equal ChatListener.custom_events.last, event
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
test 'capture exceptions launched in event listener' do
|
|
206
|
+
boom = BogusEvent.new :event => :boom, :resource => Chat.new, :channel => '/chats/'
|
|
207
|
+
EventRouter.new.process(boom)
|
|
208
|
+
|
|
209
|
+
event = Event.new :event => :custom, :resource => Chat.new, :channel => '/chats/'
|
|
210
|
+
EventRouter.new.process(event)
|
|
211
|
+
|
|
212
|
+
sleep(0.1)
|
|
213
|
+
|
|
214
|
+
assert_equal ChatListener.custom_events.last, event
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
module Alondra
|
|
4
|
+
|
|
5
|
+
class MessageQueueClientTest < ActiveSupport::TestCase
|
|
6
|
+
|
|
7
|
+
test "a sync client uses a sync zeromq context" do
|
|
8
|
+
context = SyncMessageQueueClient.new.send :context
|
|
9
|
+
assert context.class == ZMQ::Context
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
test "an async client uses an async zeromq context" do
|
|
13
|
+
context = nil
|
|
14
|
+
|
|
15
|
+
assert EM.reactor_running?
|
|
16
|
+
|
|
17
|
+
EM.schedule do
|
|
18
|
+
context = MessageQueueClient.instance.send :context
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
sleep(0.1)
|
|
22
|
+
|
|
23
|
+
assert context.class == EM::ZeroMQ::Context
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
module Alondra
|
|
4
|
+
|
|
5
|
+
class MessageQueueTest < ActiveSupport::TestCase
|
|
6
|
+
setup do
|
|
7
|
+
@original_event_router = MessageQueue.instance.send :event_router
|
|
8
|
+
@router = MockEventRouter.new
|
|
9
|
+
|
|
10
|
+
@chat = Chat.create(:name => 'Silly chat')
|
|
11
|
+
|
|
12
|
+
MessageQueue.instance.instance_variable_set :@event_router, @router
|
|
13
|
+
@event = Event.new :event => :custom, :resource => @chat, :channel => '/chats/'
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
teardown do
|
|
17
|
+
MessageQueue.instance.instance_variable_set :@event_router, @original_event_router
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
test "a message pushed asynchronously to the queue is received by the event router" do
|
|
21
|
+
assert MessageQueueClient.instance.class == AsyncMessageQueueClient
|
|
22
|
+
|
|
23
|
+
MessageQueueClient.push @event
|
|
24
|
+
|
|
25
|
+
sleep(0.1)
|
|
26
|
+
|
|
27
|
+
assert received(@event)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
test "a message pushed synchronously to the queue is received by the event router" do
|
|
31
|
+
|
|
32
|
+
client = MessageQueueClient.sync_instance
|
|
33
|
+
context = client.send :context
|
|
34
|
+
assert context.class == ZMQ::Context
|
|
35
|
+
|
|
36
|
+
client.send_message(@event)
|
|
37
|
+
|
|
38
|
+
sleep(0.1)
|
|
39
|
+
|
|
40
|
+
assert received(@event)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
test "message queue still works when an exception is thrown while processing an event" do
|
|
44
|
+
3.times do
|
|
45
|
+
bogus = BogusEvent.new :event => :custom, :resource => @chat, :channel => '/chats/'
|
|
46
|
+
|
|
47
|
+
begin
|
|
48
|
+
MessageQueueClient.push bogus
|
|
49
|
+
rescue BogusException
|
|
50
|
+
puts "rescued exception"
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
MessageQueueClient.push @event
|
|
55
|
+
|
|
56
|
+
sleep(0.1)
|
|
57
|
+
|
|
58
|
+
assert received(@event)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def received(event)
|
|
62
|
+
@router.received_events.find do |matching_event|
|
|
63
|
+
matching_event.type == event.type &&
|
|
64
|
+
matching_event.resource_type == event.resource_type &&
|
|
65
|
+
matching_event.resource.id == event.resource.id &&
|
|
66
|
+
matching_event.channel_name == event.channel_name
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
module Alondra
|
|
4
|
+
|
|
5
|
+
class PushingTest < ActiveSupport::TestCase
|
|
6
|
+
|
|
7
|
+
test "publish created events to the specified channel" do
|
|
8
|
+
chat = Factory.create :chat
|
|
9
|
+
connection = MockConnection.new
|
|
10
|
+
message = chat.messages.build(:text => 'test message')
|
|
11
|
+
|
|
12
|
+
channel_name = Channel.default_name_for(chat)
|
|
13
|
+
assert channel_name =~ /chats\/\d+/
|
|
14
|
+
|
|
15
|
+
channel = Channel[channel_name]
|
|
16
|
+
channel.subscribe connection
|
|
17
|
+
|
|
18
|
+
sleep(0.1)
|
|
19
|
+
|
|
20
|
+
message.save!
|
|
21
|
+
|
|
22
|
+
sleep(0.1)
|
|
23
|
+
|
|
24
|
+
assert connection.messages.last, "should publish a message"
|
|
25
|
+
|
|
26
|
+
last_event = ActiveSupport::JSON.decode(connection.messages.last)
|
|
27
|
+
resource = last_event['resource']
|
|
28
|
+
|
|
29
|
+
assert_equal 'created', last_event['event']
|
|
30
|
+
assert_equal 'Message', last_event['resource_type']
|
|
31
|
+
assert_equal message.id, resource['id']
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
module Alondra
|
|
4
|
+
|
|
5
|
+
class MessageQueuePerformanceTest < ActiveSupport::TestCase
|
|
6
|
+
|
|
7
|
+
NUM_MESSAGES = 1_000
|
|
8
|
+
|
|
9
|
+
setup do
|
|
10
|
+
@event = Event.new :event => :custom, :resource => Chat.new, :channel => '/chats/'
|
|
11
|
+
|
|
12
|
+
# Initialize queue
|
|
13
|
+
MessageQueueClient.push @event
|
|
14
|
+
|
|
15
|
+
@original_event_router = MessageQueue.instance.send :event_router
|
|
16
|
+
@router = MockEventRouter.new
|
|
17
|
+
|
|
18
|
+
MessageQueue.instance.instance_variable_set :@event_router, @router
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
teardown do
|
|
22
|
+
MessageQueue.instance.instance_variable_set :@event_router, @original_event_router
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
test "message queue performance" do
|
|
26
|
+
puts "send #{NUM_MESSAGES} messages to queue"
|
|
27
|
+
|
|
28
|
+
time = Benchmark.measure do
|
|
29
|
+
NUM_MESSAGES.times do
|
|
30
|
+
MessageQueueClient.async_instance.send_message @event
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
while @router.received_events.size < NUM_MESSAGES
|
|
34
|
+
sleep(0.1)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
events_per_second = NUM_MESSAGES/time.total
|
|
39
|
+
|
|
40
|
+
puts "aprox. received events per second #{events_per_second}"
|
|
41
|
+
|
|
42
|
+
assert events_per_second >= 500
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
test "message queue performance with sync client" do
|
|
47
|
+
puts "send #{NUM_MESSAGES} messages to queue"
|
|
48
|
+
|
|
49
|
+
time = Benchmark.measure do
|
|
50
|
+
NUM_MESSAGES.times do
|
|
51
|
+
MessageQueueClient.sync_instance.send_message @event
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
while @router.received_events.size < NUM_MESSAGES
|
|
55
|
+
sleep(0.1)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
events_per_second = NUM_MESSAGES/time.total
|
|
60
|
+
|
|
61
|
+
puts "aprox. received events per second #{events_per_second}"
|
|
62
|
+
|
|
63
|
+
assert events_per_second >= 500
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Factory.define :chat do |f|
|
|
2
|
+
f.name 'Test chat'
|
|
3
|
+
end
|
|
4
|
+
|
|
5
|
+
Factory.define :message do |f|
|
|
6
|
+
f.association :chat
|
|
7
|
+
f.text 'Test message'
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
Factory.sequence :username do |i|
|
|
11
|
+
"user#{i}"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
Factory.define :user do |f|
|
|
15
|
+
f.username { Factory.next(:username) }
|
|
16
|
+
f.email { |u| "#{u.username}@example.com" }
|
|
17
|
+
f.password 'secret'
|
|
18
|
+
f.password_confirmation 'secret'
|
|
19
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module Alondra
|
|
2
|
+
module IntegrationHelper
|
|
3
|
+
def login_as(user)
|
|
4
|
+
visit new_session_path
|
|
5
|
+
fill_in "login", :with => user.username
|
|
6
|
+
fill_in "password", :with => "secret"
|
|
7
|
+
click_button "Log in"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def log_out
|
|
11
|
+
click_link _('logout')
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def clean_db
|
|
15
|
+
[User, Chat, ::Message].each { |model| model.delete_all }
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Alondra
|
|
2
|
+
class MockConnection < Connection
|
|
3
|
+
|
|
4
|
+
def initialize(session = {})
|
|
5
|
+
super UUIDTools::UUID.random_create, session
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def send(message)
|
|
9
|
+
messages << message
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def receive(event)
|
|
13
|
+
messages << event.to_json
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def channels
|
|
17
|
+
@channels ||= []
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def messages
|
|
21
|
+
@messages ||= []
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
data/test/test_helper.rb
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Configure Rails Environment
|
|
2
|
+
ENV["RAILS_ENV"] = "test"
|
|
3
|
+
ENV["ALONDRA_SERVER"] = 'true'
|
|
4
|
+
|
|
5
|
+
require File.expand_path("../dummy/config/environment.rb", __FILE__)
|
|
6
|
+
require "rails/test_help"
|
|
7
|
+
require 'capybara/rails'
|
|
8
|
+
|
|
9
|
+
Alondra::Alondra.start_server_in_new_thread!
|
|
10
|
+
|
|
11
|
+
Rails.backtrace_cleaner.remove_silencers!
|
|
12
|
+
|
|
13
|
+
# Load support files
|
|
14
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|