pusher 1.3.0 → 1.4.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,56 @@
1
+ require 'sinatra'
2
+ require 'sinatra/cookies'
3
+ require 'sinatra/json'
4
+ require 'pusher'
5
+
6
+ # You can get these variables from http://dashboard.pusher.com
7
+ pusher = Pusher::Client.new(
8
+ app_id: 'your-app-id',
9
+ key: 'your-app-key',
10
+ secret: 'your-app-secret',
11
+ cluster: 'your-app-cluster'
12
+ )
13
+
14
+ set :public_folder, 'public'
15
+
16
+ get "/" do
17
+ redirect '/presence_channels.html'
18
+ end
19
+
20
+ # Emulate rails behaviour where this information would be stored in session
21
+ get '/signin' do
22
+ cookies[:user_id] = 'example_cookie'
23
+ 'Ok'
24
+ end
25
+
26
+ # Auth endpoint: https://pusher.com/docs/channels/server_api/authenticating-users
27
+ post '/pusher/auth' do
28
+ channel_data = {
29
+ user_id: 'example_user',
30
+ user_info: {
31
+ name: 'example_name',
32
+ email: 'example_email'
33
+ }
34
+ }
35
+
36
+ if cookies[:user_id] == 'example_cookie'
37
+ response = pusher.authenticate(params[:channel_name], params[:socket_id], channel_data)
38
+ json response
39
+ else
40
+ status 403
41
+ end
42
+ end
43
+
44
+ get '/pusher_trigger' do
45
+ channels = ['presence-channel-test'];
46
+
47
+ begin
48
+ pusher.trigger(channels, 'test-event', {
49
+ message: 'hello world'
50
+ })
51
+ rescue Pusher::Error => e
52
+ # (Pusher::AuthenticationError, Pusher::HTTPError, or Pusher::Error)
53
+ end
54
+
55
+ 'Triggered!'
56
+ end
@@ -0,0 +1,28 @@
1
+ <!DOCTYPE html>
2
+ <head>
3
+ <title>Pusher Test</title>
4
+ <script src="https://js.pusher.com/5.0/pusher.min.js"></script>
5
+ <script>
6
+
7
+ // Enable pusher logging - don't include this in production
8
+ Pusher.logToConsole = true;
9
+
10
+ var pusher = new Pusher('your-app-key', {
11
+ cluster: 'your-app-cluster',
12
+ forceTLS: true,
13
+ authEndpoint: '/pusher/auth'
14
+ });
15
+
16
+ var channel = pusher.subscribe('presence-channel-test');
17
+ channel.bind('test-event', function(data) {
18
+ alert(JSON.stringify(data));
19
+ });
20
+ </script>
21
+ </head>
22
+ <body>
23
+ <h1>Pusher Test</h1>
24
+ <p>
25
+ Try publishing an event to channel <code>presence-channel-test</code>
26
+ with event name <code>test-event</code>.
27
+ </p>
28
+ </body>
@@ -32,12 +32,13 @@ module Pusher
32
32
  def_delegators :default_client, :scheme=, :host=, :port=, :app_id=, :key=, :secret=, :http_proxy=
33
33
  def_delegators :default_client, :notification_host=, :notification_scheme=
34
34
 
35
- def_delegators :default_client, :authentication_token, :url
35
+ def_delegators :default_client, :authentication_token, :url, :cluster
36
36
  def_delegators :default_client, :encrypted=, :url=, :cluster=
37
37
  def_delegators :default_client, :timeout=, :connect_timeout=, :send_timeout=, :receive_timeout=, :keep_alive_timeout=
38
38
 
39
39
  def_delegators :default_client, :get, :get_async, :post, :post_async
40
- def_delegators :default_client, :channels, :channel_info, :channel_users, :trigger, :trigger_async
40
+ def_delegators :default_client, :channels, :channel_info, :channel_users
41
+ def_delegators :default_client, :trigger, :trigger_batch, :trigger_async, :trigger_batch_async
41
42
  def_delegators :default_client, :authenticate, :webhook, :channel, :[]
42
43
  def_delegators :default_client, :notify
43
44
 
@@ -86,6 +86,9 @@ module Pusher
86
86
 
87
87
  # Request info for a channel
88
88
  #
89
+ # @example Response
90
+ # [{:occupied=>true, :subscription_count => 12}]
91
+ #
89
92
  # @param info [Array] Array of attributes required (as lowercase strings)
