hkroger-websocket-rails 0.7.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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +328 -0
- data/Gemfile +27 -0
- data/MIT-LICENSE +20 -0
- data/README.md +237 -0
- data/Rakefile +72 -0
- data/bin/thin-socketrails +45 -0
- data/lib/assets/javascripts/websocket_rails/abstract_connection.js.coffee +45 -0
- data/lib/assets/javascripts/websocket_rails/channel.js.coffee +70 -0
- data/lib/assets/javascripts/websocket_rails/event.js.coffee +42 -0
- data/lib/assets/javascripts/websocket_rails/http_connection.js.coffee +66 -0
- data/lib/assets/javascripts/websocket_rails/main.js +6 -0
- data/lib/assets/javascripts/websocket_rails/websocket_connection.js.coffee +29 -0
- data/lib/assets/javascripts/websocket_rails/websocket_rails.js.coffee +158 -0
- data/lib/config.ru +3 -0
- data/lib/generators/websocket_rails/install/install_generator.rb +33 -0
- data/lib/generators/websocket_rails/install/templates/events.rb +14 -0
- data/lib/generators/websocket_rails/install/templates/websocket_rails.rb +63 -0
- data/lib/hkroger-websocket-rails.rb +1 -0
- data/lib/rails/app/controllers/websocket_rails/delegation_controller.rb +13 -0
- data/lib/rails/config/routes.rb +7 -0
- data/lib/rails/tasks/websocket_rails.tasks +42 -0
- data/lib/spec_helpers/matchers/route_matchers.rb +65 -0
- data/lib/spec_helpers/matchers/trigger_matchers.rb +113 -0
- data/lib/spec_helpers/spec_helper_event.rb +34 -0
- data/lib/websocket-rails.rb +108 -0
- data/lib/websocket_rails/base_controller.rb +197 -0
- data/lib/websocket_rails/channel.rb +97 -0
- data/lib/websocket_rails/channel_manager.rb +55 -0
- data/lib/websocket_rails/configuration.rb +169 -0
- data/lib/websocket_rails/connection_adapters.rb +195 -0
- data/lib/websocket_rails/connection_adapters/http.rb +120 -0
- data/lib/websocket_rails/connection_adapters/web_socket.rb +36 -0
- data/lib/websocket_rails/connection_manager.rb +119 -0
- data/lib/websocket_rails/controller_factory.rb +80 -0
- data/lib/websocket_rails/data_store.rb +145 -0
- data/lib/websocket_rails/dispatcher.rb +129 -0
- data/lib/websocket_rails/engine.rb +26 -0
- data/lib/websocket_rails/event.rb +189 -0
- data/lib/websocket_rails/event_map.rb +184 -0
- data/lib/websocket_rails/event_queue.rb +33 -0
- data/lib/websocket_rails/internal_events.rb +37 -0
- data/lib/websocket_rails/logging.rb +133 -0
- data/lib/websocket_rails/spec_helpers.rb +3 -0
- data/lib/websocket_rails/synchronization.rb +182 -0
- data/lib/websocket_rails/user_manager.rb +276 -0
- data/lib/websocket_rails/version.rb +3 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/controllers/chat_controller.rb +53 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/models/user.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +45 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +22 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +26 -0
- data/spec/dummy/config/environments/production.rb +49 -0
- data/spec/dummy/config/environments/test.rb +34 -0
- data/spec/dummy/config/events.rb +7 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +10 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +58 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/20130902222552_create_users.rb +10 -0
- data/spec/dummy/db/schema.rb +23 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +17 -0
- data/spec/dummy/log/production.log +0 -0
- data/spec/dummy/log/server.log +0 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +26 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/public/javascripts/application.js +2 -0
- data/spec/dummy/public/javascripts/controls.js +965 -0
- data/spec/dummy/public/javascripts/dragdrop.js +974 -0
- data/spec/dummy/public/javascripts/effects.js +1123 -0
- data/spec/dummy/public/javascripts/prototype.js +6001 -0
- data/spec/dummy/public/javascripts/rails.js +202 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/integration/connection_manager_spec.rb +135 -0
- data/spec/javascripts/support/jasmine.yml +52 -0
- data/spec/javascripts/support/jasmine_helper.rb +38 -0
- data/spec/javascripts/support/vendor/sinon-1.7.1.js +4343 -0
- data/spec/javascripts/websocket_rails/channel_spec.coffee +112 -0
- data/spec/javascripts/websocket_rails/event_spec.coffee +69 -0
- data/spec/javascripts/websocket_rails/helpers.coffee +6 -0
- data/spec/javascripts/websocket_rails/websocket_connection_spec.coffee +158 -0
- data/spec/javascripts/websocket_rails/websocket_rails_spec.coffee +274 -0
- data/spec/spec_helper.rb +41 -0
- data/spec/spec_helpers/matchers/route_matchers_spec.rb +109 -0
- data/spec/spec_helpers/matchers/trigger_matchers_spec.rb +247 -0
- data/spec/spec_helpers/spec_helper_event_spec.rb +66 -0
- data/spec/support/helper_methods.rb +42 -0
- data/spec/support/mock_web_socket.rb +41 -0
- data/spec/unit/base_controller_spec.rb +74 -0
- data/spec/unit/channel_manager_spec.rb +58 -0
- data/spec/unit/channel_spec.rb +169 -0
- data/spec/unit/connection_adapters/http_spec.rb +88 -0
- data/spec/unit/connection_adapters/web_socket_spec.rb +30 -0
- data/spec/unit/connection_adapters_spec.rb +259 -0
- data/spec/unit/connection_manager_spec.rb +148 -0
- data/spec/unit/controller_factory_spec.rb +76 -0
- data/spec/unit/data_store_spec.rb +106 -0
- data/spec/unit/dispatcher_spec.rb +203 -0
- data/spec/unit/event_map_spec.rb +120 -0
- data/spec/unit/event_queue_spec.rb +36 -0
- data/spec/unit/event_spec.rb +181 -0
- data/spec/unit/logging_spec.rb +162 -0
- data/spec/unit/synchronization_spec.rb +150 -0
- data/spec/unit/target_validator_spec.rb +88 -0
- data/spec/unit/user_manager_spec.rb +165 -0
- metadata +320 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'support/mock_web_socket'
|
|
3
|
+
|
|
4
|
+
module WebsocketRails
|
|
5
|
+
module ConnectionAdapters
|
|
6
|
+
describe WebSocket do
|
|
7
|
+
|
|
8
|
+
before do
|
|
9
|
+
@socket = MockWebSocket.new
|
|
10
|
+
Faye::WebSocket.stub(:new).and_return(@socket)
|
|
11
|
+
@adapter = WebSocket.new( mock_request, double('Dispatcher').as_null_object )
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
describe "#send" do
|
|
15
|
+
it "should send the message to the websocket connection" do
|
|
16
|
+
@socket.should_receive(:send).with(:message)
|
|
17
|
+
@adapter.send :message
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
describe "#close!" do
|
|
22
|
+
it "calls #close on the underlying WebSocket connection" do
|
|
23
|
+
@socket.should_receive(:close)
|
|
24
|
+
@adapter.close!
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module WebsocketRails
|
|
4
|
+
|
|
5
|
+
class ConnectionAdapters::Test < ConnectionAdapters::Base
|
|
6
|
+
def self.accepts?(env)
|
|
7
|
+
true
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe ConnectionAdapters do
|
|
12
|
+
|
|
13
|
+
context ".register" do
|
|
14
|
+
it "should store a reference to the adapter in the adapters array" do
|
|
15
|
+
ConnectionAdapters.register( ConnectionAdapters::Test )
|
|
16
|
+
ConnectionAdapters.adapters.include?( ConnectionAdapters::Test ).should be_true
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
context ".establish_connection" do
|
|
21
|
+
before do
|
|
22
|
+
connection_manager = double(ConnectionManager)
|
|
23
|
+
connection_manager.stub(:connections).and_return({})
|
|
24
|
+
@dispatcher = double(Dispatcher).as_null_object
|
|
25
|
+
@dispatcher.stub(:connection_manager).and_return(connection_manager)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "should return the correct connection adapter instance" do
|
|
29
|
+
adapter = ConnectionAdapters.establish_connection(mock_request, @dispatcher)
|
|
30
|
+
adapter.class.should == ConnectionAdapters::Test
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
context "ping_timer" do
|
|
36
|
+
it "should set a ping_timer to the default 10 seconds value" do
|
|
37
|
+
adapter = ConnectionAdapters.establish_connection(mock_request, @dispatcher)
|
|
38
|
+
adapter.instance_variable_get(:@ping_timer).interval.should == 10
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "should change the ping interval after creation" do
|
|
42
|
+
adapter = ConnectionAdapters.establish_connection(mock_request, @dispatcher)
|
|
43
|
+
adapter.instance_variable_get(:@ping_timer).interval.should == 10
|
|
44
|
+
|
|
45
|
+
adapter.ping_interval = 50
|
|
46
|
+
adapter.instance_variable_get(:@ping_timer).interval.should == 50
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "should not set a ping_timer if ping_interval < 1" do
|
|
50
|
+
WebsocketRails.config.default_ping_interval = 0
|
|
51
|
+
adapter = ConnectionAdapters.establish_connection(mock_request, @dispatcher)
|
|
52
|
+
adapter.instance_variable_get(:@ping_timer).should == nil
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "should set the ping_timer to the value in the config" do
|
|
56
|
+
WebsocketRails.config.default_ping_interval = 45
|
|
57
|
+
adapter = ConnectionAdapters.establish_connection(mock_request, @dispatcher)
|
|
58
|
+
adapter.instance_variable_get(:@ping_timer).interval.should == 45
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
module ConnectionAdapters
|
|
65
|
+
describe Base do
|
|
66
|
+
let(:connection_manager) { double(ConnectionManager).as_null_object }
|
|
67
|
+
let(:dispatcher) { double(Dispatcher).as_null_object }
|
|
68
|
+
let(:channel_manager) { double(ChannelManager).as_null_object }
|
|
69
|
+
let(:event) { double(Event).as_null_object }
|
|
70
|
+
|
|
71
|
+
before do
|
|
72
|
+
connection_manager.stub(:connections).and_return({})
|
|
73
|
+
dispatcher.stub(:connection_manager).and_return(connection_manager)
|
|
74
|
+
Event.stub(:new_from_json).and_return(event)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
subject { Base.new(mock_request, dispatcher) }
|
|
78
|
+
|
|
79
|
+
context "new adapter" do
|
|
80
|
+
it "should register itself in the adapters array when inherited" do
|
|
81
|
+
adapter = Class.new( ConnectionAdapters::Base )
|
|
82
|
+
ConnectionAdapters.adapters.include?( adapter ).should be_true
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it "should create a new DataStore::Connection instance" do
|
|
86
|
+
subject.data_store.should be_a DataStore::Connection
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
#before do
|
|
90
|
+
# WebsocketRails.config.stub(:user_identifier).and_return(:name)
|
|
91
|
+
# WebsocketRails::DelegationController.any_instance
|
|
92
|
+
# .stub_chain(:current_user, :name)
|
|
93
|
+
# .and_return('Frank')
|
|
94
|
+
# subject
|
|
95
|
+
#end
|
|
96
|
+
|
|
97
|
+
#it "adds itself to the UserManager Hash" do
|
|
98
|
+
# WebsocketRails.users['Frank'].should == subject
|
|
99
|
+
#end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
describe "#on_open" do
|
|
103
|
+
it "should dispatch an on_open event" do
|
|
104
|
+
on_open_event = double('event').as_null_object
|
|
105
|
+
subject.stub(:send)
|
|
106
|
+
Event.should_receive(:new_on_open).and_return(on_open_event)
|
|
107
|
+
dispatcher.should_receive(:dispatch).with(on_open_event)
|
|
108
|
+
subject.on_open
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
describe "#on_message" do
|
|
113
|
+
it "should forward the data to the dispatcher" do
|
|
114
|
+
dispatcher.should_receive(:dispatch).with(event)
|
|
115
|
+
subject.on_message encoded_message
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
describe "#on_close" do
|
|
120
|
+
it "should dispatch an on_close event" do
|
|
121
|
+
on_close_event = double('event')
|
|
122
|
+
Event.should_receive(:new_on_close).and_return(on_close_event)
|
|
123
|
+
dispatcher.should_receive(:dispatch).with(on_close_event)
|
|
124
|
+
subject.on_close("data")
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
describe "#on_error" do
|
|
129
|
+
it "should dispatch an on_error event" do
|
|
130
|
+
subject.stub(:on_close)
|
|
131
|
+
on_error_event = double('event').as_null_object
|
|
132
|
+
Event.should_receive(:new_on_error).and_return(on_error_event)
|
|
133
|
+
dispatcher.should_receive(:dispatch).with(on_error_event)
|
|
134
|
+
subject.on_error("data")
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
it "should fire the on_close event" do
|
|
138
|
+
data = "test_data"
|
|
139
|
+
subject.should_receive(:on_close).with(data)
|
|
140
|
+
subject.on_error("test_data")
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
describe "#send_message" do
|
|
145
|
+
before do
|
|
146
|
+
Event.any_instance.stub(:trigger)
|
|
147
|
+
end
|
|
148
|
+
after do
|
|
149
|
+
subject.send_message :message, "some_data"
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
it "creates and triggers a new event" do
|
|
153
|
+
Event.any_instance.should_receive(:trigger)
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
it "sets it's user identifier on the event" do
|
|
157
|
+
subject.stub(:user_identifier).and_return(:some_name_or_id)
|
|
158
|
+
Event.should_receive(:new) do |name, options|
|
|
159
|
+
options[:user_id].should == :some_name_or_id
|
|
160
|
+
end.and_call_original
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
it "sets the connection property of the event correctly" do
|
|
164
|
+
subject.stub(:user_identifier).and_return(:some_name_or_id)
|
|
165
|
+
Event.should_receive(:new) do |name, options|
|
|
166
|
+
options[:connection].should == subject
|
|
167
|
+
end.and_call_original
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
describe "#send" do
|
|
172
|
+
it "should raise a NotImplementedError exception" do
|
|
173
|
+
expect { subject.send :message }.to raise_exception(NotImplementedError)
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
describe "#user_connection?" do
|
|
178
|
+
context "when a user is signed in" do
|
|
179
|
+
before do
|
|
180
|
+
subject.stub(:user_identifier).and_return("Jimbo Jones")
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
it "returns true" do
|
|
184
|
+
subject.user_connection?.should == true
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
context "when a user is signed out" do
|
|
189
|
+
before do
|
|
190
|
+
subject.stub(:user_identifier).and_return(nil)
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
it "returns true" do
|
|
194
|
+
subject.user_connection?.should == false
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
describe "#user" do
|
|
200
|
+
it "provides access to the current_user object" do
|
|
201
|
+
user = double('User')
|
|
202
|
+
subject.stub(:user_identifier).and_return true
|
|
203
|
+
subject.stub_chain(:controller_delegate, :current_user).and_return user
|
|
204
|
+
subject.user.should == user
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
describe "#enqueue" do
|
|
209
|
+
it "should add the event to the queue" do
|
|
210
|
+
subject.enqueue 'event'
|
|
211
|
+
subject.queue.queue.should == ['event']
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
describe "#flush" do
|
|
216
|
+
before do
|
|
217
|
+
event = Event.new(:queued_event, data: 'test')
|
|
218
|
+
2.times { subject.enqueue event }
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
it "should serialize all events into one array" do
|
|
222
|
+
serialized_array = <<-EOF.strip_heredoc
|
|
223
|
+
[["queued_event",{"id":null,"channel":null,"user_id":null,"data":"test","success":null,"result":null,"token":null,"server_token":null}],
|
|
224
|
+
["queued_event",{"id":null,"channel":null,"user_id":null,"data":"test","success":null,"result":null,"token":null,"server_token":null}]]
|
|
225
|
+
EOF
|
|
226
|
+
|
|
227
|
+
subject.should_receive(:send).with(serialized_array.gsub(/\n/,'').strip)
|
|
228
|
+
subject.flush
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
describe "#trigger" do
|
|
233
|
+
it "passes a serialized event to the connections #send method" do
|
|
234
|
+
event.stub(:serialize).and_return('test')
|
|
235
|
+
subject.should_receive(:send).with "[test]"
|
|
236
|
+
subject.trigger event
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
describe "#close_connection" do
|
|
241
|
+
before do
|
|
242
|
+
subject.stub(:user_identifier).and_return(1)
|
|
243
|
+
@connection_manager = double('connection_manager').as_null_object
|
|
244
|
+
subject.stub_chain(:dispatcher, :connection_manager).and_return(@connection_manager)
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
it "calls delegates to the conection manager" do
|
|
248
|
+
@connection_manager.should_receive(:close_connection).with(subject)
|
|
249
|
+
subject.__send__(:close_connection)
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
it "deletes it's data_store" do
|
|
253
|
+
subject.data_store.should_receive(:destroy!)
|
|
254
|
+
subject.__send__(:close_connection)
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
end
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module WebsocketRails
|
|
4
|
+
describe ConnectionManager do
|
|
5
|
+
include Rack::Test::Methods
|
|
6
|
+
|
|
7
|
+
def app
|
|
8
|
+
@app ||= ConnectionManager.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def open_connection
|
|
12
|
+
subject.call(env)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
let(:connections) { subject.connections }
|
|
16
|
+
let(:dispatcher) { subject.dispatcher }
|
|
17
|
+
|
|
18
|
+
before(:each) do
|
|
19
|
+
ConnectionAdapters::Base.any_instance.stub(:send)
|
|
20
|
+
@mock_socket = ConnectionAdapters::Base.new(mock_request, dispatcher)
|
|
21
|
+
ConnectionAdapters.stub(:establish_connection).and_return(@mock_socket)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
describe "#initialize" do
|
|
25
|
+
it "should create an empty connections hash" do
|
|
26
|
+
subject.connections.should be_a Hash
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "should create a new dispatcher instance" do
|
|
30
|
+
subject.dispatcher.should be_a Dispatcher
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
context "new connections" do
|
|
35
|
+
it "should add one to the total connection count" do
|
|
36
|
+
expect { open_connection }.to change { connections.count }.by(1)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "should store the new connection in the @connections Hash" do
|
|
40
|
+
open_connection
|
|
41
|
+
connections[@mock_socket.id].should == @mock_socket
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "should return an Async Rack response" do
|
|
45
|
+
open_connection.should == [ -1, {}, [] ]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
before do
|
|
49
|
+
SecureRandom.stub(:hex).and_return(1, 2)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "gives the new connection a unique ID" do
|
|
53
|
+
@mock_socket.should_receive(:id=).with(1)
|
|
54
|
+
open_connection
|
|
55
|
+
@mock_socket.should_receive(:id=).with(2)
|
|
56
|
+
open_connection
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
context "user connections" do
|
|
60
|
+
before do
|
|
61
|
+
@mock_socket.stub(:user_connection?).and_return true
|
|
62
|
+
@mock_socket.stub(:user_identifier).and_return "El Jefe"
|
|
63
|
+
open_connection
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it "stores the connection in the UserManager" do
|
|
67
|
+
WebsocketRails.users["El Jefe"].connections.first.should == @mock_socket
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
context "new POST event" do
|
|
73
|
+
before(:each) do
|
|
74
|
+
@mock_http = ConnectionAdapters::Http.new(mock_request, dispatcher)
|
|
75
|
+
@mock_http.id = 'is_i_as_string'
|
|
76
|
+
app.connections[@mock_http.id] = @mock_http
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it "should receive the new event for the correct connection" do
|
|
80
|
+
@mock_http.should_receive(:on_message).with(encoded_message)
|
|
81
|
+
post '/websocket', {:client_id => @mock_http.id, :data => encoded_message}
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
context "open connections" do
|
|
86
|
+
before(:each) do
|
|
87
|
+
ConnectionAdapters.stub(:establish_connection).and_return(@mock_socket, ConnectionAdapters::Base.new(mock_request, dispatcher))
|
|
88
|
+
4.times { open_connection }
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
context "when receiving a new event" do
|
|
92
|
+
before(:each) { open_connection }
|
|
93
|
+
|
|
94
|
+
it "should dispatch the appropriate event through the Dispatcher" do
|
|
95
|
+
mock_event = ["new_message",{:data =>"data"}].to_json
|
|
96
|
+
dispatcher.should_receive(:dispatch) do |event|
|
|
97
|
+
event.name.should == :new_message
|
|
98
|
+
event.data.should == "data"
|
|
99
|
+
event.connection.should == @mock_socket
|
|
100
|
+
end
|
|
101
|
+
@mock_socket.on_message(mock_event)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
context "when closing" do
|
|
106
|
+
it "should remove the connection object from the @connections array" do
|
|
107
|
+
@mock_socket.on_close
|
|
108
|
+
connections.has_key?(@mock_socket.id).should be_false
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it "should decrement the connection count by one" do
|
|
112
|
+
expect { @mock_socket.on_close }.to change { connections.count }.by(-1)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
it "should dispatch the :client_disconnected event" do
|
|
116
|
+
dispatcher.should_receive(:dispatch) do |event|
|
|
117
|
+
event.name.should == :client_disconnected
|
|
118
|
+
event.connection.should == @mock_socket
|
|
119
|
+
end
|
|
120
|
+
@mock_socket.on_close
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
context "user connections" do
|
|
124
|
+
before do
|
|
125
|
+
@mock_socket.stub(:user_connection?).and_return true
|
|
126
|
+
@mock_socket.stub(:user_identifier).and_return "El Jefe"
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
it "deletes the connection from the UserManager" do
|
|
130
|
+
@mock_socket.on_close
|
|
131
|
+
WebsocketRails.users["El Jefe"].class.should == UserManager::MissingConnection
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
context "invalid connections" do
|
|
139
|
+
before(:each) do
|
|
140
|
+
ConnectionAdapters.stub(:establish_connection).and_raise(InvalidConnectionError)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
it "should return a 400 bad request error code" do
|
|
144
|
+
open_connection.first.should == 400
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
module WebsocketRails
|
|
4
|
+
describe ControllerFactory do
|
|
5
|
+
|
|
6
|
+
class TestController < BaseController
|
|
7
|
+
attr_reader :_dispatcher, :_event
|
|
8
|
+
|
|
9
|
+
def initialize_session
|
|
10
|
+
true
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
let(:dispatcher) { double('dispatcher') }
|
|
15
|
+
let(:connection) { double('connection') }
|
|
16
|
+
let(:event) { double('event') }
|
|
17
|
+
|
|
18
|
+
subject { ControllerFactory.new(dispatcher) }
|
|
19
|
+
|
|
20
|
+
before do
|
|
21
|
+
connection.stub(:id).and_return(1)
|
|
22
|
+
event.stub(:connection).and_return(connection)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "stores a reference to the dispatcher" do
|
|
26
|
+
subject.dispatcher.should == dispatcher
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "maintains a hash of controller data stores" do
|
|
30
|
+
subject.controller_stores.should be_a Hash
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe "#new_for_event" do
|
|
34
|
+
|
|
35
|
+
context "when Rails is defined and env is set to development" do
|
|
36
|
+
|
|
37
|
+
it "creates and returns a controller instance of the InternalController" do
|
|
38
|
+
rails_env = double(:rails_env)
|
|
39
|
+
Rails.stub(:env).and_return rails_env
|
|
40
|
+
rails_env.stub(:development?).and_return true
|
|
41
|
+
controller = subject.new_for_event(event, InternalController, 'some_method')
|
|
42
|
+
controller.class.should == InternalController
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "creates and returns a new controller instance" do
|
|
48
|
+
controller = subject.new_for_event(event, TestController, 'some_method')
|
|
49
|
+
controller.class.should == TestController
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "initializes the controller with the correct data_store" do
|
|
53
|
+
store = double('data_store')
|
|
54
|
+
subject.controller_stores[TestController] = store
|
|
55
|
+
controller = subject.new_for_event(event, TestController, 'some_method')
|
|
56
|
+
controller.controller_store.should == store
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "initializes the controller with the correct event" do
|
|
60
|
+
controller = subject.new_for_event(event, TestController, 'some_method')
|
|
61
|
+
controller.event.should == event
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "initializes the controller with the correct dispatcher" do
|
|
65
|
+
controller = subject.new_for_event(event, TestController, 'some_method')
|
|
66
|
+
controller._dispatcher.should == dispatcher
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it "calls #initialize_session on the controller only once" do
|
|
70
|
+
TestController.any_instance.should_receive(:initialize_session).once
|
|
71
|
+
3.times { subject.new_for_event(event, TestController, 'some_method') }
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
end
|
|
76
|
+
end
|