fbe 0.6.0 → 0.7.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 72f0ba759db6bd1370f62c85290d009b0253b1c2d0b67f6933a6b8e2b43817ef
4
- data.tar.gz: c7b030938e82ec475316cd1e4ffcf3597fe26665020114c9e8f847741853b1b4
3
+ metadata.gz: e1ce252b4d0093ff1f94e319d2c65502e134dad520398ca018fad1820b9dac78
4
+ data.tar.gz: f0039a70dcd2533e2acd36f80b7ef3ac68441f1f68611b38ee07d9c67449ddf3
5
5
  SHA512:
6
- metadata.gz: edf889e94309ab5ebd1e0760a2152bc546d44b0b8ba42df2e5b4394cbabbc3964819690d787434bf10570a55ba3ed97514516ab029fe200056996994077fe00a
7
- data.tar.gz: 45ce296b829c75109fd3a4f92f7b5f1ace1d3e77062210b0aa0214b2a7939509b9bddc95f5363d8d05f2a288484b2ada461695326b2284fe0fab8d745138ee17
6
+ metadata.gz: 25191aefeccb723456f4de449c6f042ce628c895fc7f2e941f5e63e0685bfb2bccf550e04c288ff28e288acf8a4c0b57f3402b2826cae5ccb5da549c977f1ffe
7
+ data.tar.gz: 6362777ada12c805d463db462afbfbf5bab5d20b897565b798c2ede567d097f3250622d1a67656731e94f0ac8fc37fb604ace94c150e51e47c2a83ec14f4be60
data/Gemfile CHANGED
@@ -17,5 +17,6 @@ gem 'rubocop-performance', '>0', require: false
17
17
  gem 'rubocop-rake', '>0', require: false
18
18
  gem 'simplecov', '~>0.22', require: false
19
19
  gem 'simplecov-cobertura', '~>2.1', require: false
20
+ gem 'veils', '>0', require: false
20
21
  gem 'webmock', '~>3.25', require: false
21
22
  gem 'yard', '~>0.9', require: false
data/Gemfile.lock CHANGED
@@ -70,7 +70,7 @@ GEM
70
70
  tago (> 0)
71
71
  ethon (0.16.0)
72
72
  ffi (>= 1.15.0)
73
- factbase (0.9.10)
73
+ factbase (0.10.0)
74
74
  backtrace (~> 0.4)
75
75
  decoor (~> 0.0)
76
76
  json (~> 2.7)
@@ -92,14 +92,14 @@ GEM
92
92
  net-http (>= 0.5.0)
93
93
  faraday-retry (2.3.1)
94
94
  faraday (~> 2.0)
95
- ffi (1.17.1-arm64-darwin)
96
- ffi (1.17.1-x64-mingw-ucrt)
97
- ffi (1.17.1-x86_64-darwin)
98
- ffi (1.17.1-x86_64-linux-gnu)
99
- fiber-storage (1.0.0)
95
+ ffi (1.17.2-arm64-darwin)
96
+ ffi (1.17.2-x64-mingw-ucrt)
97
+ ffi (1.17.2-x86_64-darwin)
98
+ ffi (1.17.2-x86_64-linux-gnu)
99
+ fiber-storage (1.0.1)
100
100
  gli (2.22.2)
101
101
  ostruct
102
- graphql (2.5.2)
102
+ graphql (2.5.3)
103
103
  base64
104
104
  fiber-storage
105
105
  logger
@@ -158,7 +158,7 @@ GEM
158
158
  os (1.1.4)
159
159
  ostruct (0.6.1)
160
160
  others (0.0.3)
161
- parallel (1.26.3)
161
+ parallel (1.27.0)
162
162
  parser (3.3.8.0)
163
163
  ast (~> 2.4.1)
164
164
  racc
@@ -225,6 +225,7 @@ GEM
225
225
  unicode-emoji (~> 4.0, >= 4.0.4)
226
226
  unicode-emoji (4.0.4)
227
227
  uri (1.0.3)
228
+ veils (0.4.0)
228
229
  verbose (0.0.2)
229
230
  loog (~> 0.2)
230
231
  tago (~> 0.0)