90
93
  # @return [Hash] Hash of requested attributes for this channel
91
94
  # @raise [Pusher::Error] on invalid Pusher response - see the error message for more details
@@ -99,7 +102,7 @@ module Pusher
99
102
  # Only works on presence channels (see: http://pusher.com/docs/client_api_guide/client_presence_channels and https://pusher.com/docs/rest_api)
100
103
  #
101
104
  # @example Response
102
- # [{"id"=>"4"}]
105
+ # [{:id=>"4"}]
103
106
  #
104
107
  # @param params [Hash] Hash of parameters for the API - see REST API docs
105
108
  # @return [Hash] Array of user hashes for this channel
@@ -120,6 +123,8 @@ module Pusher
120
123
  # @param custom_string [String] Allows signing additional data
121
124
  # @return [String]
122
125
  #
126
+ # @raise [Pusher::Error] if socket_id or custom_string invalid
127
+ #
123
128
  def authentication_string(socket_id, custom_string = nil)
124
129
  validate_socket_id(socket_id)
125
130
 
@@ -144,7 +149,7 @@ module Pusher
144
149
  # render :json => Pusher['private-my_channel'].authenticate(params[:socket_id])
145
150
  #
146
151
  # @example Presence channels
147
- # render :json => Pusher['private-my_channel'].authenticate(params[:socket_id], {
152
+ # render :json => Pusher['presence-my_channel'].authenticate(params[:socket_id], {
148
153
  # :user_id => current_user.id, # => required
149
154
  # :user_info => { # => optional - for example
150
155
  # :name => current_user.name,
@@ -157,6 +162,8 @@ module Pusher
157
162
  #
158
163
  # @return [Hash]
159
164
  #
165
+ # @raise [Pusher::Error] if socket_id or custom_data is invalid
166
+ #
160
167
  # @private Custom data is sent to server as JSON-encoded string
161
168
  #
162
169
  def authenticate(socket_id, custom_data = nil)
@@ -1,8 +1,10 @@
1
+ require 'base64'
2
+
1
3
  require 'pusher-signature'
2
4
 
3
5
  module Pusher
4
6
  class Client
5
- attr_accessor :scheme, :host, :port, :app_id, :key, :secret, :notification_host, :notification_scheme
7
+ attr_accessor :scheme, :host, :port, :app_id, :key, :secret, :notification_host, :notification_scheme, :encryption_master_key
6
8
  attr_reader :http_proxy, :proxy
7
9
  attr_writer :connect_timeout, :send_timeout, :receive_timeout,
8
10
  :keep_alive_timeout
@@ -12,6 +14,11 @@ module Pusher
12
14
  # Loads the configuration from an url in the environment
13
15
  def self.from_env(key = 'PUSHER_URL')
14
16
  url = ENV[key] || raise(ConfigurationError, key)
17
+ from_url(url)
18
+ end
19
+
20
+ # Loads the configuration from a url
21
+ def self.from_url(url)
15
22
  client = new
16
23
  client.url = url
17
24
  client
@@ -22,6 +29,12 @@ module Pusher
22
29
  :scheme => 'http',
23
30
  :port => 80,
24
31
  }
32
+
33
+ if options[:use_tls] || options[:encrypted]
34
+ default_options[:scheme] = "https"
35
+ default_options[:port] = 443
36
+ end
37
+
25
38
  merged_options = default_options.merge(options)
26
39
 
27
40
  if options.has_key?(:host)
@@ -44,6 +57,11 @@ module Pusher
44
57
  :scheme, :host, :port, :app_id, :key, :secret, :notification_host, :notification_scheme
45
58
  )
46
59
 
60
+ if options.has_key?(:encryption_master_key_base64)
61
+ @encryption_master_key =
62
+ Base64.decode64(options[:encryption_master_key_base64])
63
+ end
64
+
47
65
  @http_proxy = nil
48
66
  self.http_proxy = options[:http_proxy] if options[:http_proxy]
49
67
 
@@ -127,7 +145,13 @@ module Pusher
127
145
  @connect_timeout, @send_timeout, @receive_timeout = value, value, value
128
146
  end
129
147
 
