pusher-fake 0.13.0 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/features/step_definitions/api_steps.rb +11 -9
- data/features/step_definitions/channel_steps.rb +6 -3
- data/features/step_definitions/client_steps.rb +4 -2
- data/features/step_definitions/event_steps.rb +4 -2
- data/features/step_definitions/presence_steps.rb +2 -2
- data/features/step_definitions/webhook_steps.rb +1 -1
- data/features/support/environment.rb +6 -0
- data/features/support/webhooks.rb +1 -1
- data/lib/pusher-fake.rb +8 -2
- data/lib/pusher-fake/channel/presence.rb +4 -2
- data/lib/pusher-fake/channel/public.rb +3 -3
- data/lib/pusher-fake/configuration.rb +10 -2
- data/lib/pusher-fake/connection.rb +10 -9
- data/lib/pusher-fake/server/application.rb +1 -1
- data/lib/pusher-fake/webhook.rb +6 -3
- data/spec/lib/pusher-fake/channel/presence_spec.rb +84 -27
- data/spec/lib/pusher-fake/channel/private_spec.rb +37 -20
- data/spec/lib/pusher-fake/channel/public_spec.rb +29 -18
- data/spec/lib/pusher-fake/channel_spec.rb +43 -15
- data/spec/lib/pusher-fake/configuration_spec.rb +11 -3
- data/spec/lib/pusher-fake/connection_spec.rb +74 -20
- data/spec/lib/pusher-fake/server/application_spec.rb +72 -36
- data/spec/lib/pusher-fake/server_spec.rb +46 -23
- data/spec/lib/pusher-fake/webhook_spec.rb +7 -3
- data/spec/lib/pusher_fake_spec.rb +41 -10
- data/spec/spec_helper.rb +4 -2
- data/spec/support/have_configuration_option_matcher.rb +12 -39
- metadata +4 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bdcb9226aaf3bc12a6ecaf05a7a8caf22bd7580f
|
4
|
+
data.tar.gz: bd8a9a836ccdce64bb5173db0b6d2bc1f0c35342
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 55fce89eb072245cde7dd9a6c5ecf49eb733102c1dda0e48ee80781fa2054ba9f9471eadb531333a39dad1f1cd45d63e722d95e7cbc98650c9dc6c04421cb6c0
|
7
|
+
data.tar.gz: 129cf3175bf0cee5d50710f4762f16ab079d89133fe1b66eca6874e408cba1a3309b1d40d0a1740e313e89759738bbe9c8a105780294379e53d31783c31742d9
|
@@ -17,22 +17,24 @@ end
|
|
17
17
|
Then %{I should receive the following JSON:} do |string|
|
18
18
|
expected = MultiJson.load(string)
|
19
19
|
expected = expected.inject({}) do |result, (key, value)|
|
20
|
-
result
|
21
|
-
result
|
20
|
+
result.merge(key.to_sym => value)
|
22
21
|
end
|
23
22
|
|
24
|
-
@response.
|
23
|
+
expect(@response).to eq(expected)
|
25
24
|
end
|
26
25
|
|
27
26
|
Then %{I should receive the following error:} do |string|
|
28
|
-
@error.message.
|
27
|
+
expect(@error.message).to include(string.strip)
|
29
28
|
end
|
30
29
|
|
31
30
|
Then /^I should receive JSON for (\d+) users?$/ do |count|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
31
|
+
@response[:users].tap do |users|
|
32
|
+
expect(users).to have(count).items
|
33
|
+
|
34
|
+
users.map do |user|
|
35
|
+
ObjectSpace._id2ref(user["id"])
|
36
|
+
end.each do |object|
|
37
|
+
expect(object).to be_a(PusherFake::Connection)
|
38
|
+
end
|
37
39
|
end
|
38
40
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
Given %{I am subscribed to the "$channel" channel} do |channel|
|
2
|
-
|
3
|
-
|
2
|
+
steps %{
|
3
|
+
When I subscribe to the "#{channel}" channel
|
4
|
+
Then I should be subscribed to the "#{channel}" channel
|
5
|
+
}
|
4
6
|
end
|
5
7
|
|
6
8
|
Given %{$name is subscribed to the "$channel" channel} do |name, channel|
|
@@ -78,6 +80,7 @@ Then %{I should not be subscribed to the "$channel" channel} do |channel|
|
|
78
80
|
channel = Pusher.instance.channel(#{MultiJson.dump(channel)});
|
79
81
|
channel && channel.subscribed;
|
80
82
|
})
|
81
|
-
|
83
|
+
|
84
|
+
expect(subscribed).to be_false
|
82
85
|
end
|
83
86
|
end
|
@@ -37,7 +37,8 @@ Then /^([^ ]+) should receive a "([^"]+)" event on the "([^"]+)" channel$/ do |n
|
|
37
37
|
using_session(name) do
|
38
38
|
wait do
|
39
39
|
events = page.evaluate_script("Pusher.instance.events[#{MultiJson.dump([channel, event].join(":"))}]")
|
40
|
-
|
40
|
+
|
41
|
+
expect(events).to have(1).item
|
41
42
|
end
|
42
43
|
end
|
43
44
|
end
|
@@ -48,7 +49,8 @@ Then /^([^ ]+) should not receive a "([^"]+)" event on the "([^"]+)" channel$/ d
|
|
48
49
|
using_session(name) do
|
49
50
|
wait do
|
50
51
|
events = page.evaluate_script("Pusher.instance.events[#{MultiJson.dump([channel, event].join(":"))}]")
|
51
|
-
|
52
|
+
|
53
|
+
expect(events).to be_nil
|
52
54
|
end
|
53
55
|
end
|
54
56
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Then /^I should see (\d+) clients?(?: with the name "([^"]+)")?$/ do |count, name|
|
2
2
|
within("section") do
|
3
|
-
|
4
|
-
|
3
|
+
expect(page).to have_css("header h1 span", text: count)
|
4
|
+
expect(page).to have_css("ul li", count: count.to_i, text: name)
|
5
5
|
end
|
6
6
|
end
|
data/lib/pusher-fake.rb
CHANGED
@@ -6,7 +6,7 @@ require "thin"
|
|
6
6
|
|
7
7
|
module PusherFake
|
8
8
|
# The current version string.
|
9
|
-
VERSION = "0.
|
9
|
+
VERSION = "0.14.0"
|
10
10
|
|
11
11
|
autoload :Channel, "pusher-fake/channel"
|
12
12
|
autoload :Configuration, "pusher-fake/configuration"
|
@@ -23,7 +23,7 @@ module PusherFake
|
|
23
23
|
#
|
24
24
|
# @yield [Configuration] The current configuration.
|
25
25
|
def self.configure
|
26
|
-
yield
|
26
|
+
yield configuration
|
27
27
|
end
|
28
28
|
|
29
29
|
# @return [Configuration] Current configuration.
|
@@ -43,4 +43,10 @@ module PusherFake
|
|
43
43
|
|
44
44
|
"new Pusher(#{arguments})"
|
45
45
|
end
|
46
|
+
|
47
|
+
def self.log(message)
|
48
|
+
if configuration.verbose
|
49
|
+
configuration.logger << "#{message}\n"
|
50
|
+
end
|
51
|
+
end
|
46
52
|
end
|
@@ -21,9 +21,11 @@ module PusherFake
|
|
21
21
|
def remove(connection)
|
22
22
|
super
|
23
23
|
|
24
|
-
|
24
|
+
if members.key?(connection)
|
25
|
+
trigger("member_removed", channel: name, user_id: members[connection][:user_id])
|
25
26
|
|
26
|
-
|
27
|
+
emit("pusher_internal:member_removed", members.delete(connection))
|
28
|
+
end
|
27
29
|
end
|
28
30
|
|
29
31
|
# Return a hash containing presence information for the channel.
|
@@ -29,9 +29,9 @@ module PusherFake
|
|
29
29
|
# @param [Hash] data The event data.
|
30
30
|
def emit(event, data, options = {})
|
31
31
|
connections.each do |connection|
|
32
|
-
|
33
|
-
|
34
|
-
|
32
|
+
unless connection.socket.object_id == options[:socket_id]
|
33
|
+
connection.emit(event, data, name)
|
34
|
+
end
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
@@ -6,6 +6,9 @@ module PusherFake
|
|
6
6
|
# @return [String] The Pusher API key. (Defaults to +PUSHER_API_KEY+.)
|
7
7
|
attr_accessor :key
|
8
8
|
|
9
|
+
# @return [IO] An IO instance for verbose logging.
|
10
|
+
attr_accessor :logger
|
11
|
+
|
9
12
|
# @return [String] The Pusher API token. (Defaults to +PUSHER_API_SECRET+.)
|
10
13
|
attr_accessor :secret
|
11
14
|
|
@@ -14,6 +17,9 @@ module PusherFake
|
|
14
17
|
# @return [Hash] Options for the socket server.
|
15
18
|
attr_accessor :socket_options
|
16
19
|
|
20
|
+
# @return [Boolean] Enable verbose logging.
|
21
|
+
attr_accessor :verbose
|
22
|
+
|
17
23
|
# Options for the web server. See +Thin::Server+ for options.
|
18
24
|
#
|
19
25
|
# @return [Hash] Options for the web server.
|
@@ -26,7 +32,9 @@ module PusherFake
|
|
26
32
|
def initialize
|
27
33
|
self.app_id = "PUSHER_APP_ID"
|
28
34
|
self.key = "PUSHER_API_KEY"
|
35
|
+
self.logger = STDOUT.to_io
|
29
36
|
self.secret = "PUSHER_API_SECRET"
|
37
|
+
self.verbose = false
|
30
38
|
self.webhooks = []
|
31
39
|
|
32
40
|
self.socket_options = { host: "127.0.0.1", port: 8080 }
|
@@ -37,10 +45,10 @@ module PusherFake
|
|
37
45
|
#
|
38
46
|
# @param [Hash] options Custom options for Pusher client.
|
39
47
|
def to_options(options = {})
|
40
|
-
options.merge(
|
48
|
+
options.merge(
|
41
49
|
wsHost: socket_options[:host],
|
42
50
|
wsPort: socket_options[:port]
|
43
|
-
|
51
|
+
)
|
44
52
|
end
|
45
53
|
end
|
46
54
|
end
|
@@ -34,22 +34,23 @@ module PusherFake
|
|
34
34
|
#
|
35
35
|
# @param [String] data The event data as JSON.
|
36
36
|
def process(data)
|
37
|
-
message
|
38
|
-
data
|
39
|
-
event
|
40
|
-
|
41
|
-
channel
|
37
|
+
message = MultiJson.load(data, symbolize_keys: true)
|
38
|
+
data = message[:data]
|
39
|
+
event = message[:event]
|
40
|
+
name = message[:channel] || data.delete(:channel)
|
41
|
+
channel = Channel.factory(name) if name
|
42
42
|
|
43
43
|
case event
|
44
44
|
when "pusher:subscribe"
|
45
45
|
channel.add(self, data)
|
46
46
|
when "pusher:unsubscribe"
|
47
47
|
channel.remove(self)
|
48
|
+
when "pusher:ping"
|
49
|
+
emit("pusher:pong")
|
48
50
|
when CLIENT_EVENT_MATCHER
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
channel.emit(event, data, socket_id: socket.object_id)
|
51
|
+
if channel.is_a?(Channel::Private) && channel.includes?(self)
|
52
|
+
channel.emit(event, data, socket_id: socket.object_id)
|
53
|
+
end
|
53
54
|
end
|
54
55
|
end
|
55
56
|
end
|
@@ -86,7 +86,7 @@ module PusherFake
|
|
86
86
|
|
87
87
|
filter = Regexp.new(%r{\A#{prefix}})
|
88
88
|
channels = PusherFake::Channel.channels || {}
|
89
|
-
channels.inject(
|
89
|
+
channels.inject(channels: {}) do |result, (name, channel)|
|
90
90
|
unless filter && name !~ filter
|
91
91
|
channels = result[:channels]
|
92
92
|
channels[name] = {}
|
data/lib/pusher-fake/webhook.rb
CHANGED
@@ -2,10 +2,10 @@ module PusherFake
|
|
2
2
|
class Webhook
|
3
3
|
class << self
|
4
4
|
def trigger(name, data = {})
|
5
|
-
payload = MultiJson.dump(
|
5
|
+
payload = MultiJson.dump(
|
6
6
|
events: [data.merge(name: name)],
|
7
7
|
time_ms: Time.now.to_i
|
8
|
-
|
8
|
+
)
|
9
9
|
|
10
10
|
PusherFake.configuration.webhooks.each do |url|
|
11
11
|
http = EventMachine::HttpRequest.new(url)
|
@@ -23,7 +23,10 @@ module PusherFake
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def signature_for(payload)
|
26
|
-
OpenSSL::
|
26
|
+
digest = OpenSSL::Digest::SHA256.new
|
27
|
+
secret = PusherFake.configuration.secret
|
28
|
+
|
29
|
+
OpenSSL::HMAC.hexdigest(digest, secret, payload)
|
27
30
|
end
|
28
31
|
end
|
29
32
|
end
|
@@ -6,12 +6,13 @@ describe PusherFake::Channel::Presence do
|
|
6
6
|
subject { PusherFake::Channel::Presence }
|
7
7
|
|
8
8
|
it "inherits from private channel" do
|
9
|
-
subject.ancestors.
|
9
|
+
expect(subject.ancestors).to include(PusherFake::Channel::Private)
|
10
10
|
end
|
11
11
|
|
12
12
|
it "creates an empty members hash" do
|
13
13
|
channel = subject.new(name)
|
14
|
-
|
14
|
+
|
15
|
+
expect(channel.members).to eq({})
|
15
16
|
end
|
16
17
|
end
|
17
18
|
|
@@ -35,76 +36,93 @@ describe PusherFake::Channel::Presence, "#add" do
|
|
35
36
|
|
36
37
|
it "authorizes the connection" do
|
37
38
|
subject.stubs(authorized?: nil)
|
39
|
+
|
38
40
|
subject.add(connection, data)
|
39
|
-
|
41
|
+
|
42
|
+
expect(subject).to have_received(:authorized?).with(connection, data)
|
40
43
|
end
|
41
44
|
|
42
45
|
it "parses the channel_data when authorized" do
|
43
46
|
subject.stubs(authorized?: true)
|
47
|
+
|
44
48
|
subject.add(connection, data)
|
45
|
-
|
49
|
+
|
50
|
+
expect(MultiJson).to have_received(:load).with(data[:channel_data], symbolize_keys: true)
|
46
51
|
end
|
47
52
|
|
48
53
|
it "assigns the parsed channel_data to the members hash for the current connection" do
|
49
54
|
subject.stubs(authorized?: true)
|
55
|
+
|
50
56
|
subject.add(connection, data)
|
51
|
-
|
57
|
+
|
58
|
+
expect(subject.members[connection]).to eq(channel_data)
|
52
59
|
end
|
53
60
|
|
54
61
|
it "notifies the channel of the new member when authorized" do
|
55
62
|
subject.stubs(authorized?: true)
|
63
|
+
|
56
64
|
subject.add(connection, data)
|
57
|
-
|
65
|
+
|
66
|
+
expect(subject).to have_received(:emit).with("pusher_internal:member_added", channel_data)
|
58
67
|
end
|
59
68
|
|
60
69
|
it "successfully subscribes the connection when authorized" do
|
61
70
|
subject.stubs(authorized?: true)
|
71
|
+
|
62
72
|
subject.add(connection, data)
|
63
|
-
|
73
|
+
|
74
|
+
expect(connection).to have_received(:emit)
|
75
|
+
.with("pusher_internal:subscription_succeeded", subscription_data, subject.name)
|
64
76
|
end
|
65
77
|
|
66
78
|
it "adds the connection to the channel when authorized" do
|
67
79
|
subject.stubs(authorized?: true)
|
80
|
+
|
68
81
|
subject.add(connection, data)
|
69
|
-
|
82
|
+
|
83
|
+
expect(connections).to have_received(:push).with(connection)
|
70
84
|
end
|
71
85
|
|
72
86
|
it "triggers channel occupied webhook for the first connection added when authorized" do
|
73
87
|
subject.unstub(:connections)
|
74
88
|
subject.stubs(authorized?: true)
|
75
89
|
|
76
|
-
subject.add(connection, data)
|
77
|
-
|
78
|
-
|
79
|
-
PusherFake::Webhook.should have_received(:trigger).with("channel_occupied", channel: name).once
|
90
|
+
2.times { subject.add(connection, data) }
|
91
|
+
|
92
|
+
expect(PusherFake::Webhook).to have_received(:trigger).with("channel_occupied", channel: name).once
|
80
93
|
end
|
81
94
|
|
82
95
|
it "triggers the member added webhook when authorized" do
|
83
96
|
subject.stubs(authorized?: true)
|
97
|
+
|
84
98
|
subject.add(connection, data)
|
85
|
-
|
99
|
+
|
100
|
+
expect(PusherFake::Webhook).to have_received(:trigger).with("member_added", channel: name, user_id: user_id).once
|
86
101
|
end
|
87
102
|
|
88
103
|
it "unsuccessfully subscribes the connection when not authorized" do
|
89
104
|
subject.stubs(authorized?: false)
|
105
|
+
|
90
106
|
subject.add(connection, data)
|
91
|
-
|
107
|
+
|
108
|
+
expect(connection).to have_received(:emit).with("pusher_internal:subscription_error", {}, subject.name)
|
92
109
|
end
|
93
110
|
|
94
111
|
it "does not trigger channel occupied webhook when not authorized" do
|
95
112
|
subject.unstub(:connections)
|
96
113
|
subject.stubs(authorized?: false)
|
97
114
|
|
98
|
-
subject.add(connection, data)
|
99
|
-
|
100
|
-
|
101
|
-
PusherFake::Webhook.should have_received(:trigger).never
|
115
|
+
2.times { subject.add(connection, data) }
|
116
|
+
|
117
|
+
expect(PusherFake::Webhook).to have_received(:trigger).never
|
102
118
|
end
|
103
119
|
|
104
120
|
it "does not trigger the member added webhook when not authorized" do
|
105
121
|
subject.stubs(authorized?: false)
|
122
|
+
|
106
123
|
subject.add(connection, data)
|
107
|
-
|
124
|
+
|
125
|
+
expect(PusherFake::Webhook).to have_received(:trigger).never
|
108
126
|
end
|
109
127
|
end
|
110
128
|
|
@@ -124,22 +142,57 @@ describe PusherFake::Channel::Presence, "#remove" do
|
|
124
142
|
|
125
143
|
it "removes the connection from the channel" do
|
126
144
|
subject.remove(connection)
|
127
|
-
|
145
|
+
|
146
|
+
expect(subject.connections).to be_empty
|
128
147
|
end
|
129
148
|
|
130
149
|
it "removes the connection from the members hash" do
|
131
150
|
subject.remove(connection)
|
132
|
-
|
151
|
+
|
152
|
+
expect(subject.members).to_not have_key(connection)
|
133
153
|
end
|
134
154
|
|
135
155
|
it "triggers the member removed webhook" do
|
136
156
|
subject.remove(connection)
|
137
|
-
|
157
|
+
|
158
|
+
expect(PusherFake::Webhook).to have_received(:trigger).with("member_removed", channel: name, user_id: user_id).once
|
138
159
|
end
|
139
160
|
|
140
161
|
it "notifies the channel of the removed member" do
|
141
162
|
subject.remove(connection)
|
142
|
-
|
163
|
+
|
164
|
+
expect(subject).to have_received(:emit).with("pusher_internal:member_removed", channel_data)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
describe PusherFake::Channel::Presence, "#remove, for an unsubscribed connection" do
|
169
|
+
let(:name) { "name" }
|
170
|
+
let(:user_id) { "1234" }
|
171
|
+
let(:connection) { stub }
|
172
|
+
let(:channel_data) { { user_id: user_id } }
|
173
|
+
|
174
|
+
subject { PusherFake::Channel::Presence.new(name) }
|
175
|
+
|
176
|
+
before do
|
177
|
+
subject.stubs(connections: [], emit: nil, trigger: nil)
|
178
|
+
end
|
179
|
+
|
180
|
+
it "does not raise an error" do
|
181
|
+
expect {
|
182
|
+
subject.remove(connection)
|
183
|
+
}.to_not raise_error
|
184
|
+
end
|
185
|
+
|
186
|
+
it "does not trigger an event" do
|
187
|
+
subject.remove(connection)
|
188
|
+
|
189
|
+
expect(PusherFake::Webhook).to have_received(:trigger).with("member_removed", channel: name, user_id: user_id).never
|
190
|
+
end
|
191
|
+
|
192
|
+
it "does not emit an event" do
|
193
|
+
subject.remove(connection)
|
194
|
+
|
195
|
+
expect(subject).to have_received(:emit).with("pusher_internal:member_removed", channel_data).never
|
143
196
|
end
|
144
197
|
end
|
145
198
|
|
@@ -155,22 +208,26 @@ describe PusherFake::Channel::Presence, "#subscription_data" do
|
|
155
208
|
end
|
156
209
|
|
157
210
|
it "returns hash with presence information" do
|
158
|
-
subject.subscription_data
|
211
|
+
data = subject.subscription_data
|
212
|
+
|
213
|
+
expect(data).to eq({
|
159
214
|
presence: {
|
160
215
|
hash: { member[:user_id] => member[:user_info] },
|
161
216
|
count: 1
|
162
217
|
}
|
163
|
-
}
|
218
|
+
})
|
164
219
|
end
|
165
220
|
|
166
221
|
it "handles multiple members" do
|
167
222
|
members[stub] = other
|
168
223
|
|
169
|
-
subject.subscription_data
|
224
|
+
data = subject.subscription_data
|
225
|
+
|
226
|
+
expect(data).to eq({
|
170
227
|
presence: {
|
171
228
|
hash: { member[:user_id] => member[:user_info], other[:user_id] => other[:user_info] },
|
172
229
|
count: 2
|
173
230
|
}
|
174
|
-
}
|
231
|
+
})
|
175
232
|
end
|
176
233
|
end
|