airbrake-ruby 1.0.0.rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,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