slanger 0.4.1 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of slanger might be problematic. Click here for more details.

@@ -0,0 +1,114 @@
1
+ #encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe 'Integration:' do
5
+
6
+ before(:each) { start_slanger }
7
+
8
+ describe 'channel' do
9
+ it 'pushes messages to interested websocket connections' do
10
+ messages = em_stream do |websocket, messages|
11
+ case messages.length
12
+ when 1
13
+ websocket.callback { websocket.send({ event: 'pusher:subscribe', data: { channel: 'MY_CHANNEL'} }.to_json) }
14
+ when 2
15
+ Pusher['MY_CHANNEL'].trigger 'an_event', some: "Mit Raben Und Wölfen"
16
+ when 3
17
+ EM.stop
18
+ end
19
+ end
20
+
21
+ messages.should have_attributes connection_established: true, id_present: true,
22
+ last_event: 'an_event', last_data: { some: "Mit Raben Und Wölfen" }.to_json
23
+ end
24
+
25
+ it 'does not send message to excluded sockets' do
26
+ messages = em_stream do |websocket, messages|
27
+ case messages.length
28
+ when 1
29
+ websocket.callback { websocket.send({ event: 'pusher:subscribe', data: { channel: 'MY_CHANNEL'} }.to_json) }
30
+ when 2
31
+ socket_id = JSON.parse(messages.first["data"])["socket_id"]
32
+ Pusher['MY_CHANNEL'].trigger 'not_excluded_socket_event', { some: "Mit Raben Und Wölfen" }
33
+ Pusher['MY_CHANNEL'].trigger 'excluded_socket_event', { some: "Mit Raben Und Wölfen" }, socket_id
34
+ when 3
35
+ EM.stop
36
+ end
37
+ end
38
+
39
+ messages.should have_attributes connection_established: true, id_present: true,
40
+ last_event: 'not_excluded_socket_event', last_data: { some: "Mit Raben Und Wölfen" }.to_json
41
+ end
42
+
43
+ it 'enforces one subcription per channel, per socket' do
44
+ messages = em_stream do |websocket, messages|
45
+ case messages.length
46
+ when 1
47
+ websocket.callback { websocket.send({ event: 'pusher:subscribe', data: { channel: 'MY_CHANNEL'} }.to_json) }
48
+ when 2
49
+ websocket.send({ event: 'pusher:subscribe', data: { channel: 'MY_CHANNEL'} }.to_json)
50
+ when 3
51
+ EM.stop
52
+ end
53
+ end
54
+
55
+ messages.last.should == {"event"=>"pusher:error", "data"=>"{\"code\":null,\"message\":\"Existing subscription to MY_CHANNEL\"}"}
56
+ end
57
+
58
+ it 'supports unsubscribing to channels without closing the socket' do
59
+ client2_messages = nil
60
+
61
+ messages = em_stream do |client, messages|
62
+ case messages.length
63
+ when 1
64
+ client.callback { client.send({ event: 'pusher:subscribe', data: { channel: 'MY_CHANNEL'} }.to_json) }
65
+ when 2
66
+ client.send({ event: 'pusher:unsubscribe', data: { channel: 'MY_CHANNEL'} }.to_json)
67
+
68
+ client2_messages = em_stream do |client2, client2_messages|
69
+ case client2_messages.length
70
+ when 1
71
+ client2.callback { client2.send({ event: 'pusher:subscribe', data: { channel: 'MY_CHANNEL'} }.to_json) }
72
+ when 2
73
+ Pusher['MY_CHANNEL'].trigger 'an_event', { some: 'data' }
74
+ EM.next_tick { EM.stop }
75
+ end
76
+ end
77
+ end
78
+ end
79
+
80
+ messages.should have_attributes connection_established: true, id_present: true,
81
+ last_event: 'pusher_internal:subscription_succeeded', count: 2
82
+ end
83
+
84
+ it 'avoids sending duplicate events' do
85
+ client2_messages = nil
86
+
87
+ client1_messages = em_stream do |client1, client1_messages|
88
+ # if this is the first message to client 1 set up another connection from the same client
89
+ if client1_messages.one?
90
+ client1.callback do
91
+ client1.send({ event: 'pusher:subscribe', data: { channel: 'MY_CHANNEL'} }.to_json)
92
+ end
93
+
94
+ client2_messages = em_stream do |client2, client2_messages|
95
+ case client2_messages.length
96
+ when 1
97
+ client2.callback { client2.send({ event: 'pusher:subscribe', data: { channel: 'MY_CHANNEL'} }.to_json) }
98
+ when 2
99
+ socket_id = JSON.parse(client1_messages.first['data'])['socket_id']
100
+ Pusher['MY_CHANNEL'].trigger 'an_event', { some: 'data' }, socket_id
101
+ when 3
102
+ EM.stop
103
+ end
104
+ end
105
+ end
106
+ end
107
+
108
+ client1_messages.should have_attributes count: 2
109
+
110
+ client2_messages.should have_attributes last_event: 'an_event',
111
+ last_data: { some: 'data' }.to_json
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,68 @@
1
+ #encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe 'Integration' do
5
+
6
+ before(:each) { start_slanger }
7
+
8
+ context "connecting with invalid credentials" do
9
+ it "sends an error message" do
10
+ messages = em_stream(key: 'bogus_key') do |websocket, messages|
11
+ websocket.callback { EM.stop }
12
+ end
13
+ messages.should have_attributes count: 1, last_event: 'pusher:error',
14
+ connection_established: false, id_present: false
15
+ messages.first['data'] == 'Could not find app by key bogus_key'
16
+ end
17
+ end
18
+
19
+ context "connecting with valid credentials" do
20
+ it "should succeed and include activity_timeout value in handshake" do
21
+ messages = em_stream do |websocket, messages|
22
+ websocket.callback { EM.stop }
23
+ end
24
+ messages.should have_attributes activity_timeout: Slanger::Config.activity_timeout,
25
+ connection_established: true, id_present: true
26
+ end
27
+ end
28
+
29
+ context "connect with valid protocol version" do
30
+ it "should connect successfuly" do
31
+ messages = em_stream do |websocket, messages|
32
+ websocket.callback { EM.stop }
33
+ end
34
+ messages.should have_attributes connection_established: true, id_present: true
35
+ end
36
+ end
37
+
38
+ context "connect with invalid protocol version" do
39
+ it "should not connect successfuly with version bigger than supported" do
40
+ messages = em_stream(protocol: "20") do |websocket, messages|
41
+ websocket.callback { EM.stop }
42
+ end
43
+ messages.should have_attributes connection_established: false, id_present: false,
44
+ last_event: 'pusher:error'
45
+ end
46
+
47
+ it "should not connect successfuly without specified version" do
48
+ messages = em_stream(protocol: nil) do |websocket, messages|
49
+ websocket.callback { EM.stop }
50
+ end
51
+ messages.should have_attributes connection_established: false, id_present: false,
52
+ last_event: 'pusher:error'
53
+ end
54
+ end
55
+
56
+ context "given invalid JSON as input" do
57
+ it 'should not crash' do
58
+ messages = em_stream do |websocket, messages|
59
+ websocket.callback do
60
+ websocket.send("{ event: 'pusher:subscribe', data: { channel: 'MY_CHANNEL'} }23123")
61
+ EM.next_tick { EM.stop }
62
+ end
63
+ end
64
+
65
+ EM.run { new_websocket.tap { |u| u.stream { EM.next_tick { EM.stop } } }}
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,158 @@
1
+ #encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe 'Integration' do
6
+
7
+ before(:each) { start_slanger }
8
+
9
+ describe 'presence channels:' do
10
+ context 'subscribing without channel data' do
11
+ context 'and bogus authentication credentials' do
12
+ it 'sends back an error message' do
13
+ messages = em_stream do |websocket, messages|
14
+ case messages.length
15
+ when 1
16
+ websocket.send({ event: 'pusher:subscribe', data: { channel: 'presence-channel', auth: 'bogus' } }.to_json)
17
+ else
18
+ EM.stop
19
+ end
20
+ end
21
+
22
+ messages.should have_attributes connection_established: true, id_present: true,
23
+ count: 2,
24
+ last_event: 'pusher:error'
25
+
26
+ expect(JSON.parse(messages.last['data'])['message']).to match /^Invalid signature: Expected HMAC SHA256 hex digest of/
27
+ end
28
+ end
29
+ end
30
+
31
+ context 'subscribing with channel data' do
32
+ context 'and bogus authentication credentials' do
33
+ it 'sends back an error message' do
34
+ messages = em_stream do |websocket, messages|
35
+ case messages.length
36
+ when 1
37
+ websocket.send({ event: 'pusher:subscribe', data: {
38
+ channel: 'presence-lel',
39
+ auth: 'boog',
40
+ channel_data: {
41
+ user_id: "barry",
42
+ }
43
+ }.to_json }.to_json)
44
+ else
45
+ EM.stop
46
+ end
47
+ end
48
+
49
+ messages.should have_attributes first_event: 'pusher:connection_established', count: 2,
50
+ id_present: true
51
+
52
+ # Channel id should be in the payload
53
+ messages.last['event'].should == 'pusher:error'
54
+ expect(JSON.parse(messages.last['data'])['message']).to match /^Invalid signature: Expected HMAC SHA256 hex digest of/
55
+ end
56
+ end
57
+
58
+ context 'with genuine authentication credentials' do
59
+ it 'sends back a success message' do
60
+ messages = em_stream do |websocket, messages|
61
+ case messages.length
62
+ when 1
63
+ send_subscribe( user: websocket,
64
+ user_id: '0f177369a3b71275d25ab1b44db9f95f',
65
+ name: 'SG',
66
+ message: messages.first)
67
+ else
68
+ EM.stop
69
+ end
70
+ end
71
+
72
+ messages.should have_attributes connection_established: true, count: 2
73
+
74
+ messages.last.should == {"channel"=>"presence-channel",
75
+ "event" =>"pusher_internal:subscription_succeeded",
76
+ "data" => "{\"presence\":{\"count\":1,\"ids\":[\"0f177369a3b71275d25ab1b44db9f95f\"],\"hash\":{\"0f177369a3b71275d25ab1b44db9f95f\":{\"name\":\"SG\"}}}}"}
77
+ end
78
+
79
+
80
+
81
+
82
+ context 'with more than one subscriber subscribed to the channel' do
83
+ it 'sends a member added message to the existing subscribers' do
84
+ messages = em_stream do |user1, messages|
85
+ case messages.length
86
+ when 1
87
+ send_subscribe(user: user1,
88
+ user_id: '0f177369a3b71275d25ab1b44db9f95f',
89
+ name: 'SG',
90
+ message: messages.first
91
+ )
92
+
93
+ when 2
94
+ new_websocket.tap do |u|
95
+ u.stream do |message|
96
+ message = JSON.parse(message)
97
+ if message['event'] == 'pusher:connection_established'
98
+ send_subscribe \
99
+ user: u, user_id: '37960509766262569d504f02a0ee986d',
100
+ name: 'CHROME', message: message
101
+ end
102
+ end
103
+ end
104
+ else
105
+ EM.stop
106
+ end
107
+
108
+ end
109
+
110
+ messages.should have_attributes connection_established: true, count: 3
111
+ # Channel id should be in the payload
112
+ messages[1].should == {"channel"=>"presence-channel", "event"=>"pusher_internal:subscription_succeeded",
113
+ "data"=>"{\"presence\":{\"count\":1,\"ids\":[\"0f177369a3b71275d25ab1b44db9f95f\"],\"hash\":{\"0f177369a3b71275d25ab1b44db9f95f\":{\"name\":\"SG\"}}}}"}
114
+
115
+ messages.last.should == {"channel"=>"presence-channel", "event"=>"pusher_internal:member_added",
116
+ "data"=>{"user_id"=>"37960509766262569d504f02a0ee986d", "user_info"=>{"name"=>"CHROME"}}}
117
+ end
118
+
119
+ it 'does not send multiple member added and member removed messages if one subscriber opens multiple connections, i.e. multiple browser tabs.' do
120
+ messages = em_stream do |user1, messages|
121
+ case messages.length
122
+ when 1
123
+ send_subscribe(user: user1,
124
+ user_id: '0f177369a3b71275d25ab1b44db9f95f',
125
+ name: 'SG',
126
+ message: messages.first)
127
+
128
+ when 2
129
+ 10.times do
130
+ new_websocket.tap do |u|
131
+ u.stream do |message|
132
+ # remove stream callback
133
+ ## close the connection in the next tick as soon as subscription is acknowledged
134
+ u.stream { EM.next_tick { u.close_connection } }
135
+
136
+ send_subscribe({ user: u,
137
+ user_id: '37960509766262569d504f02a0ee986d',
138
+ name: 'CHROME',
139
+ message: JSON.parse(message)})
140
+ end
141
+ end
142
+ end
143
+ when 4
144
+ EM.next_tick { EM.stop }
145
+ end
146
+
147
+ end
148
+
149
+ # There should only be one set of presence messages sent to the refernce user for the second user.
150
+ messages.one? { |message| message['event'] == 'pusher_internal:member_added' && message['data']['user_id'] == '37960509766262569d504f02a0ee986d' }.should be_true
151
+ messages.one? { |message| message['event'] == 'pusher_internal:member_removed' && message['data']['user_id'] == '37960509766262569d504f02a0ee986d' }.should be_true
152
+
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,79 @@
1
+ #encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe 'Integration' do
5
+
6
+ before(:each) { start_slanger }
7
+
8
+ describe 'private channels' do
9
+ context 'with valid authentication credentials:' do
10
+ it 'accepts the subscription request' do
11
+ messages = em_stream do |websocket, messages|
12
+ case messages.length
13
+ when 1
14
+ private_channel websocket, messages.first
15
+ else
16
+ EM.stop
17
+ end
18
+ end
19
+
20
+ messages.should have_attributes connection_established: true,
21
+ count: 2,
22
+ id_present: true,
23
+ last_event: 'pusher_internal:subscription_succeeded'
24
+ end
25
+ end
26
+
27
+ context 'with bogus authentication credentials:' do
28
+ it 'sends back an error message' do
29
+ messages = em_stream do |websocket, messages|
30
+ case messages.length
31
+ when 1
32
+ websocket.send({ event: 'pusher:subscribe',
33
+ data: { channel: 'private-channel',
34
+ auth: 'bogus' } }.to_json)
35
+ else
36
+ EM.stop
37
+ end
38
+ end
39
+
40
+ messages.should have_attributes connection_established: true, count: 2, id_present: true, last_event:
41
+ 'pusher:error'
42
+
43
+ expect(JSON.parse(messages.last['data'])['message']).to match /^Invalid signature: Expected HMAC SHA256 hex digest of/
44
+ end
45
+ end
46
+
47
+ describe 'client events' do
48
+ it "sends event to other channel subscribers" do
49
+ client1_messages, client2_messages = [], []
50
+
51
+ em_thread do
52
+ client1, client2 = new_websocket, new_websocket
53
+ client2_messages, client1_messages = [], []
54
+
55
+ stream(client1, client1_messages) do |message|
56
+ case client1_messages.length
57
+ when 1
58
+ private_channel client1, client1_messages.first
59
+ when 3
60
+ EM.next_tick { EM.stop }
61
+ end
62
+ end
63
+
64
+ stream(client2, client2_messages) do |message|
65
+ case client2_messages.length
66
+ when 1
67
+ private_channel client2, client2_messages.first
68
+ when 2
69
+ client2.send({ event: 'client-something', data: { some: 'stuff' }, channel: 'private-channel' }.to_json)
70
+ end
71
+ end
72
+ end
73
+
74
+ client1_messages.one? { |m| m['event'] == 'client-something' }.should be_true
75
+ client2_messages.none? { |m| m['event'] == 'client-something' }.should be_true
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+ require 'lib/slanger/handler.rb'
3
+
4
+ class ReplacedHandler < Slanger::Handler
5
+ def authenticate
6
+ super
7
+ send_payload nil, 'pusher:info', { message: "Welcome!" }
8
+ end
9
+ end
10
+
11
+ describe 'Replacable handler' do
12
+ it 'says welcome' do
13
+ start_slanger_with_options socket_handler: ReplacedHandler
14
+
15
+ msgs = em_stream do |websocket, messages|
16
+ if messages.length == 2
17
+ EM.stop
18
+ end
19
+ end
20
+
21
+ msgs.last.should == { "event" => "pusher:info", "data" =>"{\"message\":\"Welcome!\"}" }
22
+ end
23
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Integration' do
4
+ describe 'Slanger when configured to use SSL' do
5
+ it 'encrypts the connection' do
6
+ start_slanger_with_options tls_options: {
7
+ cert_chain_file: 'spec/server.crt',
8
+ private_key_file: 'spec/server.key'
9
+ }
10
+
11
+ socket = TCPSocket.new('0.0.0.0', 8080)
12
+ expected_cert = OpenSSL::X509::Certificate.new(File.open('spec/server.crt'))
13
+ ssl_socket = OpenSSL::SSL::SSLSocket.new(socket)
14
+ ssl_socket.connect
15
+ ssl_socket.peer_cert.to_s.should == expected_cert.to_s
16
+ end
17
+ end
18
+ end