pusher-fake 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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)