@@ -257,6 +258,7 @@ DEPENDENCIES
257
258
  rubocop-rake (> 0)
258
259
  simplecov (~> 0.22)
259
260
  simplecov-cobertura (~> 2.1)
261
+ veils (> 0)
260
262
  webmock (~> 3.25)
261
263
  yard (~> 0.9)
262
264
 
data/Rakefile CHANGED
@@ -16,8 +16,6 @@ def version
16
16
  Gem::Specification.load(Dir['*.gemspec'].first).version
17
17
  end
18
18
 
19
- ENV['RACK_ENV'] = 'test'
20
-
21
19
  task default: %i[clean test picks rubocop yard]
22
20
 
23
21
  require 'rake/testtask'
data/lib/fbe/conclude.rb CHANGED
@@ -160,21 +160,20 @@ class Fbe::Conclude
160
160
  def roll(&)
161
161
  passed = 0
162
162
  start = Time.now
163
- catch :stop do
164
- @fb.txn do |fbt|
165
- fbt.query(@query).each do |a|
166
- if @quota_aware && Fbe.octo(loog: @loog, options: @options, global: @global).off_quota
167
- @loog.debug('We ran out of GitHub quota, must stop here')
168
- throw :stop
169
- end
170
- if Time.now > start + @timeout
171
- @loog.debug("We've spent more than #{start.ago}, must stop here")
172
- throw :stop
173
- end
174
- n = yield fbt, a
175
- @loog.info("#{n.what}: #{n.details}") unless n.nil?
176
- passed += 1
163
+ oct = Fbe.octo(loog: @loog, options: @options, global: @global)
164
+ @fb.txn do |fbt|
165
+ fbt.query(@query).each do |a|
166
+ if @quota_aware && oct.off_quota
167
+ @loog.debug('We ran out of GitHub quota, must stop here')
168
+ throw :commit
177
169
  end
170
+ if Time.now > start + @timeout
171
+ @loog.debug("We've spent more than #{start.ago}, must stop here")
172
+ throw :commit
173
+ end
174
+ n = yield fbt, a
175
+ @loog.info("#{n.what}: #{n.details}") unless n.nil?
176
+ passed += 1
178
177
  end
179
178
  end
180
179
  @loog.debug("Found and processed #{passed} facts by: #{@query}")
data/lib/fbe/iterate.rb CHANGED
@@ -107,11 +107,23 @@ class Fbe::Iterate
107
107
  raise 'Use "by" first' if @query.nil?
108
108
  seen = {}
109
109
  oct = Fbe.octo(loog: @loog, options: @options, global: @global)
110
+ if oct.off_quota
111
+ @loog.debug('We are off GitHub quota, cannot even start, sorry')
112
+ return
113
+ end
110
114
  repos = Fbe.unmask_repos(loog: @loog, options: @options, global: @global)
111
115
  restarted = []
112
116
  start = Time.now
113
117
  loop do
118
+ if oct.off_quota
119
+ @loog.info("We are off GitHub quota, time to stop after #{start.ago}")
120
+ break
121
+ end
114
122
  repos.each do |repo|
123
+ if oct.off_quota
124
+ @loog.debug("We are off GitHub quota, we must skip #{repo}")
125
+ break
126
+ end
115
127
  if Time.now - start > timeout
116
128
  $loog.info("We are doing this for #{start.ago} already, won't check #{repo}")
117
129
  next
@@ -152,14 +164,6 @@ class Fbe::Iterate
152
164
  end
153
165
  f.what = @label
154
166
  seen[repo] += 1
155
- if oct.off_quota
156
- @loog.debug('We are off GitHub quota, time to stop')
157
- break
158
- end
159
- end
160
- if oct.off_quota
161
- @loog.info("We are off GitHub quota, time to stop after #{start.ago}")
162
- break
163
167
  end
164
168
  unless seen.any? { |r, v| v < @repeats && !restarted.include?(r) }
165
169
  @loog.debug("No more repos to scan (out of #{repos.size}), quitting after #{start.ago}")
data/lib/fbe/octo.rb CHANGED
@@ -13,7 +13,6 @@ require 'verbose'
13
13
  require_relative '../fbe'
14
14
  require_relative 'middleware'
