airbrake-ruby 6.0.1 → 6.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/lib/airbrake-ruby/config/processor.rb +6 -0
  3. data/lib/airbrake-ruby/config.rb +3 -3
  4. data/lib/airbrake-ruby/filters/git_last_checkout_filter.rb +1 -1
  5. data/lib/airbrake-ruby/filters/git_repository_filter.rb +7 -1
  6. data/lib/airbrake-ruby/filters/sql_filter.rb +6 -6
  7. data/lib/airbrake-ruby/nested_exception.rb +10 -1
  8. data/lib/airbrake-ruby/notice.rb +5 -3
  9. data/lib/airbrake-ruby/performance_notifier.rb +38 -38
  10. data/lib/airbrake-ruby/stat.rb +1 -1
  11. data/lib/airbrake-ruby/time_truncate.rb +2 -2
  12. data/lib/airbrake-ruby/version.rb +1 -1
  13. data/lib/airbrake-ruby.rb +21 -21
  14. metadata +6 -123
  15. data/spec/airbrake_spec.rb +0 -522
  16. data/spec/async_sender_spec.rb +0 -65
  17. data/spec/backtrace_spec.rb +0 -430
  18. data/spec/benchmark_spec.rb +0 -35
  19. data/spec/code_hunk_spec.rb +0 -124
  20. data/spec/config/processor_spec.rb +0 -151
  21. data/spec/config/validator_spec.rb +0 -204
  22. data/spec/config_spec.rb +0 -188
  23. data/spec/context_spec.rb +0 -54
  24. data/spec/deploy_notifier_spec.rb +0 -50
  25. data/spec/file_cache_spec.rb +0 -35
  26. data/spec/filter_chain_spec.rb +0 -124
  27. data/spec/filters/context_filter_spec.rb +0 -32
  28. data/spec/filters/dependency_filter_spec.rb +0 -14
  29. data/spec/filters/exception_attributes_filter_spec.rb +0 -52
  30. data/spec/filters/gem_root_filter_spec.rb +0 -44
  31. data/spec/filters/git_last_checkout_filter_spec.rb +0 -61
  32. data/spec/filters/git_repository_filter.rb +0 -61
  33. data/spec/filters/git_revision_filter_spec.rb +0 -126
  34. data/spec/filters/keys_allowlist_spec.rb +0 -204
  35. data/spec/filters/keys_blocklist_spec.rb +0 -242
  36. data/spec/filters/root_directory_filter_spec.rb +0 -39
  37. data/spec/filters/sql_filter_spec.rb +0 -274
  38. data/spec/filters/system_exit_filter_spec.rb +0 -16
  39. data/spec/filters/thread_filter_spec.rb +0 -281
  40. data/spec/fixtures/notroot.txt +0 -7
  41. data/spec/fixtures/project_root/code.rb +0 -221
  42. data/spec/fixtures/project_root/empty_file.rb +0 -0
  43. data/spec/fixtures/project_root/long_line.txt +0 -1
  44. data/spec/fixtures/project_root/short_file.rb +0 -3
  45. data/spec/fixtures/project_root/vendor/bundle/ignored_file.rb +0 -5
  46. data/spec/helpers.rb +0 -9
  47. data/spec/ignorable_spec.rb +0 -14
  48. data/spec/inspectable_spec.rb +0 -45
  49. data/spec/loggable_spec.rb +0 -17
  50. data/spec/monotonic_time_spec.rb +0 -25
  51. data/spec/nested_exception_spec.rb +0 -73
  52. data/spec/notice_notifier/options_spec.rb +0 -269
  53. data/spec/notice_notifier_spec.rb +0 -361
  54. data/spec/notice_spec.rb +0 -300
  55. data/spec/performance_breakdown_spec.rb +0 -11
  56. data/spec/performance_notifier_spec.rb +0 -645
  57. data/spec/promise_spec.rb +0 -203
  58. data/spec/query_spec.rb +0 -11
  59. data/spec/queue_spec.rb +0 -18
  60. data/spec/remote_settings/callback_spec.rb +0 -162
  61. data/spec/remote_settings/settings_data_spec.rb +0 -348
  62. data/spec/remote_settings_spec.rb +0 -201
  63. data/spec/request_spec.rb +0 -9
  64. data/spec/response_spec.rb +0 -110
  65. data/spec/spec_helper.rb +0 -100
  66. data/spec/stashable_spec.rb +0 -23
  67. data/spec/stat_spec.rb +0 -39
  68. data/spec/sync_sender_spec.rb +0 -168
  69. data/spec/tdigest_spec.rb +0 -235
  70. data/spec/thread_pool_spec.rb +0 -196
  71. data/spec/time_truncate_spec.rb +0 -15
  72. data/spec/timed_trace_spec.rb +0 -127
  73. data/spec/truncator_spec.rb +0 -267
