fbe 0.23.6 → 0.23.8
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/.github/workflows/typos.yml +1 -1
- data/Gemfile.lock +8 -8
- data/lib/fbe/middleware/trace.rb +7 -1
- data/lib/fbe/octo.rb +7 -7
- data/lib/fbe.rb +1 -1
- data/test/fbe/middleware/test_trace.rb +62 -0
- data/test/fbe/test_octo.rb +123 -3
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fec8e019e6882387cebf8cd4f6c9ba1bbfc3287dc6558e8275d717b7f944273f
|
4
|
+
data.tar.gz: 3d21ec46863d2ba0e241d5d766c49521ecde20d8f683f104e2c50de917f90978
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 47f5e2144c9a13003d0cde086902abe2258fbbe471359e1bb38f84083cd8d5d0cacf9ecb8153fa7810ef3613193b81fef3ebc5a41d648778cf692a90980bc141
|
7
|
+
data.tar.gz: 3146af1240d7cb7028d93267d9b52db316d5d3f3352e1996db2d7852cfa6347ef2cbf2e21bc405bb135076805463199719eb66e48be26f65d69b8afc7362c56f
|
data/.github/workflows/typos.yml
CHANGED
data/Gemfile.lock
CHANGED
@@ -46,7 +46,7 @@ GEM
|
|
46
46
|
ast (2.4.3)
|
47
47
|
backtrace (0.4.1)
|
48
48
|
base64 (0.3.0)
|
49
|
-
baza.rb (0.9.
|
49
|
+
baza.rb (0.9.6)
|
50
50
|
backtrace (~> 0.4)
|
51
51
|
elapsed (~> 0.0)
|
52
52
|
faraday (~> 2.13)
|
@@ -69,13 +69,13 @@ GEM
|
|
69
69
|
decoor (0.1.0)
|
70
70
|
docile (1.4.1)
|
71
71
|
drb (2.2.3)
|
72
|
-
elapsed (0.0
|
72
|
+
elapsed (0.1.0)
|
73
73
|
loog (> 0)
|
74
74
|
tago (> 0)
|
75
75
|
ellipsized (0.3.0)
|
76
76
|
ethon (0.16.0)
|
77
77
|
ffi (>= 1.15.0)
|
78
|
-
factbase (0.
|
78
|
+
factbase (0.12.1)
|
79
79
|
backtrace (~> 0.4)
|
80
80
|
decoor (~> 0.0)
|
81
81
|
ellipsized (~> 0.3)
|
@@ -119,7 +119,7 @@ GEM
|
|
119
119
|
intercepted (0.2.0)
|
120
120
|
iri (0.11.2)
|
121
121
|
json (2.12.2)
|
122
|
-
judges (0.
|
122
|
+
judges (0.51.0)
|
123
123
|
backtrace (~> 0.4)
|
124
124
|
baza.rb (~> 0.5)
|
125
125
|
concurrent-ruby (~> 1.2)
|
@@ -226,10 +226,10 @@ GEM
|
|
226
226
|
simplecov (~> 0.19)
|
227
227
|
simplecov-html (0.13.1)
|
228
228
|
simplecov_json_formatter (0.1.4)
|
229
|
-
sqlite3 (2.7.
|
230
|
-
sqlite3 (2.7.
|
231
|
-
sqlite3 (2.7.
|
232
|
-
sqlite3 (2.7.
|
229
|
+
sqlite3 (2.7.1-arm64-darwin)
|
230
|
+
sqlite3 (2.7.1-x64-mingw-ucrt)
|
231
|
+
sqlite3 (2.7.1-x86_64-darwin)
|
232
|
+
sqlite3 (2.7.1-x86_64-linux-gnu)
|
233
233
|
strscan (3.1.5)
|
234
234
|
tago (0.1.0)
|
235
235
|
timeout (0.4.3)
|
data/lib/fbe/middleware/trace.rb
CHANGED
@@ -31,9 +31,12 @@ class Fbe::Middleware::Trace < Faraday::Middleware
|
|
31
31
|
#
|
32
32
|
# @param [Object] app The next middleware in the stack
|
33
33
|
# @param [Array] trace The array to store trace entries
|
34
|
-
|
34
|
+
# @param [Array<Symbol>] ignores The array of symbols (see Faraday::HttpCache::CACHE_STATUSES),
|
35
|
+
# which will be ignored
|
36
|
+
def initialize(app, trace, ignores: [])
|
35
37
|
super(app)
|
36
38
|
@trace = trace
|
39
|
+
@ignores = ignores
|
37
40
|
end
|
38
41
|
|
39
42
|
# Processes the HTTP request and records trace information.
|
@@ -47,6 +50,9 @@ class Fbe::Middleware::Trace < Faraday::Middleware
|
|
47
50
|
started_at: Time.now
|
48
51
|
}
|
49
52
|
@app.call(env).on_complete do |response_env|
|
53
|
+
next if !@ignores.empty? &&
|
54
|
+
response_env[:http_cache_trace] &&
|
55
|
+
(response_env[:http_cache_trace] & @ignores).size.positive?
|
50
56
|
finished = Time.now
|
51
57
|
duration = finished - entry[:started_at]
|
52
58
|
entry[:status] = response_env.status
|
data/lib/fbe/octo.rb
CHANGED
@@ -86,9 +86,13 @@ def Fbe.octo(options: $options, global: $global, loog: $loog)
|
|
86
86
|
methods: [:get],
|
87
87
|
backoff_factor: 2
|
88
88
|
)
|
89
|
+
builder.use(Octokit::Response::RaiseError)
|
90
|
+
builder.use(Faraday::Response::Logger, loog, formatter: Fbe::Middleware::Formatter)
|
91
|
+
builder.use(Fbe::Middleware::RateLimit)
|
92
|
+
builder.use(Fbe::Middleware::Trace, trace, ignores: [:fresh])
|
89
93
|
if options.sqlite_cache
|
90
|
-
maxsize = Filesize.from(options.sqlite_cache_maxsize || '
|
91
|
-
maxvsize = Filesize.from(options.sqlite_cache_maxvsize || '
|
94
|
+
maxsize = Filesize.from(options.sqlite_cache_maxsize || '100M').to_i
|
95
|
+
maxvsize = Filesize.from(options.sqlite_cache_maxvsize || '100K').to_i
|
92
96
|
store = Fbe::Middleware::SqliteStore.new(options.sqlite_cache, Fbe::VERSION, loog:, maxsize:, maxvsize:)
|
93
97
|
loog.info(
|
94
98
|
"Using HTTP cache in SQLite file: #{store.path} (" \
|
@@ -106,10 +110,6 @@ def Fbe.octo(options: $options, global: $global, loog: $loog)
|
|
106
110
|
serializer: Marshal, shared_cache: false, logger: Loog::NULL
|
107
111
|
)
|
108
112
|
end
|
109
|
-
builder.use(Octokit::Response::RaiseError)
|
110
|
-
builder.use(Faraday::Response::Logger, loog, formatter: Fbe::Middleware::Formatter)
|
111
|
-
builder.use(Fbe::Middleware::RateLimit)
|
112
|
-
builder.use(Fbe::Middleware::Trace, trace)
|
113
113
|
builder.adapter(Faraday.default_adapter)
|
114
114
|
end
|
115
115
|
o.middleware = stack
|
@@ -433,7 +433,7 @@ class Fbe::FakeOctokit
|
|
433
433
|
|
434
434
|
# Removes a user from an organization.
|
435
435
|
#
|
436
|
-
# @param [String]
|
436
|
+
# @param [String] _org The organization name (e.g., 'zerocracy')
|
437
437
|
# @param [String] _user The user login (not used in this mock implementation)
|
438
438
|
# @return [Boolean] Returns true when successful (204 No Content in actual API)
|
439
439
|
# @example
|
data/lib/fbe.rb
CHANGED
@@ -4,6 +4,7 @@
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
5
5
|
|
6
6
|
require 'faraday'
|
7
|
+
require 'faraday/http_cache'
|
7
8
|
require 'webmock'
|
8
9
|
require_relative '../../test__helper'
|
9
10
|
require_relative '../../../lib/fbe'
|
@@ -103,4 +104,65 @@ class TraceTest < Fbe::Test
|
|
103
104
|
assert_includes url, 'q=test'
|
104
105
|
assert_includes url, 'page=2'
|
105
106
|
end
|
107
|
+
|
108
|
+
def test_trace_and_cache_middlewares_together
|
109
|
+
WebMock.disable_net_connect!
|
110
|
+
now = Time.now
|
111
|
+
stub_request(:get, 'https://api.example.com/page')
|
112
|
+
.to_return(
|
113
|
+
status: 200,
|
114
|
+
headers: {
|
115
|
+
'date' => now.httpdate,
|
116
|
+
'cache-control' => 'public, max-age=60, s-maxage=60',
|
117
|
+
'last-modified' => (now - (6 * 60 * 60)).httpdate
|
118
|
+
},
|
119
|
+
body: 'some body 1'
|
120
|
+
)
|
121
|
+
.times(1)
|
122
|
+
.then
|
123
|
+
.to_return(
|
124
|
+
status: 200,
|
125
|
+
headers: {
|
126
|
+
'date' => (now + 70).httpdate,
|
127
|
+
'cache-control' => 'public, max-age=60, s-maxage=60',
|
128
|
+
'last-modified' => (now - (6 * 60 * 60)).httpdate,
|
129
|
+
'content-type' => 'application/json; charset=utf-8'
|
130
|
+
},
|
131
|
+
body: 'some body 2'
|
132
|
+
)
|
133
|
+
.times(1)
|
134
|
+
.then.to_raise('no more request to /page')
|
135
|
+
trace_real = []
|
136
|
+
trace_full = []
|
137
|
+
builder =
|
138
|
+
Faraday::RackBuilder.new do |f|
|
139
|
+
f.use Fbe::Middleware::Trace, trace_full
|
140
|
+
f.use(Faraday::HttpCache, serializer: Marshal, shared_cache: false, logger: Loog::NULL)
|
141
|
+
f.use Fbe::Middleware::Trace, trace_real
|
142
|
+
f.adapter :net_http
|
143
|
+
end
|
144
|
+
conn = Faraday::Connection.new(builder: builder)
|
145
|
+
5.times do
|
146
|
+
r = conn.get('https://api.example.com/page')
|
147
|
+
assert_equal('some body 1', r.body)
|
148
|
+
end
|
149
|
+
assert_equal(1, trace_real.size)
|
150
|
+
assert_equal(5, trace_full.size)
|
151
|
+
trace_real.clear
|
152
|
+
trace_full.clear
|
153
|
+
5.times do
|
154
|
+
r = conn.get('https://api.example.com/page')
|
155
|
+
assert_equal('some body 1', r.body)
|
156
|
+
end
|
157
|
+
assert_equal(0, trace_real.size)
|
158
|
+
assert_equal(5, trace_full.size)
|
159
|
+
Time.stub(:now, now + 70) do
|
160
|
+
5.times do
|
161
|
+
r = conn.get('https://api.example.com/page')
|
162
|
+
assert_equal('some body 2', r.body)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
assert_equal(1, trace_real.size)
|
166
|
+
assert_equal(10, trace_full.size)
|
167
|
+
end
|
106
168
|
end
|
data/test/fbe/test_octo.rb
CHANGED
@@ -421,14 +421,69 @@ class TestOcto < Fbe::Test
|
|
421
421
|
octo = Fbe.octo(loog: Loog::NULL, global: {}, options: Judges::Options.new({ 'sqlite_cache' => fcache }))
|
422
422
|
octo.user(123)
|
423
423
|
loog = Loog::Buffer.new
|
424
|
-
octo = Fbe.octo(loog
|
424
|
+
octo = Fbe.octo(loog:, global: {}, options: Judges::Options.new({ 'sqlite_cache' => fcache }))
|
425
425
|
WebMock.remove_request_stub(stub)
|
426
426
|
octo.user(123)
|
427
|
-
octo.print_trace!
|
428
|
-
|
427
|
+
octo.print_trace!(all: true)
|
428
|
+
refute_match('/user/123: 1', loog.to_s)
|
429
429
|
end
|
430
430
|
end
|
431
431
|
|
432
|
+
def test_octo_not_trace_cached_requests
|
433
|
+
WebMock.disable_net_connect!
|
434
|
+
now = Time.now
|
435
|
+
stub_request(:get, 'https://api.github.com/rate_limit')
|
436
|
+
.to_return(
|
437
|
+
status: 200, headers: { 'Content-Type' => 'application/json', 'X-RateLimit-Remaining' => '5000' },
|
438
|
+
body: { 'rate' => { 'limit' => 5000, 'remaining' => 5000, 'reset' => 1_672_531_200 } }.to_json
|
439
|
+
)
|
440
|
+
stub_request(:get, 'https://api.github.com/repos/zerocracy/baza.rb')
|
441
|
+
.to_return(
|
442
|
+
status: 200,
|
443
|
+
headers: {
|
444
|
+
'date' => now.httpdate,
|
445
|
+
'cache-control' => 'public, max-age=60, s-maxage=60',
|
446
|
+
'last-modified' => (now - (6 * 60 * 60)).httpdate,
|
447
|
+
'content-type' => 'application/json; charset=utf-8'
|
448
|
+
},
|
449
|
+
body: { id: 840_215_648, name: 'baza.rb' }.to_json
|
450
|
+
)
|
451
|
+
.times(1)
|
452
|
+
.then
|
453
|
+
.to_return(
|
454
|
+
status: 200,
|
455
|
+
headers: {
|
456
|
+
'date' => (now + 70).httpdate,
|
457
|
+
'cache-control' => 'public, max-age=60, s-maxage=60',
|
458
|
+
'last-modified' => (now - (6 * 60 * 60)).httpdate,
|
459
|
+
'content-type' => 'application/json; charset=utf-8'
|
460
|
+
},
|
461
|
+
body: { id: 840_215_648, name: 'baza.rb' }.to_json
|
462
|
+
)
|
463
|
+
.times(1)
|
464
|
+
.then.to_raise('no more request to /repos/zerocracy/baza.rb')
|
465
|
+
loog = Loog::Buffer.new
|
466
|
+
o = Fbe.octo(loog:, global: {}, options: Judges::Options.new({}))
|
467
|
+
o.print_trace!(all: true)
|
468
|
+
Time.stub(:now, now) do
|
469
|
+
5.times do
|
470
|
+
o.repo('zerocracy/baza.rb')
|
471
|
+
end
|
472
|
+
end
|
473
|
+
o.print_trace!(all: true)
|
474
|
+
Time.stub(:now, now + 70) do
|
475
|
+
25.times do
|
476
|
+
o.repo('zerocracy/baza.rb')
|
477
|
+
end
|
478
|
+
end
|
479
|
+
o.print_trace!(all: true)
|
480
|
+
assert_requested :get, 'https://api.github.com/repos/zerocracy/baza.rb', times: 2
|
481
|
+
output = loog.to_s
|
482
|
+
assert_match('/repos/zerocracy/baza.rb: 1', output)
|
483
|
+
refute_match('/repos/zerocracy/baza.rb: 5', output)
|
484
|
+
refute_match('/repos/zerocracy/baza.rb: 25', output)
|
485
|
+
end
|
486
|
+
|
432
487
|
def test_trace_gets_cleared_after_print
|
433
488
|
WebMock.disable_net_connect!
|
434
489
|
stub_request(:get, 'https://api.github.com/rate_limit').to_return(
|
@@ -542,4 +597,69 @@ class TestOcto < Fbe::Test
|
|
542
597
|
o.print_trace!(all: true)
|
543
598
|
assert_match(/321 quota left/, loog.to_s)
|
544
599
|
end
|
600
|
+
|
601
|
+
def test_throttling_request_to_rate_limit
|
602
|
+
WebMock.disable_net_connect!
|
603
|
+
stub_request(:get, 'https://api.github.com/rate_limit')
|
604
|
+
.to_return(
|
605
|
+
status: 200, headers: { 'Content-Type' => 'application/json', 'X-RateLimit-Remaining' => '5000' },
|
606
|
+
body: { 'rate' => { 'limit' => 5000, 'remaining' => 5000, 'reset' => 1_672_531_200 } }.to_json
|
607
|
+
)
|
608
|
+
.then.to_return(
|
609
|
+
status: 200, headers: { 'Content-Type' => 'application/json', 'X-RateLimit-Remaining' => '4900' },
|
610
|
+
body: { 'rate' => { 'limit' => 5000, 'remaining' => 4900, 'reset' => 1_672_531_200 } }.to_json
|
611
|
+
)
|
612
|
+
.then.to_return(
|
613
|
+
status: 200, headers: { 'Content-Type' => 'application/json', 'X-RateLimit-Remaining' => '4800' },
|
614
|
+
body: { 'rate' => { 'limit' => 5000, 'remaining' => 4800, 'reset' => 1_672_531_200 } }.to_json
|
615
|
+
)
|
616
|
+
.then.to_raise('no more request to /rate_limit')
|
617
|
+
stub_request(:get, 'https://api.github.com/user/1')
|
618
|
+
.to_return(
|
619
|
+
status: 200, headers: { 'Content-Type' => 'application/json' },
|
620
|
+
body: { 'id' => 1, 'login' => 'user1' }.to_json
|
621
|
+
).times(1)
|
622
|
+
stub_request(:get, 'https://api.github.com/user/111')
|
623
|
+
.to_return(
|
624
|
+
status: 200, headers: { 'Content-Type' => 'application/json' },
|
625
|
+
body: { 'id' => 111, 'login' => 'user111' }.to_json
|
626
|
+
)
|
627
|
+
.times(201)
|
628
|
+
.then.to_raise('no more request to /user/111')
|
629
|
+
loog = Loog::Buffer.new
|
630
|
+
o = Fbe.octo(loog:, global: {}, options: Judges::Options.new({}))
|
631
|
+
o.user(1)
|
632
|
+
o.print_trace!(all: true)
|
633
|
+
201.times do
|
634
|
+
o.user(111)
|
635
|
+
o.rate_limit!.remaining
|
636
|
+
end
|
637
|
+
o.print_trace!(all: true)
|
638
|
+
output = loog.to_s
|
639
|
+
assert_requested :get, 'https://api.github.com/user/1', times: 1
|
640
|
+
assert_requested :get, 'https://api.github.com/user/111', times: 201
|
641
|
+
assert_requested :get, 'https://api.github.com/rate_limit', times: 3
|
642
|
+
assert_match('2 URLs vs 2 requests', output)
|
643
|
+
assert_match('/user/1: 1', output)
|
644
|
+
assert_match('/rate_limit: 1', output)
|
645
|
+
assert_match('2 URLs vs 203 requests', output)
|
646
|
+
assert_match('/user/111: 201', output)
|
647
|
+
assert_match('/rate_limit: 2', output)
|
648
|
+
end
|
649
|
+
|
650
|
+
def test_octo_http_cache_middleware_located_in_end_of_chain
|
651
|
+
WebMock.disable_net_connect!
|
652
|
+
stub_request(:get, 'https://api.github.com/rate_limit')
|
653
|
+
.to_return(
|
654
|
+
status: 200, headers: { 'Content-Type' => 'application/json', 'X-RateLimit-Remaining' => '5000' },
|
655
|
+
body: { 'rate' => { 'limit' => 5000, 'remaining' => 5000, 'reset' => 1_672_531_200 } }.to_json
|
656
|
+
)
|
657
|
+
o = Fbe.octo(loog: fake_loog, global: {}, options: Judges::Options.new({}))
|
658
|
+
assert_equal('Faraday::HttpCache', o.middleware.handlers.last.name, <<~MSG.strip.gsub!(/\s+/, ' '))
|
659
|
+
Faraday::HttpCache middleware must be located in the end of chain middlewares,
|
660
|
+
because the Oktokit client change Faraday::HttpCache position to the last,
|
661
|
+
for more info, see: https://github.com/zerocracy/fbe/issues/230#issuecomment-3020551743 and
|
662
|
+
https://github.com/octokit/octokit.rb/blob/ea3413c3174571e87c83d358fc893cc7613091fa/lib/octokit/connection.rb#L109-L119
|
663
|
+
MSG
|
664
|
+
end
|
545
665
|
end
|