wwl-websocket-rails 0.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +328 -0
- data/Gemfile +27 -0
- data/MIT-LICENSE +20 -0
- data/README.md +239 -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 +46 -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 +68 -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 +138 -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 +208 -0
- data/lib/websocket_rails/channel.rb +97 -0
- data/lib/websocket_rails/channel_manager.rb +55 -0
- data/lib/websocket_rails/configuration.rb +177 -0
- data/lib/websocket_rails/connection_adapters/http.rb +120 -0
- data/lib/websocket_rails/connection_adapters/web_socket.rb +35 -0
- data/lib/websocket_rails/connection_adapters.rb +195 -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 +193 -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 +178 -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/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/config.ru +4 -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/log/test.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 +81 -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 +273 -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 +358 -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,58 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module WebsocketRails
|
4
|
+
|
5
|
+
describe ".channel_manager" do
|
6
|
+
it "should load a new channel manager when first called" do
|
7
|
+
WebsocketRails.channel_manager.should be_a ChannelManager
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe ".[]" do
|
12
|
+
it "should delegate to channel manager" do
|
13
|
+
ChannelManager.any_instance.should_receive(:[]).with(:awesome_channel)
|
14
|
+
WebsocketRails[:awesome_channel]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe ".channel_tokens" do
|
19
|
+
it "should delegate to channel manager" do
|
20
|
+
ChannelManager.any_instance.should_receive(:channel_tokens)
|
21
|
+
WebsocketRails.channel_tokens
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe ChannelManager do
|
26
|
+
|
27
|
+
describe "#channel_tokens" do
|
28
|
+
it "should return a Hash-like" do
|
29
|
+
subject.channel_tokens.respond_to? :[]
|
30
|
+
subject.channel_tokens.respond_to? :has_key?
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'is used to store Channel\'s token' do
|
34
|
+
ChannelManager.any_instance.should_receive(:channel_tokens)
|
35
|
+
.at_least(:twice).and_call_original
|
36
|
+
token = Channel.new(:my_new_test_channel).token
|
37
|
+
WebsocketRails.channel_tokens[:my_new_test_channel].should == token
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#[]" do
|
42
|
+
context "accessing a channel" do
|
43
|
+
it "should create the channel if it does not exist" do
|
44
|
+
subject[:awesome_channel].class.should == Channel
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "unsubscribe" do
|
50
|
+
it "should unsubscribe connection from all channels" do
|
51
|
+
subject[:awesome_channel].should_receive(:unsubscribe).with(:some_connection)
|
52
|
+
subject[:awesome_channel]
|
53
|
+
subject.unsubscribe(:some_connection)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module WebsocketRails
|
4
|
+
describe Channel do
|
5
|
+
subject { Channel.new :awesome_channel }
|
6
|
+
|
7
|
+
let(:connection) { double('connection') }
|
8
|
+
|
9
|
+
before do
|
10
|
+
connection.stub(:trigger)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should maintain a pool of subscribed connections" do
|
14
|
+
subject.subscribers.should == []
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#subscribe" do
|
18
|
+
before do
|
19
|
+
connection.stub(:user).and_return({})
|
20
|
+
WebsocketRails.config.stub(:broadcast_subscriber_events?).and_return(true)
|
21
|
+
end
|
22
|
+
it "should trigger an event when subscriber joins" do
|
23
|
+
subject.should_receive(:trigger).with("subscriber_join", connection.user)
|
24
|
+
subject.subscribe connection
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should add the connection to the subscriber pool" do
|
28
|
+
subject.subscribe connection
|
29
|
+
subject.subscribers.include?(connection).should be_true
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#unsubscribe" do
|
34
|
+
before do
|
35
|
+
connection.stub(:user).and_return({})
|
36
|
+
WebsocketRails.config.stub(:broadcast_subscriber_events?).and_return(true)
|
37
|
+
end
|
38
|
+
it "should remove connection from subscriber pool" do
|
39
|
+
subject.subscribe connection
|
40
|
+
subject.unsubscribe connection
|
41
|
+
subject.subscribers.include?(connection).should be_false
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should do nothing if connection is not subscribed to channel" do
|
45
|
+
subject.unsubscribe connection
|
46
|
+
subject.subscribers.include?(connection).should be_false
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should trigger an event when subscriber parts" do
|
50
|
+
subject.subscribers << connection
|
51
|
+
subject.should_receive(:trigger).with('subscriber_part', connection.user)
|
52
|
+
subject.unsubscribe connection
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "#trigger" do
|
57
|
+
it "should create a new event and trigger it on all subscribers" do
|
58
|
+
event = double('event').as_null_object
|
59
|
+
Event.should_receive(:new) do |name,options|
|
60
|
+
name.should == 'event'
|
61
|
+
options[:data].should == 'data'
|
62
|
+
event
|
63
|
+
end
|
64
|
+
connection.should_receive(:trigger).with(event)
|
65
|
+
subject.subscribers << connection
|
66
|
+
subject.trigger 'event', 'data'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "#trigger_event" do
|
71
|
+
it "should forward the event to subscribers if token matches" do
|
72
|
+
event = Event.new 'awesome_event', {:channel => 'awesome_channel', :token => subject.token}
|
73
|
+
subject.should_receive(:send_data).with(event)
|
74
|
+
subject.trigger_event event
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should ignore the event if the token is invalid" do
|
78
|
+
event = Event.new 'invalid_event', {:channel => 'awesome_channel', :token => 'invalid_token'}
|
79
|
+
subject.should_not_receive(:send_data).with(event)
|
80
|
+
subject.trigger_event event
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should not propagate if event.propagate is false" do
|
84
|
+
event = Event.new 'awesome_event', {:channel => 'awesome_channel', :token => subject.token, :propagate => false}
|
85
|
+
connection.should_not_receive(:trigger)
|
86
|
+
subject.subscribers << connection
|
87
|
+
subject.trigger_event event
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe "#filter_with" do
|
92
|
+
it "should add the controller to the filtered_channels hash" do
|
93
|
+
filter = double('BaseController')
|
94
|
+
subject.filter_with(filter)
|
95
|
+
subject.filtered_channels[subject.name].should eq(filter)
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should allow setting the catch_all method" do
|
99
|
+
filter = double('BaseController')
|
100
|
+
subject.filter_with(filter, :some_method)
|
101
|
+
subject.filtered_channels[subject.name].should eq([filter, :some_method])
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context "private channels" do
|
106
|
+
before do
|
107
|
+
subject.subscribers << connection
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should be public by default" do
|
111
|
+
subject.instance_variable_get(:@private).should_not be_true
|
112
|
+
end
|
113
|
+
|
114
|
+
describe "#make_private" do
|
115
|
+
it "should set the @private instance variable to true" do
|
116
|
+
subject.make_private
|
117
|
+
subject.instance_variable_get(:@private).should be_true
|
118
|
+
end
|
119
|
+
|
120
|
+
context "when Configuration#keep_subscribers_when_private? is false" do
|
121
|
+
it "should clear any existing subscribers in the channel" do
|
122
|
+
subject.subscribers.count.should == 1
|
123
|
+
subject.make_private
|
124
|
+
subject.subscribers.count.should == 0
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context "when Configuration#keep_subscribers_when_private? is true" do
|
129
|
+
before do
|
130
|
+
WebsocketRails.config.keep_subscribers_when_private = true
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should leave the existing subscribers in the channel" do
|
134
|
+
subject.subscribers.count.should == 1
|
135
|
+
subject.make_private
|
136
|
+
subject.subscribers.count.should == 1
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe "#is_private?" do
|
142
|
+
it "should return true if the channel is private" do
|
143
|
+
subject.instance_variable_set(:@private,true)
|
144
|
+
subject.is_private?.should be_true
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should return false if the channel is public" do
|
148
|
+
subject.instance_variable_set(:@private,false)
|
149
|
+
subject.is_private?.should_not be_true
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
describe "#token" do
|
154
|
+
it 'is long enough' do
|
155
|
+
subject.token.length.should > 10
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'remains the same between two call' do
|
159
|
+
subject.token.should == subject.token
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'is the same for two channels with the same name' do
|
163
|
+
subject.token.should == Channel.new(subject.name).token
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module WebsocketRails
|
4
|
+
module ConnectionAdapters
|
5
|
+
describe Http do
|
6
|
+
|
7
|
+
subject {
|
8
|
+
mr = mock_request
|
9
|
+
mr.stub(:protocol).and_return('http://')
|
10
|
+
mr.stub(:raw_host_with_port).and_return('localhost:3000')
|
11
|
+
Http.new(mr , double('Dispatcher').as_null_object )
|
12
|
+
}
|
13
|
+
|
14
|
+
it "should be a subclass of ConnectionAdapters::Base" do
|
15
|
+
subject.class.superclass.should == ConnectionAdapters::Base
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should set the Content-Length header to text/json" do
|
19
|
+
subject.headers['Content-Type'].should == "text/json"
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should set the Transfer-Encoding header to chunked" do
|
23
|
+
subject.headers['Transfer-Encoding'].should == "chunked"
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should not set the Access-Control-Allow-Origin header" do
|
27
|
+
subject.headers['Access-Control-Allow-Origin'].should be_blank
|
28
|
+
end
|
29
|
+
|
30
|
+
context "with IE CORS hack enabled" do
|
31
|
+
it "should set the Access-Control-Allow-Origin when passed an array as configuration" do
|
32
|
+
WebsocketRails.config.allowed_origins = ['http://localhost:3000']
|
33
|
+
subject.headers['Access-Control-Allow-Origin'].should == 'http://localhost:3000'
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should set the Access-Control-Allow-Origin when passed a string as configuration" do
|
37
|
+
WebsocketRails.config.allowed_origins = 'http://localhost:3000'
|
38
|
+
subject.headers['Access-Control-Allow-Origin'].should == 'http://localhost:3000'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context "#encode_chunk" do
|
43
|
+
it "should properly encode strings" do
|
44
|
+
subject.__send__(:encode_chunk,"test").should == "4\r\ntest\r\n"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "adapter methods" do
|
49
|
+
before do
|
50
|
+
@body = double('DeferrableBody').as_null_object
|
51
|
+
Http::DeferrableBody.stub(:new).and_return(@body)
|
52
|
+
end
|
53
|
+
|
54
|
+
context "#define_deferrable_callbacks" do
|
55
|
+
it "should define a callback for :succeeded" do
|
56
|
+
@body.should_receive(:callback)
|
57
|
+
subject
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should define a callback for :failed" do
|
61
|
+
@body.should_receive(:errback)
|
62
|
+
subject
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context "#send" do
|
67
|
+
it "should encode the message before sending" do
|
68
|
+
subject.should_receive(:encode_chunk).with('test message')
|
69
|
+
subject.send 'test message'
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should enqueue the message on DeferrableBody" do
|
73
|
+
encoded_message = subject.__send__(:encode_chunk,'test message')
|
74
|
+
@body.should_receive(:chunk).with(encoded_message)
|
75
|
+
subject.send 'test message'
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "#close!" do
|
80
|
+
it "calls #close! on the DefferableBody instance" do
|
81
|
+
@body.should_receive(:close!)
|
82
|
+
subject.close!
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -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
|