15
15
  require_relative 'middleware/formatter'
16
- require_relative 'middleware/quota'
17
16
 
18
17
  # Makes a call to the GitHub API.
19
18
  #
@@ -71,7 +70,6 @@ def Fbe.octo(options: $options, global: $global, loog: $loog)
71
70
  methods: [:get],
72
71
  backoff_factor: 2
73
72
  )
74
- builder.use(Fbe::Middleware::Quota, loog:, pause: options.github_api_pause || 60)
75
73
  builder.use(Faraday::HttpCache, serializer: Marshal, shared_cache: false, logger: Loog::NULL)
76
74
  builder.use(Octokit::Response::RaiseError)
77
75
  builder.use(Faraday::Response::Logger, loog, formatter: Fbe::Middleware::Formatter)
@@ -84,12 +82,13 @@ def Fbe.octo(options: $options, global: $global, loog: $loog)
84
82
  o = Fbe::FakeOctokit.new
85
83
  end
86
84
  decoor(o, loog:) do
87
- def off_quota
85
+ def off_quota(threshold: 50)
88
86
  left = @origin.rate_limit.remaining
89
- if left < 5
90
- @loog.info("Too much GitHub API quota consumed already (remaining=#{left}), stopping")
87
+ if left < threshold
88
+ @loog.info("Too much GitHub API quota consumed already (#{left} < #{threshold}), stopping")
91
89
  true
92
90
  else
91
+ @loog.debug("Still #{left} GitHub API quota left (>#{threshold})")
93
92
  false
94
93
  end
95
94
  end
@@ -149,13 +148,14 @@ class Fbe::FakeOctokit
149
148
  true
150
149
  end
151
150
 
152
- def user(name)
153
- login = name
154
- login = name == 526_301 ? 'yegor256' : 'torvalds' if login.is_a?(Integer)
151
+ # Get details of the user.
152
+ # @param [String|Integer] uid The login of the user or its ID
153
+ def user(uid)
154
+ login = (uid == 526_301 ? 'yegor256' : 'torvalds') if uid.is_a?(Integer)
155
155
  {
156
156
  id: 444,
157
157
  login:,
158
- type: name == 29_139_614 ? 'Bot' : 'User'
158
+ type: uid == 29_139_614 ? 'Bot' : 'User'
159
159
  }
160
160
  end
161
161
 
data/lib/fbe.rb CHANGED
@@ -10,5 +10,5 @@
10
10
  # License:: MIT
11
11
  module Fbe
12
12
  # Current version of the gem (changed by +.rultor.yml+ on every release)
13
- VERSION = '0.6.0' unless const_defined?(:VERSION)
13
+ VERSION = '0.7.1' unless const_defined?(:VERSION)
14
14
  end
@@ -61,6 +61,38 @@ class TestConclude < Fbe::Test
61
61
  assert_equal(42, f.bar)
62
62
  end
63
63
 
