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,181 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module WebsocketRails
|
|
4
|
+
describe Event do
|
|
5
|
+
let(:encoded_message) { '["new_message",{"id":"1234","data":{"message":"this is a message"}}]' }
|
|
6
|
+
let(:encoded_message_string) { '["new_message",{"id":"1234","data":"this is a message"}]' }
|
|
7
|
+
let(:namespace_encoded_message_string) { '["product.new_message",{"id":"1234","data":"this is a message"}]' }
|
|
8
|
+
let(:namespace_encoded_message) { '["product.new_message",{"id":"1234","data":{"message":"this is a message"}}]' }
|
|
9
|
+
let(:channel_encoded_message_string) { '["new_message",{"id":"1234","channel":"awesome_channel","user_id":null,"data":"this is a message","success":null,"result":null,"token":null,"server_token":"1234"}]' }
|
|
10
|
+
let(:synchronizable_encoded_message) { '["new_message",{"id":"1234","data":{"message":"this is a message"},"server_token":"1234"}]' }
|
|
11
|
+
let(:connection) { double('connection') }
|
|
12
|
+
let(:wrongly_encoded_message) { '["new_message",[{"id":"1234","data":{"message":"this is a message"}}]]' }
|
|
13
|
+
|
|
14
|
+
before { connection.stub(:id).and_return(1) }
|
|
15
|
+
|
|
16
|
+
describe ".new_from_json" do
|
|
17
|
+
context "messages in the global namespace" do
|
|
18
|
+
it "should decode a new message and store it" do
|
|
19
|
+
event = Event.new_from_json( encoded_message, connection )
|
|
20
|
+
event.connection.should == connection
|
|
21
|
+
event.name.should == :new_message
|
|
22
|
+
event.namespace.should == [:global]
|
|
23
|
+
event.data[:message].should == 'this is a message'
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
context "messages in a child namespace" do
|
|
28
|
+
it "should store the event with the correct namesapce" do
|
|
29
|
+
event = Event.new_from_json( namespace_encoded_message, connection )
|
|
30
|
+
event.namespace.should == [:global,:product]
|
|
31
|
+
event.name.should == :new_message
|
|
32
|
+
event.data[:message].should == 'this is a message'
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
context "invalid messages" do
|
|
37
|
+
it "should return an invalid event if data is wrongly encoded" do
|
|
38
|
+
event = Event.new_from_json( wrongly_encoded_message, connection )
|
|
39
|
+
event.is_invalid?.should be_true
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
describe ".new_on_open" do
|
|
45
|
+
before { @event = Event.new_on_open connection, {:message => 'connected'} }
|
|
46
|
+
|
|
47
|
+
it "should create an event named :client_connected" do
|
|
48
|
+
@event.name.should == :client_connected
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it "should send the connection id to the client" do
|
|
52
|
+
@event.data[:connection_id].should == 1
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "should merge the optional data with the connection id" do
|
|
56
|
+
@event.data[:message].should == 'connected'
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
describe ".new_on_close" do
|
|
61
|
+
it "should create an event named :client_disconnected" do
|
|
62
|
+
event = Event.new_on_close( connection, "optional_data" )
|
|
63
|
+
event.name.should == :client_disconnected
|
|
64
|
+
event.data.should == "optional_data"
|
|
65
|
+
event.connection.should == connection
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
describe ".new_on_error" do
|
|
70
|
+
it "should create an event named :client_error" do
|
|
71
|
+
event = Event.new_on_error( connection, "optional_data" )
|
|
72
|
+
event.name.should == :client_error
|
|
73
|
+
event.data.should == "optional_data"
|
|
74
|
+
event.connection.should == connection
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
context "new namespaced events" do
|
|
79
|
+
it "should store the namespace in the namespace attribute" do
|
|
80
|
+
event = Event.new "event", :data => {}, :connection => connection, :namespace => :product
|
|
81
|
+
event.namespace.should == [:global,:product]
|
|
82
|
+
event.name.should == :event
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it "should store nested namespaces in the namespace attribute" do
|
|
86
|
+
event = Event.new "event", :data => {}, :connection => connection, :namespace => [:product,:x_ray_vision]
|
|
87
|
+
event.namespace.should == [:global,:product,:x_ray_vision]
|
|
88
|
+
event.name.should == :event
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
context "new channel events" do
|
|
93
|
+
it "should store the channel name in the channel attribute" do
|
|
94
|
+
event = Event.new "event", :data => {}, :connection => connection, :channel => :awesome_channel
|
|
95
|
+
event.channel.should == :awesome_channel
|
|
96
|
+
event.name.should == :event
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it "should not raise an error if the channel name cannot be symbolized" do
|
|
100
|
+
expect { Event.new "event", :data => {}, :connection => connection, :channel => 5 }.to_not raise_error
|
|
101
|
+
event = Event.new "event", :data => {}, :connection => connection, :channel => 5
|
|
102
|
+
event.channel.should == :"5"
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
describe "#is_channel?" do
|
|
107
|
+
it "should return true if an event belongs to a channel" do
|
|
108
|
+
event = Event.new "event", :data => "data", :channel => :awesome_channel
|
|
109
|
+
event.is_channel?.should be_true
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
describe "#is_user?" do
|
|
114
|
+
it "returns true if the event is meant for a specific user" do
|
|
115
|
+
event = Event.new "event", :data => "data", :user_id => :username
|
|
116
|
+
event.is_user?
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
describe "#is_invalid?" do
|
|
121
|
+
it "returns true if the event name is :invalid_event" do
|
|
122
|
+
event = Event.new(:invalid_event)
|
|
123
|
+
event.is_invalid?.should be_true
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
describe "#is_internal?" do
|
|
128
|
+
it "returns true if the event is namespaced under websocket_rails" do
|
|
129
|
+
event = Event.new(:internal_event, :namespace => :websocket_rails)
|
|
130
|
+
event.is_internal?.should be_true
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
describe "#serialize" do
|
|
135
|
+
context "messages in the global namespace" do
|
|
136
|
+
it "should not add the global namespace to the event name" do
|
|
137
|
+
event = Event.new_from_json encoded_message_string, connection
|
|
138
|
+
raw_data = event.serialize
|
|
139
|
+
data = JSON.parse raw_data
|
|
140
|
+
data[0].should == "new_message"
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
context "messages in a child namespace" do
|
|
145
|
+
it "should add the namespace to the front of the event name" do
|
|
146
|
+
event = Event.new_from_json namespace_encoded_message_string, connection
|
|
147
|
+
raw_data = event.serialize
|
|
148
|
+
data = JSON.parse raw_data
|
|
149
|
+
data[0].should == "product.new_message"
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
context "messages for a channel" do
|
|
154
|
+
it "should add the channel name as the first element of the serialized array" do
|
|
155
|
+
event = Event.new_from_json channel_encoded_message_string, connection
|
|
156
|
+
event.serialize.should == channel_encoded_message_string
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
context "messages for synchronization" do
|
|
161
|
+
it "should include the unique server token" do
|
|
162
|
+
event = Event.new_from_json synchronizable_encoded_message, connection
|
|
163
|
+
raw_data = event.serialize
|
|
164
|
+
data = JSON.parse raw_data
|
|
165
|
+
data[1]['server_token'].should == '1234'
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
describe "#as_json" do
|
|
170
|
+
it "returns a Hash representation of the Event" do
|
|
171
|
+
hash = { data: { 'test' => 'test'}, channel: :awesome_channel }
|
|
172
|
+
event = Event.new 'test', hash
|
|
173
|
+
event.as_json[0].should == :test
|
|
174
|
+
event.as_json[1][:data].should == hash[:data]
|
|
175
|
+
event.as_json[1][:channel].should == hash[:channel]
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
end
|
|
181
|
+
end
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require "ostruct"
|
|
3
|
+
|
|
4
|
+
module WebsocketRails
|
|
5
|
+
describe Logging do
|
|
6
|
+
|
|
7
|
+
class LoggedClass
|
|
8
|
+
include Logging
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
let(:io) { StringIO.new }
|
|
12
|
+
let(:object) { LoggedClass.new }
|
|
13
|
+
|
|
14
|
+
before do
|
|
15
|
+
WebsocketRails.config.logger = Logger.new(io)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
describe "#info" do
|
|
19
|
+
it "logs the message" do
|
|
20
|
+
object.info "info logged"
|
|
21
|
+
io.string.should include("info logged")
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
describe "#debug" do
|
|
26
|
+
it "logs the message" do
|
|
27
|
+
object.debug "debug logged"
|
|
28
|
+
io.string.should include("debug logged")
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
describe "log_exception" do
|
|
33
|
+
let(:exception) { Exception.new('kaputt!').tap { |e| e.set_backtrace(['line 1', 'line 2']) } }
|
|
34
|
+
|
|
35
|
+
it "logs the exception message" do
|
|
36
|
+
object.log_exception(exception)
|
|
37
|
+
io.string.should include('kaputt!')
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "logs the backtrace" do
|
|
41
|
+
object.log_exception(exception)
|
|
42
|
+
io.string.should include("line 1")
|
|
43
|
+
io.string.should include("line 2")
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
context "logging an event" do
|
|
48
|
+
before do
|
|
49
|
+
data = {
|
|
50
|
+
namespace: :logger,
|
|
51
|
+
data: {message: "hello"},
|
|
52
|
+
connection: double('connection')
|
|
53
|
+
}
|
|
54
|
+
@event = Event.new(:logged_event, data)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
describe "#log_event_start" do
|
|
58
|
+
it "logs the event information" do
|
|
59
|
+
object.log_event_start(@event)
|
|
60
|
+
io.string.should include("Started Event:")
|
|
61
|
+
io.string.should include("logger.logged_event")
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
describe "#log_event_end" do
|
|
66
|
+
it "logs the total time the event took to process" do
|
|
67
|
+
time = 12
|
|
68
|
+
object.log_event_end(@event, time)
|
|
69
|
+
io.string.should include("Event #{@event.encoded_name} Finished in #{time.to_f.to_d.to_s} seconds")
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
describe "#log_event" do
|
|
74
|
+
it "logs the start of the event" do
|
|
75
|
+
object.should_receive(:log_event_start).with(@event)
|
|
76
|
+
object.log_event(@event) { true }
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it "logs the end of the event" do
|
|
80
|
+
time = Time.now
|
|
81
|
+
Time.stub(:now).and_return(time)
|
|
82
|
+
object.should_receive(:log_event_end).with(@event, 0)
|
|
83
|
+
object.log_event(@event) { true }
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it "executes the block" do
|
|
87
|
+
executed = false
|
|
88
|
+
object.log_event(@event) { executed = true }
|
|
89
|
+
executed.should == true
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it "logs any exceptions" do
|
|
93
|
+
exception = Exception.new("ouch")
|
|
94
|
+
object.should_receive(:log_exception).with(exception)
|
|
95
|
+
expect {
|
|
96
|
+
object.log_event(@event) { raise exception }
|
|
97
|
+
}.to raise_exception(exception.class, exception.message)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
describe "#log_data?" do
|
|
103
|
+
before do
|
|
104
|
+
@hash_event = Event.new(:log_test, :data => {test: true})
|
|
105
|
+
@string_event = Event.new(:log_test, :data => "message")
|
|
106
|
+
@object_event = Event.new(:log_test, :data => OpenStruct.new)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it "returns true if data is an allowed type" do
|
|
110
|
+
object.log_data?(@hash_event).should == true
|
|
111
|
+
object.log_data?(@string_event).should == true
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
it "returns false if the data is not an allows type" do
|
|
115
|
+
object.log_data?(@object_event).should == false
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
describe "#log_event?" do
|
|
120
|
+
context "with an internal event" do
|
|
121
|
+
before do
|
|
122
|
+
@event = Event.new(:internal, :namespace => :websocket_rails)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
context "when WebsocketRails.config.log_internal_events? is false" do
|
|
126
|
+
it "returns false" do
|
|
127
|
+
WebsocketRails.config.log_internal_events = false
|
|
128
|
+
object.log_event?(@event).should == false
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
context "when WebsocketRails.config.log_internal_events? is true" do
|
|
133
|
+
it "returns true" do
|
|
134
|
+
WebsocketRails.config.log_internal_events = true
|
|
135
|
+
object.log_event?(@event).should == true
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
context "with an external event" do
|
|
141
|
+
before do
|
|
142
|
+
@event = Event.new(:external)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
context "when WebsocketRails.config.log_internal_events? is false" do
|
|
146
|
+
it "returns true" do
|
|
147
|
+
WebsocketRails.config.log_internal_events = false
|
|
148
|
+
object.log_event?(@event).should == true
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
context "when WebsocketRails.config.log_internal_events? is true" do
|
|
153
|
+
it "returns true" do
|
|
154
|
+
WebsocketRails.config.log_internal_events = true
|
|
155
|
+
object.log_event?(@event).should == true
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
end
|
|
162
|
+
end
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
require "eventmachine"
|
|
3
|
+
require "ostruct"
|
|
4
|
+
|
|
5
|
+
module WebsocketRails
|
|
6
|
+
describe Synchronization do
|
|
7
|
+
|
|
8
|
+
around(:each) do |example|
|
|
9
|
+
EM.run do
|
|
10
|
+
Fiber.new do
|
|
11
|
+
@redis = Redis.new(WebsocketRails.config.redis_options)
|
|
12
|
+
@redis.del "websocket_rails.active_servers"
|
|
13
|
+
example.run
|
|
14
|
+
end.resume
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
after(:each) do
|
|
19
|
+
@redis.del "websocket_rails.active_servers"
|
|
20
|
+
EM.stop
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
let(:subject) { Synchronization.singleton }
|
|
24
|
+
|
|
25
|
+
describe "#publish" do
|
|
26
|
+
it "should add the serialized event to the websocket_rails.events channel" do
|
|
27
|
+
event = Event.new(:test_event, :channel => 'synchrony', :data => 'hello channel')
|
|
28
|
+
Redis.any_instance.should_receive(:publish).with("websocket_rails.events", event.serialize)
|
|
29
|
+
|
|
30
|
+
subject.publish(event)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
describe "#synchronize!" do
|
|
35
|
+
# need to add an integration test to cover this.
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
describe "#trigger_incoming" do
|
|
39
|
+
context "when dispatching channel events" do
|
|
40
|
+
before do
|
|
41
|
+
@event = Event.new(:channel_event, :channel => :channel_one, :data => 'hello channel one')
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "triggers the event on the correct channel" do
|
|
45
|
+
WebsocketRails[:channel_one].should_receive(:trigger_event).with @event
|
|
46
|
+
subject.trigger_incoming @event
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
context "when dispatching user events" do
|
|
51
|
+
before do
|
|
52
|
+
@event = Event.new(:channel_event, :user_id => "username", :data => 'hello channel one')
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
context "and the user is not connected to this server" do
|
|
56
|
+
it "does nothing" do
|
|
57
|
+
subject.trigger_incoming(@event).should == nil
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
context "and the user is connected to this server" do
|
|
62
|
+
before do
|
|
63
|
+
@connection = double('Connection')
|
|
64
|
+
WebsocketRails.users["username"] = @connection
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "triggers the event on the correct user" do
|
|
68
|
+
WebsocketRails.users["username"].should_receive(:trigger).with @event
|
|
69
|
+
subject.trigger_incoming @event
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
describe "#generate_server_token" do
|
|
76
|
+
before do
|
|
77
|
+
SecureRandom.stub(:urlsafe_base64).and_return(1, 2, 3)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
after do
|
|
81
|
+
@redis.del "websocket_rails.active_servers"
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it "should generate a unique server token" do
|
|
85
|
+
SecureRandom.should_receive(:urlsafe_base64).at_least(1).times
|
|
86
|
+
subject.generate_server_token
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it "should generate another id if the current id is already registered" do
|
|
90
|
+
@redis.sadd "websocket_rails.active_servers", 1
|
|
91
|
+
token = subject.generate_server_token
|
|
92
|
+
token.should == 2
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
describe "#register_server" do
|
|
97
|
+
it "should add the unique token to the active_servers key in redis" do
|
|
98
|
+
Redis.any_instance.should_receive(:sadd).with("websocket_rails.active_servers", "token")
|
|
99
|
+
subject.register_server "token"
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
describe "#remove_server" do
|
|
104
|
+
it "should remove the unique token from the active_servers key in redis" do
|
|
105
|
+
Redis.any_instance.should_receive(:srem).with("websocket_rails.active_servers", "token")
|
|
106
|
+
subject.remove_server "token"
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
describe "#register_user" do
|
|
111
|
+
before do
|
|
112
|
+
@connection = double('Connection')
|
|
113
|
+
@user = User.new
|
|
114
|
+
@user.attributes.update(name: 'Frank The Tank', email: 'frank@tank.com')
|
|
115
|
+
@user.instance_variable_set(:@new_record, false)
|
|
116
|
+
@user.instance_variable_set(:@destroyed, false)
|
|
117
|
+
@connection.stub(:user_identifier).and_return 'Frank The Tank'
|
|
118
|
+
@connection.stub(:user).and_return @user
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it "stores the serialized user object in redis" do
|
|
122
|
+
@user.persisted?.should == true
|
|
123
|
+
Redis.any_instance.should_receive(:hset).with("websocket_rails.users", @connection.user_identifier, @user.as_json.to_json)
|
|
124
|
+
Synchronization.register_user(@connection)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
describe "#destroy_user" do
|
|
129
|
+
it "stores the serialized user object in redis" do
|
|
130
|
+
Redis.any_instance.should_receive(:hdel).with("websocket_rails.users", 'user_id')
|
|
131
|
+
Synchronization.destroy_user('user_id')
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
describe "#find_user" do
|
|
136
|
+
it "retrieves the serialized user object in redis" do
|
|
137
|
+
Redis.any_instance.should_receive(:hget).with("websocket_rails.users", 'test')
|
|
138
|
+
Synchronization.find_user('test')
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
describe "#all_users" do
|
|
143
|
+
it "retrieves the entire serialized users hash redis" do
|
|
144
|
+
Redis.any_instance.should_receive(:hgetall).with("websocket_rails.users")
|
|
145
|
+
Synchronization.all_users
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
end
|
|
150
|
+
end
|