pusher-fake 0.4.0 → 0.5.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.
@@ -0,0 +1,109 @@
1
+ @javascript
2
+ Feature: Requesting channel information
3
+
4
+ Background:
5
+ Given I am connected
6
+
7
+ Scenario: Requesting all channels
8
+ When I request "/channels"
9
+ Then I should receive the following JSON:
10
+ """
11
+ { "channels" : {} }
12
+ """
13
+ When I subscribe to the "chat-message" channel
14
+ And I request "/channels"
15
+ Then I should receive the following JSON:
16
+ """
17
+ { "channels" : {
18
+ "chat-message" : {}
19
+ }
20
+ }
21
+ """
22
+ When I subscribe to the "presence-game-1" channel with presence events
23
+ And I request "/channels"
24
+ Then I should receive the following JSON:
25
+ """
26
+ { "channels" : {
27
+ "chat-message" : {},
28
+ "presence-game-1" : {}
29
+ }
30
+ }
31
+ """
32
+
33
+ Scenario: Requesting all channels, with a filter
34
+ Given I subscribe to the "chat-message" channel
35
+ And I subscribe to the "presence-game-1" channel with presence events
36
+ When I request "/channels" with the following options:
37
+ | filter_by_prefix |
38
+ | chat |
39
+ Then I should receive the following JSON:
40
+ """
41
+ { "channels" : {
42
+ "chat-message" : {}
43
+ }
44
+ }
45
+ """
46
+
47
+ Scenario: Requesting all channels, with a valid filter and info attributes
48
+ Given I subscribe to the "chat-message" channel
49
+ And I subscribe to the "presence-game-1" channel with presence events
50
+ When I request "/channels" with the following options:
51
+ | filter_by_prefix | info |
52
+ | presence- | user_count |
53
+ Then I should receive the following JSON:
54
+ """
55
+ { "channels" : {
56
+ "presence-game-1" : {
57
+ "user_count" : 1
58
+ }
59
+ }
60
+ }
61
+ """
62
+
63
+ Scenario: Requesting all channels, with an invalid filter and info attributes
64
+ Given I subscribe to the "chat-message" channel
65
+ And I subscribe to the "presence-game-1" channel with presence events
66
+ When I request "/channels" with the following options:
67
+ | filter_by_prefix | info |
68
+ | chat- | user_count |
69
+ Then I should receive the following error:
70
+ """
71
+ user_count may only be requested for presence channels - please supply filter_by_prefix begining with presence-
72
+ """
73
+
74
+ Scenario: Requesting a channel, with no occupants
75
+ When I request "/channels/empty"
76
+ Then I should receive the following JSON:
77
+ """
78
+ { "occupied" : false }
79
+ """
80
+
81
+ Scenario: Requesting a channel, with an occupant
82
+ Given I subscribe to the "non-empty" channel
83
+ When I request "/channels/non-empty"
84
+ Then I should receive the following JSON:
85
+ """
86
+ { "occupied" : true }
87
+ """
88
+
89
+ Scenario: Requesting a channel, with valid info attributes
90
+ Given I subscribe to the "presence-1" channel
91
+ And Bob is connected
92
+ And Bob is subscribed to the "presence-1" channel
93
+ When I request "/channels/presence-1" with the following options:
94
+ | info |
95
+ | user_count |
96
+ Then I should receive the following JSON:
97
+ """
98
+ { "occupied" : true,
99
+ "user_count" : 2 }
100
+ """
101
+
102
+ Scenario: Requesting a channel, with invalid info attributes
103
+ When I request "/channels/public-1" with the following options:
104
+ | info |
105
+ | user_count |
106
+ Then I should receive the following error:
107
+ """
108
+ Cannot retrieve the user count unless the channel is a presence channel
109
+ """
@@ -0,0 +1,38 @@
1
+ When %{I request "$path"} do |path|
2
+ wait do
3
+ @response = Pusher.get(path)
4
+ end
5
+ end
6
+
7
+ When %{I request "$path" with the following options:} do |path, table|
8
+ wait do
9
+ begin
10
+ @response = Pusher.get(path, table.hashes.first)
11
+ rescue => error
12
+ @error = error
13
+ end
14
+ end
15
+ end
16
+
17
+ Then %{I should receive the following JSON:} do |string|
18
+ expected = MultiJson.load(string)
19
+ expected = expected.inject({}) do |result, (key, value)|
20
+ result[key.to_sym] = value
21
+ result
22
+ end
23
+
24
+ @response.should == expected
25
+ end
26
+
27
+ Then %{I should receive the following error:} do |string|
28
+ @error.message.should include(string.strip)
29
+ end
30
+
31
+ Then /^I should receive JSON for (\d+) users?$/ do |count|
32
+ users = @response[:users]
33
+ users.length.should == count.to_i
34
+ users.each do |user|
35
+ object = ObjectSpace._id2ref(user["id"])
36
+ object.should be_a(PusherFake::Connection)
37
+ end
38
+ end
@@ -61,7 +61,7 @@ When %{$name unsubscribes from the "$channel" channel} do |name, channel|
61
61
  end