130
- ## INTERACE WITH THE API ##
148
+ # Set an encryption_master_key to use with private-encrypted channels from
149
+ # a base64 encoded string.
150
+ def encryption_master_key_base64=(s)
151
+ @encryption_master_key = s ? Base64.decode64(s) : nil
152
+ end
153
+
154
+ ## INTERACT WITH THE API ##
131
155
 
132
156
  def resource(path)
133
157
  Resource.new(self, path)
@@ -345,6 +369,8 @@ module Pusher
345
369
  #
346
370
  # @return [Hash]
347
371
  #
372
+ # @raise [Pusher::Error] if channel_name or socket_id are invalid
373
+ #
348
374
  # @private Custom data is sent to server as JSON-encoded string
349
375
  #
350
376
  def authenticate(channel_name, socket_id, custom_data = nil)
@@ -400,10 +426,17 @@ module Pusher
400
426
  channels = Array(channels).map(&:to_s)
401
427
  raise Pusher::Error, "Too many channels (#{channels.length}), max 10" if channels.length > 10
402
428
 
429
+ encoded_data = if channels.any?{ |c| c.match(/^private-encrypted-/) } then
430
+ raise Pusher::Error, "Cannot trigger to multiple channels if any are encrypted" if channels.length > 1
431
+ encrypt(channels[0], encode_data(data))
432
+ else
433
+ encode_data(data)
434
+ end
435
+
403
436
  params.merge({
404
437
  name: event_name,
405
438
  channels: channels,
406
- data: encode_data(data),
439
+ data: encoded_data,
407
440
  })
408
441
  end
409
442
 
@@ -411,7 +444,11 @@ module Pusher
411
444
  {
412
445
  batch: events.map do |event|
413
446
  event.dup.tap do |e|
414
- e[:data] = encode_data(e[:data])
447
+ e[:data] = if e[:channel].match(/^private-encrypted-/) then
448
+ encrypt(e[:channel], encode_data(e[:data]))
449
+ else
450
+ encode_data(e[:data])
451
+ end
415
452
  end
416
453
  end
417
454
  }
@@ -423,8 +460,37 @@ module Pusher
423
460
  MultiJson.encode(data)
424
461
  end
425
462
 
463
+ # Encrypts a message with a key derived from the master key and channel
464
+ # name
465
+ def encrypt(channel, encoded_data)
466
+ raise ConfigurationError, :encryption_master_key unless @encryption_master_key
467
+
468
+ # Only now load rbnacl, so that people that aren't using it don't need to
469
+ # install libsodium
470
+ require_rbnacl
471
+
472
+ secret_box = RbNaCl::SecretBox.new(
473
+ RbNaCl::Hash.sha256(channel + @encryption_master_key)
474
+ )
475
+
476
+ nonce = RbNaCl::Random.random_bytes(secret_box.nonce_bytes)
477
+ ciphertext = secret_box.encrypt(nonce, encoded_data)
478
+
479
+ MultiJson.encode({
480
+ "nonce" => Base64::encode64(nonce),
481
+ "ciphertext" => Base64::encode64(ciphertext),
482
+ })
483
+ end
484
+
426
485
  def configured?
427
486
  host && scheme && key && secret && app_id
428
487
  end
488
+
489
+ def require_rbnacl
490
+ require 'rbnacl'
491
+ rescue LoadError => e
492
+ $stderr.puts "You don't have rbnacl installed in your application. Please add it to your Gemfile and run bundle install"
493
+ raise e
494
+ end
429
495
  end
430
496
  end
@@ -26,8 +26,6 @@ module Pusher
26
26
 
27
27
  private
28
28
 
29
- # TODO: Actual links
30
- #
31
29
  # {
32
30
  # interests: [Array of interests],
33
31
  # apns: {
@@ -38,7 +36,7 @@ module Pusher
38
36
  # }
39
37
  # }
40
38
  #
41
- # @raise [Pusher::Error] if the `apns` or `gcm` key does not exist
39
+ # @raise [Pusher::Error] if the interests array is empty
42
40
  # @return [String]
43
41
  def payload(interests, data)
44
42
  interests = Array(interests).map(&:to_s)
@@ -94,6 +94,8 @@ module Pusher
94
94
  raise Error, "404 Not found (#{@uri.path})"
95
95
  when 407
96
96
  raise Error, "Proxy Authentication Required"
97
+ when 413
98
+ raise Error, "Payload Too Large > 10KB"
97
99
  else
98
100
  raise Error, "Unknown error (status code #{status_code}): #{body}"
