rollbar 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -12,40 +12,786 @@ rescue LoadError
12
12
  end
13
13
 
14
14
  describe Rollbar do
15
+ let(:notifier) { Rollbar.notifier }
16
+ context 'Notifier' do
17
+ context 'log' do
18
+ let(:exception) do
19
+ begin
20
+ foo = bar
21
+ rescue => e
22
+ e
23
+ end
24
+ end
25
+
15
26
  let(:configuration) { Rollbar.configuration }
16
27
 
17
- describe '.report_exception' do
18
- before(:each) do
19
- configure
20
- Rollbar.configure do |config|
21
- config.logger = logger_mock
28
+ it 'should report a simple message' do
29
+ expect(notifier).to receive(:report).with('error', 'test message', nil, nil)
30
+ notifier.log('error', 'test message')
31
+ end
32
+
33
+ it 'should report a simple message with extra data' do
34
+ extra_data = {:key => 'value', :hash => {:inner_key => 'inner_value'}}
35
+
36
+ expect(notifier).to receive(:report).with('error', 'test message', nil, extra_data)
37
+ notifier.log('error', 'test message', extra_data)
38
+ end
39
+
40
+ it 'should report an exception' do
41
+ expect(notifier).to receive(:report).with('error', nil, exception, nil)
42
+ notifier.log('error', exception)
43
+ end
44
+
45
+ it 'should report an exception with extra data' do
46
+ extra_data = {:key => 'value', :hash => {:inner_key => 'inner_value'}}
47
+
48
+ expect(notifier).to receive(:report).with('error', nil, exception, extra_data)
49
+ notifier.log('error', exception, extra_data)
50
+ end
51
+
52
+ it 'should report an exception with a description' do
53
+ expect(notifier).to receive(:report).with('error', 'exception description', exception, nil)
54
+ notifier.log('error', exception, 'exception description')
55
+ end
56
+
57
+ it 'should report an exception with a description and extra data' do
58
+ extra_data = {:key => 'value', :hash => {:inner_key => 'inner_value'}}
59
+
60
+ expect(notifier).to receive(:report).with('error', 'exception description', exception, extra_data)
61
+ notifier.log('error', exception, extra_data, 'exception description')
62
+ end
63
+ end
64
+
65
+ context 'debug/info/warning/error/critical' do
66
+ let(:exception) do
67
+ begin
68
+ foo = bar
69
+ rescue => e
70
+ e
71
+ end
72
+ end
73
+
74
+ let(:extra_data) { {:key => 'value', :hash => {:inner_key => 'inner_value'}} }
75
+
76
+ it 'should report with a debug level' do
77
+ expect(notifier).to receive(:report).with('debug', nil, exception, nil)
78
+ notifier.debug(exception)
79
+
80
+ expect(notifier).to receive(:report).with('debug', 'description', exception, nil)
81
+ notifier.debug(exception, 'description')
82
+
83
+ expect(notifier).to receive(:report).with('debug', 'description', exception, extra_data)
84
+ notifier.debug(exception, 'description', extra_data)
85
+ end
86
+
87
+ it 'should report with an info level' do
88
+ expect(notifier).to receive(:report).with('info', nil, exception, nil)
89
+ notifier.info(exception)
90
+
91
+ expect(notifier).to receive(:report).with('info', 'description', exception, nil)
92
+ notifier.info(exception, 'description')
93
+
94
+ expect(notifier).to receive(:report).with('info', 'description', exception, extra_data)
95
+ notifier.info(exception, 'description', extra_data)
96
+ end
97
+
98
+ it 'should report with a warning level' do
99
+ expect(notifier).to receive(:report).with('warning', nil, exception, nil)
100
+ notifier.warning(exception)
101
+
102
+ expect(notifier).to receive(:report).with('warning', 'description', exception, nil)
103
+ notifier.warning(exception, 'description')
104
+
105
+ expect(notifier).to receive(:report).with('warning', 'description', exception, extra_data)
106
+ notifier.warning(exception, 'description', extra_data)
107
+ end
108
+
109
+ it 'should report with an error level' do
110
+ expect(notifier).to receive(:report).with('error', nil, exception, nil)
111
+ notifier.error(exception)
112
+
113
+ expect(notifier).to receive(:report).with('error', 'description', exception, nil)
114
+ notifier.error(exception, 'description')
115
+
116
+ expect(notifier).to receive(:report).with('error', 'description', exception, extra_data)
117
+ notifier.error(exception, 'description', extra_data)
118
+ end
119
+
120
+ it 'should report with a critical level' do
121
+ expect(notifier).to receive(:report).with('critical', nil, exception, nil)
122
+ notifier.critical(exception)
123
+
124
+ expect(notifier).to receive(:report).with('critical', 'description', exception, nil)
125
+ notifier.critical(exception, 'description')
126
+
127
+ expect(notifier).to receive(:report).with('critical', 'description', exception, extra_data)
128
+ notifier.critical(exception, 'description', extra_data)
129
+ end
130
+ end
131
+
132
+ context 'scope' do
133
+ it 'should create a new notifier object' do
134
+ notifier2 = notifier.scope
135
+
136
+ notifier2.should_not eq(notifier)
137
+ notifier2.should be_instance_of(Rollbar::Notifier)
138
+ end
139
+
140
+ it 'should create a copy of the parent notifier\'s configuration' do
141
+ notifier.configure do |config|
142
+ config.code_version = '123'
143
+ config.payload_options = {
144
+ :a => 'a',
145
+ :b => {:c => 'c'}
146
+ }
147
+ end
148
+
149
+ notifier2 = notifier.scope
150
+
151
+ notifier2.configuration.code_version.should == '123'
152
+ notifier2.configuration.should_not equal(notifier.configuration)
153
+ notifier2.configuration.payload_options.should_not equal(notifier.configuration.payload_options)
154
+ notifier2.configuration.payload_options.should == notifier.configuration.payload_options
155
+ notifier2.configuration.payload_options.should == {
156
+ :a => 'a',
157
+ :b => {:c => 'c'}
158
+ }
159
+ end
160
+
161
+ it 'should not modify any parent notifier configuration' do
162
+ configure
163
+ Rollbar.configuration.code_version.should be_nil
164
+ Rollbar.configuration.payload_options.should be_empty
165
+
166
+ notifier.configure do |config|
167
+ config.code_version = '123'
168
+ config.payload_options = {
169
+ :a => 'a',
170
+ :b => {:c => 'c'}
171
+ }
172
+ end
173
+
174
+ notifier2 = notifier.scope
175
+
176
+ notifier2.configure do |config|
177
+ config.payload_options[:c] = 'c'
178
+ end
179
+
180
+ notifier.configuration.payload_options[:c].should be_nil
181
+
182
+ notifier3 = notifier2.scope({
183
+ :b => {:c => 3, :d => 'd'}
184
+ })
185
+
186
+ notifier3.configure do |config|
187
+ config.code_version = '456'
188
+ end
189
+
190
+ notifier.configuration.code_version.should == '123'
191
+ notifier.configuration.payload_options.should == {
192
+ :a => 'a',
193
+ :b => {:c => 'c'}
194
+ }
195
+ notifier2.configuration.code_version.should == '123'
196
+ notifier2.configuration.payload_options.should == {
197
+ :a => 'a',
198
+ :b => {:c => 'c'},
199
+ :c => 'c'
200
+ }
201
+ notifier3.configuration.code_version.should == '456'
202
+ notifier3.configuration.payload_options.should == {
203
+ :a => 'a',
204
+ :b => {:c => 3, :d => 'd'},
205
+ :c => 'c'
206
+ }
207
+
208
+ Rollbar.configuration.code_version.should be_nil
209
+ Rollbar.configuration.payload_options.should be_empty
210
+ end
211
+ end
212
+
213
+ context 'report' do
214
+ let(:logger_mock) { double("Rails.logger").as_null_object }
215
+
216
+ before(:each) do
217
+ configure
218
+ Rollbar.configure do |config|
219
+ config.logger = logger_mock
220
+ end
221
+ end
222
+
223
+ after(:each) do
224
+ Rollbar.unconfigure
225
+ configure
226
+ end
227
+
228
+ it 'should reject input that doesn\'t contain an exception, message or extra data' do
229
+ expect(logger_mock).to receive(:error).with('[Rollbar] Tried to send a report with no message, exception or extra data.')
230
+ expect(notifier).not_to receive(:schedule_payload)
231
+
232
+ result = notifier.send(:report, 'info', nil, nil, nil)
233
+ result.should == 'error'
234
+ end
235
+
236
+ it 'should be ignored if the person is ignored' do
237
+ person_data = {
238
+ :id => 1,
239
+ :username => "test",
240
+ :email => "test@example.com"
241
+ }
242
+
243
+ notifier.configure do |config|
244
+ config.ignored_person_ids += [1]
245
+ config.payload_options = { :person => person_data }
246
+ end
247
+
248
+ expect(notifier).not_to receive(:schedule_payload)
249
+
250
+ result = notifier.send(:report, 'info', 'message', nil, nil)
251
+ result.should == 'ignored'
252
+ end
253
+
254
+ it 'should evaluate callables in the payload' do
255
+ notifier.should receive(:schedule_payload) do |payload|
256
+ data = payload['data']
257
+ data[:body][:message][:extra][:callable].should == 2
258
+ end
259
+
260
+ callable = proc { 1 + 1 }
261
+ notifier.send(:report, 'warning', 'message', nil, { :callable => callable })
262
+ end
263
+ end
264
+
265
+ context 'build_payload' do
266
+ after(:each) do
267
+ Rollbar.unconfigure
268
+ configure
269
+ end
270
+
271
+ context 'a basic payload' do
272
+ let(:extra_data) { {:key => 'value', :hash => {:inner_key => 'inner_value'}} }
273
+ let(:payload) { notifier.send(:build_payload, 'info', 'message', nil, extra_data) }
274
+
275
+ it 'should have the correct root-level keys' do
276
+ payload.keys.should match_array(['access_token', 'data'])
277
+ end
278
+
279
+ it 'should have the correct data keys' do
280
+ payload['data'].keys.should include(:timestamp, :environment, :level, :language, :framework, :server,
281
+ :notifier, :body)
282
+ end
283
+
284
+ it 'should have the correct notifier name and version' do
285
+ payload['data'][:notifier][:name].should == 'rollbar-gem'
286
+ payload['data'][:notifier][:version].should == Rollbar::VERSION
287
+ end
288
+
289
+ it 'should have the correct language and framework' do
290
+ payload['data'][:language].should == 'ruby'
291
+ payload['data'][:framework].should == Rollbar.configuration.framework
292
+ payload['data'][:framework].should match(/^Rails/)
293
+ end
294
+
295
+ it 'should have the correct server keys' do
296
+ payload['data'][:server].keys.should match_array([:host, :root])
297
+ end
298
+
299
+ it 'should have the correct level and message body' do
300
+ payload['data'][:level].should == 'info'
301
+ payload['data'][:body][:message][:body].should == 'message'
302
+ end
303
+ end
304
+
305
+ it 'should merge in a new key from payload_options' do
306
+ notifier.configure do |config|
307
+ config.payload_options = { :some_new_key => 'some new value' }
308
+ end
309
+
310
+ payload = notifier.send(:build_payload, 'info', 'message', nil, nil)
311
+
312
+ payload['data'][:some_new_key].should == 'some new value'
313
+ end
314
+
315
+ it 'should overwrite existing keys from payload_options' do
316
+ payload_options = {
317
+ :notifier => 'bad notifier',
318
+ :server => { :host => 'new host', :new_server_key => 'value' }
319
+ }
320
+
321
+ notifier.configure do |config|
322
+ config.payload_options = payload_options
323
+ end
324
+
325
+ payload = notifier.send(:build_payload, 'info', 'message', nil, nil)
326
+
327
+ payload['data'][:notifier].should == 'bad notifier'
328
+ payload['data'][:server][:host].should == 'new host'
329
+ payload['data'][:server][:root].should_not be_nil
330
+ payload['data'][:server][:new_server_key].should == 'value'
331
+ end
332
+
333
+ it 'should have default environment "unspecified"' do
334
+ Rollbar.unconfigure
335
+ payload = notifier.send(:build_payload, 'info', 'message', nil, nil)
336
+ payload['data'][:environment].should == 'unspecified'
337
+ end
338
+
339
+ it 'should have an overridden environment' do
340
+ Rollbar.configure do |config|
341
+ config.environment = 'overridden'
342
+ end
343
+
344
+ payload = notifier.send(:build_payload, 'info', 'message', nil, nil)
345
+ payload['data'][:environment].should == 'overridden'
346
+ end
347
+
348
+ it 'should not have custom data under default configuration' do
349
+ payload = notifier.send(:build_payload, 'info', 'message', nil, nil)
350
+ payload['data'][:body][:message][:extra].should be_nil
351
+ end
352
+
353
+ it 'should have custom message data when custom_data_method is configured' do
354
+ Rollbar.configure do |config|
355
+ config.custom_data_method = lambda { {:a => 1, :b => [2, 3, 4]} }
356
+ end
357
+
358
+ payload = notifier.send(:build_payload, 'info', 'message', nil, nil)
359
+ payload['data'][:body][:message][:extra].should_not be_nil
360
+ payload['data'][:body][:message][:extra][:a].should == 1
361
+ payload['data'][:body][:message][:extra][:b][2].should == 4
362
+ end
363
+
364
+ it 'should merge extra data into custom message data' do
365
+ custom_method = lambda do
366
+ { :a => 1,
367
+ :b => [2, 3, 4],
368
+ :c => { :d => 'd', :e => 'e' },
369
+ :f => ['1', '2']
370
+ }
371
+ end
372
+
373
+ Rollbar.configure do |config|
374
+ config.custom_data_method = custom_method
375
+ end
376
+
377
+ payload = notifier.send(:build_payload, 'info', 'message', nil, {:c => {:e => 'g'}, :f => 'f'})
378
+ payload['data'][:body][:message][:extra].should_not be_nil
379
+ payload['data'][:body][:message][:extra][:a].should == 1
380
+ payload['data'][:body][:message][:extra][:b][2].should == 4
381
+ payload['data'][:body][:message][:extra][:c][:d].should == 'd'
382
+ payload['data'][:body][:message][:extra][:c][:e].should == 'g'
383
+ payload['data'][:body][:message][:extra][:f].should == 'f'
384
+ end
385
+
386
+ it 'should include project_gem_paths' do
387
+ notifier.configure do |config|
388
+ config.project_gems = ['rails', 'rspec']
389
+ end
390
+
391
+ payload = notifier.send(:build_payload, 'info', 'message', nil, nil)
392
+
393
+ payload['data'][:project_package_paths].should have(2).items
394
+ end
395
+
396
+ it 'should include a code_version' do
397
+ notifier.configure do |config|
398
+ config.code_version = 'abcdef'
399
+ end
400
+
401
+ payload = notifier.send(:build_payload, 'info', 'message', nil, nil)
402
+
403
+ payload['data'][:code_version].should == 'abcdef'
404
+ end
405
+
406
+ it 'should have the right hostname' do
407
+ payload = notifier.send(:build_payload, 'info', 'message', nil, nil)
408
+
409
+ payload['data'][:server][:host].should == Socket.gethostname
410
+ end
411
+
412
+ it 'should have root and branch set when configured' do
413
+ configure
414
+ Rollbar.configure do |config|
415
+ config.root = '/path/to/root'
416
+ config.branch = 'master'
417
+ end
418
+
419
+ payload = notifier.send(:build_payload, 'info', 'message', nil, nil)
420
+
421
+ payload['data'][:server][:root].should == '/path/to/root'
422
+ payload['data'][:server][:branch].should == 'master'
423
+ end
424
+ end
425
+
426
+ context 'build_payload_body' do
427
+ let(:exception) do
428
+ begin
429
+ foo = bar
430
+ rescue => e
431
+ e
432
+ end
433
+ end
434
+
435
+ it 'should build a message body when no exception is passed in' do
436
+ body = notifier.send(:build_payload_body, 'message', nil, nil)
437
+ body[:message][:body].should == 'message'
438
+ body[:message][:extra].should be_nil
439
+ body[:trace].should be_nil
440
+ end
441
+
442
+ it 'should build a message body when no exception and extra data is passed in' do
443
+ body = notifier.send(:build_payload_body, 'message', nil, {:a => 'b'})
444
+ body[:message][:body].should == 'message'
445
+ body[:message][:extra].should == {:a => 'b'}
446
+ body[:trace].should be_nil
447
+ end
448
+
449
+ it 'should build an exception body when one is passed in' do
450
+ body = notifier.send(:build_payload_body, 'message', exception, nil)
451
+ body[:message].should be_nil
452
+
453
+ trace = body[:trace]
454
+ trace.should_not be_nil
455
+ trace[:extra].should be_nil
456
+
457
+ trace[:exception][:class].should_not be_nil
458
+ trace[:exception][:message].should_not be_nil
459
+ end
460
+
461
+ it 'should build an exception body when one is passed in along with extra data' do
462
+ body = notifier.send(:build_payload_body, 'message', exception, {:a => 'b'})
463
+ body[:message].should be_nil
464
+
465
+ trace = body[:trace]
466
+ trace.should_not be_nil
467
+
468
+ trace[:exception][:class].should_not be_nil
469
+ trace[:exception][:message].should_not be_nil
470
+ trace[:extra].should == {:a => 'b'}
471
+ end
472
+ end
473
+
474
+ context 'build_payload_body_exception' do
475
+ let(:exception) do
476
+ begin
477
+ foo = bar
478
+ rescue => e
479
+ e
480
+ end
481
+ end
482
+
483
+ after(:each) do
484
+ Rollbar.unconfigure
485
+ configure
486
+ end
487
+
488
+ it 'should build valid exception data' do
489
+ body = notifier.send(:build_payload_body_exception, nil, exception, nil)
490
+ body[:message].should be_nil
491
+
492
+ trace = body[:trace]
493
+
494
+ frames = trace[:frames]
495
+ frames.should be_a_kind_of(Array)
496
+ frames.each do |frame|
497
+ frame[:filename].should be_a_kind_of(String)
498
+ frame[:lineno].should be_a_kind_of(Fixnum)
499
+ if frame[:method]
500
+ frame[:method].should be_a_kind_of(String)
501
+ end
502
+ end
503
+
504
+ # should be NameError, but can be NoMethodError sometimes on rubinius 1.8
505
+ # http://yehudakatz.com/2010/01/02/the-craziest-fing-bug-ive-ever-seen/
506
+ trace[:exception][:class].should match(/^(NameError|NoMethodError)$/)
507
+ trace[:exception][:message].should match(/^(undefined local variable or method `bar'|undefined method `bar' on an instance of)/)
508
+ end
509
+
510
+ it 'should build exception data with a description' do
511
+ body = notifier.send(:build_payload_body_exception, 'exception description', exception, nil)
512
+
513
+ trace = body[:trace]
514
+
515
+ trace[:exception][:message].should match(/^(undefined local variable or method `bar'|undefined method `bar' on an instance of)/)
516
+ trace[:exception][:description].should == 'exception description'
517
+ end
518
+
519
+ it 'should build exception data with a description and extra data' do
520
+ extra_data = {:key => 'value', :hash => {:inner_key => 'inner_value'}}
521
+ body = notifier.send(:build_payload_body_exception, 'exception description', exception, extra_data)
522
+
523
+ trace = body[:trace]
524
+
525
+ trace[:exception][:message].should match(/^(undefined local variable or method `bar'|undefined method `bar' on an instance of)/)
526
+ trace[:exception][:description].should == 'exception description'
527
+ trace[:extra][:key].should == 'value'
528
+ trace[:extra][:hash].should == {:inner_key => 'inner_value'}
529
+ end
530
+
531
+ it 'should build exception data with a extra data' do
532
+ extra_data = {:key => 'value', :hash => {:inner_key => 'inner_value'}}
533
+ body = notifier.send(:build_payload_body_exception, nil, exception, extra_data)
534
+
535
+ trace = body[:trace]
536
+
537
+ trace[:exception][:message].should match(/^(undefined local variable or method `bar'|undefined method `bar' on an instance of)/)
538
+ trace[:extra][:key].should == 'value'
539
+ trace[:extra][:hash].should == {:inner_key => 'inner_value'}
540
+ end
541
+
542
+ context 'with nested exceptions' do
543
+ let(:crashing_code) do
544
+ proc do
545
+ begin
546
+ begin
547
+ fail CauseException.new('the cause')
548
+ rescue
549
+ fail StandardError.new('the error')
550
+ end
551
+ rescue => e
552
+ e
553
+ end
554
+ end
555
+ end
556
+
557
+ let(:rescued_exception) { crashing_code.call }
558
+ let(:message) { 'message' }
559
+ let(:extra) { {} }
560
+
561
+ context 'using ruby >= 2.1' do
562
+ next unless Exception.instance_methods.include?(:cause)
563
+
564
+ it 'sends the two exceptions in the trace_chain attribute' do
565
+ body = notifier.send(:build_payload_body_exception, message, rescued_exception, extra)
566
+
567
+ body[:trace].should be_nil
568
+ body[:trace_chain].should be_kind_of(Array)
569
+
570
+ chain = body[:trace_chain]
571
+ chain[0][:exception][:class].should match(/StandardError/)
572
+ chain[0][:exception][:message].should match(/the error/)
573
+
574
+ chain[1][:exception][:class].should match(/CauseException/)
575
+ chain[1][:exception][:message].should match(/the cause/)
576
+ end
577
+
578
+ context 'using ruby <= 2.1' do
579
+ next if Exception.instance_methods.include?(:cause)
580
+
581
+ it 'sends only the last exception in the trace attribute' do
582
+ body = notifier.send(:build_payload_body_exception, message, rescued_exception, extra)
583
+
584
+ body[:trace].should be_kind_of(Hash)
585
+ body[:trace_chain].should be_nil
586
+
587
+ body[:trace][:exception][:class].should match(/StandardError/)
588
+ body[:trace][:exception][:message].should match(/the error/)
589
+ end
590
+ end
591
+ end
592
+ end
593
+ end
594
+
595
+ context 'build_payload_body_message' do
596
+ it 'should build a message' do
597
+ body = notifier.send(:build_payload_body_message, 'message', nil)
598
+ body[:message][:body].should == 'message'
599
+ body[:trace].should be_nil
600
+ end
601
+
602
+ it 'should build a message with extra data' do
603
+ extra_data = {:key => 'value', :hash => {:inner_key => 'inner_value'}}
604
+ body = notifier.send(:build_payload_body_message, 'message', extra_data)
605
+ body[:message][:body].should == 'message'
606
+ body[:message][:extra][:key].should == 'value'
607
+ body[:message][:extra][:hash].should == {:inner_key => 'inner_value'}
608
+ end
609
+
610
+ it 'should build an empty message with extra data' do
611
+ extra_data = {:key => 'value', :hash => {:inner_key => 'inner_value'}}
612
+ body = notifier.send(:build_payload_body_message, nil, extra_data)
613
+ body[:message][:body].should == 'Empty message'
614
+ body[:message][:extra][:key].should == 'value'
615
+ body[:message][:extra][:hash].should == {:inner_key => 'inner_value'}
616
+ end
617
+ end
618
+
619
+ context 'evaluate_payload' do
620
+ let(:notifier) do
621
+ notifier = Rollbar.notifier
622
+
623
+ notifier.configure do |config|
624
+ config.logger = logger_mock
625
+ end
626
+
627
+ notifier
628
+ end
629
+
630
+ let(:logger_mock) { double("Rails.logger").as_null_object }
631
+
632
+ before(:each) do
633
+ configure
634
+ notifier.configure do |config|
635
+ config.logger = logger_mock
636
+ end
637
+ end
638
+
639
+ it 'should evaluate callables and store the result' do
640
+ a = 'some string'
641
+
642
+ payload = {
643
+ :evaluate1 => lambda { 1 + 1 },
644
+ :evaluate2 => Proc.new { 2 + 2 },
645
+ :hash => {
646
+ :inner_evaluate1 => a.method(:to_s),
647
+ :inner_evaluate2 => lambda { {:key => 'value'} }
648
+ }
649
+ }
650
+
651
+ payload_copy = payload.clone
652
+ notifier.send(:evaluate_payload, payload_copy)
653
+
654
+ payload_copy[:evaluate1].should == 2
655
+ payload_copy[:evaluate2].should == 4
656
+ payload_copy[:hash][:inner_evaluate1].should == 'some string'
657
+ payload_copy[:hash][:inner_evaluate2][:key].should == 'value'
658
+ end
659
+
660
+ it 'should not crash when the callable raises an exception' do
661
+ logger_mock.should_receive(:error).with("[Rollbar] Error while evaluating callable in payload for key evaluate1")
662
+
663
+ payload = {
664
+ :evaluate1 => lambda { a = b },
665
+ :evaluate2 => Proc.new { 2 + 2 },
666
+ :key => 'value'
667
+ }
668
+
669
+ payload_copy = payload.clone
670
+ notifier.send(:evaluate_payload, payload_copy)
671
+
672
+ payload_copy[:evaluate1].should be_nil
673
+ payload_copy[:evaluate2].should == 4
674
+ payload_copy[:key].should == 'value'
22
675
  end
676
+ end
677
+
678
+ context 'enforce_valid_utf8' do
679
+ it 'should replace invalid utf8 values' do
680
+ payload = {
681
+ :bad_value => "bad value 1\255",
682
+ :bad_value_2 => "bad\255 value 2",
683
+ "bad\255 key" => "good value",
684
+ :hash => {
685
+ :inner_bad_value => "\255\255bad value 3",
686
+ "inner \255bad key" => 'inner good value',
687
+ "bad array key\255" => [
688
+ 'good array value 1',
689
+ "bad\255 array value 1\255",
690
+ {
691
+ :inner_inner_bad => "bad inner \255inner value"
692
+ }
693
+ ]
694
+ }
695
+ }
23
696
 
697
+ payload_copy = payload.clone
698
+ notifier.send(:enforce_valid_utf8, payload_copy)
699
+
700
+ payload_copy[:bad_value].should == "bad value 1"
701
+ payload_copy[:bad_value_2].should == "bad value 2"
702
+ payload_copy["bad key"].should == "good value"
703
+ payload_copy.keys.should_not include("bad\456 key")
704
+ payload_copy[:hash][:inner_bad_value].should == "bad value 3"
705
+ payload_copy[:hash]["inner bad key"].should == 'inner good value'
706
+ payload_copy[:hash]["bad array key"].should == [
707
+ 'good array value 1',
708
+ 'bad array value 1',
709
+ {
710
+ :inner_inner_bad => 'bad inner inner value'
711
+ }
712
+ ]
713
+ end
714
+ end
715
+
716
+ context 'truncate_payload' do
717
+ it 'should truncate all nested strings in the payload' do
718
+ payload = {
719
+ :truncated => '1234567',
720
+ :not_truncated => '123456',
721
+ :hash => {
722
+ :inner_truncated => '123456789',
723
+ :inner_not_truncated => '567',
724
+ :array => ['12345678', '12', {:inner_inner => '123456789'}]
725
+ }
726
+ }
727
+
728
+ payload_copy = payload.clone
729
+ notifier.send(:truncate_payload, payload_copy, 6)
730
+
731
+ payload_copy[:truncated].should == '123...'
732
+ payload_copy[:not_truncated].should == '123456'
733
+ payload_copy[:hash][:inner_truncated].should == '123...'
734
+ payload_copy[:hash][:inner_not_truncated].should == '567'
735
+ payload_copy[:hash][:array].should == ['123...', '12', {:inner_inner => '123...'}]
736
+ end
737
+
738
+ it 'should truncate utf8 strings properly' do
739
+ payload = {
740
+ :truncated => 'Ŝǻмρļẻ śţяịņģ',
741
+ :not_truncated => '123456',
742
+ }
743
+
744
+ payload_copy = payload.clone
745
+ notifier.send(:truncate_payload, payload_copy, 6)
746
+
747
+ payload_copy[:truncated].should == "Ŝǻм..."
748
+ payload_copy[:not_truncated].should == '123456'
749
+ end
750
+ end
751
+ end
752
+
753
+ context 'reporting' do
754
+ let(:exception) do
24
755
  begin
25
756
  foo = bar
26
757
  rescue => e
27
- @exception = e
758
+ e
28
759
  end
29
760
  end
30
761
 
31
762
  let(:logger_mock) { double("Rails.logger").as_null_object }
763
+ let(:user) { User.create(:email => 'email@example.com', :encrypted_password => '', :created_at => Time.now, :updated_at => Time.now) }
764
+
765
+ before(:each) do
766
+ configure
767
+ Rollbar.configure do |config|
768
+ config.logger = logger_mock
769
+ end
770
+ end
771
+
772
+ after(:each) do
773
+ Rollbar.unconfigure
774
+ configure
775
+ end
32
776
 
33
777
  it 'should report exceptions without person or request data' do
34
778
  logger_mock.should_receive(:info).with('[Rollbar] Success')
35
- Rollbar.report_exception(@exception)
779
+ Rollbar.error(exception)
36
780
  end
37
781
 
38
782
  it 'should not report anything when disabled' do
39
783
  logger_mock.should_not_receive(:info).with('[Rollbar] Success')
784
+
40
785
  Rollbar.configure do |config|
41
786
  config.enabled = false
42
787
  end
43
788
 
44
- Rollbar.report_exception(@exception)
789
+ Rollbar.error(exception).should == 'disabled'
790
+ end
45
791
 
46
- Rollbar.configure do |config|
47
- config.enabled = true
48
- end
792
+ it 'should report exceptions without person or request data' do
793
+ logger_mock.should_receive(:info).with('[Rollbar] Success')
794
+ Rollbar.error(exception)
49
795
  end
50
796
 
51
797
  it 'should be enabled when freshly configured' do
@@ -56,65 +802,25 @@ describe Rollbar do
56
802
  Rollbar.unconfigure
57
803
 
58
804
  Rollbar.configuration.enabled.should be_nil
59
- Rollbar.report_exception(@exception).should == 'disabled'
805
+ Rollbar.error(exception).should == 'disabled'
60
806
  end
61
807
 
62
- it 'should stay disabled if configure is called again' do
63
- Rollbar.unconfigure
64
-
65
- # configure once, setting enabled to false.
66
- Rollbar.configure do |config|
67
- config.enabled = false
68
- end
69
-
70
- # now configure again (perhaps to change some other values)
71
- Rollbar.configure do |config| end
72
-
73
- Rollbar.configuration.enabled.should == false
74
- Rollbar.report_exception(@exception).should == 'disabled'
75
- end
76
-
77
- it 'should report exceptions with request and person data' do
78
- logger_mock.should_receive(:info).with('[Rollbar] Success')
79
- request_data = {
80
- :params => { :foo => "bar" },
81
- :url => 'http://localhost/',
82
- :user_ip => '127.0.0.1',
83
- :headers => {},
84
- :GET => { "baz" => "boz" },
85
- :session => { :user_id => 123 },
86
- :method => "GET",
87
- }
88
- person_data = {
89
- :id => 1,
90
- :username => "test",
91
- :email => "test@example.com"
92
- }
93
- Rollbar.report_exception(@exception, request_data, person_data)
94
- end
808
+ it 'should stay disabled if configure is called again' do
809
+ Rollbar.unconfigure
95
810
 
96
- it "should work with an IO object as rack.errors" do
97
- logger_mock.should_receive(:info).with('[Rollbar] Success')
98
- request_data = {
99
- :params => { :foo => "bar" },
100
- :url => 'http://localhost/',
101
- :user_ip => '127.0.0.1',
102
- :headers => {},
103
- :GET => { "baz" => "boz" },
104
- :session => { :user_id => 123 },
105
- :method => "GET",
106
- :env => { :"rack.errors" => IO.new(2, File::WRONLY) },
107
- }
108
- person_data = {
109
- :id => 1,
110
- :username => "test",
111
- :email => "test@example.com"
112
- }
113
- Rollbar.report_exception(@exception, request_data, person_data)
811
+ # configure once, setting enabled to false.
812
+ Rollbar.configure do |config|
813
+ config.enabled = false
814
+ end
815
+
816
+ # now configure again (perhaps to change some other values)
817
+ Rollbar.configure do |config| end
818
+
819
+ Rollbar.configuration.enabled.should == false
820
+ Rollbar.error(exception).should == 'disabled'
114
821
  end
115
822
 
116
823
  it 'should ignore ignored exception classes' do
117
- saved_filters = Rollbar.configuration.exception_level_filters
118
824
  Rollbar.configure do |config|
119
825
  config.exception_level_filters = { 'NameError' => 'ignore' }
120
826
  end
@@ -123,15 +829,24 @@ describe Rollbar do
123
829
  logger_mock.should_not_receive(:warn)
124
830
  logger_mock.should_not_receive(:error)
125
831
 
126
- Rollbar.report_exception(@exception)
832
+ Rollbar.error(exception)
833
+ end
127
834
 
128
- Rollbar.configure do |config|
129
- config.exception_level_filters = saved_filters
130
- end
835
+ it "should work with an IO object as rack.errors" do
836
+ logger_mock.should_receive(:info).with('[Rollbar] Success')
837
+
838
+ Rollbar.error(exception, :env => { :"rack.errors" => IO.new(2, File::WRONLY) })
131
839
  end
132
840
 
133
841
  it 'should ignore ignored persons' do
842
+ person_data = {
843
+ :id => 1,
844
+ :username => "test",
845
+ :email => "test@example.com"
846
+ }
847
+
134
848
  Rollbar.configure do |config|
849
+ config.payload_options = {:person => person_data}
135
850
  config.ignored_person_ids += [1]
136
851
  end
137
852
 
@@ -139,27 +854,23 @@ describe Rollbar do
139
854
  logger_mock.should_not_receive(:warn)
140
855
  logger_mock.should_not_receive(:error)
141
856
 
857
+ Rollbar.error(exception)
858
+ end
859
+
860
+ it 'should not ignore non-ignored persons' do
142
861
  person_data = {
143
862
  :id => 1,
144
863
  :username => "test",
145
864
  :email => "test@example.com"
146
865
  }
147
- Rollbar.report_exception(@exception, {}, person_data)
148
- end
149
-
150
- it 'should not ignore non-ignored persons' do
151
866
  Rollbar.configure do |config|
867
+ config.payload_options = { :person => person_data }
152
868
  config.ignored_person_ids += [1]
153
869
  end
154
870
 
155
871
  Rollbar.last_report = nil
156
872
 
157
- person_data = {
158
- :id => 1,
159
- :username => "test",
160
- :email => "test@example.com"
161
- }
162
- Rollbar.report_exception(@exception, {}, person_data)
873
+ Rollbar.error(exception)
163
874
  Rollbar.last_report.should be_nil
164
875
 
165
876
  person_data = {
@@ -167,7 +878,15 @@ describe Rollbar do
167
878
  :username => "test2",
168
879
  :email => "test2@example.com"
169
880
  }
170
- Rollbar.report_exception(@exception, {}, person_data)
881
+
882
+ new_options = {
883
+ :person => person_data
884
+ }
885
+
886
+ Rollbar.scoped(new_options) do
887
+ Rollbar.error(exception)
888
+ end
889
+
171
890
  Rollbar.last_report.should_not be_nil
172
891
  end
173
892
 
@@ -178,20 +897,16 @@ describe Rollbar do
178
897
  config.exception_level_filters = { 'NameError' => callable_mock }
179
898
  end
180
899
 
181
- callable_mock.should_receive(:call).with(@exception).at_least(:once).and_return("info")
900
+ callable_mock.should_receive(:call).with(exception).at_least(:once).and_return("info")
182
901
  logger_mock.should_receive(:info)
183
902
  logger_mock.should_not_receive(:warn)
184
903
  logger_mock.should_not_receive(:error)
185
904
 
186
- Rollbar.report_exception(@exception)
187
-
188
- Rollbar.configure do |config|
189
- config.exception_level_filters = saved_filters
190
- end
905
+ Rollbar.error(exception)
191
906
  end
192
907
 
193
908
  it 'should not report exceptions when silenced' do
194
- Rollbar.should_not_receive :schedule_payload
909
+ expect_any_instance_of(Rollbar::Notifier).to_not receive(:schedule_payload)
195
910
 
196
911
  begin
197
912
  test_var = 1
@@ -200,7 +915,7 @@ describe Rollbar do
200
915
  raise
201
916
  end
202
917
  rescue => e
203
- Rollbar.report_exception(e)
918
+ Rollbar.error(e)
204
919
  end
205
920
 
206
921
  test_var.should == 2
@@ -208,10 +923,13 @@ describe Rollbar do
208
923
 
209
924
  it 'should report exception objects with no backtrace' do
210
925
  payload = nil
211
- Rollbar.stub(:schedule_payload) do |*args|
926
+
927
+ notifier.stub(:schedule_payload) do |*args|
212
928
  payload = args[0]
213
929
  end
214
- Rollbar.report_exception(StandardError.new("oops"))
930
+
931
+ Rollbar.error(StandardError.new("oops"))
932
+
215
933
  payload["data"][:body][:trace][:frames].should == []
216
934
  payload["data"][:body][:trace][:exception][:class].should == "StandardError"
217
935
  payload["data"][:body][:trace][:exception][:message].should == "oops"
@@ -219,15 +937,15 @@ describe Rollbar do
219
937
 
220
938
  it 'should return the exception data with a uuid, on platforms with SecureRandom' do
221
939
  if defined?(SecureRandom) and SecureRandom.respond_to?(:uuid)
222
- Rollbar.stub(:schedule_payload) do |*args| end
223
- exception_data = Rollbar.report_exception(StandardError.new("oops"))
940
+ exception_data = Rollbar.error(StandardError.new("oops"))
224
941
  exception_data[:uuid].should_not be_nil
225
942
  end
226
943
  end
227
944
 
228
945
  it 'should report exception objects with nonstandard backtraces' do
229
946
  payload = nil
230
- Rollbar.stub(:schedule_payload) do |*args|
947
+
948
+ notifier.stub(:schedule_payload) do |*args|
231
949
  payload = args[0]
232
950
  end
233
951
 
@@ -239,27 +957,29 @@ describe Rollbar do
239
957
 
240
958
  exception = CustomException.new("oops")
241
959
 
242
- Rollbar.report_exception(exception)
960
+ notifier.error(exception)
243
961
 
244
962
  payload["data"][:body][:trace][:frames][0][:method].should == "custom backtrace line"
245
963
  end
246
964
 
247
965
  it 'should report exceptions with a custom level' do
248
966
  payload = nil
249
- Rollbar.stub(:schedule_payload) do |*args|
967
+
968
+ notifier.stub(:schedule_payload) do |*args|
250
969
  payload = args[0]
251
970
  end
252
971
 
253
- Rollbar.report_exception(@exception)
972
+ Rollbar.error(exception)
254
973
 
255
- payload["data"][:level].should == 'error'
974
+ payload['data'][:level].should == 'error'
256
975
 
257
- Rollbar.report_exception(@exception, nil, nil, 'debug')
976
+ Rollbar.log('debug', exception)
258
977
 
259
- payload["data"][:level].should == 'debug'
978
+ payload['data'][:level].should == 'debug'
260
979
  end
261
980
  end
262
981
 
982
+ # Backwards
263
983
  context 'report_message' do
264
984
  before(:each) do
265
985
  configure
@@ -296,6 +1016,8 @@ describe Rollbar do
296
1016
  :hash => { :a => 123, :b => "xyz" })
297
1017
  end
298
1018
 
1019
+ # END Backwards
1020
+
299
1021
  it 'should not crash with circular extra_data' do
300
1022
  a = { :foo => "bar" }
301
1023
  b = { :a => a }
@@ -304,7 +1026,7 @@ describe Rollbar do
304
1026
 
305
1027
  logger_mock.should_receive(:error).with(/\[Rollbar\] Reporting internal error encountered while sending data to Rollbar./)
306
1028
 
307
- Rollbar.report_message("Test message with circular extra data", 'debug', a)
1029
+ Rollbar.error("Test message with circular extra data", a)
308
1030
  end
309
1031
 
310
1032
  it 'should be able to report form validation errors when they are present' do
@@ -319,36 +1041,13 @@ describe Rollbar do
319
1041
  user.report_validation_errors_to_rollbar
320
1042
  end
321
1043
 
322
- after(:each) do
323
- Rollbar.configure do |config|
324
- config.logger = ::Rails.logger
325
- end
326
- end
327
- end
328
-
329
- context 'report_message_with_request' do
330
- before(:each) do
331
- configure
332
- Rollbar.configure do |config|
333
- config.logger = logger_mock
334
- end
335
- end
336
-
337
- let(:logger_mock) { double("Rails.logger").as_null_object }
338
- let(:user) { User.create(:email => 'email@example.com', :encrypted_password => '', :created_at => Time.now, :updated_at => Time.now) }
339
-
340
- it 'should report simple messages' do
341
- logger_mock.should_receive(:info).with('[Rollbar] Scheduling payload')
1044
+ it 'should report messages with extra data' do
342
1045
  logger_mock.should_receive(:info).with('[Rollbar] Success')
343
- Rollbar.report_message_with_request("Test message")
344
-
345
- Rollbar.last_report[:request].should be_nil
346
- Rollbar.last_report[:person].should be_nil
1046
+ Rollbar.info("Test message with extra data", :foo => "bar",
1047
+ :hash => { :a => 123, :b => "xyz" })
347
1048
  end
348
1049
 
349
1050
  it 'should report messages with request, person data and extra data' do
350
- Rollbar.last_report = nil
351
-
352
1051
  logger_mock.should_receive(:info).with('[Rollbar] Scheduling payload')
353
1052
  logger_mock.should_receive(:info).with('[Rollbar] Success')
354
1053
 
@@ -365,11 +1064,18 @@ describe Rollbar do
365
1064
  :extra_foo => 'extra_bar'
366
1065
  }
367
1066
 
368
- Rollbar.report_message_with_request("Test message", 'info', request_data, person_data, extra_data)
1067
+ Rollbar.configure do |config|
1068
+ config.payload_options = {
1069
+ :request => request_data,
1070
+ :person => person_data
1071
+ }
1072
+ end
1073
+
1074
+ Rollbar.info("Test message", extra_data)
369
1075
 
370
1076
  Rollbar.last_report[:request].should == request_data
371
1077
  Rollbar.last_report[:person].should == person_data
372
- Rollbar.last_report[:body][:message][:extra_foo].should == 'extra_bar'
1078
+ Rollbar.last_report[:body][:message][:extra][:extra_foo].should == 'extra_bar'
373
1079
  end
374
1080
  end
375
1081
 
@@ -380,11 +1086,18 @@ describe Rollbar do
380
1086
  config.logger = logger_mock
381
1087
  config.filepath = 'test.rollbar'
382
1088
  end
1089
+ end
1090
+
1091
+ after(:each) do
1092
+ Rollbar.unconfigure
1093
+ configure
1094
+ end
383
1095
 
1096
+ let(:exception) do
384
1097
  begin
385
1098
  foo = bar
386
1099
  rescue => e
387
- @exception = e
1100
+ e
388
1101
  end
389
1102
  end
390
1103
 
@@ -394,7 +1107,7 @@ describe Rollbar do
394
1107
  logger_mock.should_not_receive(:info).with('[Rollbar] Writing payload to file')
395
1108
  logger_mock.should_receive(:info).with('[Rollbar] Sending payload').once
396
1109
  logger_mock.should_receive(:info).with('[Rollbar] Success').once
397
- Rollbar.report_exception(@exception)
1110
+ Rollbar.error(exception)
398
1111
  end
399
1112
 
400
1113
  it 'should save the payload to a file if set' do
@@ -409,7 +1122,7 @@ describe Rollbar do
409
1122
  filepath = config.filepath
410
1123
  end
411
1124
 
412
- Rollbar.report_exception(@exception)
1125
+ Rollbar.error(exception)
413
1126
 
414
1127
  File.exist?(filepath).should == true
415
1128
  File.read(filepath).should include test_access_token
@@ -427,11 +1140,18 @@ describe Rollbar do
427
1140
  Rollbar.configure do |config|
428
1141
  config.logger = logger_mock
429
1142
  end
1143
+ end
1144
+
1145
+ after(:each) do
1146
+ Rollbar.unconfigure
1147
+ configure
1148
+ end
430
1149
 
1150
+ let(:exception) do
431
1151
  begin
432
1152
  foo = bar
433
1153
  rescue => e
434
- @exception = e
1154
+ e
435
1155
  end
436
1156
  end
437
1157
 
@@ -447,7 +1167,7 @@ describe Rollbar do
447
1167
  GirlFriday::WorkQueue.immediate!
448
1168
  end
449
1169
 
450
- Rollbar.report_exception(@exception)
1170
+ Rollbar.error(exception)
451
1171
 
452
1172
  Rollbar.configure do |config|
453
1173
  config.use_async = false
@@ -468,12 +1188,7 @@ describe Rollbar do
468
1188
  }
469
1189
  end
470
1190
 
471
- Rollbar.report_exception(@exception)
472
-
473
- Rollbar.configure do |config|
474
- config.use_async = false
475
- config.async_handler = Rollbar.default_async_handler
476
- end
1191
+ Rollbar.error(exception)
477
1192
  end
478
1193
 
479
1194
  # We should be able to send String payloads, generated
@@ -497,7 +1212,7 @@ describe Rollbar do
497
1212
  it 'sends a payload generated as String, not as a Hash' do
498
1213
  logger_mock.should_receive(:info).with('[Rollbar] Success')
499
1214
 
500
- Rollbar.report_exception(@exception)
1215
+ Rollbar.report_exception(exception)
501
1216
  end
502
1217
 
503
1218
  context 'with async failover handlers' do
@@ -536,7 +1251,7 @@ describe Rollbar do
536
1251
  it 'logs the error but doesnt try to report an internal error' do
537
1252
  expect(logger_mock).to receive(:error).with(log_message)
538
1253
 
539
- Rollbar.report_exception(exception)
1254
+ Rollbar.error(exception)
540
1255
  end
541
1256
  end
542
1257
 
@@ -548,7 +1263,7 @@ describe Rollbar do
548
1263
  expect(Rollbar).not_to receive(:report_internal_error)
549
1264
  expect(handler).to receive(:call)
550
1265
 
551
- Rollbar.report_exception(exception)
1266
+ Rollbar.error(exception)
552
1267
  end
553
1268
  end
554
1269
 
@@ -560,7 +1275,7 @@ describe Rollbar do
560
1275
  it 'calls the second handler and doesnt report internal error' do
561
1276
  expect(handler2).to receive(:call)
562
1277
 
563
- Rollbar.report_exception(exception)
1278
+ Rollbar.error(exception)
564
1279
  end
565
1280
  end
566
1281
 
@@ -572,7 +1287,7 @@ describe Rollbar do
572
1287
  it 'reports internal error' do
573
1288
  expect(logger_mock).to receive(:error)
574
1289
 
575
- Rollbar.report_exception(exception)
1290
+ Rollbar.error(exception)
576
1291
  end
577
1292
  end
578
1293
  end
@@ -589,12 +1304,7 @@ describe Rollbar do
589
1304
  config.use_sucker_punch
590
1305
  end
591
1306
 
592
- Rollbar.report_exception(@exception)
593
-
594
- Rollbar.configure do |config|
595
- config.use_async = false
596
- config.async_handler = Rollbar.default_async_handler
597
- end
1307
+ Rollbar.error(exception)
598
1308
  end
599
1309
  end
600
1310
 
@@ -614,161 +1324,7 @@ describe Rollbar do
614
1324
  config.async_handler = handler
615
1325
  end
616
1326
 
617
- Rollbar.report_exception(@exception)
618
-
619
- Rollbar.configure do |config|
620
- config.use_async = false
621
- config.async_handler = Rollbar.default_async_handler
622
- end
623
- end
624
- end
625
- end
626
-
627
- context 'message_data' do
628
- before(:each) do
629
- configure
630
- @message_body = "This is a test"
631
- @level = 'debug'
632
- end
633
-
634
- it 'should build a message' do
635
- data = Rollbar.send(:message_data, @message_body, @level, {})
636
- data[:body][:message][:body].should == @message_body
637
- data[:level].should == @level
638
- data[:custom].should be_nil
639
- end
640
-
641
- it 'should accept extra_data' do
642
- user_id = 123
643
- name = "Tester"
644
-
645
- data = Rollbar.send(:message_data, @message_body, 'info',
646
- :user_id => user_id, :name => name)
647
-
648
- data[:level].should == 'info'
649
- message = data[:body][:message]
650
- message[:body].should == @message_body
651
- message[:user_id].should == user_id
652
- message[:name].should == name
653
- end
654
-
655
- it 'should build a message with custom data when configured' do
656
- Rollbar.configure do |config|
657
- config.custom_data_method = lambda { {:foo => "bar", :hello => [1, 2, 3]} }
658
- end
659
-
660
- data = Rollbar.send(:message_data, @message_body, @level, {})
661
-
662
- data[:level].should == @level
663
- data[:body][:message][:body].should == @message_body
664
- data[:custom].should_not be_nil
665
- data[:custom][:foo].should == "bar"
666
- data[:custom][:hello][2].should == 3
667
-
668
- Rollbar.configure do |config|
669
- config.custom_data_method = nil
670
- end
671
- end
672
- end
673
-
674
- describe '.exception_data' do
675
- before(:each) do
676
- configure
677
- begin
678
- foo = bar
679
- rescue => e
680
- @exception = e
681
- end
682
- end
683
-
684
- it 'should accept force_level' do
685
- level = 'critical'
686
- data = Rollbar.send(:exception_data, @exception, level)
687
- data[:level].should == level
688
- end
689
-
690
- it 'should build valid exception data' do
691
- data = Rollbar.send(:exception_data, @exception)
692
-
693
- data[:level].should_not be_nil
694
- data[:custom].should be_nil
695
-
696
- trace = data[:body][:trace]
697
-
698
- frames = trace[:frames]
699
- frames.should be_a_kind_of(Array)
700
- frames.each do |frame|
701
- frame[:filename].should be_a_kind_of(String)
702
- frame[:lineno].should be_a_kind_of(Fixnum)
703
- if frame[:method]
704
- frame[:method].should be_a_kind_of(String)
705
- end
706
- end
707
-
708
- # should be NameError, but can be NoMethodError sometimes on rubinius 1.8
709
- # http://yehudakatz.com/2010/01/02/the-craziest-fing-bug-ive-ever-seen/
710
- trace[:exception][:class].should match(/^(NameError|NoMethodError)$/)
711
- trace[:exception][:message].should match(/^(undefined local variable or method `bar'|undefined method `bar' on an instance of)/)
712
- end
713
-
714
- it 'should include custom data when configured' do
715
- Rollbar.configure do |config|
716
- config.custom_data_method = lambda { {:foo => "baz", :hello => [4, 5, 6]} }
717
- end
718
-
719
- data = Rollbar.send(:exception_data, @exception)
720
- data[:body][:trace].should_not be_nil
721
- data[:custom][:foo].should == "baz"
722
- data[:custom][:hello][2].should == 6
723
-
724
- Rollbar.configure do |config|
725
- config.custom_data_method = nil
726
- end
727
- end
728
-
729
- context 'with nested exceptions' do
730
- let(:crashing_code) do
731
- proc do
732
- begin
733
- begin
734
- fail CauseException.new('the cause')
735
- rescue
736
- fail StandardError.new('the error')
737
- end
738
- rescue => e
739
- e
740
- end
741
- end
742
- end
743
- let(:rescued_exception) { crashing_code.call }
744
-
745
- if Exception.instance_methods.include?(:cause)
746
- it 'sends the two exceptions in the trace_chain attribute' do
747
- data = Rollbar.send(:exception_data, rescued_exception)
748
- body = data[:body]
749
-
750
- body[:trace].should be_nil
751
- body[:trace_chain].should be_kind_of(Array)
752
-
753
- chain = body[:trace_chain]
754
- chain[0][:exception][:class].should match(/StandardError/)
755
- chain[0][:exception][:message].should match(/the error/)
756
-
757
- chain[1][:exception][:class].should match(/CauseException/)
758
- chain[1][:exception][:message].should match(/the cause/)
759
- end
760
-
761
- else
762
- it 'sends only the last exception in the trace attribute' do
763
- data = Rollbar.send(:exception_data, rescued_exception)
764
- body = data[:body]
765
-
766
- body[:trace].should be_kind_of(Hash)
767
- body[:trace_chain].should be_nil
768
-
769
- body[:trace][:exception][:class].should match(/StandardError/)
770
- body[:trace][:exception][:message].should match(/the error/)
771
- end
1327
+ Rollbar.error(exception)
772
1328
  end
773
1329
  end
774
1330
  end
@@ -780,15 +1336,18 @@ describe Rollbar do
780
1336
 
781
1337
  it 'should have use the Rails logger when configured to do so' do
782
1338
  configure
783
- Rollbar.send(:logger).should == ::Rails.logger
1339
+ expect(Rollbar.send(:logger)).to be_kind_of(Rollbar::LoggerProxy)
1340
+ expect(Rollbar.send(:logger).object).should == ::Rails.logger
784
1341
  end
785
1342
 
786
1343
  it 'should use the default_logger when no logger is set' do
787
1344
  logger = Logger.new(STDERR)
1345
+
788
1346
  Rollbar.configure do |config|
789
1347
  config.default_logger = lambda { logger }
790
1348
  end
791
- Rollbar.send(:logger).should == logger
1349
+
1350
+ Rollbar.send(:logger).object.should == logger
792
1351
  end
793
1352
 
794
1353
  it 'should have a default default_logger' do
@@ -800,72 +1359,11 @@ describe Rollbar do
800
1359
  end
801
1360
  end
802
1361
 
803
- context 'build_payload' do
804
- before(:each) do
805
- configure
806
- Rollbar.configure do |config|
807
- config.logger = logger_mock
808
- end
809
- end
810
-
811
- let(:logger_mock) { double("Rails.logger").as_null_object }
812
-
813
- it 'should build valid json' do
814
- data = { :foo => { :bar => 'baz'}}
815
- payload = Rollbar.send(:build_payload, data)
816
- payload["data"][:foo][:bar].should == "baz"
817
- end
818
-
819
- it 'should strip out invalid utf-8' do
820
- payload = Rollbar.send(:build_payload, {
821
- :good_key => "\255bad value",
822
- "bad\255 key" => "good value",
823
- "bad key 2\255" => "bad \255value",
824
- :hash => {
825
- "bad array \255key" => ["bad\255 array element", "good array element"]
826
- }
827
- })
828
-
829
- payload["data"][:good_key].should == 'bad value'
830
- payload["data"]["bad key"].should == 'good value'
831
- payload["data"]["bad key 2"].should == 'bad value'
832
- payload["data"][:hash].should == {
833
- "bad array key" => ["bad array element", "good array element"]
834
- }
835
- end
836
-
837
- it 'should truncate large strings if the payload is too big' do
838
- data = {:foo => {:bar => "baz"}, :large => 'a' * (128 * 1024), :small => 'b' * 1024}
839
- payload = Rollbar.send(:build_payload, data)
840
- json = Rollbar.send(:dump_payload, payload)
841
-
842
- hash = MultiJson.load(json)
843
- hash["data"]["large"].should == '%s...' % ('a' * 1021)
844
- hash["data"]["small"].should == 'b' * 1024
845
- end
846
-
847
- it 'should send a failsafe message if the payload cannot be reduced enough' do
848
- logger_mock.should_receive(:error).with(/Sending failsafe response due to Could not send payload due to it being too large after truncating attempts/)
849
- logger_mock.should_receive(:info).with('[Rollbar] Success')
850
-
851
- orig_max = Rollbar::MAX_PAYLOAD_SIZE
852
- Rollbar::MAX_PAYLOAD_SIZE = 1
853
- orig_send_failsafe = Rollbar.method(:send_failsafe)
854
-
855
- Rollbar.stub(:send_failsafe) do |message, exception|
856
- Rollbar::MAX_PAYLOAD_SIZE = orig_max
857
- orig_send_failsafe.call(message, exception)
858
- end
859
-
860
- Rollbar.report_exception(@exception)
861
- end
862
- end
863
-
864
1362
  context 'enforce_valid_utf8' do
865
1363
  it 'should replace invalid utf8 values' do
866
1364
  bad_key = "inner \x92bad key"
867
1365
  bad_key.force_encoding('ASCII-8BIT') if bad_key.respond_to?('force_encoding')
868
-
1366
+
869
1367
  payload = {
870
1368
  :bad_value => "bad value 1\255",
871
1369
  :bad_value_2 => "bad\255 value 2",
@@ -884,7 +1382,7 @@ describe Rollbar do
884
1382
  }
885
1383
 
886
1384
  payload_copy = payload.clone
887
- Rollbar.send(:enforce_valid_utf8, payload_copy)
1385
+ notifier.send(:enforce_valid_utf8, payload_copy)
888
1386
 
889
1387
  payload_copy[:bad_value].should == "bad value 1"
890
1388
  payload_copy[:bad_value_2].should == "bad value 2"
@@ -915,7 +1413,7 @@ describe Rollbar do
915
1413
  }
916
1414
 
917
1415
  payload_copy = payload.clone
918
- Rollbar.send(:truncate_payload, payload_copy, 6)
1416
+ notifier.send(:truncate_payload, payload_copy, 6)
919
1417
 
920
1418
  payload_copy[:truncated].should == '123...'
921
1419
  payload_copy[:not_truncated].should == '123456'
@@ -931,67 +1429,16 @@ describe Rollbar do
931
1429
  }
932
1430
 
933
1431
  payload_copy = payload.clone
934
- Rollbar.send(:truncate_payload, payload_copy, 6)
1432
+ notifier.send(:truncate_payload, payload_copy, 6)
935
1433
 
936
1434
  payload_copy[:truncated].should == "Ŝǻм..."
937
1435
  payload_copy[:not_truncated].should == '123456'
938
1436
  end
939
1437
  end
940
1438
 
941
- context 'base_data' do
942
- before(:each) { configure }
943
-
944
- it 'should have the correct notifier name' do
945
- Rollbar.send(:base_data)[:notifier][:name].should == 'rollbar-gem'
946
- end
947
-
948
- it 'should have the correct notifier version' do
949
- Rollbar.send(:base_data)[:notifier][:version].should == Rollbar::VERSION
950
- end
951
-
952
- it 'should have all the required keys' do
953
- data = Rollbar.send(:base_data)
954
- data[:timestamp].should_not be_nil
955
- data[:environment].should_not be_nil
956
- data[:level].should_not be_nil
957
- data[:language].should == 'ruby'
958
- data[:framework].should match(/^Rails/)
959
- end
960
-
961
- it 'should have default environment "unspecified"' do
962
- data = Rollbar.send(:base_data)
963
- data[:environment].should == 'unspecified'
964
- end
965
-
966
- it 'should have an overridden environment' do
967
- Rollbar.configure do |config|
968
- config.environment = 'overridden'
969
- end
970
-
971
- data = Rollbar.send(:base_data)
972
- data[:environment].should == 'overridden'
973
- end
974
-
975
- it 'should not have custom data under default configuration' do
976
- data = Rollbar.send(:base_data)
977
- data[:custom].should be_nil
978
- end
979
-
980
- it 'should have custom data when custom_data_method is configured' do
981
- Rollbar.configure do |config|
982
- config.custom_data_method = lambda { {:a => 1, :b => [2, 3, 4]} }
983
- end
984
-
985
- data = Rollbar.send(:base_data)
986
- data[:custom].should_not be_nil
987
- data[:custom][:a].should == 1
988
- data[:custom][:b][2].should == 4
989
- end
990
- end
991
-
992
1439
  context 'server_data' do
993
1440
  it 'should have the right hostname' do
994
- Rollbar.send(:server_data)[:host] == Socket.gethostname
1441
+ notifier.send(:server_data)[:host] == Socket.gethostname
995
1442
  end
996
1443
 
997
1444
  it 'should have root and branch set when configured' do
@@ -1001,7 +1448,7 @@ describe Rollbar do
1001
1448
  config.branch = 'master'
1002
1449
  end
1003
1450
 
1004
- data = Rollbar.send(:server_data)
1451
+ data = notifier.send(:server_data)
1005
1452
  data[:root].should == '/path/to/root'
1006
1453
  data[:branch].should == 'master'
1007
1454
  end
@@ -1020,7 +1467,7 @@ describe Rollbar do
1020
1467
  gem_paths.push(Gem::Specification.find_by_name(gem).gem_dir)
1021
1468
  }
1022
1469
 
1023
- data = Rollbar.send(:message_data, 'test', 'info', {})
1470
+ data = notifier.send(:build_payload, 'info', 'test', nil, {})['data']
1024
1471
  data[:project_package_paths].kind_of?(Array).should == true
1025
1472
  data[:project_package_paths].length.should == gem_paths.length
1026
1473
 
@@ -1043,7 +1490,7 @@ describe Rollbar do
1043
1490
  gem_paths.any?{|path| path.include? 'rollbar-gem'}.should == true
1044
1491
  gem_paths.any?{|path| path.include? 'rspec-rails'}.should == true
1045
1492
 
1046
- data = Rollbar.send(:message_data, 'test', 'info', {})
1493
+ data = notifier.send(:build_payload, 'info', 'test', nil, {})['data']
1047
1494
  data[:project_package_paths].kind_of?(Array).should == true
1048
1495
  data[:project_package_paths].length.should == gem_paths.length
1049
1496
  (data[:project_package_paths] - gem_paths).length.should == 0
@@ -1056,7 +1503,7 @@ describe Rollbar do
1056
1503
  config.project_gems = gems
1057
1504
  end
1058
1505
 
1059
- data = Rollbar.send(:message_data, 'test', 'info', {})
1506
+ data = notifier.send(:build_payload, 'info', 'test', nil, {})['data']
1060
1507
  data[:project_package_paths].kind_of?(Array).should == true
1061
1508
  data[:project_package_paths].length.should == 1
1062
1509
  end
@@ -1067,7 +1514,7 @@ describe Rollbar do
1067
1514
  begin
1068
1515
  1 / 0
1069
1516
  rescue => e
1070
- Rollbar.send(:report_internal_error, e)
1517
+ notifier.send(:report_internal_error, e)
1071
1518
  end
1072
1519
  end
1073
1520
  end
@@ -1077,12 +1524,12 @@ describe Rollbar do
1077
1524
  begin
1078
1525
  1 / 0
1079
1526
  rescue => e
1080
- Rollbar.send(:send_failsafe, "test failsafe", e)
1527
+ notifier.send(:send_failsafe, "test failsafe", e)
1081
1528
  end
1082
1529
  end
1083
1530
 
1084
1531
  it "should not crash when given all nils" do
1085
- Rollbar.send(:send_failsafe, nil, nil)
1532
+ notifier.send(:send_failsafe, nil, nil)
1086
1533
  end
1087
1534
  end
1088
1535
 
@@ -1104,6 +1551,69 @@ describe Rollbar do
1104
1551
  end
1105
1552
  end
1106
1553
 
1554
+ describe '.scoped' do
1555
+ let(:scope_options) do
1556
+ { :foo => 'bar' }
1557
+ end
1558
+
1559
+ it 'changes payload options inside the block' do
1560
+ Rollbar.reset_notifier!
1561
+ configure
1562
+
1563
+ current_notifier_id = Rollbar.notifier.object_id
1564
+
1565
+ Rollbar.scoped(scope_options) do
1566
+ configuration = Rollbar.notifier.configuration
1567
+
1568
+ expect(Rollbar.notifier.object_id).not_to be_eql(current_notifier_id)
1569
+ expect(configuration.payload_options).to be_eql(scope_options)
1570
+ end
1571
+
1572
+ expect(Rollbar.notifier.object_id).to be_eql(current_notifier_id)
1573
+ end
1574
+
1575
+ context 'if the block fails' do
1576
+ let(:crashing_block) { proc { fail } }
1577
+
1578
+ it 'restores the old notifier' do
1579
+ notifier = Rollbar.notifier
1580
+
1581
+ expect { Rollbar.scoped(&crashing_block) }.to raise_error
1582
+ expect(notifier).to be_eql(Rollbar.notifier)
1583
+ end
1584
+ end
1585
+
1586
+ context 'if the block creates a new thread' do
1587
+ let(:block) do
1588
+ proc do
1589
+ Thread.new do
1590
+ scope = Rollbar.notifier.configuration.payload_options
1591
+ Thread.main[:inner_scope] = scope
1592
+ end.join
1593
+ end
1594
+ end
1595
+
1596
+ let(:scope) do
1597
+ { :foo => 'bar' }
1598
+ end
1599
+
1600
+ it 'maintains the parent thread notifier scope' do
1601
+ Rollbar.scoped(scope, &block)
1602
+
1603
+ expect(Thread.main[:inner_scope]).to be_eql(scope)
1604
+ end
1605
+ end
1606
+ end
1607
+
1608
+ describe '.reset_notifier' do
1609
+ it 'resets the notifier' do
1610
+ notifier1_id = Rollbar.notifier.object_id
1611
+
1612
+ Rollbar.reset_notifier!
1613
+ expect(Rollbar.notifier.object_id).not_to be_eql(notifier1_id)
1614
+ end
1615
+ end
1616
+
1107
1617
  # configure with some basic params
1108
1618
  def configure
1109
1619
  Rollbar.reconfigure do |config|