airbrake-ruby 4.13.3-java → 5.0.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/lib/airbrake-ruby.rb +23 -32
  3. data/lib/airbrake-ruby/async_sender.rb +1 -1
  4. data/lib/airbrake-ruby/backtrace.rb +6 -5
  5. data/lib/airbrake-ruby/config.rb +37 -13
  6. data/lib/airbrake-ruby/config/processor.rb +84 -0
  7. data/lib/airbrake-ruby/config/validator.rb +6 -0
  8. data/lib/airbrake-ruby/file_cache.rb +1 -1
  9. data/lib/airbrake-ruby/filter_chain.rb +16 -1
  10. data/lib/airbrake-ruby/filters/dependency_filter.rb +1 -0
  11. data/lib/airbrake-ruby/filters/gem_root_filter.rb +1 -0
  12. data/lib/airbrake-ruby/filters/git_last_checkout_filter.rb +3 -3
  13. data/lib/airbrake-ruby/filters/git_repository_filter.rb +3 -0
  14. data/lib/airbrake-ruby/filters/git_revision_filter.rb +2 -0
  15. data/lib/airbrake-ruby/filters/{keys_whitelist.rb → keys_allowlist.rb} +3 -3
  16. data/lib/airbrake-ruby/filters/{keys_blacklist.rb → keys_blocklist.rb} +3 -3
  17. data/lib/airbrake-ruby/filters/keys_filter.rb +26 -18
  18. data/lib/airbrake-ruby/filters/root_directory_filter.rb +1 -0
  19. data/lib/airbrake-ruby/filters/sql_filter.rb +4 -4
  20. data/lib/airbrake-ruby/filters/system_exit_filter.rb +1 -0
  21. data/lib/airbrake-ruby/filters/thread_filter.rb +2 -0
  22. data/lib/airbrake-ruby/ignorable.rb +1 -0
  23. data/lib/airbrake-ruby/notice.rb +1 -8
  24. data/lib/airbrake-ruby/notice_notifier.rb +7 -0
  25. data/lib/airbrake-ruby/performance_breakdown.rb +1 -6
  26. data/lib/airbrake-ruby/performance_notifier.rb +2 -15
  27. data/lib/airbrake-ruby/promise.rb +1 -0
  28. data/lib/airbrake-ruby/query.rb +1 -6
  29. data/lib/airbrake-ruby/queue.rb +1 -8
  30. data/lib/airbrake-ruby/remote_settings.rb +145 -0
  31. data/lib/airbrake-ruby/remote_settings/settings_data.rb +120 -0
  32. data/lib/airbrake-ruby/request.rb +1 -8
  33. data/lib/airbrake-ruby/stat.rb +1 -12
  34. data/lib/airbrake-ruby/sync_sender.rb +3 -2
  35. data/lib/airbrake-ruby/tdigest.rb +2 -0
  36. data/lib/airbrake-ruby/thread_pool.rb +2 -0
  37. data/lib/airbrake-ruby/truncator.rb +8 -2
  38. data/lib/airbrake-ruby/version.rb +11 -1
  39. data/spec/airbrake_spec.rb +71 -36
  40. data/spec/backtrace_spec.rb +26 -26
  41. data/spec/code_hunk_spec.rb +2 -2
  42. data/spec/config/processor_spec.rb +209 -0
  43. data/spec/config/validator_spec.rb +18 -1
  44. data/spec/config_spec.rb +13 -6
  45. data/spec/filter_chain_spec.rb +27 -0
  46. data/spec/filters/gem_root_filter_spec.rb +4 -4
  47. data/spec/filters/git_last_checkout_filter_spec.rb +20 -3
  48. data/spec/filters/{keys_whitelist_spec.rb → keys_allowlist_spec.rb} +11 -10
  49. data/spec/filters/{keys_blacklist_spec.rb → keys_blocklist_spec.rb} +20 -10
  50. data/spec/filters/root_directory_filter_spec.rb +4 -4
  51. data/spec/filters/sql_filter_spec.rb +5 -5
  52. data/spec/notice_notifier/options_spec.rb +6 -6
  53. data/spec/notice_notifier_spec.rb +2 -2
  54. data/spec/notice_spec.rb +1 -1
  55. data/spec/performance_breakdown_spec.rb +0 -12
  56. data/spec/performance_notifier_spec.rb +2 -27
  57. data/spec/query_spec.rb +1 -11
  58. data/spec/queue_spec.rb +1 -13
  59. data/spec/remote_settings/settings_data_spec.rb +365 -0
  60. data/spec/remote_settings_spec.rb +230 -0
  61. data/spec/request_spec.rb +1 -13
  62. data/spec/spec_helper.rb +4 -4
  63. data/spec/stat_spec.rb +0 -9
  64. data/spec/sync_sender_spec.rb +3 -1
  65. data/spec/thread_pool_spec.rb +25 -5
  66. metadata +22 -14