99
101
  end
@@ -1,3 +1,3 @@
1
1
  module Pusher
2
- VERSION = '1.3.0'
2
+ VERSION = '1.4.1'
3
3
  end
@@ -9,21 +9,23 @@ Gem::Specification.new do |s|
9
9
  s.authors = ["Pusher"]
10
10
  s.email = ["support@pusher.com"]
11
11
  s.homepage = "http://github.com/pusher/pusher-http-ruby"
12
- s.summary = %q{Pusher API client}
13
- s.description = %q{Wrapper for pusher.com REST api}
12
+ s.summary = %q{Pusher Channels API client}
13
+ s.description = %q{Wrapper for Pusher Channels REST api: : https://pusher.com/channels}
14
14
  s.license = "MIT"
15
15
 
16
- s.add_dependency "multi_json", "~> 1.0"
16
+ s.add_dependency "multi_json", "~> 1.15"
17
17
  s.add_dependency 'pusher-signature', "~> 0.1.8"
18
- s.add_dependency "httpclient", "~> 2.7"
18
+ s.add_dependency "httpclient", "~> 2.8"
19
19
  s.add_dependency "jruby-openssl" if defined?(JRUBY_VERSION)
20
20
 
21
- s.add_development_dependency "rspec", "~> 3.0"
22
- s.add_development_dependency "webmock"
23
- s.add_development_dependency "em-http-request", "~> 1.1.0"
24
- s.add_development_dependency "rake", "~> 10.4.2"
25
- s.add_development_dependency "rack", "~> 1.6.4"
26
- s.add_development_dependency "json", "~> 1.8.3"
21
+ s.add_development_dependency "rspec", "~> 3.9"
22
+ s.add_development_dependency "webmock", "~> 3.9"
23
+ s.add_development_dependency "em-http-request", "~> 1.1"
24
+ s.add_development_dependency "addressable", "~> 2.7"
25
+ s.add_development_dependency "rake", "~> 13.0"
26
+ s.add_development_dependency "rack", "~> 2.2"
27
+ s.add_development_dependency "json", "~> 2.3"
28
+ s.add_development_dependency "rbnacl", "~> 7.1"
27
29
 
28
30
  s.files = `git ls-files`.split("\n")
29
31
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
@@ -71,15 +71,17 @@ describe Pusher::Channel do
71
71
 
72
72
  describe '#info' do
73
73
  it "should call the Client#channel_info" do
74
- expect(@client).to receive(:get).with("/channels/mychannel", anything)
74
+ expect(@client).to receive(:get)
75
+ .with("/channels/mychannel", anything)
76
+ .and_return({:occupied => true, :subscription_count => 12})
75
77
  @channel = @client['mychannel']
76
78
  @channel.info
77
79
  end
78
80
 
79
81
  it "should assemble the requested attributes into the info option" do
80
- expect(@client).to receive(:get).with(anything, {
81
- :info => "user_count,connection_count"
82
- })
82
+ expect(@client).to receive(:get)
83
+ .with(anything, {:info => "user_count,connection_count"})
84
+ .and_return({:occupied => true, :subscription_count => 12, :user_count => 12})
83
85
  @channel = @client['presence-foo']
84
86
  @channel.info(%w{user_count connection_count})
85
87
  end
@@ -1,7 +1,12 @@
1
- require 'spec_helper'
1
+ require 'base64'
2
2
 
3
+ require 'rbnacl'
3
4
  require 'em-http'
4
5
 
6
+ require 'spec_helper'
7
+
8
+ encryption_master_key = RbNaCl::Random.random_bytes(32)
9
+
5
10
  describe Pusher do
6
11
  # The behaviour should be the same when using the Client object, or the
7
12
  # 'global' client delegated through the Pusher class
@@ -87,19 +92,53 @@ describe Pusher do
87
92
  expect(@client.host).to eq('api.staging.pusherapp.com')
88
93
  end
89
94
 
90
- it 'should get override the url configuration if it comes after' do
95
+ it 'should override the url configuration if it comes after' do
91
96
  @client.url = "http://somekey:somesecret@api.staging.pusherapp.com:8080/apps/87"
92
97
  @client.cluster = 'eu'
93
98
  expect(@client.host).to eq('api-eu.pusher.com')
94
99
  end
95
100
 
96
- it 'should overrie by the host configuration if it comes after' do
101
+ it 'should override the host configuration if it comes after' do
97
102
  @client.host = 'api.staging.pusher.com'
98
103
  @client.cluster = 'eu'
99
104
  expect(@client.host).to eq('api-eu.pusher.com')
100
105
  end
101
106
  end
102
107
 
108
+ describe 'configuring TLS' do
109
+ it 'should set port and scheme if "use_tls" enabled' do
110
+ client = Pusher::Client.new({
111
+ :use_tls => true,
112
+ })
113
+ expect(client.scheme).to eq('https')
114
+ expect(client.port).to eq(443)
115
+ end
116
+
117
+ it 'should set port and scheme if "encrypted" enabled' do
118
+ client = Pusher::Client.new({
119
+ :encrypted => true,
120
+ })
121
+ expect(client.scheme).to eq('https')
122
+ expect(client.port).to eq(443)
123
+ end
124
+
125
+ it 'should use non-TLS port and scheme if "encrypted" or "use_tls" are not set' do
126
+ client = Pusher::Client.new
127
+ expect(client.scheme).to eq('http')
128
+ expect(client.port).to eq(80)
129
+ end
130
+
131
+ it 'should override port if "use_tls" option set but a different port is specified' do
132
+ client = Pusher::Client.new({
133
+ :use_tls => true,
134
+ :port => 8443
135
+ })
136
+ expect(client.scheme).to eq('https')
137
+ expect(client.port).to eq(8443)
138
+ end
139
+
140
+ end
141
+
103
142
  describe 'configuring a http proxy' do
104
143
  it "should be possible to configure everything by setting the http_proxy" do
105
144
  @client.http_proxy = 'http://someuser:somepassword@proxy.host.com:8080'
@@ -109,6 +148,10 @@ describe Pusher do
109
148
  end
110
149
 
111
150
  describe 'configuring from env' do
151
+ after do
152
+ ENV['PUSHER_URL'] = nil
153
+ end
154
+
112
155
  it "works" do
113
156
  url = "http://somekey:somesecret@api.staging.pusherapp.com:8080/apps/87"
114
157
  ENV['PUSHER_URL'] = url
@@ -118,7 +161,27 @@ describe Pusher do
118
161
  expect(client.secret).to eq("somesecret")
119
162
  expect(client.app_id).to eq("87")
120
163
  expect(client.url.to_s).to eq("http://api.staging.pusherapp.com:8080/apps/87")
121
- ENV['PUSHER_URL'] = nil
164
+ end
165
+ end
166
+
167
+ describe 'configuring from url' do
168
+ it "works" do
169
+ url = "http://somekey:somesecret@api.staging.pusherapp.com:8080/apps/87"
170
+
171
+ client = Pusher::Client.from_url(url)
172
+ expect(client.key).to eq("somekey")
173
+ expect(client.secret).to eq("somesecret")
174
+ expect(client.app_id).to eq("87")
175
+ expect(client.url.to_s).to eq("http://api.staging.pusherapp.com:8080/apps/87")
176
+ end
177
+ end
178
+
179
+ describe 'can set encryption_master_key_base64' do
180
+ it "sets encryption_master_key" do
181
+ @client.encryption_master_key_base64 =
182
+ Base64.encode64(encryption_master_key)
183
+
184
+ expect(@client.encryption_master_key).to eq(encryption_master_key)
122
185
  end
123
186
  end
124
187
 
@@ -127,6 +190,8 @@ describe Pusher do
127
190
  @client.app_id = '20'
128
191
  @client.key = '12345678900000001'
129
192
  @client.secret = '12345678900000001'
193
+ @client.encryption_master_key_base64 =
194
+ Base64.encode64(encryption_master_key)
130
195
  end
131
196
 
132
197
  describe '#[]' do
@@ -272,6 +337,46 @@ describe Pusher do
272
337
  }
