airbrake-ruby 1.0.0.rc.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,121 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Airbrake::AsyncSender do
4
+ before do
5
+ stub_request(:post, /.*/).to_return(status: 201, body: '{}')
6
+ @sender = described_class.new(Airbrake::Config.new)
7
+ @workers = @sender.instance_variable_get(:@workers)
8
+ end
9
+
10
+ describe "#new" do
11
+ context "workers_count parameter" do
12
+ let(:new_workers) { 5 }
13
+ let(:config) { Airbrake::Config.new(workers: new_workers) }
14
+
15
+ it "spawns alive threads in an enclosed ThreadGroup" do
16
+ expect(@workers).to be_a(ThreadGroup)
17
+ expect(@workers.list).to all(be_alive)
18
+ expect(@workers).to be_enclosed
19
+ end
20
+
21
+ it "controls the number of spawned threads" do
22
+ expect(@workers.list.size).to eq(1)
23
+
24
+ sender = described_class.new(config)
25
+ workers = sender.instance_variable_get(:@workers)
26
+
27
+ expect(workers.list.size).to eq(new_workers)
28
+ sender.close
29
+ end
30
+ end
31
+
32
+ context "queue" do
33
+ before do
34
+ @stdout = StringIO.new
35
+ end
36
+
37
+ let(:notices) { 1000 }
38
+
39
+ let(:config) do
40
+ Airbrake::Config.new(logger: Logger.new(@stdout), workers: 3, queue_size: 10)
41
+ end
42
+
43
+ it "limits the size of the queue, but still sends all notices" do
44
+ sender = described_class.new(config)
45
+
46
+ notices.times { |i| sender.send(i) }
47
+ sender.close
48
+
49
+ log = @stdout.string.split("\n")
50
+ expect(log.grep(/\*\*Airbrake: \{\}/).size).to eq(notices)
51
+ end
52
+ end
53
+ end
54
+
55
+ describe "#close" do
56
+ before do
57
+ @stderr = StringIO.new
58
+ config = Airbrake::Config.new(logger: Logger.new(@stderr))
59
+ @sender = described_class.new(config)
60
+ @workers = @sender.instance_variable_get(:@workers).list
61
+ end
62
+
63
+ context "when there are no unsent notices" do
64
+ it "joins the spawned thread" do
65
+ expect(@workers).to all(be_alive)
66
+ @sender.close
67
+ expect(@workers).to all(be_stop)
68
+ end
69
+ end
70
+
71
+ context "when there are some unsent notices" do
72
+ before do
73
+ 300.times { |i| @sender.send(i) }
74
+ expect(@sender.instance_variable_get(:@unsent).size).not_to be_zero
75
+ @sender.close
76
+ end
77
+
78
+ it "warns about the number of notices" do
79
+ expect(@stderr.string).to match(/waiting to send \d+ unsent notice/)
80
+ end
81
+
82
+ it "prints the debug message the correct number of times" do
83
+ log = @stderr.string.split("\n")
84
+ expect(log.grep(/\*\*Airbrake: \{\}/).size).to eq(300)
85
+ end
86
+
87
+ it "waits until the unsent notices queue is empty" do
88
+ expect(@sender.instance_variable_get(:@unsent).size).to be_zero
89
+ end
90
+ end
91
+
92
+ context "when it was already closed" do
93
+ it "doesn't increase the unsent queue size" do
94
+ @sender.close
95
+ expect(@sender.instance_variable_get(:@unsent).size).to be_zero
96
+
97
+ expect { @sender.close }.
98
+ to raise_error(Airbrake::Error, 'attempted to close already closed sender')
99
+ end
100
+ end
101
+ end
102
+
103
+ describe "#has_workers?" do
104
+ it "returns false when the sender is not closed, but has 0 workers" do
105
+ sender = described_class.new(Airbrake::Config.new)
106
+ expect(sender.has_workers?).to be_truthy
107
+
108
+ sender.instance_variable_get(:@workers).list.each(&:kill)
109
+ sleep 1
110
+ expect(sender.has_workers?).to be_falsey
111
+ end
112
+
113
+ it "returns false when the sender is closed" do
114
+ sender = described_class.new(Airbrake::Config.new)
115
+ expect(sender.has_workers?).to be_truthy
116
+
117
+ sender.close
118
+ expect(sender.has_workers?).to be_falsey
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,77 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Airbrake::Backtrace do
4
+ describe ".parse" do
5
+ context "UNIX backtrace" do
6
+ let(:backtrace) { described_class.new(AirbrakeTestError.new) }
7
+
8
+ let(:parsed_backtrace) do
9
+ # rubocop:disable Metrics/LineLength, Style/HashSyntax, Style/SpaceAroundOperators, Style/SpaceInsideHashLiteralBraces
10
+ [{:file=>"/home/kyrylo/code/airbrake/ruby/spec/spec_helper.rb", :line=>23, :function=>"<top (required)>"},
11
+ {:file=>"/opt/rubies/ruby-2.2.2/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb", :line=>54, :function=>"require"},
12
+ {:file=>"/opt/rubies/ruby-2.2.2/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb", :line=>54, :function=>"require"},
13
+ {:file=>"/home/kyrylo/code/airbrake/ruby/spec/airbrake_spec.rb", :line=>1, :function=>"<top (required)>"},
14
+ {:file=>"/home/kyrylo/.gem/ruby/2.2.2/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb", :line=>1327, :function=>"load"},
15
+ {:file=>"/home/kyrylo/.gem/ruby/2.2.2/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb", :line=>1327, :function=>"block in load_spec_files"},
16
+ {:file=>"/home/kyrylo/.gem/ruby/2.2.2/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb", :line=>1325, :function=>"each"},
17
+ {:file=>"/home/kyrylo/.gem/ruby/2.2.2/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb", :line=>1325, :function=>"load_spec_files"},
18
+ {:file=>"/home/kyrylo/.gem/ruby/2.2.2/gems/rspec-core-3.3.2/lib/rspec/core/runner.rb", :line=>102, :function=>"setup"},
19
+ {:file=>"/home/kyrylo/.gem/ruby/2.2.2/gems/rspec-core-3.3.2/lib/rspec/core/runner.rb", :line=>88, :function=>"run"},
20
+ {:file=>"/home/kyrylo/.gem/ruby/2.2.2/gems/rspec-core-3.3.2/lib/rspec/core/runner.rb", :line=>73, :function=>"run"},
21
+ {:file=>"/home/kyrylo/.gem/ruby/2.2.2/gems/rspec-core-3.3.2/lib/rspec/core/runner.rb", :line=>41, :function=>"invoke"},
22
+ {:file=>"/home/kyrylo/.gem/ruby/2.2.2/gems/rspec-core-3.3.2/exe/rspec", :line=>4, :function=>"<main>"}]
23
+ # rubocop:enable Metrics/LineLength, Style/HashSyntax,Style/SpaceAroundOperators, Style/SpaceInsideHashLiteralBraces
24
+ end
25
+
26
+ it "returns a properly formatted array of hashes" do
27
+ expect(described_class.parse(AirbrakeTestError.new)).
28
+ to eq(parsed_backtrace)
29
+ end
30
+ end
31
+
32
+ context "Windows backtrace" do
33
+ let(:windows_bt) do
34
+ ["C:/Program Files/Server/app/models/user.rb:13:in `magic'",
35
+ "C:/Program Files/Server/app/controllers/users_controller.rb:8:in `index'"]
36
+ end
37
+
38
+ let(:ex) { AirbrakeTestError.new.tap { |e| e.set_backtrace(windows_bt) } }
39
+
40
+ let(:parsed_backtrace) do
41
+ # rubocop:disable Metrics/LineLength, Style/HashSyntax, Style/SpaceInsideHashLiteralBraces, Style/SpaceAroundOperators
42
+ [{:file=>"C:/Program Files/Server/app/models/user.rb", :line=>13, :function=>"magic"},
43
+ {:file=>"C:/Program Files/Server/app/controllers/users_controller.rb", :line=>8, :function=>"index"}]
44
+ # rubocop:enable Metrics/LineLength, Style/HashSyntax, Style/SpaceInsideHashLiteralBraces, Style/SpaceAroundOperators
45
+ end
46
+
47
+ it "returns a properly formatted array of hashes" do
48
+ expect(described_class.parse(ex)).to eq(parsed_backtrace)
49
+ end
50
+ end
51
+
52
+ context "JRuby Java exceptions" do
53
+ let(:backtrace_array) do
54
+ # rubocop:disable Metrics/LineLength, Style/HashSyntax, Style/SpaceInsideHashLiteralBraces, Style/SpaceAroundOperators
55
+ [{:file=>"InstanceMethodInvoker.java", :line=>26, :function=>"org.jruby.java.invokers.InstanceMethodInvoker.call"},
56
+ {:file=>"Interpreter.java", :line=>126, :function=>"org.jruby.ir.interpreter.Interpreter.INTERPRET_EVAL"},
57
+ {:file=>"RubyKernel$INVOKER$s$0$3$eval19.gen", :line=>nil, :function=>"org.jruby.RubyKernel$INVOKER$s$0$3$eval19.call"},
58
+ {:file=>"RubyKernel$INVOKER$s$0$0$loop.gen", :line=>nil, :function=>"org.jruby.RubyKernel$INVOKER$s$0$0$loop.call"},
59
+ {:file=>"IRBlockBody.java", :line=>139, :function=>"org.jruby.runtime.IRBlockBody.doYield"},
60
+ {:file=>"RubyKernel$INVOKER$s$rbCatch19.gen", :line=>nil, :function=>"org.jruby.RubyKernel$INVOKER$s$rbCatch19.call"},
61
+ {:file=>"/opt/rubies/jruby-9.0.0.0/bin/irb", :line=>nil, :function=>"opt.rubies.jruby_minus_9_dot_0_dot_0_dot_0.bin.irb.invokeOther4:start"},
62
+ {:file=>"/opt/rubies/jruby-9.0.0.0/bin/irb", :line=>13, :function=>"opt.rubies.jruby_minus_9_dot_0_dot_0_dot_0.bin.irb.RUBY$script"},
63
+ {:file=>"Compiler.java", :line=>111, :function=>"org.jruby.ir.Compiler$1.load"},
64
+ {:file=>"Main.java", :line=>225, :function=>"org.jruby.Main.run"},
65
+ {:file=>"Main.java", :line=>197, :function=>"org.jruby.Main.main"}]
66
+ # rubocop:enable Metrics/LineLength, Style/HashSyntax, Style/SpaceInsideHashLiteralBraces, Style/SpaceAroundOperators
67
+ end
68
+
69
+ it "returns a properly formatted array of hashes" do
70
+ allow(described_class).to receive(:java_exception?).and_return(true)
71
+
72
+ expect(described_class.parse(JavaAirbrakeTestError.new)).
73
+ to eq(backtrace_array)
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Airbrake::Config do
4
+ let(:config) { described_class.new }
5
+
6
+ describe "#new" do
7
+ describe "options" do
8
+ it "doesn't set the default project_id" do
9
+ expect(config.project_id).to be_nil
10
+ end
11
+
12
+ it "doesn't set the default project_key" do
13
+ expect(config.project_key).to be_nil
14
+ end
15
+
16
+ it "doesn't set the default proxy" do
17
+ expect(config.proxy).to be_empty
18
+ end
19
+
20
+ it "sets the default logger" do
21
+ expect(config.logger).to be_a Logger
22
+ end
23
+
24
+ it "doesn't set the default app_version" do
25
+ expect(config.app_version).to be_nil
26
+ end
27
+
28
+ it "sets the default host" do
29
+ expect(config.host).to eq('https://airbrake.io')
30
+ end
31
+
32
+ it "sets the default endpoint" do
33
+ expect(config.endpoint).not_to be_nil
34
+ end
35
+
36
+ it "creates a new Config and merges it with the user config" do
37
+ cfg = described_class.new(logger: StringIO.new)
38
+ expect(cfg.logger).to be_a StringIO
39
+ end
40
+
41
+ it "raises error on unknown config options" do
42
+ expect { described_class.new(unknown_option: true) }.
43
+ to raise_error(Airbrake::Error, /unknown option/)
44
+ end
45
+
46
+ it "sets the default number of workers" do
47
+ expect(config.workers).to eq(1)
48
+ end
49
+
50
+ it "sets the default number of queue size" do
51
+ expect(config.queue_size).to eq(100)
52
+ end
53
+
54
+ it "doesn't set the default root_directory" do
55
+ expect(config.root_directory).to be_nil
56
+ end
57
+
58
+ it "doesn't set the default environment" do
59
+ expect(config.environment).to be_nil
60
+ end
61
+
62
+ it "doesn't set default notify_environments" do
63
+ expect(config.ignore_environments).to be_empty
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,157 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Airbrake::FilterChain do
4
+ before do
5
+ @chain = described_class.new(config)
6
+ end
7
+
8
+ let(:config) { Airbrake::Config.new }
9
+
10
+ describe "#refine" do
11
+ describe "execution order" do
12
+ let(:notice) do
13
+ Airbrake::Notice.new(config, AirbrakeTestError.new)
14
+ end
15
+
16
+ it "executes filters starting from the oldest" do
17
+ nums = []
18
+
19
+ 3.times do |i|
20
+ @chain.add_filter(proc { nums << i })
21
+ end
22
+
23
+ @chain.refine(notice)
24
+
25
+ expect(nums).to eq([0, 1, 2])
26
+ end
27
+
28
+ it "stops execution once a notice was ignored" do
29
+ nums = []
30
+
31
+ 5.times do |i|
32
+ @chain.add_filter(proc do |notice|
33
+ nums << i
34
+ notice.ignore! if i == 2
35
+ end)
36
+ end
37
+
38
+ @chain.refine(notice)
39
+
40
+ expect(nums).to eq([0, 1, 2])
41
+ end
42
+ end
43
+
44
+ describe "default backtrace filters" do
45
+ let(:ex) { AirbrakeTestError.new.tap { |e| e.set_backtrace(backtrace) } }
46
+ let(:notice) { Airbrake::Notice.new(config, ex) }
47
+
48
+ before do
49
+ Gem.path << '/my/gem/root' << '/my/other/gem/root'
50
+ @chain.refine(notice)
51
+ @bt = notice[:errors].first[:backtrace].map { |frame| frame[:file] }
52
+ end
53
+
54
+ shared_examples 'root directories' do |root_directory, bt, expected_bt|
55
+ let(:backtrace) { bt }
56
+
57
+ before do
58
+ config = Airbrake::Config.new(root_directory: root_directory)
59
+ chain = described_class.new(config)
60
+ chain.refine(notice)
61
+ @bt = notice[:errors].first[:backtrace].map { |frame| frame[:file] }
62
+ end
63
+
64
+ it "filters it out" do
65
+ expect(@bt).to eq(expected_bt)
66
+ end
67
+ end
68
+
69
+ # rubocop:disable Metrics/LineLength
70
+ context "gem root" do
71
+ bt = [
72
+ "/home/kyrylo/code/airbrake/ruby/spec/spec_helper.rb:23:in `<top (required)>'",
73
+ "/my/gem/root/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb:1327:in `load'",
74
+ "/opt/rubies/ruby-2.2.2/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in `require'",
75
+ "/my/other/gem/root/gems/rspec-core-3.3.2/exe/rspec:4:in `<main>'"
76
+ ]
77
+
78
+ expected_bt = [
79
+ "/home/kyrylo/code/airbrake/ruby/spec/spec_helper.rb",
80
+ "[GEM_ROOT]/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb",
81
+ "/opt/rubies/ruby-2.2.2/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb",
82
+ "[GEM_ROOT]/gems/rspec-core-3.3.2/exe/rspec"
83
+ ]
84
+
85
+ include_examples 'root directories', nil, bt, expected_bt
86
+ end
87
+
88
+ context "root directory" do
89
+ context "when normal string path" do
90
+ bt = [
91
+ "/home/kyrylo/code/airbrake/ruby/spec/spec_helper.rb:23:in `<top (required)>'",
92
+ "/var/www/project/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb:1327:in `load'",
93
+ "/opt/rubies/ruby-2.2.2/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in `require'",
94
+ "/var/www/project/gems/rspec-core-3.3.2/exe/rspec:4:in `<main>'"
95
+ ]
96
+
97
+ expected_bt = [
98
+ "/home/kyrylo/code/airbrake/ruby/spec/spec_helper.rb",
99
+ "[PROJECT_ROOT]/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb",
100
+ "/opt/rubies/ruby-2.2.2/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb",
101
+ "[PROJECT_ROOT]/gems/rspec-core-3.3.2/exe/rspec"
102
+ ]
103
+
104
+ include_examples 'root directories', '/var/www/project', bt, expected_bt
105
+ end
106
+
107
+ context "when equals to a part of filename" do
108
+ bt = [
109
+ "/home/kyrylo/code/airbrake/ruby/spec/spec_helper.rb:23:in `<top (required)>'",
110
+ "/var/www/gems/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb:1327:in `load'",
111
+ "/opt/rubies/ruby-2.2.2/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in `require'",
112
+ "/var/www/gems/gems/rspec-core-3.3.2/exe/rspec:4:in `<main>'"
113
+ ]
114
+
115
+ expected_bt = [
116
+ "/home/kyrylo/code/airbrake/ruby/spec/spec_helper.rb",
117
+ "[PROJECT_ROOT]/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb",
118
+ "/opt/rubies/ruby-2.2.2/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb",
119
+ "[PROJECT_ROOT]/gems/rspec-core-3.3.2/exe/rspec"
120
+ ]
121
+
122
+ include_examples 'root directories', '/var/www/gems', bt, expected_bt
123
+ end
124
+
125
+ context "when normal pathname path" do
126
+ bt = [
127
+ "/home/kyrylo/code/airbrake/ruby/spec/spec_helper.rb:23:in `<top (required)>'",
128
+ "/var/www/project/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb:1327:in `load'",
129
+ "/opt/rubies/ruby-2.2.2/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in `require'",
130
+ "/var/www/project/gems/rspec-core-3.3.2/exe/rspec:4:in `<main>'"
131
+ ]
132
+
133
+ expected_bt = [
134
+ "/home/kyrylo/code/airbrake/ruby/spec/spec_helper.rb",
135
+ "[PROJECT_ROOT]/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb",
136
+ "/opt/rubies/ruby-2.2.2/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb",
137
+ "[PROJECT_ROOT]/gems/rspec-core-3.3.2/exe/rspec"
138
+ ]
139
+
140
+ include_examples 'root directories',
141
+ Pathname.new('/var/www/project'), bt, expected_bt
142
+ end
143
+ end
144
+ # rubocop:enable Metrics/LineLength
145
+ end
146
+
147
+ describe "default ignore filters" do
148
+ context "system exit filter" do
149
+ it "marks SystemExit exceptions as ignored" do
150
+ notice = Airbrake::Notice.new(config, SystemExit.new)
151
+ expect { @chain.refine(notice) }.
152
+ to(change { notice.ignored? }.from(false).to(true))
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,190 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Airbrake::Notice do
4
+ let(:notice) do
5
+ described_class.new(Airbrake::Config.new, AirbrakeTestError.new, bingo: '1')
6
+ end
7
+
8
+ describe "#new" do
9
+ context "nested exceptions" do
10
+ it "unwinds nested exceptions" do
11
+ begin
12
+ begin
13
+ raise AirbrakeTestError
14
+ rescue AirbrakeTestError
15
+ Ruby21Error.raise_error('bingo')
16
+ end
17
+ rescue Ruby21Error => ex
18
+ notice = described_class.new(Airbrake::Config.new, ex)
19
+
20
+ expect(notice[:errors].size).to eq(2)
21
+ expect(notice[:errors][0][:message]).to eq('bingo')
22
+ expect(notice[:errors][1][:message]).to eq('App crashed!')
23
+ end
24
+ end
25
+
26
+ it "unwinds no more than 3 nested exceptions" do
27
+ begin
28
+ begin
29
+ raise AirbrakeTestError
30
+ rescue AirbrakeTestError
31
+ begin
32
+ Ruby21Error.raise_error('bongo')
33
+ rescue Ruby21Error
34
+ begin
35
+ Ruby21Error.raise_error('bango')
36
+ rescue Ruby21Error
37
+ Ruby21Error.raise_error('bingo')
38
+ end
39
+ end
40
+ end
41
+ rescue Ruby21Error => ex
42
+ notice = described_class.new(Airbrake::Config.new, ex)
43
+
44
+ expect(notice[:errors].size).to eq(3)
45
+ expect(notice[:errors][0][:message]).to eq('bingo')
46
+ expect(notice[:errors][1][:message]).to eq('bango')
47
+ expect(notice[:errors][2][:message]).to eq('bongo')
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ describe "#to_json" do
54
+ context "app_version" do
55
+ context "when missing" do
56
+ it "doesn't include app_version" do
57
+ expect(notice.to_json).not_to match(/"context":{"version":"1.2.3"/)
58
+ end
59
+ end
60
+
61
+ context "when present" do
62
+ let(:config) do
63
+ Airbrake::Config.new(app_version: '1.2.3', root_directory: '/one/two')
64
+ end
65
+
66
+ let(:notice) { described_class.new(config, AirbrakeTestError.new) }
67
+
68
+ it "includes app_version" do
69
+ expect(notice.to_json).to match(/"context":{"version":"1.2.3"/)
70
+ end
71
+
72
+ it "includes root_directory" do
73
+ expect(notice.to_json).to match(%r{"rootDirectory":"/one/two"})
74
+ end
75
+ end
76
+ end
77
+
78
+ context "truncation" do
79
+ shared_examples 'payloads' do |size, msg|
80
+ it msg do
81
+ ex = AirbrakeTestError.new
82
+
83
+ backtrace = []
84
+ size.times { backtrace << "bin/rails:3:in `<main>'" }
85
+ ex.set_backtrace(backtrace)
86
+
87
+ notice = described_class.new(Airbrake::Config.new, ex)
88
+
89
+ expect(notice.to_json.bytesize).to be < 64000
90
+ end
91
+ end
92
+
93
+ max_msg = 'truncates to the max allowed size'
94
+
95
+ context "with an extremely huge payload" do
96
+ include_examples 'payloads', 200_000, max_msg
97
+ end
98
+
99
+ context "with a big payload" do
100
+ include_examples 'payloads', 50_000, max_msg
101
+ end
102
+
103
+ small_msg = "doesn't truncate it"
104
+
105
+ context "with a small payload" do
106
+ include_examples 'payloads', 1000, small_msg
107
+ end
108
+
109
+ context "with a tiny payload" do
110
+ include_examples 'payloads', 300, small_msg
111
+ end
112
+
113
+ describe "object replacement with its string version" do
114
+ let(:klass) { Class.new {} }
115
+ let(:ex) { AirbrakeTestError.new }
116
+ let(:params) { { bingo: [Object.new, klass.new] } }
117
+ let(:notice) { described_class.new(Airbrake::Config.new, ex, params) }
118
+
119
+ before do
120
+ backtrace = []
121
+ backtrace_size.times { backtrace << "bin/rails:3:in `<main>'" }
122
+ ex.set_backtrace(backtrace)
123
+ end
124
+
125
+ context "with payload within the limits" do
126
+ let(:backtrace_size) { 1000 }
127
+
128
+ it "doesn't happen" do
129
+ expect(notice.to_json).
130
+ to match(/bingo":\["#<Object:.+>","#<#<Class:.+>:.+>"/)
131
+ end
132
+ end
133
+
134
+ context "with payload bigger than the limit" do
135
+ context "with payload within the limits" do
136
+ let(:backtrace_size) { 50_000 }
137
+
138
+ it "happens" do
139
+ expect(notice.to_json).
140
+ to match(/bingo":\[".+Object.+",".+Class.+"/)
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
146
+
147
+ it "overwrites the 'notifier' payload with the default values" do
148
+ notice[:notifier] = { name: 'bingo', bango: 'bongo' }
149
+
150
+ expect(notice.to_json).
151
+ to match(/"notifier":{"name":"airbrake-ruby","version":".+","url":".+"}/)
152
+ end
153
+ end
154
+
155
+ describe "#[]" do
156
+ it "accesses payload" do
157
+ expect(notice[:params]).to eq(bingo: '1')
158
+ end
159
+
160
+ it "raises error if notice is ignored" do
161
+ notice.ignore!
162
+ expect { notice[:params] }.
163
+ to raise_error(Airbrake::Error, 'cannot access ignored notice')
164
+ end
165
+ end
166
+
167
+ describe "#[]=" do
168
+ it "sets a payload value" do
169
+ hash = { bingo: 'bango' }
170
+ notice[:params] = hash
171
+ expect(notice[:params]).to equal(hash)
172
+ end
173
+
174
+ it "raises error if notice is ignored" do
175
+ notice.ignore!
176
+ expect { notice[:params] = {} }.
177
+ to raise_error(Airbrake::Error, 'cannot access ignored notice')
178
+ end
179
+
180
+ it "raises error when trying to assign unrecognized key" do
181
+ expect { notice[:bingo] = 1 }.
182
+ to raise_error(Airbrake::Error, /:bingo is not recognized among/)
183
+ end
184
+
185
+ it "raises when setting non-hash objects as the value" do
186
+ expect { notice[:params] = Object.new }.
187
+ to raise_error(Airbrake::Error, 'Got Object value, wanted a Hash')
188
+ end
189
+ end
190
+ end