@@ -89,4 +89,31 @@ RSpec.describe Airbrake::FilterChain do
89
89
  expect(subject.inspect).to eq('[Proc]')
90
90
  end
91
91
  end
92
+
93
+ describe "#includes?" do
94
+ context "when a custom filter class is included in the filter chain" do
95
+ it "returns true" do
96
+ klass = Class.new {}
97
+
98
+ subject.add_filter(klass.new)
99
+ expect(subject.includes?(klass)).to eq(true)
100
+ end
101
+ end
102
+
103
+ context "when Proc filter class is included in the filter chain" do
104
+ it "returns true" do
105
+ subject.add_filter(proc {})
106
+ expect(subject.includes?(Proc)).to eq(true)
107
+ end
108
+ end
109
+
110
+ context "when filter class is NOT included in the filter chain" do
111
+ it "returns false" do
112
+ klass = Class.new {}
113
+
114
+ subject.add_filter(proc {})
115
+ expect(subject.includes?(klass)).to eq(false)
116
+ end
117
+ end
118
+ end
92
119
  end
@@ -7,18 +7,18 @@ RSpec.describe Airbrake::Filters::GemRootFilter do
7
7
  after { 2.times { Gem.path.pop } }
8
8
 
9
9
  it "replaces gem root in the backtrace with a label" do
10
- # rubocop:disable Metrics/LineLength
10
+ # rubocop:disable Layout/LineLength
11
11
  notice[:errors].first[:backtrace] = [
12
12
  { file: "/home/kyrylo/code/airbrake/ruby/spec/spec_helper.rb" },
13
13
  { file: "#{root1}/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb" },
14
14
  { file: "/opt/rubies/ruby-2.2.2/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb" },
15
15
  { file: "#{root2}/gems/rspec-core-3.3.2/exe/rspec" },
16
16
  ]
17
- # rubocop:enable Metrics/LineLength
17
+ # rubocop:enable Layout/LineLength
18
18
 
19
19
  subject.call(notice)
20
20
 
21
- # rubocop:disable Metrics/LineLength
21
+ # rubocop:disable Layout/LineLength
22
22
  expect(notice[:errors].first[:backtrace]).to(
23
23
  eq(
24
24
  [
@@ -29,7 +29,7 @@ RSpec.describe Airbrake::Filters::GemRootFilter do
29
29
  ],
30
30
  ),
31
31
  )
32
- # rubocop:enable Metrics/LineLength
32
+ # rubocop:enable Layout/LineLength
33
33
  end
34
34
 
35
35
  it "does not filter file when it is nil" do
@@ -21,24 +21,41 @@ RSpec.describe Airbrake::Filters::GitLastCheckoutFilter do
21
21
  end
22
22
 
23
23
  context "when .git directory exists" do
24
- before { subject.call(notice) }
24
+ context "when AIRBRAKE_DEPLOY_USERNAME env variable is set" do
25
+ before { ENV['AIRBRAKE_DEPLOY_USERNAME'] = 'deployer' }
25
26
 
26
- it "attaches last checkouted username" do
27
- expect(notice[:context][:lastCheckout][:username]).not_to be_empty
27
+ it "attaches username from the environment" do
28
+ subject.call(notice)
29
+ expect(notice[:context][:lastCheckout][:username]).to eq('deployer')
30
+ end
31
+ end
32
+
33
+ context "when AIRBRAKE_DEPLOY_USERNAME env variable is NOT set" do
34
+ before { ENV['AIRBRAKE_DEPLOY_USERNAME'] = nil }
35
+
36
+ it "attaches last checkouted username" do
37
+ subject.call(notice)
38
+ username = notice[:context][:lastCheckout][:username]
39
+ expect(username).not_to be_empty
40
+ expect(username).not_to be_nil
41
+ end
28
42
  end
