airbrake-ruby 5.2.0-java → 5.2.1-java
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.
- checksums.yaml +4 -4
- data/lib/airbrake-ruby.rb +3 -2
- data/lib/airbrake-ruby/async_sender.rb +3 -1
- data/lib/airbrake-ruby/context.rb +51 -0
- data/lib/airbrake-ruby/filter_chain.rb +2 -0
- data/lib/airbrake-ruby/filters/context_filter.rb +4 -5
- data/lib/airbrake-ruby/filters/exception_attributes_filter.rb +1 -1
- data/lib/airbrake-ruby/filters/git_last_checkout_filter.rb +1 -1
- data/lib/airbrake-ruby/filters/git_revision_filter.rb +1 -1
- data/lib/airbrake-ruby/filters/keys_filter.rb +2 -2
- data/lib/airbrake-ruby/filters/sql_filter.rb +2 -2
- data/lib/airbrake-ruby/filters/thread_filter.rb +1 -1
- data/lib/airbrake-ruby/ignorable.rb +0 -2
- data/lib/airbrake-ruby/notice_notifier.rb +3 -4
- data/lib/airbrake-ruby/performance_notifier.rb +1 -2
- data/lib/airbrake-ruby/remote_settings/settings_data.rb +1 -1
- data/lib/airbrake-ruby/tdigest.rb +7 -6
- data/lib/airbrake-ruby/thread_pool.rb +5 -3
- data/lib/airbrake-ruby/timed_trace.rb +1 -3
- data/lib/airbrake-ruby/version.rb +1 -1
- data/spec/airbrake_spec.rb +139 -76
- data/spec/async_sender_spec.rb +10 -8
- data/spec/backtrace_spec.rb +13 -10
- data/spec/benchmark_spec.rb +5 -3
- data/spec/code_hunk_spec.rb +24 -15
- data/spec/config/processor_spec.rb +12 -4
- data/spec/config/validator_spec.rb +5 -2
- data/spec/config_spec.rb +24 -16
- data/spec/context_spec.rb +54 -0
- data/spec/deploy_notifier_spec.rb +6 -4
- data/spec/file_cache_spec.rb +1 -0
- data/spec/filter_chain_spec.rb +29 -24
- data/spec/filters/context_filter_spec.rb +14 -5
- data/spec/filters/dependency_filter_spec.rb +3 -1
- data/spec/filters/exception_attributes_filter_spec.rb +5 -3
- data/spec/filters/gem_root_filter_spec.rb +5 -2
- data/spec/filters/git_last_checkout_filter_spec.rb +10 -12
- data/spec/filters/git_repository_filter.rb +9 -9
- data/spec/filters/git_revision_filter_spec.rb +19 -19
- data/spec/filters/keys_allowlist_spec.rb +25 -16
- data/spec/filters/keys_blocklist_spec.rb +25 -18
- data/spec/filters/root_directory_filter_spec.rb +3 -3
- data/spec/filters/sql_filter_spec.rb +26 -26
- data/spec/filters/system_exit_filter_spec.rb +4 -2
- data/spec/filters/thread_filter_spec.rb +15 -13
- data/spec/loggable_spec.rb +2 -2
- data/spec/monotonic_time_spec.rb +8 -6
- data/spec/nested_exception_spec.rb +46 -46
- data/spec/notice_notifier/options_spec.rb +23 -13
- data/spec/notice_notifier_spec.rb +52 -47
- data/spec/notice_spec.rb +6 -2
- data/spec/performance_notifier_spec.rb +67 -60
- data/spec/promise_spec.rb +38 -32
- data/spec/remote_settings/callback_spec.rb +27 -8
- data/spec/remote_settings/settings_data_spec.rb +4 -4
- data/spec/remote_settings_spec.rb +18 -8
- data/spec/response_spec.rb +34 -12
- data/spec/stashable_spec.rb +5 -5
- data/spec/stat_spec.rb +7 -5
- data/spec/sync_sender_spec.rb +49 -16
- data/spec/tdigest_spec.rb +60 -55
- data/spec/thread_pool_spec.rb +65 -55
- data/spec/time_truncate_spec.rb +4 -2
- data/spec/timed_trace_spec.rb +32 -30
- data/spec/truncator_spec.rb +72 -43
- metadata +51 -48
data/spec/stashable_spec.rb
CHANGED
@@ -5,19 +5,19 @@ RSpec.describe Airbrake::Stashable do
|
|
5
5
|
end
|
6
6
|
|
7
7
|
describe "#stash" do
|
8
|
-
subject { klass.new }
|
8
|
+
subject(:instance) { klass.new }
|
9
9
|
|
10
10
|
it "returns a hash" do
|
11
|
-
expect(
|
11
|
+
expect(instance.stash).to be_a(Hash)
|
12
12
|
end
|
13
13
|
|
14
14
|
it "returns an empty hash" do
|
15
|
-
expect(
|
15
|
+
expect(instance.stash).to be_empty
|
16
16
|
end
|
17
17
|
|
18
18
|
it "remembers what was put in the stash" do
|
19
|
-
|
20
|
-
expect(
|
19
|
+
instance.stash[:foo] = 1
|
20
|
+
expect(instance.stash[:foo]).to eq(1)
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
data/spec/stat_spec.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
RSpec.describe Airbrake::Stat do
|
2
|
+
subject(:stat) { described_class.new }
|
3
|
+
|
2
4
|
describe "#to_h" do
|
3
5
|
it "converts to a hash" do
|
4
|
-
expect(
|
6
|
+
expect(stat.to_h).to eq(
|
5
7
|
'count' => 0,
|
6
8
|
'sum' => 0.0,
|
7
9
|
'sumsq' => 0.0,
|
@@ -11,19 +13,19 @@ RSpec.describe Airbrake::Stat do
|
|
11
13
|
end
|
12
14
|
|
13
15
|
describe "#increment_ms" do
|
14
|
-
before {
|
16
|
+
before { stat.increment_ms(1000) }
|
15
17
|
|
16
18
|
its(:sum) { is_expected.to eq(1000) }
|
17
19
|
its(:sumsq) { is_expected.to eq(1000000) }
|
18
20
|
|
19
21
|
it "updates tdigest" do
|
20
|
-
expect(
|
22
|
+
expect(stat.tdigest.size).to eq(1)
|
21
23
|
end
|
22
24
|
end
|
23
25
|
|
24
26
|
describe "#inspect" do
|
25
27
|
it "provides custom inspect output" do
|
26
|
-
expect(
|
28
|
+
expect(stat.inspect).to eq(
|
27
29
|
'#<struct Airbrake::Stat count=0, sum=0.0, sumsq=0.0>',
|
28
30
|
)
|
29
31
|
end
|
@@ -31,7 +33,7 @@ RSpec.describe Airbrake::Stat do
|
|
31
33
|
|
32
34
|
describe "#pretty_print" do
|
33
35
|
it "is an alias of #inspect" do
|
34
|
-
expect(
|
36
|
+
expect(stat.method(:pretty_print)).to eql(stat.method(:inspect))
|
35
37
|
end
|
36
38
|
end
|
37
39
|
end
|
data/spec/sync_sender_spec.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
RSpec.describe Airbrake::SyncSender do
|
2
|
+
subject(:sync_sender) { described_class.new }
|
3
|
+
|
2
4
|
before do
|
3
5
|
Airbrake::Config.instance = Airbrake::Config.new(
|
4
6
|
project_id: 1, project_key: 'banana',
|
@@ -14,7 +16,7 @@ RSpec.describe Airbrake::SyncSender do
|
|
14
16
|
before { stub_request(:post, endpoint).to_return(body: '{}') }
|
15
17
|
|
16
18
|
it "sets the Content-Type header to JSON" do
|
17
|
-
|
19
|
+
sync_sender.send({}, promise)
|
18
20
|
expect(
|
19
21
|
a_request(:post, endpoint).with(
|
20
22
|
headers: { 'Content-Type' => 'application/json' },
|
@@ -23,7 +25,7 @@ RSpec.describe Airbrake::SyncSender do
|
|
23
25
|
end
|
24
26
|
|
25
27
|
it "sets the User-Agent header to the notifier slug" do
|
26
|
-
|
28
|
+
sync_sender.send({}, promise)
|
27
29
|
expect(
|
28
30
|
a_request(:post, endpoint).with(
|
29
31
|
headers: {
|
@@ -36,7 +38,7 @@ RSpec.describe Airbrake::SyncSender do
|
|
36
38
|
end
|
37
39
|
|
38
40
|
it "sets the Authorization header to the project key" do
|
39
|
-
|
41
|
+
sync_sender.send({}, promise)
|
40
42
|
expect(
|
41
43
|
a_request(:post, endpoint).with(
|
42
44
|
headers: { 'Authorization' => 'Bearer banana' },
|
@@ -45,19 +47,46 @@ RSpec.describe Airbrake::SyncSender do
|
|
45
47
|
end
|
46
48
|
|
47
49
|
it "catches exceptions raised while sending" do
|
50
|
+
# rubocop:disable RSpec/VerifiedDoubles
|
48
51
|
https = double("foo")
|
49
|
-
|
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
|
+
|
50
58
|
allow(https).to receive(:request).and_raise(StandardError.new('foo'))
|
51
|
-
|
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(
|
52
80
|
/HTTP error: foo/,
|
53
81
|
)
|
54
|
-
expect(subject.send({}, promise)).to be_an(Airbrake::Promise)
|
55
|
-
expect(promise.value).to eq('error' => '**Airbrake: HTTP error: foo')
|
56
82
|
end
|
57
83
|
|
58
84
|
context "when request body is nil" do
|
85
|
+
# rubocop:disable RSpec/MultipleExpectations
|
59
86
|
it "doesn't send data" do
|
60
|
-
|
87
|
+
allow(Airbrake::Loggable.instance).to receive(:error)
|
88
|
+
|
89
|
+
allow_any_instance_of(Airbrake::Truncator)
|
61
90
|
.to receive(:reduce_max_size).and_return(0)
|
62
91
|
|
63
92
|
encoded = Base64.encode64("\xD3\xE6\xBC\x9D\xBA").encode!('ASCII-8BIT')
|
@@ -70,16 +99,18 @@ RSpec.describe Airbrake::SyncSender do
|
|
70
99
|
|
71
100
|
notice = Airbrake::Notice.new(ex)
|
72
101
|
|
73
|
-
expect(
|
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(
|
74
107
|
/data was not sent/,
|
75
108
|
)
|
76
|
-
expect(Airbrake::Loggable.instance).to
|
109
|
+
expect(Airbrake::Loggable.instance).to have_received(:error).with(
|
77
110
|
/truncation failed/,
|
78
111
|
)
|
79
|
-
expect(subject.send(notice, promise)).to be_an(Airbrake::Promise)
|
80
|
-
expect(promise.value)
|
81
|
-
.to match('error' => '**Airbrake: data was not sent because of missing body')
|
82
112
|
end
|
113
|
+
# rubocop:enable RSpec/MultipleExpectations
|
83
114
|
end
|
84
115
|
|
85
116
|
context "when IP is rate limited" do
|
@@ -93,13 +124,14 @@ RSpec.describe Airbrake::SyncSender do
|
|
93
124
|
)
|
94
125
|
end
|
95
126
|
|
127
|
+
# rubocop:disable RSpec/MultipleExpectations
|
96
128
|
it "returns error" do
|
97
129
|
p1 = Airbrake::Promise.new
|
98
|
-
|
130
|
+
sync_sender.send({}, p1)
|
99
131
|
expect(p1.value).to match('error' => '**Airbrake: IP is rate limited')
|
100
132
|
|
101
133
|
p2 = Airbrake::Promise.new
|
102
|
-
|
134
|
+
sync_sender.send({}, p2)
|
103
135
|
expect(p2.value).to match('error' => '**Airbrake: IP is rate limited')
|
104
136
|
|
105
137
|
# Wait for X-RateLimit-Delay and then make a new request to make sure p2
|
@@ -107,11 +139,12 @@ RSpec.describe Airbrake::SyncSender do
|
|
107
139
|
sleep 1
|
108
140
|
|
109
141
|
p3 = Airbrake::Promise.new
|
110
|
-
|
142
|
+
sync_sender.send({}, p3)
|
111
143
|
expect(p3.value).to match('error' => '**Airbrake: IP is rate limited')
|
112
144
|
|
113
145
|
expect(a_request(:post, endpoint)).to have_been_made.twice
|
114
146
|
end
|
147
|
+
# rubocop:enable RSpec/MultipleExpectations
|
115
148
|
end
|
116
149
|
|
117
150
|
context "when the provided method is :put" do
|
data/spec/tdigest_spec.rb
CHANGED
@@ -1,16 +1,18 @@
|
|
1
1
|
RSpec.describe Airbrake::TDigest do
|
2
|
+
subject(:tdigest) { described_class.new }
|
3
|
+
|
2
4
|
describe "byte serialization" do
|
3
5
|
it "loads serialized data" do
|
4
|
-
|
5
|
-
10.times {
|
6
|
-
bytes =
|
6
|
+
tdigest.push(60, 100)
|
7
|
+
10.times { tdigest.push(rand * 100) }
|
8
|
+
bytes = tdigest.as_bytes
|
7
9
|
new_tdigest = described_class.from_bytes(bytes)
|
8
|
-
expect(new_tdigest.percentile(0.9)).to eq(
|
10
|
+
expect(new_tdigest.percentile(0.9)).to eq(tdigest.percentile(0.9))
|
9
11
|
expect(new_tdigest.as_bytes).to eq(bytes)
|
10
12
|
end
|
11
13
|
|
12
14
|
it "handles zero size" do
|
13
|
-
bytes =
|
15
|
+
bytes = tdigest.as_bytes
|
14
16
|
expect(described_class.from_bytes(bytes).size).to be_zero
|
15
17
|
end
|
16
18
|
|
@@ -24,65 +26,64 @@ RSpec.describe Airbrake::TDigest do
|
|
24
26
|
|
25
27
|
describe "small byte serialization" do
|
26
28
|
it "loads serialized data" do
|
27
|
-
10.times {
|
28
|
-
bytes =
|
29
|
+
10.times { tdigest.push(10) }
|
30
|
+
bytes = tdigest.as_small_bytes
|
29
31
|
new_tdigest = described_class.from_bytes(bytes)
|
30
32
|
# Expect some rounding error due to compression
|
31
33
|
expect(new_tdigest.percentile(0.9).round(5)).to eq(
|
32
|
-
|
34
|
+
tdigest.percentile(0.9).round(5),
|
33
35
|
)
|
34
36
|
expect(new_tdigest.as_small_bytes).to eq(bytes)
|
35
37
|
end
|
36
38
|
|
37
39
|
it "handles zero size" do
|
38
|
-
bytes =
|
40
|
+
bytes = tdigest.as_small_bytes
|
39
41
|
expect(described_class.from_bytes(bytes).size).to be_zero
|
40
42
|
end
|
41
43
|
end
|
42
44
|
|
43
45
|
describe "JSON serialization" do
|
44
46
|
it "loads serialized data" do
|
45
|
-
|
46
|
-
json =
|
47
|
+
tdigest.push(60, 100)
|
48
|
+
json = tdigest.as_json
|
47
49
|
new_tdigest = described_class.from_json(json)
|
48
|
-
expect(new_tdigest.percentile(0.9)).to eq(
|
50
|
+
expect(new_tdigest.percentile(0.9)).to eq(tdigest.percentile(0.9))
|
49
51
|
end
|
50
52
|
end
|
51
53
|
|
52
54
|
describe "#percentile" do
|
53
55
|
it "returns nil if empty" do
|
54
|
-
expect(
|
56
|
+
expect(tdigest.percentile(0.90)).to be_nil # This should not crash
|
55
57
|
end
|
56
58
|
|
57
59
|
it "raises ArgumentError of input not between 0 and 1" do
|
58
|
-
expect {
|
60
|
+
expect { tdigest.percentile(1.1) }.to raise_error(ArgumentError)
|
59
61
|
end
|
60
62
|
|
61
63
|
describe "with only single value" do
|
62
64
|
it "returns the value" do
|
63
|
-
|
64
|
-
expect(
|
65
|
+
tdigest.push(60, 100)
|
66
|
+
expect(tdigest.percentile(0.90)).to eq(60)
|
65
67
|
end
|
66
68
|
|
67
69
|
it "returns 0 for all percentiles when only 0 present" do
|
68
|
-
|
69
|
-
expect(
|
70
|
+
tdigest.push(0)
|
71
|
+
expect(tdigest.percentile([0.0, 0.5, 1.0])).to eq([0, 0, 0])
|
70
72
|
end
|
71
73
|
end
|
72
74
|
|
73
75
|
describe "with alot of uniformly distributed points" do
|
74
76
|
it "has minimal error" do
|
75
77
|
seed = srand(1234) # Makes the values a proper fixture
|
76
|
-
N = 100_000
|
77
78
|
maxerr = 0
|
78
|
-
values = Array.new(
|
79
|
+
values = Array.new(100_000).map { rand }
|
79
80
|
srand(seed)
|
80
81
|
|
81
|
-
|
82
|
-
|
82
|
+
tdigest.push(values)
|
83
|
+
tdigest.compress!
|
83
84
|
|
84
85
|
0.step(1, 0.1).each do |i|
|
85
|
-
q =
|
86
|
+
q = tdigest.percentile(i)
|
86
87
|
maxerr = [maxerr, (i - q).abs].max
|
87
88
|
end
|
88
89
|
|
@@ -93,7 +94,7 @@ RSpec.describe Airbrake::TDigest do
|
|
93
94
|
|
94
95
|
describe "#push" do
|
95
96
|
it "calls _cumulate so won't crash because of uninitialized mean_cumn" do
|
96
|
-
|
97
|
+
tdigest.push(
|
97
98
|
[
|
98
99
|
125000000.0,
|
99
100
|
104166666.66666666,
|
@@ -132,59 +133,62 @@ RSpec.describe Airbrake::TDigest do
|
|
132
133
|
end
|
133
134
|
|
134
135
|
it "does not blow up if data comes in sorted" do
|
135
|
-
|
136
|
-
expect(
|
137
|
-
|
138
|
-
expect(
|
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
|
139
140
|
end
|
140
141
|
end
|
141
142
|
|
142
143
|
describe "#size" do
|
143
144
|
it "reports the number of observations" do
|
144
145
|
n = 10_000
|
145
|
-
n.times {
|
146
|
-
|
147
|
-
expect(
|
146
|
+
n.times { tdigest.push(rand) }
|
147
|
+
tdigest.compress!
|
148
|
+
expect(tdigest.size).to eq(n)
|
148
149
|
end
|
149
150
|
end
|
150
151
|
|
151
152
|
describe "#+" do
|
152
153
|
it "works with empty tdigests" do
|
153
154
|
other = described_class.new(0.001, 50, 1.2)
|
154
|
-
expect((
|
155
|
+
expect((tdigest + other).centroids.size).to eq(0)
|
155
156
|
end
|
156
157
|
|
157
158
|
describe "adding two tdigests" do
|
159
|
+
let(:other) { described_class.new(0.001, 50, 1.2) }
|
160
|
+
|
158
161
|
before do
|
159
|
-
|
160
|
-
[subject, @other].each do |td|
|
162
|
+
[tdigest, other].each do |td|
|
161
163
|
td.push(60, 100)
|
162
164
|
10.times { td.push(rand * 100) }
|
163
165
|
end
|
164
166
|
end
|
165
167
|
|
168
|
+
# rubocop:disable RSpec/MultipleExpectations
|
166
169
|
it "has the parameters of the left argument (the calling tdigest)" do
|
167
|
-
new_tdigest =
|
170
|
+
new_tdigest = tdigest + other
|
168
171
|
expect(new_tdigest.instance_variable_get(:@delta)).to eq(
|
169
|
-
|
172
|
+
tdigest.instance_variable_get(:@delta),
|
170
173
|
)
|
171
174
|
expect(new_tdigest.instance_variable_get(:@k)).to eq(
|
172
|
-
|
175
|
+
tdigest.instance_variable_get(:@k),
|
173
176
|
)
|
174
177
|
expect(new_tdigest.instance_variable_get(:@cx)).to eq(
|
175
|
-
|
178
|
+
tdigest.instance_variable_get(:@cx),
|
176
179
|
)
|
177
180
|
end
|
181
|
+
# rubocop:enable RSpec/MultipleExpectations
|
178
182
|
|
179
183
|
it "returns a tdigest with less than or equal centroids" do
|
180
|
-
new_tdigest =
|
184
|
+
new_tdigest = tdigest + other
|
181
185
|
expect(new_tdigest.centroids.size)
|
182
|
-
.to be <=
|
186
|
+
.to be <= tdigest.centroids.size + other.centroids.size
|
183
187
|
end
|
184
188
|
|
185
189
|
it "has the size of the two digests combined" do
|
186
|
-
new_tdigest =
|
187
|
-
expect(new_tdigest.size).to eq(
|
190
|
+
new_tdigest = tdigest + other
|
191
|
+
expect(new_tdigest.size).to eq(tdigest.size + other.size)
|
188
192
|
end
|
189
193
|
end
|
190
194
|
end
|
@@ -192,14 +196,15 @@ RSpec.describe Airbrake::TDigest do
|
|
192
196
|
describe "#merge!" do
|
193
197
|
it "works with empty tdigests" do
|
194
198
|
other = described_class.new(0.001, 50, 1.2)
|
195
|
-
|
196
|
-
expect(
|
199
|
+
tdigest.merge!(other)
|
200
|
+
expect(tdigest.centroids.size).to be_zero
|
197
201
|
end
|
198
202
|
|
199
203
|
describe "with populated tdigests" do
|
204
|
+
let(:other) { described_class.new(0.001, 50, 1.2) }
|
205
|
+
|
200
206
|
before do
|
201
|
-
|
202
|
-
[subject, @other].each do |td|
|
207
|
+
[tdigest, other].each do |td|
|
203
208
|
td.push(60, 100)
|
204
209
|
10.times { td.push(rand * 100) }
|
205
210
|
end
|
@@ -207,23 +212,23 @@ RSpec.describe Airbrake::TDigest do
|
|
207
212
|
|
208
213
|
it "has the parameters of the calling tdigest" do
|
209
214
|
vars = %i[@delta @k @cx]
|
210
|
-
expected =
|
211
|
-
|
215
|
+
expected = vars.map { |v| [v, tdigest.instance_variable_get(v)] }.to_h
|
216
|
+
tdigest.merge!(other)
|
212
217
|
vars.each do |v|
|
213
|
-
expect(
|
218
|
+
expect(tdigest.instance_variable_get(v)).to eq(expected[v])
|
214
219
|
end
|
215
220
|
end
|
216
221
|
|
217
222
|
it "returns a tdigest with less than or equal centroids" do
|
218
|
-
combined_size =
|
219
|
-
|
220
|
-
expect(
|
223
|
+
combined_size = tdigest.centroids.size + other.centroids.size
|
224
|
+
tdigest.merge!(other)
|
225
|
+
expect(tdigest.centroids.size).to be <= combined_size
|
221
226
|
end
|
222
227
|
|
223
228
|
it "has the size of the two digests combined" do
|
224
|
-
combined_size =
|
225
|
-
|
226
|
-
expect(
|
229
|
+
combined_size = tdigest.size + other.size
|
230
|
+
tdigest.merge!(other)
|
231
|
+
expect(tdigest.size).to eq(combined_size)
|
227
232
|
end
|
228
233
|
end
|
229
234
|
end
|