62
62
 
63
63
  Then %{I should be subscribed to the "$channel" channel} do |channel|
64
- Capybara.timeout do
64
+ timeout_after(5) do
65
65
  subscribed = page.evaluate_script(%{
66
66
  var
67
67
  channel = Pusher.instance.channel(#{MultiJson.dump(channel)});
@@ -14,14 +14,14 @@ Given "I change my socket ID" do
14
14
  end
15
15
 
16
16
  Then "I should be connected" do
17
- Capybara.timeout do
17
+ timeout_after(5) do
18
18
  state = page.evaluate_script("Pusher.instance.connection.state")
19
19
  state == "connected"
20
20
  end
21
21
  end
22
22
 
23
23
  Then "I should not be connected" do
24
- Capybara.timeout do
24
+ timeout_after(5) do
25
25
  state = page.evaluate_script("Pusher.instance.connection.state")
26
26
  state == "unavailable"
27
27
  end
@@ -7,7 +7,7 @@ Then /^the server should have received the following (user )*event:$/ do |user_e
7
7
  end
8
8
  end if user_event
9
9
 
10
- Capybara.timeout do
10
+ timeout_after(5) do
11
11
  $events.include?(event)
12
12
  end
13
13
 
@@ -0,0 +1,15 @@
1
+ module Capybara
2
+ module Timing
3
+ def wait(seconds = 0.25, &block)
4
+ sleep(seconds) && yield
5
+ end
6
+
7
+ def timeout_after(seconds, &block)
8
+ Timeout::timeout(seconds) do
9
+ sleep(0.05) until yield
10
+ end
11
+ end
12
+ end
13
+ end
14
+
15
+ World(Capybara::Timing)
@@ -28,8 +28,8 @@ end.tap do |thread|
28
28
  at_exit { thread.exit }
29
29
 
30
30
  # Wait for the webhook endpoint server to start.
31
- Capybara.timeout do
32
- thread[:ready]
31
+ Timeout::timeout(5) do
32
+ sleep(0.05) until thread[:ready]
33
33
  end
34
34
  end
35
35
 
@@ -0,0 +1,14 @@
1
+ @javascript
2
+ Feature: Requesting user information
3
+
4
+ Scenario: Requesting users for a channel
5
+ Given I am connected
6
+ And Bob is connected
7
+ When I request "/channels/public-1/users"
8
+ Then I should receive JSON for 0 users
9
+ When I subscribe to the "public-1" channel
10
+ And I request "/channels/public-1/users"
11
+ Then I should receive JSON for 1 user
12
+ When Bob is subscribed to the "public-1" channel
13
+ And I request "/channels/public-1/users"
14
+ Then I should receive JSON for 2 users
@@ -16,7 +16,7 @@ require "pusher-fake/webhook"
16
16
 
17
17
  module PusherFake
18
18
  # The current version string.
19
- VERSION = "0.4.0"
19
+ VERSION = "0.5.0"
20
20
 
21
21
  # Call this method to modify the defaults.
22
22
  #
@@ -2,10 +2,10 @@ module PusherFake
2
2
  module Channel
3
3
  class << self
4
4
  # Name matcher for private channels.
5
- PRIVATE_CHANNEL_MATCHER = /^private-/.freeze
5
+ PRIVATE_CHANNEL_MATCHER = /\Aprivate-/.freeze
6
6
 
7
7
  # Name matcher for presence channels.
8
- PRESENCE_CHANNEL_MATCHER = /^presence-/.freeze
8
+ PRESENCE_CHANNEL_MATCHER = /\Apresence-/.freeze
9
9
 
10
10
  # @return [Hash] Cache of existing channels.
11
11
  attr_accessor :channels
@@ -48,9 +48,10 @@ module PusherFake
48
48
  # @param [String] name The name of the channel.
49
49
  # @return [Class] The class to use for the channel.
50
50
  def class_for(name)
51
- if name =~ PRIVATE_CHANNEL_MATCHER
51
+ case name
52
+ when PRIVATE_CHANNEL_MATCHER
52
53
  Private
53
- elsif name =~ PRESENCE_CHANNEL_MATCHER
54
+ when PRESENCE_CHANNEL_MATCHER
54
55
  Presence
55
56
  else
56
57
  Public
@@ -15,6 +15,8 @@ module PusherFake
15
15
 
16
16
  # Remove the +connection+ from the channel and notify the channel.
17
17
  #
18
+ # Also trigger the member_removed webhook.
19
+ #
18
20
  # @param [Connection] connection The connection to remove.
19
21
  def remove(connection)
20
22
  super
@@ -39,9 +41,11 @@ module PusherFake
39
41
 
40
42
  private
41
43
 
42
- # Store the member data for the connection and notify connections a
44
+ # Store the member data for the connection and notify the channel a
43
45
  # member was added.
44
46
  #
47
+ # Also trigger the member_added webhook.
48
+ #
45
49
  # @param [Connection] connection The connection a subscription succeeded for.
46
50
  # @param [Hash] options The options for the channel.
47
51
  def subscription_succeeded(connection, options = {})
@@ -45,6 +45,8 @@ module PusherFake
45
45
 
46
46
  # Remove the +connection+ from the channel.
47
47
  #
48
+ # If it is the last connection, trigger the channel_vacated webhook.
49
+ #
48
50
  # @param [Connection] connection The connection to remove.
49
51
  def remove(connection)
50
52
  connections.delete(connection)
@@ -64,9 +66,11 @@ module PusherFake
64
66
 
65
67
  private
66
68
 
67
- # Notify the channel of the successful subscription and add the
69
+ # Notify the +connection+ of the successful subscription and add the
68
70
  # connection to the channel.
69
71
  #
72
+ # If it is the first connection, trigger the channel_occupied webhook.
73
+ #
70
74
  # @param [Connection] connection The connection a subscription succeeded for.
71
75
  # @param [Hash] options The options for the channel.
72
76
  def subscription_succeeded(connection, options = {})
@@ -1,5 +1,8 @@
1
1
  module PusherFake
2
2
  class Connection
3
+ # Name matcher for client events.
4
+ CLIENT_EVENT_MATCHER = /\Aclient-(.+)\Z/.freeze
5
+
3
6
  # @return [EventMachine::WebSocket::Connection] The socket object for this connection.
4
7
  attr_reader :socket
5
8
 
@@ -18,9 +21,8 @@ module PusherFake
18
21
  def emit(event, data = {}, channel = nil)
19
22
  message = { event: event, data: data }
20
23
  message[:channel] = channel if channel
21
- message = MultiJson.dump(message)
22
24
 
23
- socket.send(message)
25
+ socket.send(MultiJson.dump(message))
24
26
  end
25
27
 
26
28
  # Notify the Pusher client that a connection has been established.
@@ -43,7 +45,7 @@ module PusherFake
43
45
  channel.add(self, data)
44
46
  when "pusher:unsubscribe"
45
47
  channel.remove(self)
46
- when /^client-(.+)$/
48
+ when CLIENT_EVENT_MATCHER
47
49
  return unless channel.is_a?(Channel::Private)
48
50
  return unless channel.includes?(self)
49
51
 
@@ -1,20 +1,115 @@
1
1
  module PusherFake
2
2
  module Server
3
3
  class Application
4
- # Process an API request by emitting the event with data to the
5
- # requested channels.
4
+ CHANNEL_FILTER_ERROR = "user_count may only be requested for presence channels - " +
5
+ "please supply filter_by_prefix begining with presence-".freeze
6
+
7
+ CHANNEL_USER_COUNT_ERROR = "Cannot retrieve the user count unless the channel is a presence channel".freeze
8
+
9
+ PRESENCE_PREFIX_MATCHER = /\Apresence-/.freeze
10
+
11
+ # Process an API request.
6
12
  #
7
13
  # @param [Hash] environment The request environment.
8
14
  # @return [Rack::Response] A successful response.
9
15
  def self.call(environment)
10
- request = Rack::Request.new(environment)
11
- event = MultiJson.load(request.body.read)
16
+ id = PusherFake.configuration.app_id
17
+ request = Rack::Request.new(environment)
18
+ response = case request.path
19
+ when %r{\A/apps/#{id}/events\Z}
20
+ events(request)
21
+ when %r{\A/apps/#{id}/channels\Z}
22
+ channels(request)
23
+ when %r{\A/apps/#{id}/channels/([^/]+)\Z}
24
+ channel($1, request)
25
+ when %r{\A/apps/#{id}/channels/([^/]+)/users\Z}
26
+ users($1)
27
+ end
28
+
29
+ Rack::Response.new(MultiJson.dump(response)).finish
30
+ rescue => error
31
+ Rack::Response.new(error.message, 400).finish
32
+ end
12
33
 
34
+ # Emit an event with data to the requested channel(s).
35
+ #
36
+ # @param [Rack::Request] request The HTTP request.
37
+ # @return [Hash] An empty hash.
38
+ def self.events(request)
39
+ event = MultiJson.load(request.body.read)
13
40
  event["channels"].each do |channel|
14
41
  Channel.factory(channel).emit(event["name"], event["data"], socket_id: event["socket_id"])
15
42
  end
16
43
 
17
- Rack::Response.new("{}").finish
44
+ {}
45
+ end
46
+
47
+ # Return a hash of channel information.
48
+ #
49
+ # Occupied status is always included. A user count may be requested for
50
+ # presence channels.
51
+ #
52
+ # @param [String] name The channel name.
53
+ # @params [Rack::Request] request The HTTP request.
54
+ # @return [Hash] A hash of channel information.
55
+ def self.channel(name, request)
56
+ info = request.params["info"].to_s.split(",")
57
+
58
+ if info.include?("user_count") && name !~ PRESENCE_PREFIX_MATCHER
59
+ raise CHANNEL_USER_COUNT_ERROR
60
+ end
61
+
62
+ channels = PusherFake::Channel.channels || {}
63
+ channel = channels[name]
64
+
65
+ {}.tap do |result|
66
+ result[:occupied] = !channel.nil? && channel.connections.length > 0
67
+ result[:user_count] = channel.connections.length if channel && info.include?("user_count")
68
+ end
69
+ end
70
+
71
+ # Returns a hash of occupied channels, optionally filtering with a prefix.
72
+ #
73
+ # When filtering to presence chanenls, the user count maybe also be requested.
74
+ #
75
+ # @param [Rack::Request] request The HTTP request.
76
+ # @return [Hash] A hash of occupied channels.
77
+ def self.channels(request)
78
+ info = request.params["info"].to_s.split(",")
79
+ prefix = request.params["filter_by_prefix"].to_s
80
+
81
+ if info.include?("user_count") && prefix !~ PRESENCE_PREFIX_MATCHER
82
+ raise CHANNEL_FILTER_ERROR
83
+ end
84
+
85
+ filter = Regexp.new(%r{\A#{prefix}})
86
+ channels = PusherFake::Channel.channels || {}
87
+ channels.inject({ channels: {} }) do |result, (name, channel)|
88
+ unless filter && name !~ filter
89
+ channels = result[:channels]
90
+ channels[name] = {}
91
+ channels[name][:user_count] = channel.connections.length if info.include?("user_count")
92
+ end
93
+
94
+ result
95
+ end
96
+ end
97
+
98
+ # Returns a hash of the IDs for the users in the channel.
99
+ #
100
+ # @param [String] name The channel name.
101
+ # @return [Hash] A hash of user IDs.
102
+ def self.users(name)
103
+ channels = PusherFake::Channel.channels || {}
104
+ channel = channels[name]
105
+
106
+ if channel
107
+ users = channel.connections.map do |connection|
108
+ { id: connection.object_id }
109
+ end
110
+ end
111
+
112
+ { users: users || [] }
18
113
  end
19
114
  end
20
115
  end
@@ -1,17 +1,10 @@
1
1
  require "spec_helper"
2
2
 
3
- describe PusherFake::Server::Application, ".call" do
4
- let(:body) { stub(read: json) }
5
- let(:data) { mock }
6
- let(:json) { mock }
7
- let(:name) { "event-name" }
8
- let(:event) { { "channels" => channels, "name" => name, "data" => data, "socket_id" => socket_id } }
9
- let(:request) { stub(body: body) }
10
- let(:channels) { ["channel-1", "channel-2"] }
3
+ shared_examples_for "an API request" do
4
+ let(:hash) { mock }
5
+ let(:string) { mock }
6
+ let(:request) { stub(path: path) }
11
7
  let(:response) { mock }
12
- let(:channel_1) { stub(emit: true) }
13
- let(:channel_2) { stub(emit: true) }
14
- let(:socket_id) { stub }
15
8
  let(:environment) { mock }
16
9
 
17
10
  subject { PusherFake::Server::Application }
@@ -19,11 +12,9 @@ describe PusherFake::Server::Application, ".call" do
19
12
  before do
20
13
  response.stubs(finish: response)
21
14
 
22
- MultiJson.stubs(load: event)
15
+ MultiJson.stubs(dump: string)
23
16
  Rack::Request.stubs(new: request)
24
17
  Rack::Response.stubs(new: response)
25
- PusherFake::Channel.stubs(:factory).with(channels[0]).returns(channel_1)
26
- PusherFake::Channel.stubs(:factory).with(channels[1]).returns(channel_2)
27
18
  end
28
19
 
29
20
  it "creates a request" do
@@ -31,28 +22,85 @@ describe PusherFake::Server::Application, ".call" do
31
22
  Rack::Request.should have_received(:new).with(environment)
32
23
  end
33
24
 
34
- it "parses the request body as JSON" do
25
+ it "dumps the response hash to JSON" do
35
26
  subject.call(environment)
36
- MultiJson.should have_received(:load).with(json)
27
+ MultiJson.should have_received(:dump).with(hash)
37
28
  end
38
29
 
39
- it "creates channels by name" do
30
+ it "creates a Rack response with the response JSON" do
40
31
  subject.call(environment)
32
+ Rack::Response.should have_received(:new).with(string)
33
+ end
41
34
 
42
- channels.each do |channel|
43
- PusherFake::Channel.should have_received(:factory).with(channel)
35
+ it "finishes the response" do
36
+ subject.call(environment)
37
+ response.should have_received(:finish).with()
38
+ end
39
+
40
+ it "returns the response" do
41
+ subject.call(environment).should == response
42
+ end
43
+ end
44
+
45
+ describe PusherFake::Server::Application, ".call, for triggering events" do
46
+ it_should_behave_like "an API request" do
47
+ let(:id) { PusherFake.configuration.app_id }
48
+ let(:path) { "/apps/#{id}/events" }
49
+
50
+ before do
51
+ subject.stubs(events: hash)
52
+ end
53
+
54
+ it "emits events" do
55
+ subject.call(environment)
56
+ subject.should have_received(:events).with(request)
44
57
  end
45
58
  end
59
+ end
46
60
 
47
- it "emits the event to the channels" do
61
+ describe PusherFake::Server::Application, ".call, for retrieving occupied channels" do
62
+ it_should_behave_like "an API request" do
63
+ let(:id) { PusherFake.configuration.app_id }
64
+ let(:path) { "/apps/#{id}/channels" }
65
+
66
+ before do
67
+ subject.stubs(channels: hash)
68
+ end
69
+
70
+ it "filters the occupied channels" do
71
+ subject.call(environment)
72
+ subject.should have_received(:channels).with(request)
73
+ end
74
+ end
75
+ end
76
+
77
+ describe PusherFake::Server::Application, ".call, raising an error" do
78
+ let(:id) { PusherFake.configuration.app_id }
79
+ let(:path) { "/apps/#{id}/channels" }
80
+ let(:message) { "Example error message." }
81
+ let(:request) { stub(path: path) }
82
+ let(:response) { mock }
83
+ let(:environment) { mock }
84
+
85
+ subject { PusherFake::Server::Application }
86
+
87
+ before do
88
+ subject.stubs(:channels).raises(message)
89
+
90
+ response.stubs(finish: response)
91
+
92
+ Rack::Request.stubs(new: request)
93
+ Rack::Response.stubs(new: response)
94
+ end
95
+
96
+ it "creates a request" do
48
97
  subject.call(environment)
49
- channel_1.should have_received(:emit).with(name, data, socket_id: socket_id)
50
- channel_2.should have_received(:emit).with(name, data, socket_id: socket_id)
98
+ Rack::Request.should have_received(:new).with(environment)
51
99
  end
52
100
 
53
- it "creates a Rack response with an empty JSON object" do
101
+ it "creates a Rack response with the error message" do
54
102
  subject.call(environment)
55
- Rack::Response.should have_received(:new).with("{}")
103
+ Rack::Response.should have_received(:new).with(message, 400)
56
104
  end
57
105
 
58
106
  it "finishes the response" do
@@ -64,3 +112,256 @@ describe PusherFake::Server::Application, ".call" do
64
112
  subject.call(environment).should == response
65
113
  end
66
114
  end
115
+
116
+ describe PusherFake::Server::Application, ".events" do
117
+ let(:body) { stub(read: json) }
118
+ let(:data) { mock }
119
+ let(:json) { mock }
120
+ let(:name) { "event-name" }
121
+ let(:event) { { "channels" => channels, "name" => name, "data" => data, "socket_id" => socket_id } }
122
+ let(:request) { stub(body: body) }
123
+ let(:channels) { ["channel-1", "channel-2"] }
124
+ let(:channel_1) { stub(emit: true) }
125
+ let(:channel_2) { stub(emit: true) }
126
+ let(:socket_id) { stub }
127
+
128
+ subject { PusherFake::Server::Application }
129
+
130
+ before do
131
+ MultiJson.stubs(load: event)
132
+ PusherFake::Channel.stubs(:factory).with(channels[0]).returns(channel_1)
133
+ PusherFake::Channel.stubs(:factory).with(channels[1]).returns(channel_2)
134
+ end
135
+
136
+ it "parses the request body as JSON" do
137
+ subject.events(request)
138
+ MultiJson.should have_received(:load).with(json)
139
+ end
140
+
141
+ it "creates channels by name" do
142
+ subject.events(request)
143
+
144
+ channels.each do |channel|
145
+ PusherFake::Channel.should have_received(:factory).with(channel)
146
+ end
147
+ end
148
+
149
+ it "emits the event to the channels" do
150
+ subject.events(request)
151
+
152
+ channel_1.should have_received(:emit).with(name, data, socket_id: socket_id)
153
+ channel_2.should have_received(:emit).with(name, data, socket_id: socket_id)
154
+ end
155
+ end
156
+
157
+ describe PusherFake::Server::Application, ".channels, requesting all channels" do
158
+ let(:request) { stub(params: {}) }
159
+ let(:channels) { { "channel-1" => mock, "channel-2" => mock } }
160
+
161
+ subject { PusherFake::Server::Application }
162
+
163
+ before do
164
+ PusherFake::Channel.stubs(channels: channels)
165
+ end
166
+
167
+ it "returns a hash of all the channels" do
168
+ subject.channels(request).should == {
169
+ channels: {
170
+ "channel-1" => {},
171
+ "channel-2" => {}
172
+ }
173
+ }
174
+ end
175
+ end
176
+
177
+ describe PusherFake::Server::Application, ".channels, requesting channels with a filter" do
178
+ let(:params) { { "filter_by_prefix" => "public-" } }
179
+ let(:request) { stub(params: params) }
180
+ let(:channels) { { "public-1" => mock, "presence-1" => mock } }
181
+
182
+ subject { PusherFake::Server::Application }
183
+
184
+ before do
185
+ PusherFake::Channel.stubs(channels: channels)
186
+ end
187
+
188
+ it "returns a hash of the channels matching the filter" do
189
+ subject.channels(request).should == { channels: { "public-1" => {} } }
190
+ end
191
+ end
192
+
193
+ describe PusherFake::Server::Application, ".channels, requesting user count for channels with a filter" do
194
+ let(:params) { { "filter_by_prefix" => "presence-", "info" => "user_count" } }
195
+ let(:request) { stub(params: params) }
196
+ let(:channel) { stub(connections: [mock, mock]) }
197
+ let(:channels) { { "public-1" => mock, "presence-1" => channel } }
198
+
199
+ subject { PusherFake::Server::Application }
200
+
201
+ before do
202
+ PusherFake::Channel.stubs(channels: channels)
203
+ end
204
+
205
+ it "returns a hash of the channels matching the filter and include the user count" do
206
+ subject.channels(request).should == { channels: { "presence-1" => { user_count: 2 } } }
207
+ end
208
+ end
209
+
210
+ describe PusherFake::Server::Application, ".channels, requesting all channels with no channels occupied" do
211
+ let(:request) { stub(params: {}) }
212
+ let(:channels) { nil }
213
+
214
+ subject { PusherFake::Server::Application }
215
+
216
+ before do
217
+ PusherFake::Channel.stubs(channels: channels)
218
+ end
219
+
220
+ it "returns a hash of no channels" do
221
+ subject.channels(request).should == { channels: {} }
222
+ end
223
+ end
224
+
225
+ describe PusherFake::Server::Application, ".channels, requesting a user count on a non-presence channel" do
226
+ let(:params) { { "filter_by_prefix" => "public-", "info" => "user_count" } }
227
+ let(:request) { stub(params: params) }
228
+
229
+ subject { PusherFake::Server::Application }
230
+
231
+ it "raises an error" do
232
+ lambda {
233
+ subject.channels(request)
234
+ }.should raise_error(subject::CHANNEL_FILTER_ERROR)
235
+ end
236
+ end
237
+
238
+ describe PusherFake::Server::Application, ".channel, for an occupied channel" do
239
+ let(:name) { "public-1" }
240
+ let(:request) { stub(params: {}) }
241
+ let(:channel) { stub(connections: [mock]) }
242
+ let(:channels) { { name => channel } }
243
+
244
+ subject { PusherFake::Server::Application }
245
+
246
+ before do
247
+ PusherFake::Channel.stubs(channels: channels)
248
+ end
249
+
250
+ it "returns a hash with the occupied status" do
251
+ subject.channel(name, request).should == { occupied: true }
252
+ end
253
+ end
254
+
255
+ describe PusherFake::Server::Application, ".channel, for an unoccupied channel" do
256
+ let(:name) { "public-1" }
257
+ let(:request) { stub(params: {}) }
258
+ let(:channel) { stub(connections: []) }
259
+ let(:channels) { { name => channel } }
260
+
261
+ subject { PusherFake::Server::Application }
262
+
263
+ before do
264
+ PusherFake::Channel.stubs(channels: channels)
265
+ end
266
+
267
+ it "returns a hash with the occupied status" do
268
+ subject.channel(name, request).should == { occupied: false }
269
+ end
270
+ end
271
+
272
+ describe PusherFake::Server::Application, ".channel, for an unknown channel" do
273
+ let(:request) { stub(params: {}) }
274
+ let(:channels) { {} }
275
+
276
+ subject { PusherFake::Server::Application }
277
+
278
+ before do
279
+ PusherFake::Channel.stubs(channels: channels)
280
+ end
281
+
282
+ it "returns a hash with the occupied status" do
283
+ subject.channel("fake", request).should == { occupied: false }
284
+ end
285
+ end
286
+
287
+ describe PusherFake::Server::Application, ".channel, request user count for a presence channel" do
288
+ let(:name) { "presence-1" }
289
+ let(:params) { { "info" => "user_count" } }
290
+ let(:request) { stub(params: params) }
291
+ let(:channel) { stub(connections: [mock, mock]) }
292
+ let(:channels) { { name => channel } }
293
+
294
+ subject { PusherFake::Server::Application }
295
+
296
+ before do
297
+ PusherFake::Channel.stubs(channels: channels)
298
+ end
299
+
300
+ it "returns a hash with the occupied status" do
301
+ subject.channel(name, request).should == { occupied: true, user_count: 2 }
302
+ end
303
+ end
304
+
305
+ describe PusherFake::Server::Application, ".channel, requesting a user count on a non-presence channel" do
306
+ let(:params) { { "info" => "user_count" } }
307
+ let(:request) { stub(params: params) }
308
+
309
+ subject { PusherFake::Server::Application }
310
+
311
+ it "raises an error" do
312
+ lambda {
313
+ subject.channel("public-1", request)
314
+ }.should raise_error(subject::CHANNEL_USER_COUNT_ERROR)
315
+ end
316
+ end
317
+
318
+ describe PusherFake::Server::Application, ".users, for an occupied channel" do
319
+ let(:name) { "public-1" }
320
+ let(:user_1) { mock }
321
+ let(:user_2) { mock }
322
+ let(:channel) { stub(connections: [user_1, user_2]) }
323
+ let(:channels) { { name => channel } }
324
+
325
+ subject { PusherFake::Server::Application }
326
+
327
+ before do
328
+ PusherFake::Channel.stubs(channels: channels)
329
+ end
330
+
331
+ it "returns a hash with the occupied status" do
332
+ subject.users(name).should == { users: [
333
+ { id: user_1.object_id },
334
+ { id: user_2.object_id }
335
+ ] }
336
+ end
337
+ end
338
+
339
+ describe PusherFake::Server::Application, ".users, for an empty channel" do
340
+ let(:name) { "public-1" }
341
+ let(:channel) { stub(connections: []) }
342
+ let(:channels) { { name => channel } }
343
+
344
+ subject { PusherFake::Server::Application }
345
+
346
+ before do
347
+ PusherFake::Channel.stubs(channels: channels)
348
+ end
349
+
350
+ it "returns a hash with the occupied status" do
351
+ subject.users(name).should == { users: [] }
352
+ end
353
+ end
354
+
355
+ describe PusherFake::Server::Application, ".users, for an unknown channel" do
356
+ let(:channels) { {} }
357
+
358
+ subject { PusherFake::Server::Application }
359
+
360
+ before do
361
+ PusherFake::Channel.stubs(channels: channels)
362
+ end
363
+
364
+ it "returns a hash with the occupied status" do
365
+ subject.users("fake").should == { users: [] }
366
+ end
367
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pusher-fake
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-14 00:00:00.000000000 Z
12
+ date: 2013-01-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: em-http-request
@@ -98,7 +98,7 @@ dependencies:
98
98
  requirements:
99
99
  - - '='
100
100
  - !ruby/object:Gem::Version
101
- version: 0.13.0
101
+ version: 0.14.1
102
102
  type: :development
103
103
  prerelease: false
104
104
  version_requirements: !ruby/object:Gem::Requirement
@@ -106,7 +106,7 @@ dependencies:
106
106
  requirements:
107
107
  - - '='
108
108
  - !ruby/object:Gem::Version
109
- version: 0.13.0
109
+ version: 0.14.1
110
110
  - !ruby/object:Gem::Dependency
111
111
  name: cucumber
112
112
  requirement: !ruby/object:Gem::Requirement
@@ -130,7 +130,7 @@ dependencies:
130
130
  requirements:
131
131
  - - '='
132
132
  - !ruby/object:Gem::Version
133
- version: 0.11.1
133
+ version: 0.11.2
134
134
  type: :development
135
135
  prerelease: false
136
136
  version_requirements: !ruby/object:Gem::Requirement
@@ -138,7 +138,7 @@ dependencies:
138
138
  requirements:
139
139
  - - '='
140
140
  - !ruby/object:Gem::Version
141
- version: 0.11.1
141
+ version: 0.11.2
142
142
  - !ruby/object:Gem::Dependency
143
143
  name: rake
144
144
  requirement: !ruby/object:Gem::Requirement
@@ -235,11 +235,13 @@ files:
235
235
  - lib/pusher-fake/server.rb
236
236
  - lib/pusher-fake/webhook.rb
237
237
  - lib/pusher-fake.rb
238
+ - features/channel.feature
238
239
  - features/channel_presence.feature
239
240
  - features/channel_subscribe.feature
240
241
  - features/channel_trigger.feature
241
242
  - features/channel_webhooks.feature
242
243
  - features/client_connect.feature
244
+ - features/step_definitions/api_steps.rb
243
245
  - features/step_definitions/channel_steps.rb
244
246
  - features/step_definitions/client_steps.rb
245
247
  - features/step_definitions/event_steps.rb
@@ -251,8 +253,9 @@ files:
251
253
  - features/support/application.rb
252
254
  - features/support/environment.rb
253
255
  - features/support/pusher-fake.rb
254
- - features/support/wait.rb
256
+ - features/support/timing.rb
255
257
  - features/support/webhooks.rb
258
+ - features/user.feature
256
259
  - spec/lib/pusher-fake/channel/presence_spec.rb
257
260
  - spec/lib/pusher-fake/channel/private_spec.rb
258
261
  - spec/lib/pusher-fake/channel/public_spec.rb
@@ -279,7 +282,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
279
282
  version: '0'
280
283
  segments:
281
284
  - 0
282
- hash: 422324926089299174
285
+ hash: 399560288532115736
283
286
  required_rubygems_version: !ruby/object:Gem::Requirement
284
287
  none: false
285
288
  requirements:
@@ -288,7 +291,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
288
291
  version: '0'
289
292
  segments:
290
293
  - 0
291
- hash: 422324926089299174
294
+ hash: 399560288532115736
292
295
  requirements: []
293
296
  rubyforge_project:
294
297
  rubygems_version: 1.8.23
@@ -296,11 +299,13 @@ signing_key:
296
299
  specification_version: 3
297
300
  summary: A fake Pusher server for development and testing.
298
301
  test_files:
302
+ - features/channel.feature
299
303
  - features/channel_presence.feature
300
304
  - features/channel_subscribe.feature
301
305
  - features/channel_trigger.feature
302
306
  - features/channel_webhooks.feature
303
307
  - features/client_connect.feature
308
+ - features/step_definitions/api_steps.rb
304
309
  - features/step_definitions/channel_steps.rb
305
310
  - features/step_definitions/client_steps.rb
306
311
  - features/step_definitions/event_steps.rb
@@ -312,8 +317,9 @@ test_files:
312
317
  - features/support/application.rb
313
318
  - features/support/environment.rb
314
319
  - features/support/pusher-fake.rb
315
- - features/support/wait.rb
320
+ - features/support/timing.rb
316
321
  - features/support/webhooks.rb
322
+ - features/user.feature
317
323
  - spec/lib/pusher-fake/channel/presence_spec.rb
318
324
  - spec/lib/pusher-fake/channel/private_spec.rb
319
325
  - spec/lib/pusher-fake/channel/public_spec.rb
@@ -1,9 +0,0 @@
1
- module Capybara
2
- module Wait
3
- def wait(seconds = 0.25, &block)
4
- sleep(seconds) && yield
5
- end
6
- end
7
- end
8
-
9
- World(Capybara::Wait)