29
43
 
30
44
  it "attaches last checkouted email" do
45
+ subject.call(notice)
31
46
  expect(notice[:context][:lastCheckout][:email]).to(
32
47
  match(/\A\w+[\w.-]*@\w+\.?\w+?\z/),
33
48
  )
34
49
  end
35
50
 
36
51
  it "attaches last checkouted revision" do
52
+ subject.call(notice)
37
53
  expect(notice[:context][:lastCheckout][:revision]).not_to be_empty
38
54
  expect(notice[:context][:lastCheckout][:revision].size).to eq(40)
39
55
  end
40
56
 
41
57
  it "attaches last checkouted time" do
58
+ subject.call(notice)
42
59
  expect(notice[:context][:lastCheckout][:time]).not_to be_empty
43
60
  expect(notice[:context][:lastCheckout][:time].size).to eq(25)
44
61
  end
@@ -1,4 +1,4 @@
1
- RSpec.describe Airbrake::Filters::KeysWhitelist do
1
+ RSpec.describe Airbrake::Filters::KeysAllowlist do
2
2
  subject { described_class.new(patterns) }
3
3
 
4
4
  let(:notice) { Airbrake::Notice.new(AirbrakeTestError.new) }
@@ -70,10 +70,10 @@ RSpec.describe Airbrake::Filters::KeysWhitelist do
70
70
 
71
71
  it "logs an error" do
