pusher 1.3.0 → 1.4.1

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,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
-