websocket-rails 0.5.0 → 0.6.0
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/CHANGELOG.md +11 -2
- data/lib/generators/websocket_rails/install/templates/websocket_rails.rb +7 -0
- data/lib/websocket_rails/configuration.rb +8 -0
- data/lib/websocket_rails/connection_adapters.rb +34 -29
- data/lib/websocket_rails/connection_manager.rb +35 -9
- data/lib/websocket_rails/event.rb +6 -2
- data/lib/websocket_rails/synchronization.rb +48 -3
- data/lib/websocket_rails/user_manager.rb +210 -19
- data/lib/websocket_rails/version.rb +1 -1
- data/spec/dummy/app/models/user.rb +2 -0
- data/spec/dummy/config/environments/test.rb +1 -2
- data/spec/dummy/config/{initializers/events.rb → events.rb} +0 -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/integration/connection_manager_spec.rb +2 -2
- data/spec/unit/connection_adapters_spec.rb +77 -41
- data/spec/unit/connection_manager_spec.rb +45 -9
- data/spec/unit/synchronization_spec.rb +47 -18
- data/spec/unit/user_manager_spec.rb +115 -11
- metadata +12 -7
@@ -7,8 +7,7 @@ Dummy::Application.configure do
|
|
7
7
|
# and recreated between test runs. Don't rely on the data there!
|
8
8
|
config.cache_classes = true
|
9
9
|
|
10
|
-
|
11
|
-
config.whiny_nils = true
|
10
|
+
config.eager_load = true
|
12
11
|
|
13
12
|
# Show full error reports and disable caching
|
14
13
|
config.consider_all_requests_local = true
|
File without changes
|
Binary file
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# This file is auto-generated from the current state of the database. Instead
|
3
|
+
# of editing this file, please use the migrations feature of Active Record to
|
4
|
+
# incrementally modify your database, and then regenerate this schema definition.
|
5
|
+
#
|
6
|
+
# Note that this schema.rb definition is the authoritative source for your
|
7
|
+
# database schema. If you need to create the application database on another
|
8
|
+
# system, you should be using db:schema:load, not running all the migrations
|
9
|
+
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
|
10
|
+
# you'll amass, the slower it'll run and the greater likelihood for issues).
|
11
|
+
#
|
12
|
+
# It's strongly recommended that you check this file into your version control system.
|
13
|
+
|
14
|
+
ActiveRecord::Schema.define(version: 20130902222552) do
|
15
|
+
|
16
|
+
create_table "users", force: true do |t|
|
17
|
+
t.string "name"
|
18
|
+
t.string "email"
|
19
|
+
t.datetime "created_at"
|
20
|
+
t.datetime "updated_at"
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
data/spec/dummy/db/test.sqlite3
CHANGED
Binary file
|
@@ -0,0 +1,17 @@
|
|
1
|
+
[1m[36m (1.2ms)[0m [1mCREATE TABLE "schema_migrations" ("version" varchar(255) NOT NULL) [0m
|
2
|
+
[1m[35m (0.7ms)[0m CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version")
|
3
|
+
[1m[36mActiveRecord::SchemaMigration Load (0.1ms)[0m [1mSELECT "schema_migrations".* FROM "schema_migrations"[0m
|
4
|
+
Migrating to CreateUsers (20130902222552)
|
5
|
+
[1m[35m (0.0ms)[0m begin transaction
|
6
|
+
[1m[36m (0.3ms)[0m [1mCREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255), "email" varchar(255), "created_at" datetime, "updated_at" datetime) [0m
|
7
|
+
[1m[35mSQL (1.4ms)[0m INSERT INTO "schema_migrations" ("version") VALUES (?) [["version", "20130902222552"]]
|
8
|
+
[1m[36m (0.9ms)[0m [1mcommit transaction[0m
|
9
|
+
[1m[35mActiveRecord::SchemaMigration Load (0.1ms)[0m SELECT "schema_migrations".* FROM "schema_migrations"
|
10
|
+
[1m[36mActiveRecord::SchemaMigration Load (0.1ms)[0m [1mSELECT "schema_migrations".* FROM "schema_migrations"[0m
|
11
|
+
[1m[35mActiveRecord::SchemaMigration Load (0.1ms)[0m SELECT "schema_migrations".* FROM "schema_migrations"
|
12
|
+
[1m[36m (1.0ms)[0m [1mCREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255), "email" varchar(255), "created_at" datetime, "updated_at" datetime) [0m
|
13
|
+
[1m[35m (1.0ms)[0m CREATE TABLE "schema_migrations" ("version" varchar(255) NOT NULL)
|
14
|
+
[1m[36m (0.8ms)[0m [1mCREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version")[0m
|
15
|
+
[1m[35m (0.1ms)[0m SELECT version FROM "schema_migrations"
|
16
|
+
[1m[36m (0.8ms)[0m [1mINSERT INTO "schema_migrations" (version) VALUES ('20130902222552')[0m
|
17
|
+
[1m[35mActiveRecord::SchemaMigration Load (0.1ms)[0m SELECT "schema_migrations".* FROM "schema_migrations"
|
@@ -111,7 +111,7 @@ module WebsocketRails
|
|
111
111
|
end
|
112
112
|
|
113
113
|
context "WebSocket Adapter" do
|
114
|
-
let(:socket) { @server.connections.first }
|
114
|
+
let(:socket) { @server.connections.first[1] }
|
115
115
|
|
116
116
|
before do
|
117
117
|
::Faye::WebSocket.stub(:websocket?).and_return(true)
|
@@ -122,7 +122,7 @@ module WebsocketRails
|
|
122
122
|
end
|
123
123
|
|
124
124
|
describe "HTTP Adapter" do
|
125
|
-
let(:socket) { @server.connections.first }
|
125
|
+
let(:socket) { @server.connections.first[1] }
|
126
126
|
|
127
127
|
before do
|
128
128
|
@server = ConnectionManager.new
|
@@ -18,8 +18,15 @@ module WebsocketRails
|
|
18
18
|
end
|
19
19
|
|
20
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
|
+
|
21
28
|
it "should return the correct connection adapter instance" do
|
22
|
-
adapter = ConnectionAdapters.establish_connection(
|
29
|
+
adapter = ConnectionAdapters.establish_connection(mock_request, @dispatcher)
|
23
30
|
adapter.class.should == ConnectionAdapters::Test
|
24
31
|
end
|
25
32
|
end
|
@@ -28,11 +35,18 @@ module WebsocketRails
|
|
28
35
|
|
29
36
|
module ConnectionAdapters
|
30
37
|
describe Base do
|
31
|
-
let(:
|
32
|
-
let(:
|
33
|
-
let(:
|
34
|
-
|
35
|
-
|
38
|
+
let(:connection_manager) { double(ConnectionManager).as_null_object }
|
39
|
+
let(:dispatcher) { double(Dispatcher).as_null_object }
|
40
|
+
let(:channel_manager) { double(ChannelManager).as_null_object }
|
41
|
+
let(:event) { double(Event).as_null_object }
|
42
|
+
|
43
|
+
before do
|
44
|
+
connection_manager.stub(:connections).and_return({})
|
45
|
+
dispatcher.stub(:connection_manager).and_return(connection_manager)
|
46
|
+
Event.stub(:new_from_json).and_return(event)
|
47
|
+
end
|
48
|
+
|
49
|
+
subject { Base.new(mock_request, dispatcher) }
|
36
50
|
|
37
51
|
context "new adapter" do
|
38
52
|
it "should register itself in the adapters array when inherited" do
|
@@ -44,17 +58,17 @@ module WebsocketRails
|
|
44
58
|
subject.data_store.should be_a DataStore::Connection
|
45
59
|
end
|
46
60
|
|
47
|
-
before do
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
end
|
61
|
+
#before do
|
62
|
+
# WebsocketRails.config.stub(:user_identifier).and_return(:name)
|
63
|
+
# WebsocketRails::DelegationController.any_instance
|
64
|
+
# .stub_chain(:current_user, :name)
|
65
|
+
# .and_return('Frank')
|
66
|
+
# subject
|
67
|
+
#end
|
54
68
|
|
55
|
-
it "adds itself to the UserManager Hash" do
|
56
|
-
|
57
|
-
end
|
69
|
+
#it "adds itself to the UserManager Hash" do
|
70
|
+
# WebsocketRails.users['Frank'].should == subject
|
71
|
+
#end
|
58
72
|
end
|
59
73
|
|
60
74
|
describe "#on_open" do
|
@@ -81,11 +95,6 @@ module WebsocketRails
|
|
81
95
|
dispatcher.should_receive(:dispatch).with(on_close_event)
|
82
96
|
subject.on_close("data")
|
83
97
|
end
|
84
|
-
|
85
|
-
it "removes itself from the global UserMnaager" do
|
86
|
-
subject.on_close
|
87
|
-
WebsocketRails.users[subject.id].nil?.should == true
|
88
|
-
end
|
89
98
|
end
|
90
99
|
|
91
100
|
describe "#on_error" do
|
@@ -137,45 +146,72 @@ module WebsocketRails
|
|
137
146
|
end
|
138
147
|
end
|
139
148
|
|
140
|
-
describe "#
|
141
|
-
|
142
|
-
|
143
|
-
|
149
|
+
describe "#user_connection?" do
|
150
|
+
context "when a user is signed in" do
|
151
|
+
before do
|
152
|
+
subject.stub(:user_identifier).and_return("Jimbo Jones")
|
153
|
+
end
|
154
|
+
|
155
|
+
it "returns true" do
|
156
|
+
subject.user_connection?.should == true
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
context "when a user is signed out" do
|
161
|
+
before do
|
162
|
+
subject.stub(:user_identifier).and_return(nil)
|
163
|
+
end
|
164
|
+
|
165
|
+
it "returns true" do
|
166
|
+
subject.user_connection?.should == false
|
167
|
+
end
|
144
168
|
end
|
145
169
|
end
|
146
170
|
|
147
|
-
describe "#
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
subject.
|
152
|
-
subject.
|
153
|
-
subject.trigger 'event'
|
171
|
+
describe "#user" do
|
172
|
+
it "provides access to the current_user object" do
|
173
|
+
user = double('User')
|
174
|
+
subject.stub(:user_identifier).and_return true
|
175
|
+
subject.stub_chain(:controller_delegate, :current_user).and_return user
|
176
|
+
subject.user.should == user
|
154
177
|
end
|
178
|
+
end
|
155
179
|
|
156
|
-
|
157
|
-
|
158
|
-
subject.
|
180
|
+
describe "#enqueue" do
|
181
|
+
it "should add the event to the queue" do
|
182
|
+
subject.enqueue 'event'
|
183
|
+
subject.queue.queue.should == ['event']
|
159
184
|
end
|
160
|
-
=end
|
161
185
|
end
|
162
186
|
|
163
187
|
describe "#flush" do
|
164
188
|
before do
|
165
|
-
event =
|
166
|
-
|
167
|
-
3.times { subject.enqueue event }
|
189
|
+
event = Event.new(:queued_event, data: 'test')
|
190
|
+
2.times { subject.enqueue event }
|
168
191
|
end
|
169
192
|
|
170
193
|
it "should serialize all events into one array" do
|
171
|
-
serialized_array =
|
172
|
-
|
194
|
+
serialized_array = <<-EOF.strip_heredoc
|
195
|
+
[["queued_event",{"id":null,"channel":null,"user_id":null,"data":"test","success":null,"result":null,"server_token":null}],
|
196
|
+
["queued_event",{"id":null,"channel":null,"user_id":null,"data":"test","success":null,"result":null,"server_token":null}]]
|
197
|
+
EOF
|
198
|
+
|
199
|
+
subject.should_receive(:send).with(serialized_array.gsub(/\n/,'').strip)
|
173
200
|
subject.flush
|
174
201
|
end
|
175
202
|
end
|
176
203
|
|
204
|
+
describe "#trigger" do
|
205
|
+
it "passes a serialized event to the connections #send method" do
|
206
|
+
event.stub(:serialize).and_return('test')
|
207
|
+
subject.should_receive(:send).with "[test]"
|
208
|
+
subject.trigger event
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
177
212
|
describe "#close_connection" do
|
178
213
|
before do
|
214
|
+
subject.stub(:user_identifier).and_return(1)
|
179
215
|
@connection_manager = double('connection_manager').as_null_object
|
180
216
|
subject.stub_chain(:dispatcher, :connection_manager).and_return(@connection_manager)
|
181
217
|
end
|
@@ -17,13 +17,13 @@ module WebsocketRails
|
|
17
17
|
|
18
18
|
before(:each) do
|
19
19
|
ConnectionAdapters::Base.any_instance.stub(:send)
|
20
|
-
@mock_socket = ConnectionAdapters::Base.new(mock_request,dispatcher)
|
20
|
+
@mock_socket = ConnectionAdapters::Base.new(mock_request, dispatcher)
|
21
21
|
ConnectionAdapters.stub(:establish_connection).and_return(@mock_socket)
|
22
22
|
end
|
23
23
|
|
24
24
|
describe "#initialize" do
|
25
|
-
it "should create an empty connections
|
26
|
-
subject.connections.should be_a
|
25
|
+
it "should create an empty connections hash" do
|
26
|
+
subject.connections.should be_a Hash
|
27
27
|
end
|
28
28
|
|
29
29
|
it "should create a new dispatcher instance" do
|
@@ -36,20 +36,44 @@ module WebsocketRails
|
|
36
36
|
expect { open_connection }.to change { connections.count }.by(1)
|
37
37
|
end
|
38
38
|
|
39
|
-
it "should store the new connection in the @connections
|
39
|
+
it "should store the new connection in the @connections Hash" do
|
40
40
|
open_connection
|
41
|
-
connections
|
41
|
+
connections[@mock_socket.id].should == @mock_socket
|
42
42
|
end
|
43
43
|
|
44
44
|
it "should return an Async Rack response" do
|
45
45
|
open_connection.should == [ -1, {}, [] ]
|
46
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
|
47
70
|
end
|
48
71
|
|
49
72
|
context "new POST event" do
|
50
73
|
before(:each) do
|
51
|
-
@mock_http = ConnectionAdapters::Http.new(mock_request,dispatcher)
|
52
|
-
|
74
|
+
@mock_http = ConnectionAdapters::Http.new(mock_request, dispatcher)
|
75
|
+
@mock_http.id = 1
|
76
|
+
app.connections[@mock_http.id] = @mock_http
|
53
77
|
end
|
54
78
|
|
55
79
|
it "should receive the new event for the correct connection" do
|
@@ -60,7 +84,7 @@ module WebsocketRails
|
|
60
84
|
|
61
85
|
context "open connections" do
|
62
86
|
before(:each) do
|
63
|
-
ConnectionAdapters.stub(:establish_connection).and_return(@mock_socket,ConnectionAdapters::Base.new(mock_request,dispatcher))
|
87
|
+
ConnectionAdapters.stub(:establish_connection).and_return(@mock_socket, ConnectionAdapters::Base.new(mock_request, dispatcher))
|
64
88
|
4.times { open_connection }
|
65
89
|
end
|
66
90
|
|
@@ -81,7 +105,7 @@ module WebsocketRails
|
|
81
105
|
context "when closing" do
|
82
106
|
it "should remove the connection object from the @connections array" do
|
83
107
|
@mock_socket.on_close
|
84
|
-
connections.
|
108
|
+
connections.has_key?(@mock_socket.id).should be_false
|
85
109
|
end
|
86
110
|
|
87
111
|
it "should decrement the connection count by one" do
|
@@ -95,6 +119,18 @@ module WebsocketRails
|
|
95
119
|
end
|
96
120
|
@mock_socket.on_close
|
97
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
|
98
134
|
end
|
99
135
|
|
100
136
|
end
|
@@ -1,18 +1,8 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
require "eventmachine"
|
3
|
+
require "ostruct"
|
3
4
|
|
4
5
|
module WebsocketRails
|
5
|
-
#class Synchronization
|
6
|
-
# def test_block(channel, &block)
|
7
|
-
# # do nothing beyatch
|
8
|
-
# block.call
|
9
|
-
# end
|
10
|
-
|
11
|
-
# def synchronize!
|
12
|
-
# test_block("something") { raise "FTW!" }
|
13
|
-
# end
|
14
|
-
#end
|
15
|
-
|
16
6
|
describe Synchronization do
|
17
7
|
|
18
8
|
around(:each) do |example|
|
@@ -59,7 +49,7 @@ module WebsocketRails
|
|
59
49
|
|
60
50
|
context "when dispatching user events" do
|
61
51
|
before do
|
62
|
-
@event = Event.new(:channel_event, :user_id =>
|
52
|
+
@event = Event.new(:channel_event, :user_id => "username", :data => 'hello channel one')
|
63
53
|
end
|
64
54
|
|
65
55
|
context "and the user is not connected to this server" do
|
@@ -71,18 +61,18 @@ module WebsocketRails
|
|
71
61
|
context "and the user is connected to this server" do
|
72
62
|
before do
|
73
63
|
@connection = double('Connection')
|
74
|
-
WebsocketRails.users[
|
64
|
+
WebsocketRails.users["username"] = @connection
|
75
65
|
end
|
76
66
|
|
77
67
|
it "triggers the event on the correct user" do
|
78
|
-
WebsocketRails.users[
|
68
|
+
WebsocketRails.users["username"].should_receive(:trigger).with @event
|
79
69
|
subject.trigger_incoming @event
|
80
70
|
end
|
81
71
|
end
|
82
72
|
end
|
83
73
|
end
|
84
74
|
|
85
|
-
describe "#
|
75
|
+
describe "#generate_server_token" do
|
86
76
|
before do
|
87
77
|
SecureRandom.stub(:urlsafe_base64).and_return(1, 2, 3)
|
88
78
|
end
|
@@ -91,14 +81,14 @@ module WebsocketRails
|
|
91
81
|
@redis.del "websocket_rails.active_servers"
|
92
82
|
end
|
93
83
|
|
94
|
-
it "should generate a unique token" do
|
84
|
+
it "should generate a unique server token" do
|
95
85
|
SecureRandom.should_receive(:urlsafe_base64).at_least(1).times
|
96
|
-
subject.
|
86
|
+
subject.generate_server_token
|
97
87
|
end
|
98
88
|
|
99
89
|
it "should generate another id if the current id is already registered" do
|
100
90
|
@redis.sadd "websocket_rails.active_servers", 1
|
101
|
-
token = subject.
|
91
|
+
token = subject.generate_server_token
|
102
92
|
token.should == 2
|
103
93
|
end
|
104
94
|
end
|
@@ -117,5 +107,44 @@ module WebsocketRails
|
|
117
107
|
end
|
118
108
|
end
|
119
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
|
+
|
120
149
|
end
|
121
150
|
end
|