273
338
  end
274
339
  end
340
+
341
+ it "should fail to publish to encrypted channels when missing key" do
342
+ @client.encryption_master_key_base64 = nil
343
+ expect {
344
+ @client.trigger('private-encrypted-channel', 'event', {'some' => 'data'})
345
+ }.to raise_error(Pusher::ConfigurationError)
346
+ expect(WebMock).not_to have_requested(:post, @api_path)
347
+ end
348
+
349
+ it "should fail to publish to multiple channels if one is encrypted" do
350
+ expect {
351
+ @client.trigger(
352
+ ['private-encrypted-channel', 'some-other-channel'],
353
+ 'event',
354
+ {'some' => 'data'},
355
+ )
356
+ }.to raise_error(Pusher::Error)
357
+ expect(WebMock).not_to have_requested(:post, @api_path)
358
+ end
359
+
360
+ it "should encrypt publishes to encrypted channels" do
361
+ @client.trigger(
362
+ 'private-encrypted-channel',
363
+ 'event',
364
+ {'some' => 'data'},
365
+ )
366
+
367
+ expect(WebMock).to have_requested(:post, @api_path).with { |req|
368
+ data = MultiJson.decode(MultiJson.decode(req.body)["data"])
369
+
370
+ key = RbNaCl::Hash.sha256(
371
+ 'private-encrypted-channel' + encryption_master_key
372
+ )
373
+
374
+ expect(MultiJson.decode(RbNaCl::SecretBox.new(key).decrypt(
375
+ Base64.decode64(data["nonce"]),
376
+ Base64.decode64(data["ciphertext"]),
377
+ ))).to eq({ 'some' => 'data' })
378
+ }
379
+ end
275
380
  end
