pusher 0.17.0 → 2.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/spec/client_spec.rb DELETED
@@ -1,488 +0,0 @@
1
- require 'spec_helper'
2
-
3
- require 'em-http'
4
-
5
- describe Pusher do
6
- # The behaviour should be the same when using the Client object, or the
7
- # 'global' client delegated through the Pusher class
8
- [lambda { Pusher }, lambda { Pusher::Client.new }].each do |client_gen|
9
- before :each do
10
- @client = client_gen.call
11
- end
12
-
13
- describe 'default configuration' do
14
- it 'should be preconfigured for api host' do
15
- expect(@client.host).to eq('api.pusherapp.com')
16
- end
17
-
18
- it 'should be preconfigured for port 80' do
19
- expect(@client.port).to eq(80)
20
- end
21
-
22
- it 'should use standard logger if no other logger if defined' do
23
- Pusher.logger.debug('foo')
24
- expect(Pusher.logger).to be_kind_of(Logger)
25
- end
26
- end
27
-
28
- describe 'logging configuration' do
29
- it "can be configured to use any logger" do
30
- logger = double("ALogger")
31
- expect(logger).to receive(:debug).with('foo')
32
- Pusher.logger = logger
33
- Pusher.logger.debug('foo')
34
- Pusher.logger = nil
35
- end
36
- end
37
-
38
- describe "configuration using url" do
39
- it "should be possible to configure everything by setting the url" do
40
- @client.url = "test://somekey:somesecret@api.staging.pusherapp.com:8080/apps/87"
41
-
42
- expect(@client.scheme).to eq('test')
43
- expect(@client.host).to eq('api.staging.pusherapp.com')
44
- expect(@client.port).to eq(8080)
45
- expect(@client.key).to eq('somekey')
46
- expect(@client.secret).to eq('somesecret')
47
- expect(@client.app_id).to eq('87')
48
- end
49
-
50
- it "should override scheme and port when setting encrypted=true after url" do
51
- @client.url = "http://somekey:somesecret@api.staging.pusherapp.com:8080/apps/87"
52
- @client.encrypted = true
53
-
54
- expect(@client.scheme).to eq('https')
55
- expect(@client.port).to eq(443)
56
- end
57
-
58
- it "should fail on bad urls" do
59
- expect { @client.url = "gopher/somekey:somesecret@://api.staging.pusherapp.co://m:8080\apps\87" }.to raise_error(URI::InvalidURIError)
60
- end
61
- end
62
-
63
- describe 'configuring the cluster' do
64
- it 'should set a new default host' do
65
- @client.cluster = 'eu'
66
- expect(@client.host).to eq('api-eu.pusher.com')
67
- end
68
-
69
- it 'should be overridden by host if it comes after' do
70
- @client.cluster = 'eu'
71
- @client.host = 'api.staging.pusher.com'
72
- expect(@client.host).to eq('api.staging.pusher.com')
73
- end
74
-
75
- it 'should be overridden by url if it comes after' do
76
- @client.cluster = 'eu'
77
- @client.url = "http://somekey:somesecret@api.staging.pusherapp.com:8080/apps/87"
78
-
79
- expect(@client.host).to eq('api.staging.pusherapp.com')
80
- end
81
-
82
- it 'should get override the url configuration if it comes after' do
83
- @client.url = "http://somekey:somesecret@api.staging.pusherapp.com:8080/apps/87"
84
- @client.cluster = 'eu'
85
- expect(@client.host).to eq('api-eu.pusher.com')
86
- end
87
-
88
- it 'should overrie by the host configuration if it comes after' do
89
- @client.host = 'api.staging.pusher.com'
90
- @client.cluster = 'eu'
91
- expect(@client.host).to eq('api-eu.pusher.com')
92
- end
93
- end
94
-
95
- describe 'configuring a http proxy' do
96
- it "should be possible to configure everything by setting the http_proxy" do
97
- @client.http_proxy = 'http://someuser:somepassword@proxy.host.com:8080'
98
-
99
- expect(@client.proxy).to eq({:scheme => 'http', :host => 'proxy.host.com', :port => 8080, :user => 'someuser', :password => 'somepassword'})
100
- end
101
- end
102
-
103
- describe 'when configured' do
104
- before :each do
105
- @client.app_id = '20'
106
- @client.key = '12345678900000001'
107
- @client.secret = '12345678900000001'
108
- end
109
-
110
- describe '#[]' do
111
- before do
112
- @channel = @client['test_channel']
113
- end
114
-
115
- it 'should return a channel' do
116
- expect(@channel).to be_kind_of(Pusher::Channel)
117
- end
118
-
119
- %w{app_id key secret}.each do |config|
120
- it "should raise exception if #{config} not configured" do
121
- @client.send("#{config}=", nil)
122
- expect {
123
- @client['test_channel']
124
- }.to raise_error(Pusher::ConfigurationError)
125
- end
126
- end
127
- end
128
-
129
- describe '#channels' do
130
- it "should call the correct URL and symbolise response correctly" do
131
- api_path = %r{/apps/20/channels}
132
- stub_request(:get, api_path).to_return({
133
- :status => 200,
134
- :body => MultiJson.encode('channels' => {
135
- "channel1" => {},
136
- "channel2" => {}
137
- })
138
- })
139
- expect(@client.channels).to eq({
140
- :channels => {
141
- "channel1" => {},
142
- "channel2" => {}
143
- }
144
- })
145
- end
146
- end
147
-
148
- describe '#channel_info' do
149
- it "should call correct URL and symbolise response" do
150
- api_path = %r{/apps/20/channels/mychannel}
151
- stub_request(:get, api_path).to_return({
152
- :status => 200,
153
- :body => MultiJson.encode({
154
- 'occupied' => false,
155
- })
156
- })
157
- expect(@client.channel_info('mychannel')).to eq({
158
- :occupied => false,
159
- })
160
- end
161
- end
162
-
163
- describe '#channel_users' do
164
- it "should call correct URL and symbolise response" do
165
- api_path = %r{/apps/20/channels/mychannel/users}
166
- stub_request(:get, api_path).to_return({
167
- :status => 200,
168
- :body => MultiJson.encode({
169
- 'users' => [{ 'id' => 1 }]
170
- })
171
- })
172
- expect(@client.channel_users('mychannel')).to eq({
173
- :users => [{ 'id' => 1}]
174
- })
175
- end
176
- end
177
-
178
- describe '#authenticate' do
179
- before :each do
180
- @custom_data = {:uid => 123, :info => {:name => 'Foo'}}
181
- end
182
-
183
- it 'should return a hash with signature including custom data and data as json string' do
184
- allow(MultiJson).to receive(:encode).with(@custom_data).and_return 'a json string'
185
-
186
- response = @client.authenticate('test_channel', '1.1', @custom_data)
187
-
188
- expect(response).to eq({
189
- :auth => "12345678900000001:#{hmac(@client.secret, "1.1:test_channel:a json string")}",
190
- :channel_data => 'a json string'
191
- })
192
- end
193
-
194
- end
195
-
196
- describe '#trigger' do
197
- before :each do
198
- @api_path = %r{/apps/20/events}
199
- stub_request(:post, @api_path).to_return({
200
- :status => 200,
201
- :body => MultiJson.encode({})
202
- })
203
- end
204
-
205
- it "should call correct URL" do
206
- expect(@client.trigger(['mychannel'], 'event', {'some' => 'data'})).
207
- to eq({})
208
- end
209
-
210
- it "should not allow too many channels" do
211
- expect {
212
- @client.trigger((0..11).map{|i| 'mychannel#{i}'},
213
- 'event', {'some' => 'data'}, {
214
- :socket_id => "12.34"
215
- })}.to raise_error(Pusher::Error)
216
- end
217
-
218
- it "should pass any parameters in the body of the request" do
219
- @client.trigger(['mychannel', 'c2'], 'event', {'some' => 'data'}, {
220
- :socket_id => "12.34"
221
- })
222
- expect(WebMock).to have_requested(:post, @api_path).with { |req|
223
- parsed = MultiJson.decode(req.body)
224
- expect(parsed["name"]).to eq('event')
225
- expect(parsed["channels"]).to eq(["mychannel", "c2"])
226
- expect(parsed["socket_id"]).to eq('12.34')
227
- }
228
- end
229
-
230
- it "should convert non string data to JSON before posting" do
231
- @client.trigger(['mychannel'], 'event', {'some' => 'data'})
232
- expect(WebMock).to have_requested(:post, @api_path).with { |req|
233
- expect(MultiJson.decode(req.body)["data"]).to eq('{"some":"data"}')
234
- }
235
- end
236
-
237
- it "should accept a single channel as well as an array" do
238
- @client.trigger('mychannel', 'event', {'some' => 'data'})
239
- expect(WebMock).to have_requested(:post, @api_path).with { |req|
240
- expect(MultiJson.decode(req.body)["channels"]).to eq(['mychannel'])
241
- }
242
- end
243
- end
244
-
245
- describe '#trigger_async' do
246
- before :each do
247
- @api_path = %r{/apps/20/events}
248
- stub_request(:post, @api_path).to_return({
249
- :status => 200,
250
- :body => MultiJson.encode({})
251
- })
252
- end
253
-
254
- it "should call correct URL" do
255
- EM.run {
256
- @client.trigger_async('mychannel', 'event', {'some' => 'data'}).callback { |r|
257
- expect(r).to eq({})
258
- EM.stop
259
- }
260
- }
261
- end
262
-
263
- it "should pass any parameters in the body of the request" do
264
- EM.run {
265
- @client.trigger_async('mychannel', 'event', {'some' => 'data'}, {
266
- :socket_id => "12.34"
267
- }).callback {
268
- expect(WebMock).to have_requested(:post, @api_path).with { |req|
269
- expect(MultiJson.decode(req.body)["socket_id"]).to eq('12.34')
270
- }
271
- EM.stop
272
- }
273
- }
274
- end
275
-
276
- it "should convert non string data to JSON before posting" do
277
- EM.run {
278
- @client.trigger_async('mychannel', 'event', {'some' => 'data'}).callback {
279
- expect(WebMock).to have_requested(:post, @api_path).with { |req|
280
- expect(MultiJson.decode(req.body)["data"]).to eq('{"some":"data"}')
281
- }
282
- EM.stop
283
- }
284
- }
285
- end
286
- end
287
-
288
- [:get, :post].each do |verb|
289
- describe "##{verb}" do
290
- before :each do
291
- @url_regexp = %r{api.pusherapp.com}
292
- stub_request(verb, @url_regexp).
293
- to_return(:status => 200, :body => "{}")
294
- end
295
-
296
- let(:call_api) { @client.send(verb, '/path') }
297
-
298
- it "should use http by default" do
299
- call_api
300
- expect(WebMock).to have_requested(verb, %r{http://api.pusherapp.com/apps/20/path})
301
- end
302
-
303
- it "should use https if configured" do
304
- @client.encrypted = true
305
- call_api
306
- expect(WebMock).to have_requested(verb, %r{https://api.pusherapp.com})
307
- end
308
-
309
- it "should format the respose hash with symbols at first level" do
310
- stub_request(verb, @url_regexp).to_return({
311
- :status => 200,
312
- :body => MultiJson.encode({'something' => {'a' => 'hash'}})
313
- })
314
- expect(call_api).to eq({
315
- :something => {'a' => 'hash'}
316
- })
317
- end
318
-
319
- it "should catch all http exceptions and raise a Pusher::HTTPError wrapping the original error" do
320
- stub_request(verb, @url_regexp).to_raise(HTTPClient::TimeoutError)
321
-
322
- error = nil
323
- begin
324
- call_api
325
- rescue => e
326
- error = e
327
- end
328
-
329
- expect(error.class).to eq(Pusher::HTTPError)
330
- expect(error).to be_kind_of(Pusher::Error)
331
- expect(error.message).to eq('Exception from WebMock (HTTPClient::TimeoutError)')
332
- expect(error.original_error.class).to eq(HTTPClient::TimeoutError)
333
- end
334
-
335
- it "should raise Pusher::Error if call returns 400" do
336
- stub_request(verb, @url_regexp).to_return({:status => 400})
337
- expect { call_api }.to raise_error(Pusher::Error)
338
- end
339
-
340
- it "should raise AuthenticationError if pusher returns 401" do
341
- stub_request(verb, @url_regexp).to_return({:status => 401})
342
- expect { call_api }.to raise_error(Pusher::AuthenticationError)
343
- end
344
-
345
- it "should raise Pusher::Error if pusher returns 404" do
346
- stub_request(verb, @url_regexp).to_return({:status => 404})
347
- expect { call_api }.to raise_error(Pusher::Error, '404 Not found (/apps/20/path)')
348
- end
349
-
350
- it "should raise Pusher::Error if pusher returns 407" do
351
- stub_request(verb, @url_regexp).to_return({:status => 407})
352
- expect { call_api }.to raise_error(Pusher::Error, 'Proxy Authentication Required')
353
- end
354
-
355
- it "should raise Pusher::Error if pusher returns 500" do
356
- stub_request(verb, @url_regexp).to_return({:status => 500, :body => "some error"})
357
- expect { call_api }.to raise_error(Pusher::Error, 'Unknown error (status code 500): some error')
358
- end
359
- end
360
- end
361
-
362
- describe "async calling without eventmachine" do
363
- [[:get, :get_async], [:post, :post_async]].each do |verb, method|
364
- describe "##{method}" do
365
- before :each do
366
- @url_regexp = %r{api.pusherapp.com}
367
- stub_request(verb, @url_regexp).
368
- to_return(:status => 200, :body => "{}")
369
- end
370
-
371
- let(:call_api) {
372
- @client.send(method, '/path').tap { |c|
373
- # Allow the async thread (inside httpclient) to run
374
- while !c.finished?
375
- sleep 0.01
376
- end
377
- }
378
- }
379
-
380
- it "should use http by default" do
381
- call_api
382
- expect(WebMock).to have_requested(verb, %r{http://api.pusherapp.com/apps/20/path})
383
- end
384
-
385
- it "should use https if configured" do
386
- @client.encrypted = true
387
- call_api
388
- expect(WebMock).to have_requested(verb, %r{https://api.pusherapp.com})
389
- end
390
-
391
- # Note that the raw httpclient connection object is returned and
392
- # the response isn't handled (by handle_response) in the normal way.
393
- it "should return a httpclient connection object" do
394
- connection = call_api
395
- expect(connection.finished?).to be_truthy
396
- response = connection.pop
397
- expect(response.status).to eq(200)
398
- expect(response.body.read).to eq("{}")
399
- end
400
- end
401
- end
402
- end
403
-
404
- describe "async calling with eventmachine" do
405
- [[:get, :get_async], [:post, :post_async]].each do |verb, method|
406
- describe "##{method}" do
407
- before :each do
408
- @url_regexp = %r{api.pusherapp.com}
409
- stub_request(verb, @url_regexp).
410
- to_return(:status => 200, :body => "{}")
411
- end
412
-
413
- let(:call_api) { @client.send(method, '/path') }
414
-
415
- it "should use http by default" do
416
- EM.run {
417
- call_api.callback {
418
- expect(WebMock).to have_requested(verb, %r{http://api.pusherapp.com/apps/20/path})
419
- EM.stop
420
- }
421
- }
422
- end
423
-
424
- it "should use https if configured" do
425
- EM.run {
426
- @client.encrypted = true
427
- call_api.callback {
428
- expect(WebMock).to have_requested(verb, %r{https://api.pusherapp.com})
429
- EM.stop
430
- }
431
- }
432
- end
433
-
434
- it "should format the respose hash with symbols at first level" do
435
- EM.run {
436
- stub_request(verb, @url_regexp).to_return({
437
- :status => 200,
438
- :body => MultiJson.encode({'something' => {'a' => 'hash'}})
439
- })
440
- call_api.callback { |response|
441
- expect(response).to eq({
442
- :something => {'a' => 'hash'}
443
- })
444
- EM.stop
445
- }
446
- }
447
- end
448
-
449
- it "should errback with Pusher::Error on unsuccessful response" do
450
- EM.run {
451
- stub_request(verb, @url_regexp).to_return({:status => 400})
452
-
453
- call_api.errback { |e|
454
- expect(e.class).to eq(Pusher::Error)
455
- EM.stop
456
- }.callback {
457
- fail
458
- }
459
- }
460
- end
461
- end
462
- end
463
- end
464
- end
465
- end
466
-
467
- describe 'configuring cluster' do
468
- it 'should allow clients to specify the cluster only with the default host' do
469
- client = Pusher::Client.new({
470
- :scheme => 'http',
471
- :cluster => 'eu',
472
- :port => 80
473
- })
474
- expect(client.host).to eq('api-eu.pusher.com')
475
- end
476
-
477
- it 'should always have host override any supplied cluster value' do
478
- client = Pusher::Client.new({
479
- :scheme => 'http',
480
- :host => 'api.staging.pusherapp.com',
481
- :cluster => 'eu',
482
- :port => 80
483
- })
484
- expect(client.host).to eq('api.staging.pusherapp.com')
485
- end
486
- end
487
- end
488
-
data/spec/spec_helper.rb DELETED
@@ -1,26 +0,0 @@
1
- begin
2
- require 'bundler/setup'
3
- rescue LoadError
4
- puts 'although not required, it is recommended that you use bundler when running the tests'
5
- end
6
-
7
- ENV['PUSHER_URL']= 'http://some:secret@api.secret.pusherapp.com:441/apps/54'
8
-
9
- require 'rspec'
10
- require 'em-http' # As of webmock 1.4.0, em-http must be loaded first
11
- require 'webmock/rspec'
12
-
13
- require 'pusher'
14
- require 'eventmachine'
15
-
16
- RSpec.configure do |config|
17
- config.before(:each) do
18
- WebMock.reset!
19
- WebMock.disable_net_connect!
20
- end
21
- end
22
-
23
- def hmac(key, data)
24
- digest = OpenSSL::Digest::SHA256.new
25
- OpenSSL::HMAC.hexdigest(digest, key, data)
26
- end
@@ -1,117 +0,0 @@
1
- require 'spec_helper'
2
-
3
- require 'rack'
4
- require 'stringio'
5
-
6
- describe Pusher::WebHook do
7
- before :each do
8
- @hook_data = {
9
- "time_ms" => 123456,
10
- "events" => [
11
- {"name" => 'foo'}
12
- ]
13
- }
14
- end
15
-
16
- describe "initialization" do
17
- it "can be initialized with Rack::Request" do
18
- request = Rack::Request.new({
19
- 'HTTP_X_PUSHER_KEY' => '1234',
20
- 'HTTP_X_PUSHER_SIGNATURE' => 'asdf',
21
- 'CONTENT_TYPE' => 'application/json',
22
- 'rack.input' => StringIO.new(MultiJson.encode(@hook_data))
23
- })
24
- wh = Pusher::WebHook.new(request)
25
- expect(wh.key).to eq('1234')
26
- expect(wh.signature).to eq('asdf')
27
- expect(wh.data).to eq(@hook_data)
28
- end
29
-
30
- it "can be initialized with a hash" do
31
- request = {
32
- :key => '1234',
33
- :signature => 'asdf',
34
- :content_type => 'application/json',
35
- :body => MultiJson.encode(@hook_data),
36
- }
37
- wh = Pusher::WebHook.new(request)
38
- expect(wh.key).to eq('1234')
39
- expect(wh.signature).to eq('asdf')
40
- expect(wh.data).to eq(@hook_data)
41
- end
42
- end
43
-
44
- describe "after initialization" do
45
- before :each do
46
- @body = MultiJson.encode(@hook_data)
47
- request = {
48
- :key => '1234',
49
- :signature => hmac('asdf', @body),
50
- :content_type => 'application/json',
51
- :body => @body
52
- }
53
-
54
- @client = Pusher::Client.new
55
- @wh = Pusher::WebHook.new(request, @client)
56
- end
57
-
58
- it "should validate" do
59
- @client.key = '1234'
60
- @client.secret = 'asdf'
61
- expect(@wh).to be_valid
62
- end
63
-
64
- it "should not validate if key is wrong" do
65
- @client.key = '12345'
66
- @client.secret = 'asdf'
67
- expect(Pusher.logger).to receive(:warn).with("Received webhook with unknown key: 1234")
68
- expect(@wh).not_to be_valid
69
- end
70
-
71
- it "should not validate if secret is wrong" do
72
- @client.key = '1234'
73
- @client.secret = 'asdfxxx'
74
- digest = OpenSSL::Digest::SHA256.new
75
- expected = OpenSSL::HMAC.hexdigest(digest, @client.secret, @body)
76
- expect(Pusher.logger).to receive(:warn).with("Received WebHook with invalid signature: got #{@wh.signature}, expected #{expected}")
77
- expect(@wh).not_to be_valid
78
- end
79
-
80
- it "should validate with an extra token" do
81
- @client.key = '12345'
82
- @client.secret = 'xxx'
83
- expect(@wh.valid?({:key => '1234', :secret => 'asdf'})).to be_truthy
84
- end
85
-
86
- it "should validate with an array of extra tokens" do
87
- @client.key = '123456'
88
- @client.secret = 'xxx'
89
- expect(@wh.valid?([
90
- {:key => '12345', :secret => 'wtf'},
91
- {:key => '1234', :secret => 'asdf'}
92
- ])).to be_truthy
93
- end
94
-
95
- it "should not validate if all keys are wrong with extra tokens" do
96
- @client.key = '123456'
97
- @client.secret = 'asdf'
98
- expect(Pusher.logger).to receive(:warn).with("Received webhook with unknown key: 1234")
99
- expect(@wh.valid?({:key => '12345', :secret => 'asdf'})).to be_falsey
100
- end
101
-
102
- it "should not validate if secret is wrong with extra tokens" do
103
- @client.key = '123456'
104
- @client.secret = 'asdfxxx'
105
- expect(Pusher.logger).to receive(:warn).with(/Received WebHook with invalid signature/)
106
- expect(@wh.valid?({:key => '1234', :secret => 'wtf'})).to be_falsey
107
- end
108
-
109
- it "should expose events" do
110
- expect(@wh.events).to eq(@hook_data["events"])
111
- end
112
-
113
- it "should expose time" do
114
- expect(@wh.time).to eq(Time.at(123.456))
115
- end
116
- end
117
- end