64
+ def test_considers_until_quota
65
+ WebMock.disable_net_connect!
66
+ fb = Factbase.new
67
+ 5.times do
68
+ fb.insert.foo = 1
69
+ end
70
+ options = Judges::Options.new
71
+ stub_request(:get, %r{https://api.github.com/users/.*}).to_return(
72
+ {
73
+ body: { id: rand(100) }.to_json,
74
+ headers: { 'Content-Type' => 'application/json', 'X-RateLimit-Remaining' => '999' }
75
+ },
76
+ {
77
+ body: { id: rand(100) }.to_json,
78
+ headers: { 'Content-Type' => 'application/json', 'X-RateLimit-Remaining' => '9' }
79
+ }
80
+ )
81
+ stub_request(:get, 'https://api.github.com/rate_limit').to_return(
82
+ body: 'hm...', headers: { 'X-RateLimit-Remaining' => '777' }
83
+ ).times(1)
84
+ global = {}
85
+ o = Fbe.octo(loog: Loog::NULL, options:, global:)
86
+ Fbe.conclude(fb:, judge: 'boom', loog: Loog::NULL, options:, global:) do
87
+ quota_aware
88
+ on '(exists foo)'
89
+ consider do |f|
90
+ f.bar = o.user("user-#{rand(100)}")[:id]
91
+ end
92
+ end
93
+ assert_equal(2, fb.query('(exists bar)').each.to_a.size)
94
+ end
95
+
64
96
  def test_ignores_globals
65
97
  $fb = nil
66
98
  $loog = nil
@@ -56,7 +56,7 @@ class TestOcto < Fbe::Test
56
56
  global = {}
57
57
  o = Fbe.octo(loog: Loog::NULL, global:, options: Judges::Options.new)
58
58
  stub_request(:get, 'https://api.github.com/users/yegor256')
59
- .to_return(status: 200, body: '{}', headers: { 'Cache-Control' => 'public, max-age=60', 'etag' => 'abc' })
59
+ .to_return(body: '{}', headers: { 'Cache-Control' => 'public, max-age=60', 'etag' => 'abc' })
60
60
  .times(1)
61
61
  .then
62
62
  .to_raise('second request should be cached, not passed to GitHub API!')
@@ -64,12 +64,50 @@ class TestOcto < Fbe::Test
64
64
  o.user('yegor256')
65
65
  end
66
66
 
67
+ def test_rate_limit_remaining
68
+ WebMock.disable_net_connect!
69
+ stub_request(:get, 'https://api.github.com/rate_limit').to_return(
70
+ { body: '{}', headers: { 'X-RateLimit-Remaining' => '222' } }
71
+ )
72
+ stub_request(:get, 'https://api.github.com/user/42').to_return(
73
+ body: '', headers: { 'X-RateLimit-Remaining' => '4' }
74
+ )
75
+ o = Octokit::Client.new
76
+ assert_equal(222, o.rate_limit.remaining)
77
+ o.user(42)
78
+ assert_equal(4, o.rate_limit.remaining)
79
+ assert_equal(4, o.rate_limit.remaining)
80
+ end
81
+
67
82
  def test_off_quota
68
83
  WebMock.disable_net_connect!
69
- stub_request(:get, 'https://api.github.com/rate_limit')
70
- .to_return(status: 200, body: '{}', headers: { 'X-RateLimit-Remaining' => '1000' })
84
+ stub_request(:get, 'https://api.github.com/rate_limit').to_return(
85
+ body: '{}', headers: { 'X-RateLimit-Remaining' => '333' }
86
+ )
87
+ stub_request(:get, 'https://api.github.com/user/42').to_return(
88
+ body: '', headers: { 'X-RateLimit-Remaining' => '3' }
89
+ )
71
90
  o = Fbe.octo(loog: Loog::NULL, global: {}, options: Judges::Options.new)
72
91
  refute(o.off_quota)
92
+ o.user(42)
93
+ assert(o.off_quota)
94
+ end
95
+
96
+ def test_off_quota_twice
97
+ WebMock.disable_net_connect!
98
+ stub_request(:get, 'https://api.github.com/rate_limit').to_return(
99
+ body: '{}', headers: { 'X-RateLimit-Remaining' => '333' }
100
+ )
101
+ stub_request(:get, 'https://api.github.com/user/42').to_return(
102
+ { body: '', headers: { 'X-RateLimit-Remaining' => '5555' } },
103
+ { body: '', headers: { 'X-RateLimit-Remaining' => '5' } }
104
+ )
105
+ o = Fbe.octo(loog: Loog::VERBOSE, global: {}, options: Judges::Options.new)
106
+ refute(o.off_quota)
107
+ o.user(42)
108
+ refute(o.off_quota)
109
+ o.user(42)
110
+ assert(o.off_quota)
73
111
  end
74
112
 
75
113
  def test_retrying
@@ -80,7 +118,7 @@ class TestOcto < Fbe::Test
80
118
  .to_raise(Octokit::TooManyRequests.new)
81
119
  .times(1)
82
120
  .then
83
- .to_return(status: 200, body: '{}')
121
+ .to_return(body: '{}')
84
122
  o.user('yegor256')
85
123
  end
86
124
 
@@ -92,7 +130,7 @@ class TestOcto < Fbe::Test
92
130
  .to_return(status: 503)
93
131
  .times(1)
94
132
  .then
95
- .to_return(status: 200, body: '{}')
133
+ .to_return(body: '{}')
96
134
  o.user('yegor256')
97
135
  end
98
136
 
@@ -133,29 +171,20 @@ class TestOcto < Fbe::Test
133
171
 
134
172
  def test_pauses_when_quota_is_exceeded
135
173
  WebMock.disable_net_connect!
136
- global = {}
137
- pause = 0.1
138
- o = Fbe.octo(loog: Loog::NULL, global:, options: Judges::Options.new({ 'github_api_pause' => pause }))
139
- limit = 100
140
- start_time = Time.now
141
- 105.times do |i|
142
- n = i + 1
143
- user = "test#{n}"
144
- limit = 100 if n > 100
145
- stub_request(:get, "https://api.github.com/users/#{user}")
146
- .then
147
- .to_return(
148
- status: 200, body: '{}',
149
- headers: {
150
- 'x-ratelimit-remaining' => limit.to_s
151
- }
152
- )
153
- .times(1)
154
- o.user(user)
155
- refute(o.off_quota) if n > 100
156
- limit -= 1
157
- end
158
- assert_in_delta(pause, Time.now - start_time, 5)
174
+ o = Fbe.octo(loog: Loog::NULL, global: {}, options: Judges::Options.new({ 'github_api_pause' => 0.01 }))
175
+ stub_request(:get, 'https://api.github.com/users/foo')
176
+ .to_return(
177
+ body: '{}',
178
+ headers: { 'x-ratelimit-remaining' => '1' }
179
+ )
180
+ .to_return(
181
+ body: '{}',
182
+ headers: { 'x-ratelimit-remaining' => '10000' }
183
+ )
184
+ o.user('foo')
185
+ assert(o.off_quota)
186
+ o.user('foo')
187
+ refute(o.off_quota)
159
188
  end
160
189
 
161
190
  def test_fetches_fake_check_runs_for_ref
@@ -193,4 +222,10 @@ class TestOcto < Fbe::Test
193
222
  result = o.workflow_run_job('zerocracy/baza', 0)
194
223
  assert_equal(0, result[:id])
195
224
  end
225
+
226
+ def test_reads_quota
227
+ WebMock.enable_net_connect!
228
+ o = Fbe.octo(loog: Loog::VERBOSE, global: {}, options: Judges::Options.new({ 'github_api_pause' => 0.01 }))
229
+ refute_nil(o.off_quota)
230
+ end
196
231
  end
data/test/test__helper.rb CHANGED
@@ -5,6 +5,8 @@
5
5
 
6
6
  $stdout.sync = true
7
7
 
8
+ ENV['RACK_ENV'] = 'test'
9
+
8
10
  require 'simplecov'
9
11
  require 'simplecov-cobertura'
10
12
  unless SimpleCov.running || ARGV.include?('--no-cov')
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fbe
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-04-14 00:00:00.000000000 Z
10
+ date: 2025-04-16 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: backtrace
@@ -305,7 +305,6 @@ files:
305
305
  - lib/fbe/just_one.rb
306
306
  - lib/fbe/middleware.rb
307
307
  - lib/fbe/middleware/formatter.rb
308
- - lib/fbe/middleware/quota.rb
309
308
  - lib/fbe/octo.rb
310
309
  - lib/fbe/overwrite.rb
311
310
  - lib/fbe/pmp.rb
@@ -317,7 +316,6 @@ files:
317
316
  - renovate.json
318
317
  - rules/basic.fe
319
318
  - test/fbe/middleware/test_formatter.rb
320
- - test/fbe/middleware/test_quota.rb
321
319
  - test/fbe/test_award.rb
322
320
  - test/fbe/test_bylaws.rb
323
321
  - test/fbe/test_conclude.rb
@@ -1,64 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # SPDX-FileCopyrightText: Copyright (c) 2024-2025 Zerocracy
4
- # SPDX-License-Identifier: MIT
5
-
6
- require 'faraday'
7
- require_relative '../middleware'
8
-
9
- # Faraday Middleware that monitors GitHub API rate limits.
10
- #
11
- # Author:: Yegor Bugayenko (yegor256@gmail.com)
12
- # Copyright:: Copyright (c) 2024-2025 Zerocracy
13
- # License:: MIT
14
- class Fbe::Middleware::Quota < Faraday::Middleware
15
- # Constructor.
16
- #
17
- # @param [Object] app The Faraday app
18
- # @param [Loog] loog The logging facility
19
- # @param [Integer] pause Seconds to pause when rate limit is reached
20
- # @param [Integer] limit Maximum number of requests before checking rate limit
21
- # @param [Integer] rate Minimum remaining requests threshold
22
- def initialize(app, loog: Loog::NULL, pause: 60, limit: 100, rate: 5)
23
- super(app)
24
- @requests = 0
25
- @app = app
26
- raise 'The "loog" cannot be nil' if loog.nil?
27
- @loog = loog
28
- raise 'The "pause" cannot be nil' if pause.nil?
29
- raise 'The "pause" must be a positive integer' unless pause.positive?
30
- @pause = pause
31
- raise 'The "limit" cannot be nil' if limit.nil?
32
- raise 'The "limit" must be a positive integer' unless limit.positive?
33
- @limit = limit
34
- raise 'The "rate" cannot be nil' if rate.nil?
35
- raise 'The "rate" must be a positive integer' unless rate.positive?
36
- @rate = rate
37
- end
38
-
39
- # Process the request and handle rate limiting.
40
- #
41
- # @param [Faraday::Env] env The environment
42
- # @return [Faraday::Response] The response
43
- def call(env)
44
- @requests += 1
45
- response = @app.call(env)
46
- if out_of_limit?(env)
47
- @loog.info("Too much GitHub API quota consumed, pausing for #{@pause} seconds")
48
- sleep(@pause)
49
- @requests = 0
50
- end
51
- response
52
- end
53
-
54
- private
55
-
56
- # Check if we're approaching the rate limit.
57
- #
58
- # @param [Faraday::Env] env The environment
59
- # @return [Boolean] True if we should pause to avoid hitting rate limits
60
- def out_of_limit?(env)
61
- remaining = env.response_headers['x-ratelimit-remaining'].to_i
62
- (@requests % @limit).zero? && remaining < @rate
63
- end
64
- end
@@ -1,66 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # SPDX-FileCopyrightText: Copyright (c) 2024-2025 Zerocracy
4
- # SPDX-License-Identifier: MIT
5
-
6
- require 'faraday'
7
- require 'logger'
8
- require 'loog'
9
- require 'judges'
10
- require 'judges/options'
11
- require_relative '../../../lib/fbe/middleware'
12
- require_relative '../../../lib/fbe/middleware/quota'
13
- require_relative '../../test__helper'
14
-
15
- class QuotaTest < Fbe::Test
16
- class FakeApp
17
- def initialize
18
- @calls = 0
19
- end
20
-
21
- def call(env)
22
- @calls += 1
23
- response_headers = {
24
- 'x-ratelimit-remaining' => (100 - @calls).to_s
25
- }
26
- env[:response_headers] = response_headers
27
- env
28
- end
29
- end
30
-
31
- def test_quota_middleware_pauses_when_quota_low
32
- loog = Loog::NULL
33
- pause = 0.1
34
- app = FakeApp.new
35
- middleware = Fbe::Middleware::Quota.new(app, loog:, pause:)
36
- start_time = Time.now
37
- 105.times do
38
- env = Judges::Options.new(
39
- 'method' => :get,
40
- 'url' => 'http://example.com',
41
- 'request_headers' => {},
42
- 'response_headers' => {}
43
- )
44
- middleware.call(env)
45
- end
46
- assert_in_delta pause, Time.now - start_time, 0.4
47
- end
48
-
49
- def test_quota_middleware_logs_when_quota_low
50
- pause = 0.1
51
- log_output = StringIO.new
52
- loog = Logger.new(log_output)
53
- app = FakeApp.new
54
- middleware = Fbe::Middleware::Quota.new(app, loog:, pause:)
55
- 105.times do
56
- env = Judges::Options.new(
57
- 'method' => :get,
58
- 'url' => 'http://example.com',
59
- 'request_headers' => {},
60
- 'response_headers' => {}
61
- )
62
- middleware.call(env)
63
- end
64
- assert_match(/Too much GitHub API quota/, log_output.string)
65
- end
66
- end