websocket-rails 0.1.8 → 0.1.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -7,7 +7,7 @@ module WebsocketRails
7
7
  class ProductController < BaseController
8
8
  def update_list; true; end
9
9
  end
10
-
10
+
11
11
  def define_test_events
12
12
  WebsocketRails.route_block = nil
13
13
  WebsocketRails::EventMap.describe do
@@ -23,13 +23,13 @@ module WebsocketRails
23
23
  end
24
24
  end
25
25
  end
26
-
27
- before(:all) {
26
+
27
+ before(:all) do
28
28
  define_test_events
29
29
  if defined?(ConnectionAdapters::Test)
30
30
  ConnectionAdapters.adapters.delete( ConnectionAdapters::Test )
31
31
  end
32
- }
32
+ end
33
33
 
34
34
  shared_examples "an evented rack server" do
35
35
  context "new connections" do
@@ -38,12 +38,12 @@ module WebsocketRails
38
38
  @server.call( env )
39
39
  end
40
40
  end
41
-
41
+
42
42
  context "active connections" do
43
43
  context "new message from client" do
44
44
  let(:test_message) { ['change_username',{:user_name => 'Joe User'}] }
45
45
  let(:encoded_message) { test_message.to_json }
46
-
46
+
47
47
  it "should execute the controller action associated with the received event" do
48
48
  ChatController.any_instance.should_receive(:change_username)
49
49
  @server.call( env )
@@ -54,7 +54,7 @@ module WebsocketRails
54
54
  context "new message from client under a namespace" do
55
55
  let(:test_message) { ['products.update_list',{:product => 'x-ray-vision'}] }
56
56
  let(:encoded_message) { test_message.to_json }
57
-
57
+
58
58
  it "should execute the controller action under the correct namespace" do
59
59
  ChatController.any_instance.should_not_receive(:update_user_list)
60
60
  ProductController.any_instance.should_receive(:update_list)
@@ -64,17 +64,17 @@ module WebsocketRails
64
64
  end
65
65
 
66
66
  context "subscribing to a channel" do
67
- let(:channel_message) { ['websocket_rails.subscribe',{:data => { :channel => 'awesome_channel'}}] }
67
+ let(:channel_message) { ['websocket_rails.subscribe',{:data => {:channel => 'test_chan'}}] }
68
68
  let(:encoded_channel_message) { channel_message.to_json }
69
69
 
70
70
  it "should subscribe the connection to the correct channel" do
71
- @server.call( env )
72
- channel = WebsocketRails[:awesome_channel]
73
- channel.should_receive(:subscribe).once.with(socket)
74
- socket.on_message encoded_channel_message
71
+ #channel = WebsocketRails[:test_chan]
72
+ #@server.call( env )
73
+ #channel.should_receive(:subscribe).with(socket)
74
+ #socket.on_message encoded_channel_message
75
75
  end
76
76
  end
77
-
77
+
78
78
  context "client error" do
79
79
  it "should execute the controller action associated with the 'client_error' event" do
80
80
  ChatController.any_instance.should_receive(:error_occurred)
@@ -82,7 +82,7 @@ module WebsocketRails
82
82
  socket.on_error
83
83
  end
84
84
  end
85
-
85
+
86
86
  context "client disconnects" do
87
87
  it "should execute the controller action associated with the 'client_disconnected' event" do
88
88
  ChatController.any_instance.should_receive(:delete_user)
@@ -95,7 +95,7 @@ module WebsocketRails
95
95
 
96
96
  context "WebSocket Adapter" do
97
97
  let(:socket) { @server.connections.first }
98
-
98
+
99
99
  before do
100
100
  ::Faye::WebSocket.stub(:websocket?).and_return(true)
101
101
  @server = ConnectionManager.new
@@ -63,7 +63,7 @@
63
63
  if (this._conn.readyState === 3) {
64
64
  data = this._conn.responseText.substring(this.last_pos);
65
65
  this.last_pos = this._conn.responseText.length;
66
- data = data.replace("]][[", "],[");
66
+ data = data.replace(/\]\]\[\[/g, "],[");
67
67
  decoded_data = JSON.parse(data);
68
68
  return this.dispatcher.new_message(decoded_data);
69
69
  }