data/spec/spec_helper.rb DELETED
@@ -1,100 +0,0 @@
1
- require 'simplecov'
2
- SimpleCov.start if ENV['COVERAGE']
3
-
4
- require 'airbrake-ruby'
5
-
6
- require 'rspec/its'
7
-
8
- require 'webmock'
9
- require 'webmock/rspec'
10
- require 'pry'
11
-
12
- require 'pathname'
13
- require 'webrick'
14
- require 'English'
15
- require 'base64'
16
- require 'pp'
17
-
18
- require 'helpers'
19
-
20
- RSpec.configure do |c|
21
- c.order = 'random'
22
- c.color = true
23
- c.disable_monkey_patching!
24
- c.include Helpers
25
- end
26
-
27
- Thread.abort_on_exception = true
28
-
29
- WebMock.disable_net_connect!(allow_localhost: true)
30
-
31
- class AirbrakeTestError < RuntimeError
32
- attr_reader :backtrace
33
-
34
- def initialize(*)
35
- super
36
- # rubocop:disable Layout/LineLength
37
- @backtrace = [
38
- "/home/kyrylo/code/airbrake/ruby/spec/spec_helper.rb:23:in `<top (required)>'",
39
- "/opt/rubies/ruby-2.2.2/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in `require'",
40
- "/opt/rubies/ruby-2.2.2/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in `require'",
41
- "/home/kyrylo/code/airbrake/ruby/spec/airbrake_spec.rb:1:in `<top (required)>'",
42
- "/home/kyrylo/.gem/ruby/2.2.2/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb:1327:in `load'",
43
- "/home/kyrylo/.gem/ruby/2.2.2/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb:1327:in `block in load_spec_files'",
44
- "/home/kyrylo/.gem/ruby/2.2.2/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb:1325:in `each'",
45
- "/home/kyrylo/.gem/ruby/2.2.2/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb:1325:in `load_spec_files'",
46
- "/home/kyrylo/.gem/ruby/2.2.2/gems/rspec-core-3.3.2/lib/rspec/core/runner.rb:102:in `setup'",
47
- "/home/kyrylo/.gem/ruby/2.2.2/gems/rspec-core-3.3.2/lib/rspec/core/runner.rb:88:in `run'",
48
- "/home/kyrylo/.gem/ruby/2.2.2/gems/rspec-core-3.3.2/lib/rspec/core/runner.rb:73:in `run'",
49
- "/home/kyrylo/.gem/ruby/2.2.2/gems/rspec-core-3.3.2/lib/rspec/core/runner.rb:41:in `invoke'",
50
- "/home/kyrylo/.gem/ruby/2.2.2/gems/rspec-core-3.3.2/exe/rspec:4:in `<main>'",
51
- ]
52
- # rubocop:enable Layout/LineLength
53
- end
54
-
55
- # rubocop:disable Naming/AccessorMethodName
56
- def set_backtrace(backtrace)
57
- @backtrace = backtrace
58
- end
59
- # rubocop:enable Naming/AccessorMethodName
60
-
61
- def message
62
- 'App crashed!'
63
- end
64
- end
65
-
66
- class JavaAirbrakeTestError < AirbrakeTestError
67
- def initialize(*)
68
- super
69
- # rubocop:disable Layout/LineLength
70
- @backtrace = [
71
- "org.jruby.java.invokers.InstanceMethodInvoker.call(InstanceMethodInvoker.java:26)",
72
- "org.jruby.ir.interpreter.Interpreter.INTERPRET_EVAL(Interpreter.java:126)",
73
- "org.jruby.RubyKernel$INVOKER$s$0$3$eval19.call(RubyKernel$INVOKER$s$0$3$eval19.gen)",
74
- "org.jruby.RubyKernel$INVOKER$s$0$0$loop.call(RubyKernel$INVOKER$s$0$0$loop.gen)",
75
- "org.jruby.runtime.IRBlockBody.doYield(IRBlockBody.java:139)",
76
- "org.jruby.RubyKernel$INVOKER$s$rbCatch19.call(RubyKernel$INVOKER$s$rbCatch19.gen)",
77
- "opt.rubies.jruby_minus_9_dot_0_dot_0_dot_0.bin.irb.invokeOther4:start(/opt/rubies/jruby-9.0.0.0/bin/irb)",
78
- "opt.rubies.jruby_minus_9_dot_0_dot_0_dot_0.bin.irb.RUBY$script(/opt/rubies/jruby-9.0.0.0/bin/irb:13)",
79
- "org.jruby.ir.Compiler$1.load(Compiler.java:111)",
80
- "org.jruby.Main.run(Main.java:225)",
81
- "org.jruby.Main.main(Main.java:197)",
82
- ]
83
- # rubocop:enable Layout/LineLength
84
- end
85
-
86
- def is_a?(*)
87
- true
88
- end
89
- end
90
-
91
- class Ruby21Error < RuntimeError
92
- attr_accessor :cause
93
-
94
- def self.raise_error(msg)
95
- ex = new(msg)
96
- ex.cause = $ERROR_INFO
97
-
98
- raise ex
99
- end
100
- end
@@ -1,23 +0,0 @@
1
- RSpec.describe Airbrake::Stashable do
2
- let(:klass) do
3
- mod = described_class
4
- Class.new { include(mod) }
5
- end
6
-
7
- describe "#stash" do
8
- subject(:instance) { klass.new }
9
-
10
- it "returns a hash" do
11
- expect(instance.stash).to be_a(Hash)
12
- end
13
-
14
- it "returns an empty hash" do
15
- expect(instance.stash).to be_empty
16
- end
17
-
18
- it "remembers what was put in the stash" do
19
- instance.stash[:foo] = 1
20
- expect(instance.stash[:foo]).to eq(1)
21
- end
22
- end
23
- end
data/spec/stat_spec.rb DELETED
@@ -1,39 +0,0 @@
1
- RSpec.describe Airbrake::Stat do
2
- subject(:stat) { described_class.new }
3
-
4
- describe "#to_h" do
5
- it "converts to a hash" do
6
- expect(stat.to_h).to eq(
7
- 'count' => 0,
8
- 'sum' => 0.0,
9
- 'sumsq' => 0.0,
10
- 'tdigest' => 'AAAAAkA0AAAAAAAAAAAAAA==',
11
- )
12
- end
13
- end
14
-
15
- describe "#increment_ms" do
16
- before { stat.increment_ms(1000) }
17
-
18
- its(:sum) { is_expected.to eq(1000) }
19
- its(:sumsq) { is_expected.to eq(1000000) }
20
-
21
- it "updates tdigest" do
22
- expect(stat.tdigest.size).to eq(1)
23
- end
24
- end
25
-
26
- describe "#inspect" do
27
- it "provides custom inspect output" do
28
- expect(stat.inspect).to eq(
29
- '#<struct Airbrake::Stat count=0, sum=0.0, sumsq=0.0>',
30
- )
31
- end
32
- end
33
-
34
- describe "#pretty_print" do
35
- it "is an alias of #inspect" do
36
- expect(stat.method(:pretty_print)).to eql(stat.method(:inspect))
37
- end
38
- end
39
- end
@@ -1,168 +0,0 @@
1
- RSpec.describe Airbrake::SyncSender do
2
- subject(:sync_sender) { described_class.new }
3
-
4
- before do
5
- Airbrake::Config.instance = Airbrake::Config.new(
6
- project_id: 1, project_key: 'banana',
7
- )
8
- end
9
-
10
- describe "#send" do
11
- let(:promise) { Airbrake::Promise.new }
12
-
13
- let(:notice) { Airbrake::Notice.new(AirbrakeTestError.new) }
14
- let(:endpoint) { 'https://api.airbrake.io/api/v3/projects/1/notices' }
15
-
16
- before { stub_request(:post, endpoint).to_return(body: '{}') }
17
-
18
- it "sets the Content-Type header to JSON" do
19
- sync_sender.send({}, promise)
20
- expect(
21
- a_request(:post, endpoint).with(
22
- headers: { 'Content-Type' => 'application/json' },
23
- ),
24
- ).to have_been_made.once
25
- end
26
-
27
- it "sets the User-Agent header to the notifier slug" do
28
- sync_sender.send({}, promise)
29
- expect(
30
- a_request(:post, endpoint).with(
31
- headers: {
32
- 'User-Agent' => %r{
33
- airbrake-ruby/\d+\.\d+\.\d+(\.rc\.\d+)?\sRuby/\d+\.\d+\.\d+
34
- }x,
35
- },
36
- ),
37
- ).to have_been_made.once
38
- end
39
-
40
- it "sets the Authorization header to the project key" do
41
- sync_sender.send({}, promise)
42
- expect(
43
- a_request(:post, endpoint).with(
44
- headers: { 'Authorization' => 'Bearer banana' },
45
- ),
46
- ).to have_been_made.once
47
- end
48
-
49
- it "catches exceptions raised while sending" do
50
- # rubocop:disable RSpec/VerifiedDoubles
51
- https = double("foo")
52
- # rubocop:enable RSpec/VerifiedDoubles
53
-
54
- # rubocop:disable RSpec/SubjectStub
55
- allow(sync_sender).to receive(:build_https).and_return(https)
56
- # rubocop:enable RSpec/SubjectStub
57
-
58
- allow(https).to receive(:request).and_raise(StandardError.new('foo'))
59
-
60
- expect(sync_sender.send({}, promise)).to be_an(Airbrake::Promise)
61
- expect(promise.value).to eq('error' => '**Airbrake: HTTP error: foo')
62
- end
63
-
64
- it "logs exceptions raised while sending" do
65
- allow(Airbrake::Loggable.instance).to receive(:error)
66
-
67
- # rubocop:disable RSpec/VerifiedDoubles
68
- https = double("foo")
69
- # rubocop:enable RSpec/VerifiedDoubles
70
-
71
- # rubocop:disable RSpec/SubjectStub
72
- allow(sync_sender).to receive(:build_https).and_return(https)
73
- # rubocop:enable RSpec/SubjectStub
74
-
75
- allow(https).to receive(:request).and_raise(StandardError.new('foo'))
76
-
77
- sync_sender.send({}, promise)
78
-
79
- expect(Airbrake::Loggable.instance).to have_received(:error).with(
80
- /HTTP error: foo/,
81
- )
82
- end
83
-
84
- context "when request body is nil" do
85
- # rubocop:disable RSpec/MultipleExpectations
86
- it "doesn't send data" do
87
- allow(Airbrake::Loggable.instance).to receive(:error)
88
-
89
- allow_any_instance_of(Airbrake::Truncator)
90
- .to receive(:reduce_max_size).and_return(0)
91
-
92
- encoded = Base64.encode64("\xD3\xE6\xBC\x9D\xBA").encode!('ASCII-8BIT')
93
- bad_string = Base64.decode64(encoded)
94
-
95
- ex = AirbrakeTestError.new
96
- backtrace = []
97
- 10.times { backtrace << "bin/rails:3:in `<#{bad_string}>'" }
98
- ex.set_backtrace(backtrace)
99
-
100
- notice = Airbrake::Notice.new(ex)
101
-
102
- expect(sync_sender.send(notice, promise)).to be_an(Airbrake::Promise)
103
- expect(promise.value)
104
- .to match('error' => '**Airbrake: data was not sent because of missing body')
105
-
106
- expect(Airbrake::Loggable.instance).to have_received(:error).with(
107
- /data was not sent/,
108
- )
109
- expect(Airbrake::Loggable.instance).to have_received(:error).with(
110
- /truncation failed/,
111
- )
112
- end
113
- # rubocop:enable RSpec/MultipleExpectations
114
- end
115
-
116
- context "when IP is rate limited" do
117
- let(:endpoint) { %r{https://api.airbrake.io/api/v3/projects/1/notices} }
118
-
119
- before do
120
- stub_request(:post, endpoint).to_return(
121
- status: 429,
122
- body: '{"message":"IP is rate limited"}',
123
- headers: { 'X-RateLimit-Delay' => '1' },
124
- )
125
- end
126
-
127
- # rubocop:disable RSpec/MultipleExpectations
128
- it "returns error" do
129
- p1 = Airbrake::Promise.new
130
- sync_sender.send({}, p1)
131
- expect(p1.value).to match('error' => '**Airbrake: IP is rate limited')
132
-
133
- p2 = Airbrake::Promise.new
134
- sync_sender.send({}, p2)
135
- expect(p2.value).to match('error' => '**Airbrake: IP is rate limited')
136
-
137
- # Wait for X-RateLimit-Delay and then make a new request to make sure p2
138
- # was ignored (no request made for it).
139
- sleep 1
140
-
141
- p3 = Airbrake::Promise.new
142
- sync_sender.send({}, p3)
143
- expect(p3.value).to match('error' => '**Airbrake: IP is rate limited')
144
-
145
- expect(a_request(:post, endpoint)).to have_been_made.twice
146
- end
147
- # rubocop:enable RSpec/MultipleExpectations
148
- end
149
-
150
- context "when the provided method is :put" do
151
- before { stub_request(:put, endpoint).to_return(status: 200, body: '') }
152
-
153
- it "PUTs the request" do
154
- sender = described_class.new(:put)
155
- sender.send({}, promise)
156
- expect(a_request(:put, endpoint)).to have_been_made
157
- end
158
- end
159
-
160
- context "when the provided method is :post" do
161
- it "POSTs the request" do
162
- sender = described_class.new(:post)
163
- sender.send({}, promise)
164
- expect(a_request(:post, endpoint)).to have_been_made
165
- end
166
- end
167
- end
168
- end
data/spec/tdigest_spec.rb DELETED
@@ -1,235 +0,0 @@
1
- RSpec.describe Airbrake::TDigest do
2
- subject(:tdigest) { described_class.new }
3
-
4
- describe "byte serialization" do
5
- it "loads serialized data" do
6
- tdigest.push(60, 100)
7
- 10.times { tdigest.push(rand * 100) }
8
- bytes = tdigest.as_bytes
9
- new_tdigest = described_class.from_bytes(bytes)
10
- expect(new_tdigest.percentile(0.9)).to eq(tdigest.percentile(0.9))
11
- expect(new_tdigest.as_bytes).to eq(bytes)
12
- end
13
-
14
- it "handles zero size" do
15
- bytes = tdigest.as_bytes
16
- expect(described_class.from_bytes(bytes).size).to be_zero
17
- end
18
-
19
- it "preserves compression" do
20
- td = described_class.new(0.001)
21
- bytes = td.as_bytes
22
- new_tdigest = described_class.from_bytes(bytes)
23
- expect(new_tdigest.compression).to eq(td.compression)
24
- end
25
- end
26
-
27
- describe "small byte serialization" do
28
- it "loads serialized data" do
29
- 10.times { tdigest.push(10) }
30
- bytes = tdigest.as_small_bytes
31
- new_tdigest = described_class.from_bytes(bytes)
32
- # Expect some rounding error due to compression
33
- expect(new_tdigest.percentile(0.9).round(5)).to eq(
34
- tdigest.percentile(0.9).round(5),
35
- )
36
- expect(new_tdigest.as_small_bytes).to eq(bytes)
37
- end
38
-
39
- it "handles zero size" do
40
- bytes = tdigest.as_small_bytes
41
- expect(described_class.from_bytes(bytes).size).to be_zero
42
- end
43
- end
44
-
45
- describe "JSON serialization" do
46
- it "loads serialized data" do
47
- tdigest.push(60, 100)
48
- json = tdigest.as_json
49
- new_tdigest = described_class.from_json(json)
50
- expect(new_tdigest.percentile(0.9)).to eq(tdigest.percentile(0.9))
51
- end
52
- end
53
-
54
- describe "#percentile" do
55
- it "returns nil if empty" do
56
- expect(tdigest.percentile(0.90)).to be_nil # This should not crash
57
- end
58
-
59
- it "raises ArgumentError of input not between 0 and 1" do
60
- expect { tdigest.percentile(1.1) }.to raise_error(ArgumentError)
61
- end
62
-
63
- describe "with only single value" do
64
- it "returns the value" do
65
- tdigest.push(60, 100)
66
- expect(tdigest.percentile(0.90)).to eq(60)
67
- end
68
-
69
- it "returns 0 for all percentiles when only 0 present" do
70
- tdigest.push(0)
71
- expect(tdigest.percentile([0.0, 0.5, 1.0])).to eq([0, 0, 0])
72
- end
73
- end
74
-
75
- describe "with alot of uniformly distributed points" do
76
- it "has minimal error" do
77
- seed = srand(1234) # Makes the values a proper fixture
78
- maxerr = 0
79
- values = Array.new(100_000).map { rand }
80
- srand(seed)
81
-
82
- tdigest.push(values)
83
- tdigest.compress!
84
-
85
- 0.step(1, 0.1).each do |i|
86
- q = tdigest.percentile(i)
87
- maxerr = [maxerr, (i - q).abs].max
88
- end
89
-
90
- expect(maxerr).to be < 0.02
91
- end
92
- end
93
- end
94
-
95
- describe "#push" do
96
- it "calls _cumulate so won't crash because of uninitialized mean_cumn" do
97
- tdigest.push(
98
- [
99
- 125000000.0,
100
- 104166666.66666666,
101
- 135416666.66666666,
102
- 104166666.66666666,
103
- 104166666.66666666,
104
- 93750000.0,
105
- 125000000.0,
106
- 62500000.0,
107
- 114583333.33333333,
108
- 156250000.0,
109
- 124909090.90909092,
110
- 104090909.0909091,
111
- 135318181.81818184,
112
- 104090909.0909091,
113
- 104090909.0909091,
114
- 93681818.18181819,
115
- 124909090.90909092,
116
- 62454545.45454546,
117
- 114500000.00000001,
118
- 156136363.63636366,
119
- 123567567.56756756,
120
- 102972972.97297296,
121
- 133864864.86486486,
122
- 102972972.97297296,
123
- 102972972.97297296,
124
- 92675675.67567568,
125
- 123567567.56756756,
126
- 61783783.78378378,
127
- 113270270.27027026,
128
- 154459459.45945945,
129
- 123829787.23404256,
130
- 103191489.36170213,
131
- ],
132
- )
133
- end
134
-
135
- it "does not blow up if data comes in sorted" do
136
- tdigest.push(0..10_000)
137
- expect(tdigest.centroids.size).to be < 5_000
138
- tdigest.compress!
139
- expect(tdigest.centroids.size).to be < 1_000
140
- end
141
- end
142
-
143
- describe "#size" do
144
- it "reports the number of observations" do
145
- n = 10_000
146
- n.times { tdigest.push(rand) }
147
- tdigest.compress!
148
- expect(tdigest.size).to eq(n)
149
- end
150
- end
151
-
152
- describe "#+" do
153
- it "works with empty tdigests" do
154
- other = described_class.new(0.001, 50, 1.2)
155
- expect((tdigest + other).centroids.size).to eq(0)
156
- end
157
-
158
- describe "adding two tdigests" do
159
- let(:other) { described_class.new(0.001, 50, 1.2) }
160
-
161
- before do
162
- [tdigest, other].each do |td|
163
- td.push(60, 100)
164
- 10.times { td.push(rand * 100) }
165
- end
166
- end
167
-
168
- # rubocop:disable RSpec/MultipleExpectations
169
- it "has the parameters of the left argument (the calling tdigest)" do
170
- new_tdigest = tdigest + other
171
- expect(new_tdigest.instance_variable_get(:@delta)).to eq(
172
- tdigest.instance_variable_get(:@delta),
173
- )
174
- expect(new_tdigest.instance_variable_get(:@k)).to eq(
175
- tdigest.instance_variable_get(:@k),
176
- )
177
- expect(new_tdigest.instance_variable_get(:@cx)).to eq(
178
- tdigest.instance_variable_get(:@cx),
179
- )
180
- end
181
- # rubocop:enable RSpec/MultipleExpectations
182
-
183
- it "returns a tdigest with less than or equal centroids" do
184
- new_tdigest = tdigest + other
185
- expect(new_tdigest.centroids.size)
186
- .to be <= tdigest.centroids.size + other.centroids.size
187
- end
188
-
189
- it "has the size of the two digests combined" do
190
- new_tdigest = tdigest + other
191
- expect(new_tdigest.size).to eq(tdigest.size + other.size)
192
- end
193
- end
194
- end
195
-
196
- describe "#merge!" do
197
- it "works with empty tdigests" do
198
- other = described_class.new(0.001, 50, 1.2)
199
- tdigest.merge!(other)
200
- expect(tdigest.centroids.size).to be_zero
201
- end
202
-
203
- describe "with populated tdigests" do
204
- let(:other) { described_class.new(0.001, 50, 1.2) }
205
-
206
- before do
207
- [tdigest, other].each do |td|
208
- td.push(60, 100)
209
- 10.times { td.push(rand * 100) }
210
- end
211
- end
212
-
213
- it "has the parameters of the calling tdigest" do
214
- vars = %i[@delta @k @cx]
215
- expected = vars.map { |v| [v, tdigest.instance_variable_get(v)] }.to_h
216
- tdigest.merge!(other)
217
- vars.each do |v|
218
- expect(tdigest.instance_variable_get(v)).to eq(expected[v])
219
- end
220
- end
221
-
222
- it "returns a tdigest with less than or equal centroids" do
223
- combined_size = tdigest.centroids.size + other.centroids.size
224
- tdigest.merge!(other)
225
- expect(tdigest.centroids.size).to be <= combined_size
226
- end
227
-
228
- it "has the size of the two digests combined" do
229
- combined_size = tdigest.size + other.size
230
- tdigest.merge!(other)
231
- expect(tdigest.size).to eq(combined_size)
232
- end
233
- end
234
- end
235
- end