276
381
 
277
382
  describe '#trigger_batch' do
@@ -303,6 +408,55 @@ describe Pusher do
303
408
  )
304
409
  }
305
410
  end
411
+
412
+ it "should fail to publish to encrypted channels when missing key" do
413
+ @client.encryption_master_key_base64 = nil
414
+ expect {
415
+ @client.trigger_batch(
416
+ {
417
+ channel: 'private-encrypted-channel',
418
+ name: 'event',
419
+ data: {'some' => 'data'},
420
+ },
421
+ {channel: 'mychannel', name: 'event', data: 'already encoded'},
422
+ )
423
+ }.to raise_error(Pusher::ConfigurationError)
424
+ expect(WebMock).not_to have_requested(:post, @api_path)
425
+ end
426
+
427
+ it "should encrypt publishes to encrypted channels" do
428
+ @client.trigger_batch(
429
+ {
430
+ channel: 'private-encrypted-channel',
431
+ name: 'event',
432
+ data: {'some' => 'data'},
433
+ },
434
+ {channel: 'mychannel', name: 'event', data: 'already encoded'},
435
+ )
436
+
437
+ expect(WebMock).to have_requested(:post, @api_path).with { |req|
438
+ batch = MultiJson.decode(req.body)["batch"]
439
+ expect(batch.length).to eq(2)
440
+
441
+ expect(batch[0]["channel"]).to eq("private-encrypted-channel")
442
+ expect(batch[0]["name"]).to eq("event")
443
+
444
+ data = MultiJson.decode(batch[0]["data"])
445
+
446
+ key = RbNaCl::Hash.sha256(
447
+ 'private-encrypted-channel' + encryption_master_key
448
+ )
449
+
450
+ expect(MultiJson.decode(RbNaCl::SecretBox.new(key).decrypt(
451
+ Base64.decode64(data["nonce"]),
452
+ Base64.decode64(data["ciphertext"]),
453
+ ))).to eq({ 'some' => 'data' })
454
+
455
+ expect(batch[1]["channel"]).to eq("mychannel")
456
+ expect(batch[1]["name"]).to eq("event")
457
+ expect(batch[1]["data"]).to eq("already encoded")
458
+ }
459
+ end
306
460
  end
307
461
 
308
462
  describe '#trigger_async' do
@@ -415,6 +569,11 @@ describe Pusher do
415
569
  expect { call_api }.to raise_error(Pusher::Error, 'Proxy Authentication Required')
416
570
  end
417
571
 
572
+ it "should raise Pusher::Error if pusher returns 413" do
573
+ stub_request(verb, @url_regexp).to_return({:status => 413})
574
+ expect { call_api }.to raise_error(Pusher::Error, 'Payload Too Large > 10KB')
575
+ end
576
+
418
577
  it "should raise Pusher::Error if pusher returns 500" do
419
578
  stub_request(verb, @url_regexp).to_return({:status => 500, :body => "some error"})
420
579
  expect { call_api }.to raise_error(Pusher::Error, 'Unknown error (status code 500): some error')
@@ -612,4 +771,3 @@ describe Pusher do
612
771
  end
613
772
  end
614
773
  end
615
-