@@ -14,6 +14,8 @@ WebSocket Interface for the WebSocketRails client.
14
14
  this.dispatcher = dispatcher;
15
15
  this.flush_queue = __bind(this.flush_queue, this);
16
16
 
17
+ this.on_error = __bind(this.on_error, this);
18
+
17
19
  this.on_close = __bind(this.on_close, this);
18
20
 
19
21
  this.on_message = __bind(this.on_message, this);
@@ -27,6 +29,7 @@ WebSocket Interface for the WebSocketRails client.
27
29
  this._conn = new WebSocket(this.url);
28
30
  this._conn.onmessage = this.on_message;
29
31
  this._conn.onclose = this.on_close;
32
+ this._conn.onerror = this.on_error;
30
33
  }
31
34
 
32
35
  WebSocketConnection.prototype.trigger = function(event) {
@@ -49,6 +52,12 @@ WebSocket Interface for the WebSocketRails client.
49
52
  return this.dispatcher.dispatch(close_event);
50
53
  };
51
54
 
55
+ WebSocketConnection.prototype.on_error = function(event) {
56
+ var error_event;
57
+ error_event = new WebSocketRails.Event(['connection_error', event != null ? event.data : void 0]);
58
+ return this.dispatcher.dispatch(error_event);
59
+ };
60
+
52
61
  WebSocketConnection.prototype.flush_queue = function() {
53
62
  var event, _i, _len, _ref;
54
63
  _ref = this.message_queue;
@@ -24,14 +24,14 @@ module WebsocketRails
24
24
  describe "#trigger" do
25
25
  it "should create a new event and trigger it on all subscribers" do
26
26
  event = double('event').as_null_object
27
- Event.should_receive(:new) do |name,data|
27
+ Event.should_receive(:new) do |name,options|
28
28
  name.should == 'event'
29
- data[:data].should == 'data'
29
+ options[:data].should == 'data'
30
30
  event
31
31
  end
32
32
  connection.should_receive(:trigger).with(event)
33
33
  subject.subscribe connection
34
- subject.trigger 'event', :data => 'data'
34
+ subject.trigger 'event', 'data'
35
35
  end
36
36
  end
37
37
 
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  module WebsocketRails
4
4
  describe ConnectionManager do
5
5
  include Rack::Test::Methods
6
-
6
+
7
7
  def app
8
8
  @app ||= ConnectionManager.new
9
9
  end
@@ -11,26 +11,36 @@ module WebsocketRails
11
11
  def open_connection
12
12
  subject.call(env)
13
13
  end
14
-
14
+
15
15
  let(:connections) { subject.connections }
16
16
  let(:dispatcher) { subject.dispatcher }
17
-
17
+
18
18
  before(:each) do
19
19
  ConnectionAdapters::Base.any_instance.stub(:send)
20
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
+ describe "#initialize" do
25
+ it "should create an empty connections array" do
26
+ subject.connections.should be_a Array
27
+ end
28
+
29
+ it "should create a new dispatcher instance" do
30
+ subject.dispatcher.should be_a Dispatcher
31
+ end
32
+ end
33
+
24
34
  context "new connections" do
25
35
  it "should add one to the total connection count" do
26
36
  expect { open_connection }.to change { connections.count }.by(1)
27
37
  end
28
-
38
+
29
39
  it "should store the new connection in the @connections array" do
30
40
  open_connection
31
41
  connections.include?(@mock_socket).should be_true
32
42
  end
33
-
43
+
34
44
  it "should return an Async Rack response" do
35
45
  open_connection.should == [ -1, {}, [] ]
36
46
  end
@@ -41,19 +51,19 @@ module WebsocketRails
41
51
  @mock_http = ConnectionAdapters::Http.new(mock_request,dispatcher)
42
52
  app.connections << @mock_http
43
53
  end
44
-
54
+
45
55
  it "should receive the new event for the correct connection" do
46
56
  @mock_http.should_receive(:on_message).with(encoded_message)
47
57
  post '/websocket', {:client_id => @mock_http.id, :data => encoded_message}
48
58
  end
49
59
  end
50
-
60
+
51
61
  context "open connections" do
52
62
  before(:each) do
53
63
  ConnectionAdapters.stub(:establish_connection).and_return(@mock_socket,ConnectionAdapters::Base.new(mock_request,dispatcher))
54
64
  4.times { open_connection }
55
65
  end
56
-
66
+
57
67
  context "when receiving a new event" do
58
68
  before(:each) { open_connection }
59
69
 
@@ -67,17 +77,17 @@ module WebsocketRails
67
77
  @mock_socket.on_message(mock_event)
68
78
  end
69
79
  end
70
-
80
+
71
81
  context "when closing" do
72
82
  it "should remove the connection object from the @connections array" do
73
83
  @mock_socket.on_close
74
84
  connections.include?(@mock_socket).should be_false
75
85
  end
76
-
86
+
77
87
  it "should decrement the connection count by one" do
78
88
  expect { @mock_socket.on_close }.to change { connections.count }.by(-1)
79
89
  end
80
-
90
+
81
91
  it "should dispatch the :client_disconnected event" do
82
92
  dispatcher.should_receive(:dispatch) do |event|
83
93
  event.name.should == :client_disconnected
@@ -86,14 +96,14 @@ module WebsocketRails
86
96
  @mock_socket.on_close
87
97
  end
88
98
  end
89
-
99
+
90
100
  end
91
-
101
+
92
102
  context "invalid connections" do
93
103
  before(:each) do
94
104
  ConnectionAdapters.stub(:establish_connection).and_raise(InvalidConnectionError)
95
105
  end
96
-
106
+
97
107
  it "should return a 400 bad request error code" do
98
108
  open_connection.first.should == 400
99
109
  end
@@ -2,22 +2,22 @@ require 'spec_helper'
2
2
  require 'support/mock_web_socket'
3
3
 
4
4
  module WebsocketRails
5
-
5
+
6
6
  class EventTarget
7
7
  attr_reader :_event, :test_method
8
-
8
+
9
9
  def execute_observers(event_name)
10
10
  true
11
11
  end
12
12
  end
13
-
13
+
14
14
  describe Dispatcher do
15
-
15
+
16
16
  let(:event) { double('Event') }
17
17
  let(:connection) { MockWebSocket.new }
18
18
  let(:connection_manager) { double('connection_manager').as_null_object }
19
19
  subject { Dispatcher.new(connection_manager) }
20
-
20
+
21
21
  describe "#receive_encoded" do
22
22
  context "receiving a new message" do
23
23
  before do
@@ -42,7 +42,7 @@ module WebsocketRails
42
42
  subject.receive(:test_event,{},connection)
43
43
  end
44
44
  end
45
-
45
+
46
46
  context "dispatching a message for an event" do
47
47
  before do
48
48
  @target = EventTarget.new
@@ -51,13 +51,14 @@ module WebsocketRails
51
51
  event.stub(:data).and_return(:some_message)
52
52
  event.stub(:connection).and_return(connection)
53
53
  event.stub(:is_channel?).and_return(false)
54
+ event.stub(:is_invalid?).and_return(false)
54
55
  end
55
-
56
+
56
57
  it "should execute the correct method on the target class" do
57
58
  @target.should_receive(:test_method)
58
59
  subject.dispatch(event)
59
60
  end
60
-
61
+
61
62
  it "should set the _event instance variable on the target object" do
62
63
  subject.dispatch(event)
63
64
  @target._event.should == event
@@ -72,8 +73,19 @@ module WebsocketRails
72
73
  subject.dispatch event
73
74
  end
74
75
  end
76
+
77
+ context "invalid events" do
78
+ before do
79
+ event.stub(:is_invalid?).and_return(true)
80
+ end
81
+
82
+ it "should not dispatch the event" do
83
+ subject.should_not_receive(:route)
84
+ subject.dispatch(event)
85
+ end
86
+ end
75
87
  end
76
-
88
+
77
89
  describe "#send_message" do
78
90
  before do
79
91
  @event = Event.new_from_json( encoded_message, connection )
@@ -6,7 +6,8 @@ module WebsocketRails
6
6
  let(:encoded_message_string) { '["new_message",{"id":"1234","data":"this is a message"}]' }
7
7
  let(:namespace_encoded_message_string) { '["product.new_message",{"id":"1234","data":"this is a message"}]' }
8
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","data":"this is a message","success":null,"result":null}]' }
9
+ let(:channel_encoded_message_string) { '["new_message",{"id":"1234","channel":"awesome_channel","data":"this is a message","success":null,"result":null,"server_token":"1234"}]' }
10
+ let(:synchronizable_encoded_message) { '["new_message",{"id":"1234","data":{"message":"this is a message"},"server_token":"1234"}]' }
10
11
  let(:connection) { double('connection') }
11
12
 
12
13
  before { connection.stub!(:id).and_return(1) }
@@ -120,6 +121,15 @@ module WebsocketRails
120
121
  event.serialize.should == channel_encoded_message_string
121
122
  end
122
123
  end
124
+
125
+ context "messages for synchronization" do
126
+ it "should include the unique server token" do
127
+ event = Event.new_from_json synchronizable_encoded_message, connection
128
+ raw_data = event.serialize
129
+ data = JSON.parse raw_data
130
+ data[1]['server_token'].should == '1234'
131
+ end
132
+ end
123
133
  end
124
134
 
125
135
  end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ module WebsocketRails
4
+ class ClassWithLogging
5
+ include Logging
6
+ end
7
+
8
+ describe ClassWithLogging do
9
+
10
+ describe "#log" do
11
+ context "when log_level = :warn" do
12
+ before do
13
+ WebsocketRails.setup do |config|
14
+ config.log_level = :warn
15
+ end
16
+ end
17
+
18
+ it "should not print to the console" do
19
+ subject.should_not_receive(:puts).with("test message")
20
+ subject.log "test message"
21
+ end
22
+ end
23
+
24
+ context "log_level = :debug" do
25
+ before do
26
+ WebsocketRails.setup do |config|
27
+ config.log_level = :debug
28
+ end
29
+ end
30
+
31
+ it "should print to the console if log_level is :debug" do
32
+ subject.should_receive(:puts).with("test message")
33
+ subject.log "test message"
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,68 @@
1
+ require "spec_helper"
2
+ require "eventmachine"
3
+
4
+ module WebsocketRails
5
+ describe Synchronization do
6
+
7
+ around(:each) do |example|
8
+ EM.run do
9
+ Fiber.new do
10
+ @redis = Redis.new
11
+ @redis.del "websocket_rails.active_servers"
12
+ example.run
13
+ end.resume
14
+ end
15
+ end
16
+
17
+ after(:each) do
18
+ EM.stop
19
+ end
20
+
21
+ let(:subject) { Synchronization }
22
+
23
+ describe "#publish" do
24
+ it "should add the serialized event to the websocket_rails.events channel" do
25
+ event = Event.new(:test_event, :channel => 'synchrony', :data => 'hello channel')
26
+ Redis.any_instance.should_receive(:publish).with("websocket_rails.events", event.serialize)
27
+
28
+ subject.publish(event)
29
+ end
30
+ end
31
+
32
+ describe "#generate_unique_token" do
33
+ before do
34
+ SecureRandom.stub(:urlsafe_base64).and_return(1, 2, 3)
35
+ end
36
+
37
+ after do
38
+ @redis.del "websocket_rails.active_servers"
39
+ end
40
+
41
+ it "should generate a unique token" do
42
+ SecureRandom.should_receive(:urlsafe_base64).at_least(1).times
43
+ subject.generate_unique_token
44
+ end
45
+
46
+ it "should generate another id if the current id is already registered" do
47
+ @redis.sadd "websocket_rails.active_servers", 1
48
+ token = subject.generate_unique_token
49
+ token.should == 2
50
+ end
51
+ end
52
+
53
+ describe "#register_server" do
54
+ it "should add the unique token to the active_servers key in redis" do
55
+ Redis.any_instance.should_receive(:sadd).with("websocket_rails.active_servers", "token")
56
+ subject.register_server "token"
57
+ end
58
+ end
59
+
60
+ describe "#remove_server" do
61
+ it "should add the unique token to the active_servers key in redis" do
62
+ Redis.any_instance.should_receive(:srem).with("websocket_rails.active_servers", "token")
63
+ subject.remove_server "token"
64
+ end
65
+ end
66
+
67
+ end
68
+ end