pusher-fake 0.14.0 → 1.0.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.
@@ -13,7 +13,7 @@
13
13
  <ul></ul>
14
14
  </section>
15
15
 
16
- <script src="/javascripts/vendor/pusher-2.1.6.js"></script>
16
+ <script src="/javascripts/vendor/pusher-2.2.1.js"></script>
17
17
  <script>
18
18
  window.addEventListener("DOMContentLoaded", function() {
19
19
  // Create the client instance using the PusherFake server.
@@ -22,15 +22,9 @@ Thread.new do
22
22
  EventMachine.run do
23
23
  Thin::Logging.silent = true
24
24
  Thin::Server.start("0.0.0.0", 8082, WebhookEndpoint)
25
- Thread.current[:ready] = true
26
25
  end
27
26
  end.tap do |thread|
28
27
  at_exit { thread.exit }
29
-
30
- # Wait for the webhook endpoint server to start.
31
- Timeout::timeout(5) do
32
- sleep(0.05) until thread[:ready]
33
- end
34
28
  end
35
29
 
36
- PusherFake.configuration.webhooks = ["http://localhost:8082"]
30
+ PusherFake.configuration.webhooks = ["http://127.0.0.1:8082"]
@@ -6,7 +6,7 @@ require "thin"
6
6
 
7
7
  module PusherFake
8
8
  # The current version string.
9
- VERSION = "0.14.0"
9
+ VERSION = "1.0.0"
10
10
 
11
11
  autoload :Channel, "pusher-fake/channel"
12
12
  autoload :Configuration, "pusher-fake/configuration"
@@ -22,7 +22,7 @@ module PusherFake
22
22
  # @option options [String] :auth The authentication string.
23
23
  # @return [Boolean] +true+ if authorized, +false+ otherwise.
24
24
  def authorized?(connection, options)
25
- authentication_for(connection.socket.object_id, options[:channel_data]) == options[:auth]
25
+ authentication_for(connection.id, options[:channel_data]) == options[:auth]
26
26
  end
27
27
 
28
28
  # Generate an authentication string from the channel based on the
@@ -29,7 +29,7 @@ module PusherFake
29
29
  # @param [Hash] data The event data.
30
30
  def emit(event, data, options = {})
31
31
  connections.each do |connection|
32
- unless connection.socket.object_id == options[:socket_id]
32
+ unless connection.id == options[:socket_id]
33
33
  connection.emit(event, data, name)
34
34
  end
35
35
  end
@@ -13,21 +13,30 @@ module PusherFake
13
13
  @socket = socket
14
14
  end
15
15
 
16
+ # The ID of the connection.
17
+ #
18
+ # @return [Integer] The object ID of the socket.
19
+ def id
20
+ socket.object_id.to_s
21
+ end
22
+
16
23
  # Emit an event to the connection.
17
24
  #
18
25
  # @param [String] event The event name.
19
26
  # @param [Hash] data The event data.
20
27
  # @param [String] channel The channel name.
21
28
  def emit(event, data = {}, channel = nil)
22
- message = { event: event, data: data }
29
+ message = { event: event, data: MultiJson.dump(data) }
23
30
  message[:channel] = channel if channel
24
31
 
32
+ PusherFake.log("SEND #{id}: #{message}")
33
+
25
34
  socket.send(MultiJson.dump(message))
26
35
  end
27
36
 
28
37
  # Notify the Pusher client that a connection has been established.
29
38
  def establish
30
- emit("pusher:connection_established", socket_id: socket.object_id, activity_timeout: 120)
39
+ emit("pusher:connection_established", socket_id: id, activity_timeout: 120)
31
40
  end
32
41
 
33
42
  # Process an event.
@@ -35,9 +44,12 @@ module PusherFake
35
44
  # @param [String] data The event data as JSON.
36
45
  def process(data)
37
46
  message = MultiJson.load(data, symbolize_keys: true)
47
+
48
+ PusherFake.log("RECV #{id}: #{message}")
49
+
38
50
  data = message[:data]
39
51
  event = message[:event]
40
- name = message[:channel] || data.delete(:channel)
52
+ name = message[:channel] || data[:channel]
41
53
  channel = Channel.factory(name) if name
42
54
 
43
55
  case event
@@ -49,9 +61,27 @@ module PusherFake
49
61
  emit("pusher:pong")
50
62
  when CLIENT_EVENT_MATCHER
51
63
  if channel.is_a?(Channel::Private) && channel.includes?(self)
52
- channel.emit(event, data, socket_id: socket.object_id)
64
+ channel.emit(event, data, socket_id: id)
65
+
66
+ trigger(channel, id, event, data)
53
67
  end
54
68
  end
55
69
  end
70
+
71
+ private
72
+
73
+ def trigger(channel, id, event, data)
74
+ Thread.new do
75
+ hook = {
76
+ event: event,
77
+ channel: channel.name,
78
+ socket_id: id
79
+ }
80
+ hook[:data] = MultiJson.dump(data) if data
81
+ hook[:user_id] = channel.members[self][:user_id] if channel.is_a?(Channel::Presence)
82
+
83
+ channel.trigger("client_event", hook)
84
+ end
85
+ end
56
86
  end
57
87
  end
@@ -39,8 +39,15 @@ module PusherFake
39
39
  # @return [Hash] An empty hash.
40
40
  def self.events(request)
41
41
  event = MultiJson.load(request.body.read)
42
- event["channels"].each do |channel|
43
- Channel.factory(channel).emit(event["name"], event["data"], socket_id: event["socket_id"])
42
+ data = begin
43
+ MultiJson.load(event["data"])
44
+ rescue MultiJson::LoadError
45
+ event["data"]
46
+ end
47
+
48
+ event["channels"].each do |channel_name|
49
+ channel = Channel.factory(channel_name)
50
+ channel.emit(event["name"], data, socket_id: event["socket_id"])
44
51
  end
45
52
 
46
53
  {}
@@ -107,7 +114,7 @@ module PusherFake
107
114
 
108
115
  if channel
109
116
  users = channel.connections.map do |connection|
110
- { id: connection.object_id }
117
+ { id: connection.id }
111
118
  end
112
119
  end
113
120
 
@@ -7,6 +7,7 @@ module PusherFake
7
7
  time_ms: Time.now.to_i
8
8
  )
9
9
 
10
+ PusherFake.log("HOOK: #{payload}")
10
11
  PusherFake.configuration.webhooks.each do |url|
11
12
  http = EventMachine::HttpRequest.new(url)
12
13
  http.post(body: payload, head: headers_for(payload))
@@ -133,8 +133,7 @@ end
133
133
  describe PusherFake::Channel::Private, "#authorized?" do
134
134
  let(:data) { { auth: authentication, channel_data: channel_data } }
135
135
  let(:name) { "private-channel" }
136
- let(:socket) { stub }
137
- let(:connection) { stub(socket: socket) }
136
+ let(:connection) { stub(id: "1") }
138
137
  let(:channel_data) { "{}" }
139
138
  let(:authentication) { "authentication" }
140
139
 
@@ -144,10 +143,10 @@ describe PusherFake::Channel::Private, "#authorized?" do
144
143
  subject.stubs(:authentication_for)
145
144
  end
146
145
 
147
- it "generates authentication for the connection socket ID" do
146
+ it "generates authentication for the connection ID" do
148
147
  subject.authorized?(connection, data)
149
148
 
150
- expect(subject).to have_received(:authentication_for).with(socket.object_id, channel_data)
149
+ expect(subject).to have_received(:authentication_for).with(connection.id, channel_data)
151
150
  end
152
151
 
153
152
  it "returns true if the authentication matches" do
@@ -55,11 +55,9 @@ describe PusherFake::Channel, "#emit" do
55
55
  let(:data) { stub }
56
56
  let(:name) { "name" }
57
57
  let(:event) { "event" }
58
- let(:socket_1) { stub }
59
- let(:socket_2) { stub }
60
58
  let(:connections) { [connection_1, connection_2] }
61
- let(:connection_1) { stub(emit: nil, socket: socket_1) }
62
- let(:connection_2) { stub(emit: nil, socket: socket_2) }
59
+ let(:connection_1) { stub(emit: nil, id: "1") }
60
+ let(:connection_2) { stub(emit: nil, id: "2") }
63
61
 
64
62
  subject { PusherFake::Channel::Public.new(name) }
65
63
 
@@ -74,8 +72,8 @@ describe PusherFake::Channel, "#emit" do
74
72
  expect(connection_2).to have_received(:emit).with(event, data, name)
75
73
  end
76
74
 
77
- it "ignores connection if socket_id matches the connections socket object_id" do
78
- subject.emit(event, data, socket_id: socket_2.object_id)
75
+ it "ignores connection if socket_id matches the connections ID" do
76
+ subject.emit(event, data, socket_id: connection_2.id)
79
77
 
80
78
  expect(connection_1).to have_received(:emit).with(event, data, name)
81
79
  expect(connection_2).to have_received(:emit).never
@@ -1,5 +1,28 @@
1
1
  require "spec_helper"
2
2
 
3
+ shared_examples_for "#process" do
4
+ let(:json) { stub }
5
+
6
+ subject { PusherFake::Connection.new(stub) }
7
+
8
+ before do
9
+ PusherFake.stubs(:log)
10
+ MultiJson.stubs(load: message)
11
+ end
12
+
13
+ it "parses the JSON data" do
14
+ subject.process(json)
15
+
16
+ expect(MultiJson).to have_received(:load).with(json, symbolize_keys: true)
17
+ end
18
+
19
+ it "logs receiving the event" do
20
+ subject.process(json)
21
+
22
+ expect(PusherFake).to have_received(:log).with("RECV #{subject.id}: #{message}")
23
+ end
24
+ end
25
+
3
26
  describe PusherFake::Connection do
4
27
  let(:socket) { stub }
5
28
 
@@ -18,11 +41,15 @@ describe PusherFake::Connection, "#emit" do
18
41
  let(:event) { "name" }
19
42
  let(:socket) { stub(:send) }
20
43
  let(:channel) { "channel" }
21
- let(:message) { { event: event, data: data } }
44
+ let(:message) { { event: event, data: MultiJson.dump(data) } }
22
45
  let(:channel_json) { MultiJson.dump(message.merge(channel: channel)) }
23
46
 
24
47
  subject { PusherFake::Connection.new(socket) }
25
48
 
49
+ before do
50
+ PusherFake.stubs(:log)
51
+ end
52
+
26
53
  it "sends the event to the socket as JSON" do
27
54
  subject.emit(event, data)
28
55
 
@@ -34,6 +61,12 @@ describe PusherFake::Connection, "#emit" do
34
61
 
35
62
  expect(socket).to have_received(:send).with(channel_json)
36
63
  end
64
+
65
+ it "logs sending the event" do
66
+ subject.emit(event, data)
67
+
68
+ expect(PusherFake).to have_received(:log).with("SEND #{subject.id}: #{message}")
69
+ end
37
70
  end
38
71
 
39
72
  describe PusherFake::Connection, "#establish" do
@@ -45,204 +78,225 @@ describe PusherFake::Connection, "#establish" do
45
78
  subject.stubs(:emit)
46
79
  end
47
80
 
48
- it "emits the connection established event with the socket ID" do
81
+ it "emits the connection established event with the connection ID" do
49
82
  subject.establish
50
83
 
51
84
  expect(subject).to have_received(:emit)
52
- .with("pusher:connection_established", socket_id: socket.object_id, activity_timeout: 120)
85
+ .with("pusher:connection_established", socket_id: subject.id, activity_timeout: 120)
53
86
  end
54
87
  end
55
88
 
56
- describe PusherFake::Connection, "#process, with a subscribe event" do
57
- let(:data) { { channel: name, auth: "auth" } }
58
- let(:json) { stub }
59
- let(:name) { "channel" }
60
- let(:channel) { stub(add: nil) }
61
- let(:message) { { event: "pusher:subscribe", data: data } }
89
+ describe PusherFake::Connection, "#id" do
90
+ let(:id) { socket.object_id.to_s }
91
+ let(:socket) { stub }
62
92
 
63
- subject { PusherFake::Connection.new(stub) }
93
+ subject { PusherFake::Connection.new(socket) }
64
94
 
65
- before do
66
- MultiJson.stubs(load: message)
67
- PusherFake::Channel.stubs(factory: channel)
95
+ it "returns the object ID of the socket" do
96
+ expect(subject.id).to eq(id)
68
97
  end
98
+ end
69
99
 
70
- it "parses the JSON data" do
71
- subject.process(json)
100
+ describe PusherFake::Connection, "#process, with a subscribe event" do
101
+ it_should_behave_like "#process" do
102
+ let(:data) { { channel: name, auth: "auth" } }
103
+ let(:name) { "channel" }
104
+ let(:channel) { stub(add: nil) }
105
+ let(:message) { { event: "pusher:subscribe", data: data } }
72
106
 
73
- expect(MultiJson).to have_received(:load).with(json, symbolize_keys: true)
74
- end
107
+ before do
108
+ PusherFake::Channel.stubs(factory: channel)
109
+ end
75
110
 
76
- it "creates a channel from the event data" do
77
- subject.process(json)
111
+ it "creates a channel from the event data" do
112
+ subject.process(json)
78
113
 
79
- expect(PusherFake::Channel).to have_received(:factory).with(name)
80
- end
114
+ expect(PusherFake::Channel).to have_received(:factory).with(name)
115
+ end
81
116
 
82
- it "attempts to add the connection to the channel" do
83
- subject.process(json)
117
+ it "attempts to add the connection to the channel" do
118
+ subject.process(json)
84
119
 
85
- expect(channel).to have_received(:add).with(subject, data)
120
+ expect(channel).to have_received(:add).with(subject, data)
121
+ end
86
122
  end
87
123
  end
88
124
 
89
125
  describe PusherFake::Connection, "#process, with an unsubscribe event" do
90
- let(:json) { stub }
91
- let(:name) { "channel" }
92
- let(:channel) { stub(remove: nil) }
93
- let(:message) { { event: "pusher:unsubscribe", channel: name } }
126
+ it_should_behave_like "#process" do
127
+ let(:name) { "channel" }
128
+ let(:channel) { stub(remove: nil) }
129
+ let(:message) { { event: "pusher:unsubscribe", channel: name } }
94
130
 
95
- subject { PusherFake::Connection.new(stub) }
131
+ before do
132
+ PusherFake::Channel.stubs(factory: channel)
133
+ end
96
134
 
97
- before do
98
- MultiJson.stubs(load: message)
99
- PusherFake::Channel.stubs(factory: channel)
100
- end
135
+ it "creates a channel from the event data" do
136
+ subject.process(json)
101
137
 
102
- it "parses the JSON data" do
103
- subject.process(json)
138
+ expect(PusherFake::Channel).to have_received(:factory).with(name)
139
+ end
104
140
 
105
- expect(MultiJson).to have_received(:load).with(json, symbolize_keys: true)
106
- end
107
-
108
- it "creates a channel from the event data" do
109
- subject.process(json)
110
-
111
- expect(PusherFake::Channel).to have_received(:factory).with(name)
112
- end
113
-
114
- it "removes the connection from the channel" do
115
- subject.process(json)
141
+ it "removes the connection from the channel" do
142
+ subject.process(json)
116
143
 
117
- expect(channel).to have_received(:remove).with(subject)
144
+ expect(channel).to have_received(:remove).with(subject)
145
+ end
118
146
  end
119
147
  end
120
148
 
121
149
  describe PusherFake::Connection, "#process, with a ping event" do
122
- let(:json) { stub }
123
- let(:message) { { event: "pusher:ping", data: {} } }
150
+ it_should_behave_like "#process" do
151
+ let(:message) { { event: "pusher:ping", data: {} } }
124
152
 
125
- subject { PusherFake::Connection.new(stub) }
153
+ before do
154
+ subject.stubs(:emit)
155
+ end
126
156
 
127
- before do
128
- MultiJson.stubs(load: message)
129
- PusherFake::Channel.stubs(:factory)
130
- subject.stubs(:emit)
131
- end
157
+ it "does not create a channel" do
158
+ subject.process(json)
132
159
 
133
- it "parses the JSON data" do
134
- subject.process(json)
160
+ expect(PusherFake::Channel).to have_received(:factory).never
161
+ end
135
162
 
136
- expect(MultiJson).to have_received(:load).with(json, symbolize_keys: true)
163
+ it "emits a pong event" do
164
+ subject.process(json)
165
+
166
+ expect(subject).to have_received(:emit).with("pusher:pong")
167
+ end
137
168
  end
169
+ end
138
170
 
139
- it "does not create a channel" do
140
- subject.process(json)
171
+ describe PusherFake::Connection, "#process, with a client event" do
172
+ it_should_behave_like "#process" do
173
+ let(:data) { {} }
174
+ let(:name) { "channel" }
175
+ let(:event) { "client-hello-world" }
176
+ let(:channel) { stub(emit: nil, includes?: nil, is_a?: true) }
177
+ let(:message) { { event: event, data: data, channel: name } }
141
178
 
142
- expect(PusherFake::Channel).to have_received(:factory).never
143
- end
179
+ before do
180
+ subject.stubs(:trigger)
181
+ PusherFake::Channel.stubs(factory: channel)
182
+ end
144
183
 
145
- it "emits a pong event" do
146
- subject.process(json)
184
+ it "creates a channel from the event data" do
185
+ subject.process(json)
147
186
 
148
- expect(subject).to have_received(:emit).with("pusher:pong")
149
- end
150
- end
187
+ expect(PusherFake::Channel).to have_received(:factory).with(name)
188
+ end
151
189
 
152
- describe PusherFake::Connection, "#process, with a client event" do
153
- let(:data) { {} }
154
- let(:json) { stub }
155
- let(:name) { "channel" }
156
- let(:event) { "client-hello-world" }
157
- let(:channel) { stub(emit: nil, includes?: nil, is_a?: true) }
158
- let(:message) { { event: event, data: data, channel: name } }
190
+ it "ensures the channel is private" do
191
+ subject.process(json)
159
192
 
160
- subject { PusherFake::Connection.new(stub) }
193
+ expect(channel).to have_received(:is_a?).with(PusherFake::Channel::Private)
194
+ end
161
195
 
162
- before do
163
- MultiJson.stubs(load: message)
164
- PusherFake::Channel.stubs(factory: channel)
165
- end
196
+ it "checks if the connection is in the channel" do
197
+ subject.process(json)
166
198
 
167
- it "parses the JSON data" do
168
- subject.process(json)
199
+ expect(channel).to have_received(:includes?).with(subject)
200
+ end
169
201
 
170
- expect(MultiJson).to have_received(:load).with(json, symbolize_keys: true)
171
- end
202
+ it "emits the event to the channel when the connection is in the channel" do
203
+ channel.stubs(includes?: true)
172
204
 
173
- it "creates a channel from the event data" do
174
- subject.process(json)
205
+ subject.process(json)
175
206
 
176
- expect(PusherFake::Channel).to have_received(:factory).with(name)
177
- end
207
+ expect(channel).to have_received(:emit).with(event, data, socket_id: subject.id)
208
+ end
178
209
 
179
- it "ensures the channel is private" do
180
- subject.process(json)
210
+ it "does not emit the event to the channel when the channel is not private" do
211
+ channel.stubs(includes?: true, is_a?: false)
181
212
 
182
- expect(channel).to have_received(:is_a?).with(PusherFake::Channel::Private)
183
- end
213
+ subject.process(json)
184
214
 
185
- it "checks if the connection is in the channel" do
186
- subject.process(json)
215
+ expect(channel).to have_received(:emit).never
216
+ end
217
+
218
+ it "does not emit the event to the channel when the connection is not in the channel" do
219
+ channel.stubs(includes?: false)
187
220
 
188
- expect(channel).to have_received(:includes?).with(subject)
221
+ subject.process(json)
222
+
223
+ expect(channel).to have_received(:emit).never
224
+ end
189
225
  end
226
+ end
190
227
 
191
- it "emits the event to the channel when the connection is in the channel" do
192
- channel.stubs(includes?: true)
228
+ describe PusherFake::Connection, "#process, with a client event trigger a webhook" do
229
+ it_should_behave_like "#process" do
230
+ let(:data) { { example: "data" } }
231
+ let(:name) { "channel" }
232
+ let(:event) { "client-hello-world" }
233
+ let(:user_id) { 1 }
234
+ let(:channel) { stub(name: name, emit: nil, includes?: nil) }
235
+ let(:message) { { event: event, channel: name } }
236
+ let(:options) { { channel: name, event: event, socket_id: subject.id } }
193
237
 
194
- subject.process(json)
238
+ before do
239
+ channel.stubs(:trigger)
240
+ channel.stubs(:includes?).with(subject).returns(true)
241
+ channel.stubs(:is_a?).with(PusherFake::Channel::Private).returns(true)
242
+ channel.stubs(:is_a?).with(PusherFake::Channel::Presence).returns(false)
195
243
 
196
- expect(channel).to have_received(:emit).with(event, data, socket_id: subject.socket.object_id)
197
- end
244
+ # NOTE: Hack to avoid race condition in unit tests.
245
+ Thread.stubs(:new).yields
198
246
 
199
- it "does not emit the event to the channel when the channel is not private" do
200
- channel.stubs(includes?: true, is_a?: false)
247
+ PusherFake::Channel.stubs(factory: channel)
248
+ end
201
249
 
202
- subject.process(json)
250
+ it "triggers the client event webhook" do
251
+ subject.process(json)
203
252
 
204
- expect(channel).to have_received(:emit).never
205
- end
253
+ expect(channel).to have_received(:trigger)
254
+ .with("client_event", options).once
255
+ end
206
256
 
207
- it "does not emit the event to the channel when the connection is not in the channel" do
208
- channel.stubs(includes?: false)
257
+ it "includes data in event when present" do
258
+ message[:data] = data
209
259
 
210
- subject.process(json)
260
+ subject.process(json)
211
261
 
212
- expect(channel).to have_received(:emit).never
213
- end
214
- end
262
+ expect(channel).to have_received(:trigger).
263
+ with("client_event", options.merge(data: MultiJson.dump(data))).once
264
+ end
215
265
 
216
- describe PusherFake::Connection, "#process, with an unknown event" do
217
- let(:data) { {} }
218
- let(:json) { stub }
219
- let(:name) { "channel" }
220
- let(:event) { "hello-world" }
221
- let(:channel) { stub(emit: nil) }
222
- let(:message) { { event: event, data: data, channel: name } }
266
+ it "includes user ID in event when on a presence channel" do
267
+ channel.stubs(:is_a?).with(PusherFake::Channel::Presence).returns(true)
268
+ channel.stubs(members: { subject => { user_id: user_id } })
223
269
 
224
- subject { PusherFake::Connection.new(stub) }
270
+ subject.process(json)
225
271
 
226
- before do
227
- MultiJson.stubs(load: message)
228
- PusherFake::Channel.stubs(factory: channel)
272
+ expect(channel).to have_received(:trigger).
273
+ with("client_event", options.merge(user_id: user_id)).once
274
+ end
229
275
  end
276
+ end
230
277
 
231
- it "parses the JSON data" do
232
- subject.process(json)
278
+ describe PusherFake::Connection, "#process, with an unknown event" do
279
+ it_should_behave_like "#process" do
280
+ let(:data) { {} }
281
+ let(:name) { "channel" }
282
+ let(:event) { "hello-world" }
283
+ let(:channel) { stub(emit: nil) }
284
+ let(:message) { { event: event, data: data, channel: name } }
233
285
 
234
- expect(MultiJson).to have_received(:load).with(json, symbolize_keys: true)
235
- end
286
+ before do
287
+ PusherFake::Channel.stubs(factory: channel)
288
+ end
236
289
 
237
- it "creates a channel from the event data" do
238
- subject.process(json)
290
+ it "creates a channel from the event data" do
291
+ subject.process(json)
239
292
 
240
- expect(PusherFake::Channel).to have_received(:factory).with(name)
241
- end
293
+ expect(PusherFake::Channel).to have_received(:factory).with(name)
294
+ end
242
295
 
243
- it "does not emit the event" do
244
- subject.process(json)
296
+ it "does not emit the event" do
297
+ subject.process(json)
245
298
 
246
- expect(channel).to have_received(:emit).never
299
+ expect(channel).to have_received(:emit).never
300
+ end
247
301
  end
248
302
  end