72
72
  expect(Airbrake::Loggable.instance).to receive(:error).with(
73
- /KeysWhitelist is invalid.+patterns: \[#<Object:.+>\]/,
73
+ /KeysAllowlist is invalid.+patterns: \[#<Object:.+>\]/,
74
74
  )
75
- keys_whitelist = described_class.new(patterns)
76
- keys_whitelist.call(notice)
75
+ keys_allowlist = described_class.new(patterns)
76
+ keys_allowlist.call(notice)
77
77
  end
78
78
  end
79
79
 
@@ -83,10 +83,10 @@ RSpec.describe Airbrake::Filters::KeysWhitelist do
83
83
  context "and when the filter is called once" do
84
84
  it "logs an error" do
85
85
  expect(Airbrake::Loggable.instance).to receive(:error).with(
86
- /KeysWhitelist is invalid.+patterns: \[#<Proc:.+>\]/,
86
+ /KeysAllowlist is invalid.+patterns: \[#<Proc:.+>\]/,
87
87
  )
88
- keys_whitelist = described_class.new(patterns)
89
- keys_whitelist.call(notice)
88
+ keys_allowlist = described_class.new(patterns)
89
+ keys_allowlist.call(notice)
90
90
  end
91
91
 
92
92
  include_examples(
@@ -113,10 +113,10 @@ RSpec.describe Airbrake::Filters::KeysWhitelist do
113
113
 
114
114
  it "logs an error" do
115
115
  expect(Airbrake::Loggable.instance).to receive(:error).with(
116
- /KeysWhitelist is invalid.+patterns: \[#<Object:.+>\]/,
116
+ /KeysAllowlist is invalid.+patterns: \[#<Object:.+>\]/,
117
117
  )
118
- keys_whitelist = described_class.new(patterns)
119
- keys_whitelist.call(notice)
118
+ keys_allowlist = described_class.new(patterns)
119
+ keys_allowlist.call(notice)
120
120
  end
121
121
  end
122
122
 
@@ -151,6 +151,7 @@ RSpec.describe Airbrake::Filters::KeysWhitelist do
151
151
  # thing. One is a Java exception, the other is a Ruby exception.
152
152
  # Likely a bug: https://github.com/jruby/jruby/issues/1903
153
153
  raise ex unless RUBY_ENGINE == 'jruby'
154
+
154
155
  expect { subject.call(notice) }.to raise_error(java.lang.StackOverflowError)
155
156
  end
156
157
  end
@@ -1,4 +1,4 @@
1
- RSpec.describe Airbrake::Filters::KeysBlacklist do
1
+ RSpec.describe Airbrake::Filters::KeysBlocklist do
2
2
  subject { described_class.new(patterns) }
3
3
 
4
4
  let(:notice) { Airbrake::Notice.new(AirbrakeTestError.new) }
@@ -91,10 +91,10 @@ RSpec.describe Airbrake::Filters::KeysBlacklist do
91
91
 
92
92
  it "logs an error" do
93
93
  expect(Airbrake::Loggable.instance).to receive(:error).with(
94
- /KeysBlacklist is invalid.+patterns: \[#<Object:.+>\]/,
94
+ /KeysBlocklist is invalid.+patterns: \[#<Object:.+>\]/,
95
95
  )
96
- keys_blacklist = described_class.new(patterns)
97
- keys_blacklist.call(notice)
96
+ keys_blocklist = described_class.new(patterns)
97
+ keys_blocklist.call(notice)
98
98
  end
99
99
  end
100
100
 
@@ -104,10 +104,10 @@ RSpec.describe Airbrake::Filters::KeysBlacklist do
104
104
  context "and when the filter is called once" do
105
105
  it "logs an error" do
106
106
  expect(Airbrake::Loggable.instance).to receive(:error).with(
107
- /KeysBlacklist is invalid.+patterns: \[#<Proc:.+>\]/,
107
+ /KeysBlocklist is invalid.+patterns: \[#<Proc:.+>\]/,
108
108
  )
109
- keys_blacklist = described_class.new(patterns)
110
- keys_blacklist.call(notice)
109
+ keys_blocklist = described_class.new(patterns)
110
+ keys_blocklist.call(notice)
111
111
  end
112
112
  end
113
113
 
@@ -133,10 +133,10 @@ RSpec.describe Airbrake::Filters::KeysBlacklist do
133
133
 
134
134
  it "logs an error" do
135
135
  expect(Airbrake::Loggable.instance).to receive(:error).with(
136
- /KeysBlacklist is invalid.+patterns: \[#<Object:.+>\]/,
136
+ /KeysBlocklist is invalid.+patterns: \[#<Object:.+>\]/,
137
137
  )
138
- keys_blacklist = described_class.new(patterns)
139
- keys_blacklist.call(notice)
138
+ keys_blocklist = described_class.new(patterns)
139
+ keys_blocklist.call(notice)
140
140
  end
141
141
  end
142
142
 
@@ -150,6 +150,16 @@ RSpec.describe Airbrake::Filters::KeysBlacklist do
150
150
  { bongo: { bish: '[Filtered]' } },
151
151
  ],
152
152
  )
153
+
154
+ it "doesn't mutate the original hash" do
155
+ params = { bongo: { bish: 'bash' } }
156
+ notice[:params] = params
157
+
158
+ blocklist = described_class.new([:bish])
159
+ blocklist.call(notice)
160
+
161
+ expect(params[:bongo][:bish]).to eq('bash')
162
+ end
153
163
  end
154
164
 
155
165
  context "and it is recursive" do
@@ -5,18 +5,18 @@ RSpec.describe Airbrake::Filters::RootDirectoryFilter do
5
5
  let(:notice) { Airbrake::Notice.new(AirbrakeTestError.new) }
6
6
 
7
7
  it "replaces root directory in the backtrace with a label" do
8
- # rubocop:disable Metrics/LineLength
8
+ # rubocop:disable Layout/LineLength
9
9
  notice[:errors].first[:backtrace] = [
10
10
  { file: "/home/kyrylo/code/airbrake/ruby/spec/spec_helper.rb" },
11
11
  { file: "#{root_directory}/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb " },
12
12
  { file: "/opt/rubies/ruby-2.2.2/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb" },
13
13
  { file: "#{root_directory}/gems/rspec-core-3.3.2/exe/rspec" },
14
14
  ]
15
- # rubocop:enable Metrics/LineLength
15
+ # rubocop:enable Layout/LineLength
16
16
 
17
17
  subject.call(notice)
18
18
 
19
- # rubocop:disable Metrics/LineLength
19
+ # rubocop:disable Layout/LineLength
20
20
  expect(notice[:errors].first[:backtrace]).to(
21
21
  eq(
22
22
  [
@@ -27,7 +27,7 @@ RSpec.describe Airbrake::Filters::RootDirectoryFilter do
27
27
  ],
28
28
  ),
29
29
  )
30
- # rubocop:enable Metrics/LineLength
30
+ # rubocop:enable Layout/LineLength
31
31
  end
32
32
 
33
33
  it "does not filter file when it is nil" do
@@ -10,7 +10,7 @@ RSpec.describe Airbrake::Filters::SqlFilter do
10
10
  end
11
11
  end
12
12
 
13
- shared_examples "query blacklisting" do |query, opts|
13
+ shared_examples "query blocklisting" do |query, opts|
14
14
  it "ignores '#{query}'" do
15
15
  filter = described_class.new('postgres')
16
16
  q = Airbrake::Query.new(query: query, method: 'GET', route: '/', timing: 1)
@@ -22,7 +22,7 @@ RSpec.describe Airbrake::Filters::SqlFilter do
22
22
 
23
23
  ALL_DIALECTS = %i[mysql postgres sqlite cassandra oracle].freeze
24
24
 
25
- # rubocop:disable Metrics/LineLength
25
+ # rubocop:disable Layout/LineLength
26
26
  [
27
27
  {
28
28
  input: 'SELECT * FROM things;',
@@ -229,7 +229,7 @@ RSpec.describe Airbrake::Filters::SqlFilter do
229
229
  ].each do |test|
230
230
  include_examples 'query filtering', test
231
231
  end
232
- # rubocop:enable Metrics/LineLength
232
+ # rubocop:enable Layout/LineLength
233
233
 
234
234
  [
235
235
  'COMMIT',
@@ -263,12 +263,12 @@ RSpec.describe Airbrake::Filters::SqlFilter do
263
263
 
264
264
  'SELECT t.oid, t.typname FROM pg_type as t WHERE t.typname IN (?)',
265
265
  ].each do |query|
266
- include_examples 'query blacklisting', query, should_ignore: true
266
+ include_examples 'query blocklisting', query, should_ignore: true
267
267
  end
268
268
 
269
269
  [
270
270
  'UPDATE "users" SET "last_sign_in_at" = ? WHERE "users"."id" = ?',
271
271
  ].each do |query|
272
- include_examples 'query blacklisting', query, should_ignore: false
272
+ include_examples 'query blocklisting', query, should_ignore: false
273
273
  end
274
274
  end
@@ -149,10 +149,10 @@ RSpec.describe Airbrake::NoticeNotifier do
149
149
  expect(proxied_request.header['proxy-authorization'].first)
150
150
  .to eq('Basic dXNlcjpwYXNzd29yZA==')
151
151
 
152
- # rubocop:disable Metrics/LineLength
152
+ # rubocop:disable Layout/LineLength
153
153
  expect(proxied_request.request_line)
154
154
  .to eq("POST http://localhost:#{proxy.config[:Port]}/api/v3/projects/105138/notices HTTP/1.1\r\n")
155
- # rubocop:enable Metrics/LineLength
155
+ # rubocop:enable Layout/LineLength
156
156
  end
157
157
  end
158
158
 
@@ -234,14 +234,14 @@ RSpec.describe Airbrake::NoticeNotifier do
234
234
  end
235
235
  end
236
236
 
237
- describe ":blacklist_keys" do
237
+ describe ":blocklist_keys" do
238
238
  # Fixes https://github.com/airbrake/airbrake-ruby/issues/276
239
- context "when specified along with :whitelist_keys" do
239
+ context "when specified along with :allowlist_keys" do
240
240
  context "and when context payload is present" do
241
241
  before do
242
242
  Airbrake::Config.instance.merge(
243
- blacklist_keys: %i[password password_confirmation],
244
- whitelist_keys: [:email, /user/i, 'account_id'],
243
+ blocklist_keys: %i[password password_confirmation],
244
+ allowlist_keys: [:email, /user/i, 'account_id'],
245
245
  )
246
246
  end
247
247
 
@@ -309,7 +309,7 @@ RSpec.describe Airbrake::NoticeNotifier do
309
309
 
310
310
  notice = subject.build_notice(Exception.new)
311
311
 
312
- # rubocop:disable Metrics/LineLength
312
+ # rubocop:disable Layout/LineLength
313
313
  expect(notice[:errors].first[:backtrace]).to eq(
314
314
  [
315
315
  { file: 'org/jruby/RubyKernel.java', line: 998, function: 'eval' },
@@ -317,7 +317,7 @@ RSpec.describe Airbrake::NoticeNotifier do
317
317
  { file: '/ruby/stdlib/irb.rb:489', line: 489, function: 'block in eval_input' },
318
318
  ],
319
319
  )
320
- # rubocop:enable Metrics/LineLength
320
+ # rubocop:enable Layout/LineLength
321
321
  end
322
322
  end
323
323
 
@@ -268,7 +268,7 @@ RSpec.describe Airbrake::Notice do
268
268
  it "sets a payload value" do
269
269
  hash = { bingo: 'bango' }
270
270
  notice[:params] = hash
271
- expect(notice[:params]).to equal(hash)
271
+ expect(notice[:params]).to eq(hash)
272
272
  end
273
273
 
274
274
  it "raises error if notice is ignored" do
@@ -3,21 +3,9 @@ RSpec.describe Airbrake::PerformanceBreakdown do
3
3
  subject do
4
4
  described_class.new(
5
5
  method: 'GET', route: '/', response_type: '', groups: {},
6
- start_time: Time.now
7
6
  )
8
7
  end
9
8
 
10
9
  it { is_expected.to respond_to(:stash) }
11
10
  end
12
-
13
- describe "#end_time" do
14
- it "is always equal to start_time + 1 second by default" do
15
- time = Time.now
16
- performance_breakdown = described_class.new(
17
- method: 'GET', route: '/', response_type: '', groups: {},
18
- start_time: time
19
- )
20
- expect(performance_breakdown.end_time).to eq(time + 1)
21
- end
22
- end
23
11
  end
@@ -389,7 +389,7 @@ RSpec.describe Airbrake::PerformanceNotifier do
389
389
  subject.close
390
390
 
391
391
  expect(promise).to be_an(Airbrake::Promise)
392
- expect(promise.value).to eq('' => nil)
392
+ expect(promise.value).to eq('' => '')
393
393
  end
394
394
 
395
395
  it "checks performance stat configuration" do
@@ -541,31 +541,6 @@ RSpec.describe Airbrake::PerformanceNotifier do
541
541
  end
542
542
  end
543
543
 
544
- context "when :start_time is specified (deprecated)" do
545
- before do
546
- allow(Kernel).to receive(:warn)
547
- end
548
-
549
- it "uses the value of :start_time to update stat" do
550
- subject.notify(
551
- Airbrake::Query.new(
552
- method: 'POST',
553
- route: '/foo',
554
- query: 'SELECT * FROM things',
555
- start_time: Time.new(2018, 1, 1, 0, 49, 0, 0),
556
- end_time: Time.new(2018, 1, 1, 0, 50, 0, 0),
557
- ),
558
- )
559
- subject.close
560
-
561
- expect(
562
- a_request(:put, queries).with(
563
- body: /"count":1,"sum":60000.0,"sumsq":3600000000.0/,
564
- ),
565
- ).to have_been_made
566
- end
567
- end
568
-
569
544
  context "when provided :timing is zero" do
570
545
  it "doesn't notify" do
571
546
  queue = Airbrake::Queue.new(queue: 'bananas', error_count: 0, timing: 0)
@@ -601,7 +576,7 @@ RSpec.describe Airbrake::PerformanceNotifier do
601
576
  body: %r|\A{"queries":\[{"method":"POST","route":"/foo"|,
602
577
  ),
603
578
  ).to have_been_made
604
- expect(retval).to eq('' => nil)
579
+ expect(retval).to eq('' => '')
605
580
  end
606
581
  end
607
582
 
@@ -2,20 +2,10 @@ RSpec.describe Airbrake::Query do
2
2
  describe "#stash" do
3
3
  subject do
4
4
  described_class.new(
5
- method: 'GET', route: '/', query: '', start_time: Time.now,
5
+ method: 'GET', route: '/', query: '',
6
6
  )
7
7
  end
8
8
 
9
9
  it { is_expected.to respond_to(:stash) }
10
10
  end
11
-
12
- describe "#end_time" do
13
- it "is always equal to start_time + 1 second by default" do
14
- time = Time.now
15
- query = described_class.new(
16
- method: 'GET', route: '/', query: '', start_time: time,
17
- )
18
- expect(query.end_time).to eq(time + 1)
19
- end
20
- end
21
11
  end