airbrake-ruby 4.13.3-java → 5.0.0-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.
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