websocket-rails 0.1.8 → 0.1.9

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.
@@ -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