pusher-fake 0.13.0 → 0.14.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.
- 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
|