fbe 0.29.1 → 0.31.0
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 +4 -4
- data/fbe.gemspec +1 -1
- data/lib/fbe/conclude.rb +27 -10
- data/lib/fbe/unmask_repos.rb +11 -2
- data/lib/fbe.rb +1 -1
- metadata +1 -31
- data/renovate.json +0 -6
- data/test/fbe/middleware/test_formatter.rb +0 -104
- data/test/fbe/middleware/test_rate_limit.rb +0 -152
- data/test/fbe/middleware/test_sqlite_store.rb +0 -446
- data/test/fbe/middleware/test_trace.rb +0 -168
- data/test/fbe/test_award.rb +0 -126
- data/test/fbe/test_bylaws.rb +0 -111
- data/test/fbe/test_conclude.rb +0 -172
- data/test/fbe/test_copy.rb +0 -39
- data/test/fbe/test_delete.rb +0 -117
- data/test/fbe/test_delete_one.rb +0 -56
- data/test/fbe/test_enter.rb +0 -35
- data/test/fbe/test_fb.rb +0 -102
- data/test/fbe/test_github_graph.rb +0 -169
- data/test/fbe/test_if_absent.rb +0 -107
- data/test/fbe/test_issue.rb +0 -26
- data/test/fbe/test_iterate.rb +0 -253
- data/test/fbe/test_just_one.rb +0 -33
- data/test/fbe/test_kill_if.rb +0 -39
- data/test/fbe/test_octo.rb +0 -791
- data/test/fbe/test_overwrite.rb +0 -103
- data/test/fbe/test_pmp.rb +0 -34
- data/test/fbe/test_regularly.rb +0 -27
- data/test/fbe/test_repeatedly.rb +0 -31
- data/test/fbe/test_sec.rb +0 -21
- data/test/fbe/test_tombstone.rb +0 -56
- data/test/fbe/test_unmask_repos.rb +0 -66
- data/test/fbe/test_who.rb +0 -25
- data/test/test__helper.rb +0 -45
- data/test/test_fbe.rb +0 -17
@@ -1,446 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Zerocracy
|
4
|
-
# SPDX-License-Identifier: MIT
|
5
|
-
|
6
|
-
require 'qbash'
|
7
|
-
require 'securerandom'
|
8
|
-
require_relative '../../../lib/fbe/middleware'
|
9
|
-
require_relative '../../../lib/fbe/middleware/sqlite_store'
|
10
|
-
require_relative '../../test__helper'
|
11
|
-
|
12
|
-
# Test.
|
13
|
-
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
14
|
-
# Copyright:: Copyright (c) 2024-2025 Zerocracy
|
15
|
-
# License:: MIT
|
16
|
-
class SqliteStoreTest < Fbe::Test
|
17
|
-
def test_simple_caching_algorithm
|
18
|
-
with_tmpfile('x.db') do |f|
|
19
|
-
store = Fbe::Middleware::SqliteStore.new(f, '0.0.0')
|
20
|
-
k = 'some-key'
|
21
|
-
assert_nil(store.read(k))
|
22
|
-
assert_nil(store.delete(k))
|
23
|
-
v1 = 'first value to save'
|
24
|
-
assert_nil(store.write(k, v1))
|
25
|
-
assert_equal(v1, store.read(k))
|
26
|
-
v2 = 'another value to save'
|
27
|
-
assert_nil(store.write(k, v2))
|
28
|
-
assert_equal(v2, store.read(k))
|
29
|
-
assert_nil(store.delete(k))
|
30
|
-
assert_nil(store.read(k))
|
31
|
-
assert_path_exists(f)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def test_returns_empty_list
|
36
|
-
with_tmpfile('b.db') do |f|
|
37
|
-
store = Fbe::Middleware::SqliteStore.new(f, '0.0.0', loog: fake_loog)
|
38
|
-
assert_empty(store.all)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def test_clear_all_keys
|
43
|
-
with_tmpfile('a.db') do |f|
|
44
|
-
store = Fbe::Middleware::SqliteStore.new(f, '0.0.0', loog: fake_loog)
|
45
|
-
k = 'a key'
|
46
|
-
store.write(k, 'some value')
|
47
|
-
store.clear
|
48
|
-
assert_empty(store.all)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def test_empty_all_if_not_written
|
53
|
-
with_tmpfile do |f|
|
54
|
-
store = Fbe::Middleware::SqliteStore.new(f, '0.0.0', loog: fake_loog)
|
55
|
-
assert_empty(store.all)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def test_wrong_db_path
|
60
|
-
assert_raises(ArgumentError) do
|
61
|
-
Fbe::Middleware::SqliteStore.new(nil, '0.0.0', loog: fake_loog).read('my_key')
|
62
|
-
end
|
63
|
-
assert_raises(ArgumentError) do
|
64
|
-
Fbe::Middleware::SqliteStore.new('', '0.0.0', loog: fake_loog).read('my_key')
|
65
|
-
end
|
66
|
-
assert_raises(ArgumentError) do
|
67
|
-
Fbe::Middleware::SqliteStore.new('/fakepath/fakefolder/test.db', '0.0.0', loog: fake_loog).read('my_key')
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def test_not_db_file
|
72
|
-
with_tmpfile do |f|
|
73
|
-
File.binwrite(f, Array.new(20) { rand(0..255) }.pack('C*'))
|
74
|
-
ex =
|
75
|
-
assert_raises(SQLite3::NotADatabaseException) do
|
76
|
-
Fbe::Middleware::SqliteStore.new(f, '0.0.0', loog: fake_loog).read('my_key')
|
77
|
-
end
|
78
|
-
assert_match('file is not a database', ex.message)
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
def test_defer_db_close_callback
|
83
|
-
txt = <<~RUBY
|
84
|
-
require 'tempfile'
|
85
|
-
require 'sqlite3'
|
86
|
-
require 'fbe/middleware/sqlite_store'
|
87
|
-
SQLite3::Database.class_eval do
|
88
|
-
prepend(Module.new do
|
89
|
-
def close
|
90
|
-
super
|
91
|
-
puts 'closed sqlite after process exit'
|
92
|
-
end
|
93
|
-
end)
|
94
|
-
end
|
95
|
-
Tempfile.open('test.db') do |f|
|
96
|
-
Fbe::Middleware::SqliteStore.new(f.path, '0.0.0').then do |s|
|
97
|
-
s.write('my_key', 'my_value')
|
98
|
-
s.read('my_key')
|
99
|
-
end
|
100
|
-
end
|
101
|
-
RUBY
|
102
|
-
out =
|
103
|
-
qbash(
|
104
|
-
'bundle exec ruby ' \
|
105
|
-
"-I#{Shellwords.escape(File.expand_path('../../../lib', __dir__))} " \
|
106
|
-
"-e #{Shellwords.escape(txt)} 2>&1"
|
107
|
-
)
|
108
|
-
assert_match('closed sqlite after process exit', out)
|
109
|
-
end
|
110
|
-
|
111
|
-
def test_different_versions
|
112
|
-
with_tmpfile('d.db') do |f|
|
113
|
-
Fbe::Middleware::SqliteStore.new(f, '0.0.1', loog: fake_loog).then do |store|
|
114
|
-
store.write('kkk1', 'some value')
|
115
|
-
store.write('kkk2', 'another value')
|
116
|
-
end
|
117
|
-
Fbe::Middleware::SqliteStore.new(f, '0.0.1', loog: fake_loog).then do |store|
|
118
|
-
assert_equal('some value', store.read('kkk1'))
|
119
|
-
assert_equal('another value', store.read('kkk2'))
|
120
|
-
end
|
121
|
-
Fbe::Middleware::SqliteStore.new(f, '0.0.2', loog: fake_loog).then do |store|
|
122
|
-
assert_nil(store.read('kkk1'))
|
123
|
-
assert_nil(store.read('kkk2'))
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
def test_initialize_wrong_version
|
129
|
-
with_tmpfile('e.db') do |f|
|
130
|
-
msg = 'Version cannot be nil or empty'
|
131
|
-
assert_raises(ArgumentError) { Fbe::Middleware::SqliteStore.new(f, nil, loog: fake_loog) }.then do |ex|
|
132
|
-
assert_match(msg, ex.message)
|
133
|
-
end
|
134
|
-
assert_raises(ArgumentError) { Fbe::Middleware::SqliteStore.new(f, '', loog: fake_loog) }.then do |ex|
|
135
|
-
assert_match(msg, ex.message)
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
def test_skip_write_if_value_more_then_10k_bytes
|
141
|
-
with_tmpfile('a.db') do |f|
|
142
|
-
Fbe::Middleware::SqliteStore.new(f, '0.0.1', loog: fake_loog).then do |store|
|
143
|
-
store.write('a', 'a' * 9_997)
|
144
|
-
store.write('b', 'b' * 9_998)
|
145
|
-
store.write('c', SecureRandom.alphanumeric((19_999 * 1.4).to_i))
|
146
|
-
store.write('d', SecureRandom.alphanumeric((30_000 * 1.4).to_i))
|
147
|
-
assert_equal('a' * 9_997, store.read('a'))
|
148
|
-
assert_equal('b' * 9_998, store.read('b'))
|
149
|
-
assert_nil(store.read('c'))
|
150
|
-
assert_nil(store.read('d'))
|
151
|
-
end
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
def test_shrink_cache_if_more_then_10_mb
|
156
|
-
with_tmpfile('large.db') do |f|
|
157
|
-
Fbe::Middleware::SqliteStore.new(f, '0.0.1', loog: fake_loog).then do |store|
|
158
|
-
store.write('a', 'aa')
|
159
|
-
Time.stub(:now, (Time.now - (5 * 60 * 60)).round) do
|
160
|
-
store.write('b', 'bb')
|
161
|
-
store.write('c', 'cc')
|
162
|
-
end
|
163
|
-
assert_equal('cc', store.read('c'))
|
164
|
-
Time.stub(:now, rand((Time.now - (5 * 60 * 60))..Time.now).round) do
|
165
|
-
key = 'a' * 65_536
|
166
|
-
value = SecureRandom.alphanumeric(8_192)
|
167
|
-
52.times do
|
168
|
-
store.write(key, value)
|
169
|
-
key = key.next
|
170
|
-
end
|
171
|
-
end
|
172
|
-
end
|
173
|
-
assert_operator(File.size(f), :>, 10 * 1024 * 1024)
|
174
|
-
Fbe::Middleware::SqliteStore.new(f, '0.0.1', loog: fake_loog).then do |store|
|
175
|
-
assert_equal('aa', store.read('a'))
|
176
|
-
assert_nil(store.read('b'))
|
177
|
-
assert_equal('cc', store.read('c'))
|
178
|
-
assert_operator(File.size(f), :<=, 10 * 1024 * 1024)
|
179
|
-
end
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
|
-
def test_upgrade_sqlite_schema_for_add_touched_at_column
|
184
|
-
with_tmpfile('a.db') do |f|
|
185
|
-
SQLite3::Database.new(f).tap do |d|
|
186
|
-
d.execute 'CREATE TABLE IF NOT EXISTS cache(key TEXT UNIQUE NOT NULL, value TEXT);'
|
187
|
-
[
|
188
|
-
['key1', Zlib::Deflate.deflate(JSON.dump('value1'))],
|
189
|
-
['key2', Zlib::Deflate.deflate(JSON.dump('value2'))]
|
190
|
-
].each { d.execute 'INSERT INTO cache(key, value) VALUES(?1, ?2);', _1 }
|
191
|
-
d.execute 'CREATE TABLE IF NOT EXISTS meta(key TEXT UNIQUE NOT NULL, value TEXT);'
|
192
|
-
d.execute "INSERT INTO meta(key, value) VALUES('version', ?);", ['0.0.1']
|
193
|
-
end
|
194
|
-
Fbe::Middleware::SqliteStore.new(f, '0.0.1', loog: fake_loog).then do |store|
|
195
|
-
assert_equal('value1', store.read('key1'))
|
196
|
-
assert_equal('value2', store.read('key2'))
|
197
|
-
rescue SQLite3::SQLException => e
|
198
|
-
assert_nil(e)
|
199
|
-
end
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
|
-
def test_use_compress_for_stored_data
|
204
|
-
with_tmpfile('c.db') do |f|
|
205
|
-
Fbe::Middleware::SqliteStore.new(f, '0.0.1', loog: fake_loog).then do |store|
|
206
|
-
a = SecureRandom.alphanumeric(200)
|
207
|
-
store.write('a', a)
|
208
|
-
store.write('b', 'b' * 100_000)
|
209
|
-
assert_equal(a, store.read('a'))
|
210
|
-
assert_equal('b' * 100_000, store.read('b'))
|
211
|
-
store.all.each do |k, v|
|
212
|
-
case k
|
213
|
-
when 'a'
|
214
|
-
assert_operator(v.size, :<, a.size)
|
215
|
-
when 'b'
|
216
|
-
assert_operator(v.size, :<, 100_000)
|
217
|
-
end
|
218
|
-
end
|
219
|
-
end
|
220
|
-
end
|
221
|
-
end
|
222
|
-
|
223
|
-
def test_corrupted_compression_stored_data
|
224
|
-
with_tmpfile('c.db') do |f|
|
225
|
-
SQLite3::Database.new(f).tap do |d|
|
226
|
-
d.execute 'CREATE TABLE IF NOT EXISTS cache(key TEXT UNIQUE NOT NULL, value TEXT);'
|
227
|
-
[
|
228
|
-
['my_key', JSON.dump('value1')]
|
229
|
-
].each { d.execute 'INSERT INTO cache(key, value) VALUES(?1, ?2);', _1 }
|
230
|
-
d.execute 'CREATE TABLE IF NOT EXISTS meta(key TEXT UNIQUE NOT NULL, value TEXT);'
|
231
|
-
d.execute "INSERT INTO meta(key, value) VALUES('version', ?);", ['0.0.1']
|
232
|
-
end
|
233
|
-
Fbe::Middleware::SqliteStore.new(f, '0.0.1', loog: fake_loog).then do |store|
|
234
|
-
assert_nil(store.read('my_key'))
|
235
|
-
assert_predicate(store.all.count, :zero?)
|
236
|
-
end
|
237
|
-
end
|
238
|
-
end
|
239
|
-
|
240
|
-
def test_upgrade_sqlite_schema_for_add_created_at_column
|
241
|
-
with_tmpfile('a.db') do |f|
|
242
|
-
SQLite3::Database.new(f).tap do |d|
|
243
|
-
d.execute 'CREATE TABLE IF NOT EXISTS cache(key TEXT UNIQUE NOT NULL, value TEXT, touched_at TEXT NOT NULL);'
|
244
|
-
[
|
245
|
-
['key1', Zlib::Deflate.deflate(JSON.dump('value1')), Time.now.utc.iso8601],
|
246
|
-
['key2', Zlib::Deflate.deflate(JSON.dump('value2')), Time.now.utc.iso8601]
|
247
|
-
].each { d.execute 'INSERT INTO cache(key, value, touched_at) VALUES(?1, ?2, ?3);', _1 }
|
248
|
-
d.execute 'CREATE TABLE IF NOT EXISTS meta(key TEXT UNIQUE NOT NULL, value TEXT);'
|
249
|
-
d.execute "INSERT INTO meta(key, value) VALUES('version', ?);", ['0.0.1']
|
250
|
-
end
|
251
|
-
Fbe::Middleware::SqliteStore.new(f, '0.0.1', loog: fake_loog).then do |store|
|
252
|
-
assert_equal('value1', store.read('key1'))
|
253
|
-
assert_equal('value2', store.read('key2'))
|
254
|
-
rescue SQLite3::SQLException => e
|
255
|
-
assert_nil(e)
|
256
|
-
end
|
257
|
-
end
|
258
|
-
end
|
259
|
-
|
260
|
-
def test_set_correct_ttl
|
261
|
-
with_tmpfile('c.db') do |f|
|
262
|
-
s = Fbe::Middleware::SqliteStore.new(f, '0.0.1', loog: fake_loog, ttl: nil)
|
263
|
-
refute_nil(s)
|
264
|
-
s = Fbe::Middleware::SqliteStore.new(f, '0.0.1', loog: fake_loog, ttl: 24)
|
265
|
-
refute_nil(s)
|
266
|
-
end
|
267
|
-
end
|
268
|
-
|
269
|
-
def test_set_incorrect_ttl
|
270
|
-
with_tmpfile('c.db') do |f|
|
271
|
-
ex =
|
272
|
-
assert_raises(ArgumentError) do
|
273
|
-
Fbe::Middleware::SqliteStore.new(f, '0.0.1', loog: fake_loog, ttl: 0)
|
274
|
-
end
|
275
|
-
assert_equal('TTL can be nil or Integer > 0', ex.message)
|
276
|
-
ex =
|
277
|
-
assert_raises(ArgumentError) do
|
278
|
-
Fbe::Middleware::SqliteStore.new(f, '0.0.1', loog: fake_loog, ttl: -10)
|
279
|
-
end
|
280
|
-
assert_equal('TTL can be nil or Integer > 0', ex.message)
|
281
|
-
ex =
|
282
|
-
assert_raises(ArgumentError) do
|
283
|
-
Fbe::Middleware::SqliteStore.new(f, '0.0.1', loog: fake_loog, ttl: 10.0)
|
284
|
-
end
|
285
|
-
assert_equal('TTL can be nil or Integer > 0', ex.message)
|
286
|
-
ex =
|
287
|
-
assert_raises(ArgumentError) do
|
288
|
-
Fbe::Middleware::SqliteStore.new(f, '0.0.1', loog: fake_loog, ttl: '10')
|
289
|
-
end
|
290
|
-
assert_equal('TTL can be nil or Integer > 0', ex.message)
|
291
|
-
ex =
|
292
|
-
assert_raises(ArgumentError) do
|
293
|
-
Fbe::Middleware::SqliteStore.new(f, '0.0.1', loog: fake_loog, ttl: Object.new)
|
294
|
-
end
|
295
|
-
assert_equal('TTL can be nil or Integer > 0', ex.message)
|
296
|
-
end
|
297
|
-
end
|
298
|
-
|
299
|
-
def test_delete_keys_if_ttl_expired
|
300
|
-
with_tmpfile('c.db') do |f|
|
301
|
-
now = Time.now
|
302
|
-
Time.stub(:now, now) do
|
303
|
-
Fbe::Middleware::SqliteStore.new(f, '0.0.1', loog: fake_loog, ttl: 24).then do |s|
|
304
|
-
s.write('test1', 'value1')
|
305
|
-
s.write('test2', 'value2')
|
306
|
-
end
|
307
|
-
end
|
308
|
-
Time.stub(:now, now + (12 * 60 * 60)) do
|
309
|
-
Fbe::Middleware::SqliteStore.new(f, '0.0.1', loog: fake_loog, ttl: 24).then do |s|
|
310
|
-
s.write('test3', 'value3')
|
311
|
-
s.write('test4', 'value4')
|
312
|
-
end
|
313
|
-
end
|
314
|
-
Time.stub(:now, now + (24 * 60 * 60)) do
|
315
|
-
Fbe::Middleware::SqliteStore.new(f, '0.0.1', loog: fake_loog, ttl: 24).then do |s|
|
316
|
-
assert_equal('value1', s.read('test1'))
|
317
|
-
assert_equal('value2', s.read('test2'))
|
318
|
-
assert_equal('value3', s.read('test3'))
|
319
|
-
assert_equal('value4', s.read('test4'))
|
320
|
-
end
|
321
|
-
end
|
322
|
-
Time.stub(:now, now + (24 * 60 * 60) + 1) do
|
323
|
-
Fbe::Middleware::SqliteStore.new(f, '0.0.1', loog: fake_loog, ttl: 24).then do |s|
|
324
|
-
assert_nil(s.read('test1'))
|
325
|
-
assert_nil(s.read('test2'))
|
326
|
-
assert_equal('value3', s.read('test3'))
|
327
|
-
assert_equal('value4', s.read('test4'))
|
328
|
-
end
|
329
|
-
end
|
330
|
-
end
|
331
|
-
end
|
332
|
-
|
333
|
-
def test_set_correct_cache_min_age
|
334
|
-
with_tmpfile('c.db') do |f|
|
335
|
-
s = Fbe::Middleware::SqliteStore.new(f, '0.0.1', loog: fake_loog, cache_min_age: nil)
|
336
|
-
refute_nil(s)
|
337
|
-
s = Fbe::Middleware::SqliteStore.new(f, '0.0.1', loog: fake_loog, cache_min_age: 600)
|
338
|
-
refute_nil(s)
|
339
|
-
end
|
340
|
-
end
|
341
|
-
|
342
|
-
def test_set_incorrect_cache_min_age
|
343
|
-
with_tmpfile('c.db') do |f|
|
344
|
-
msg = 'Cache min age can be nil or Integer > 0'
|
345
|
-
[0, -50, 120.0, '120', Object.new].each do |cache_min_age|
|
346
|
-
ex =
|
347
|
-
assert_raises(ArgumentError) do
|
348
|
-
Fbe::Middleware::SqliteStore.new(f, '0.0.1', loog: fake_loog, cache_min_age:)
|
349
|
-
end
|
350
|
-
assert_equal(msg, ex.message)
|
351
|
-
end
|
352
|
-
end
|
353
|
-
end
|
354
|
-
|
355
|
-
def test_not_overwrite_cache_control
|
356
|
-
with_tmpfile('t.db') do |f|
|
357
|
-
Fbe::Middleware::SqliteStore.new(f, '0.0.1', loog: fake_loog, cache_min_age: 30).then do |store|
|
358
|
-
store.write(
|
359
|
-
'test1',
|
360
|
-
faraday_value(resp: { 'response_headers' => { 'cache-control' => 'public, max-age=60, s-maxage=60' } })
|
361
|
-
)
|
362
|
-
store.write(
|
363
|
-
'test2',
|
364
|
-
faraday_value(resp: { 'response_headers' => { 'cache-control' => 'public, max-age=30, s-maxage=30' } })
|
365
|
-
)
|
366
|
-
store.write(
|
367
|
-
'test3',
|
368
|
-
faraday_value(resp: { 'response_headers' => { 'content-type' => 'application/json; charset=utf-8' } })
|
369
|
-
)
|
370
|
-
store.write('test4', faraday_value(resp: { 'status' => 200, 'body' => '{"some":"value"}' }))
|
371
|
-
store.write('test5', faraday_value(resp: {}))
|
372
|
-
store.write('test6', [[JSON.dump({ 'method' => 'get' }), 1]])
|
373
|
-
store.write('test7', faraday_value(resp: 'some string'))
|
374
|
-
store.write('test8', faraday_value(resp: nil))
|
375
|
-
end
|
376
|
-
Fbe::Middleware::SqliteStore.new(f, '0.0.1', loog: fake_loog).then do |store|
|
377
|
-
assert_equal(
|
378
|
-
'public, max-age=60, s-maxage=60',
|
379
|
-
JSON.parse(store.read('test1')[0][1]).dig('response_headers', 'cache-control')
|
380
|
-
)
|
381
|
-
assert_equal(
|
382
|
-
'public, max-age=30, s-maxage=30',
|
383
|
-
JSON.parse(store.read('test2')[0][1]).dig('response_headers', 'cache-control')
|
384
|
-
)
|
385
|
-
assert_nil(JSON.parse(store.read('test3')[0][1]).dig('response_headers', 'cache-control'))
|
386
|
-
assert_nil(JSON.parse(store.read('test4')[0][1]).dig('response_headers', 'cache-control'))
|
387
|
-
assert_nil(JSON.parse(store.read('test5')[0][1]).dig('response_headers', 'cache-control'))
|
388
|
-
assert_equal(1, store.read('test6')[0][1])
|
389
|
-
assert_equal(JSON.dump('some string'), store.read('test7')[0][1])
|
390
|
-
assert_nil(store.read('test8')[0][1])
|
391
|
-
end
|
392
|
-
end
|
393
|
-
end
|
394
|
-
|
395
|
-
def test_overwrite_cache_control
|
396
|
-
with_tmpfile('t.db') do |f|
|
397
|
-
Fbe::Middleware::SqliteStore.new(f, '0.0.1', loog: fake_loog, cache_min_age: 300).then do |store|
|
398
|
-
store.write(
|
399
|
-
'test1',
|
400
|
-
faraday_value(resp: { 'response_headers' => { 'cache-control' => 'public, max-age=60, s-maxage=60' } })
|
401
|
-
)
|
402
|
-
end
|
403
|
-
Fbe::Middleware::SqliteStore.new(f, '0.0.1', loog: fake_loog, cache_min_age: 1555).then do |store|
|
404
|
-
store.write(
|
405
|
-
'test2',
|
406
|
-
faraday_value(resp: { 'response_headers' => { 'cache-control' => 'public, max-age=60, s-maxage=60' } })
|
407
|
-
)
|
408
|
-
end
|
409
|
-
store = Fbe::Middleware::SqliteStore.new(f, '0.0.1', loog: fake_loog)
|
410
|
-
assert_equal(
|
411
|
-
'public, max-age=300, s-maxage=300',
|
412
|
-
JSON.parse(store.read('test1')[0][1]).dig('response_headers', 'cache-control')
|
413
|
-
)
|
414
|
-
assert_equal(
|
415
|
-
'public, max-age=1555, s-maxage=1555',
|
416
|
-
JSON.parse(store.read('test2')[0][1]).dig('response_headers', 'cache-control')
|
417
|
-
)
|
418
|
-
end
|
419
|
-
end
|
420
|
-
|
421
|
-
private
|
422
|
-
|
423
|
-
def with_tmpfile(name = 'test.db', &)
|
424
|
-
Dir.mktmpdir do |dir|
|
425
|
-
yield File.expand_path(name, dir)
|
426
|
-
end
|
427
|
-
end
|
428
|
-
|
429
|
-
def faraday_value(
|
430
|
-
req: {
|
431
|
-
'method' => 'get',
|
432
|
-
'url' => 'https://example.com/test',
|
433
|
-
'headers' => { 'Content-Type' => 'application/json' }
|
434
|
-
},
|
435
|
-
resp: {
|
436
|
-
'status' => 200,
|
437
|
-
'body' => '{"some":"value"}',
|
438
|
-
'response_headers' => { 'content-type' => 'application/json; charset=utf-8' }
|
439
|
-
}
|
440
|
-
)
|
441
|
-
value = []
|
442
|
-
value << JSON.dump(req) if req
|
443
|
-
value << JSON.dump(resp) if resp
|
444
|
-
[value]
|
445
|
-
end
|
446
|
-
end
|
@@ -1,168 +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 'faraday/http_cache'
|
8
|
-
require 'webmock'
|
9
|
-
require_relative '../../../lib/fbe'
|
10
|
-
require_relative '../../../lib/fbe/middleware'
|
11
|
-
require_relative '../../../lib/fbe/middleware/trace'
|
12
|
-
require_relative '../../test__helper'
|
13
|
-
|
14
|
-
# Test.
|
15
|
-
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
16
|
-
# Copyright:: Copyright (c) 2024-2025 Zerocracy
|
17
|
-
# License:: MIT
|
18
|
-
class TraceTest < Fbe::Test
|
19
|
-
def test_traces_successful_request
|
20
|
-
trace = []
|
21
|
-
stub_request(:get, 'http://example.com/test')
|
22
|
-
.to_return(status: 200, body: 'success')
|
23
|
-
conn =
|
24
|
-
Faraday.new do |f|
|
25
|
-
f.use Fbe::Middleware::Trace, trace
|
26
|
-
f.adapter :net_http
|
27
|
-
end
|
28
|
-
conn.get('http://example.com/test')
|
29
|
-
assert_equal 1, trace.size
|
30
|
-
entry = trace.first
|
31
|
-
assert_equal :get, entry[:method]
|
32
|
-
assert_equal 'http://example.com/test', entry[:url]
|
33
|
-
assert_equal 200, entry[:status]
|
34
|
-
assert_instance_of Time, entry[:started_at]
|
35
|
-
assert_instance_of Time, entry[:finished_at]
|
36
|
-
assert_instance_of Float, entry[:duration]
|
37
|
-
assert_operator entry[:duration], :>=, 0
|
38
|
-
assert_operator entry[:finished_at], :>=, entry[:started_at]
|
39
|
-
end
|
40
|
-
|
41
|
-
def test_traces_multiple_requests
|
42
|
-
trace = []
|
43
|
-
stub_request(:get, 'http://example.com/endpoint1').to_return(status: 200)
|
44
|
-
stub_request(:post, 'http://example.com/endpoint2').to_return(status: 201)
|
45
|
-
stub_request(:delete, 'http://example.com/endpoint3').to_return(status: 404)
|
46
|
-
conn =
|
47
|
-
Faraday.new do |f|
|
48
|
-
f.use Fbe::Middleware::Trace, trace
|
49
|
-
f.adapter :net_http
|
50
|
-
end
|
51
|
-
conn.get('http://example.com/endpoint1')
|
52
|
-
conn.post('http://example.com/endpoint2')
|
53
|
-
conn.delete('http://example.com/endpoint3')
|
54
|
-
assert_equal 3, trace.size
|
55
|
-
assert_equal :get, trace[0][:method]
|
56
|
-
assert_equal 200, trace[0][:status]
|
57
|
-
assert_equal :post, trace[1][:method]
|
58
|
-
assert_equal 201, trace[1][:status]
|
59
|
-
assert_equal :delete, trace[2][:method]
|
60
|
-
assert_equal 404, trace[2][:status]
|
61
|
-
end
|
62
|
-
|
63
|
-
def test_traces_error_responses
|
64
|
-
trace = []
|
65
|
-
stub_request(:get, 'http://example.com/error').to_return(status: 500, body: 'error')
|
66
|
-
conn =
|
67
|
-
Faraday.new do |f|
|
68
|
-
f.use Fbe::Middleware::Trace, trace
|
69
|
-
f.adapter :net_http
|
70
|
-
end
|
71
|
-
conn.get('http://example.com/error')
|
72
|
-
assert_equal 1, trace.size
|
73
|
-
entry = trace.first
|
74
|
-
assert_equal 500, entry[:status]
|
75
|
-
assert_equal 'http://example.com/error', entry[:url]
|
76
|
-
end
|
77
|
-
|
78
|
-
def test_handles_connection_errors
|
79
|
-
trace = []
|
80
|
-
stub_request(:get, 'http://example.com/timeout').to_timeout
|
81
|
-
conn =
|
82
|
-
Faraday.new do |f|
|
83
|
-
f.use Fbe::Middleware::Trace, trace
|
84
|
-
f.adapter :net_http
|
85
|
-
end
|
86
|
-
assert_raises(Faraday::ConnectionFailed) do
|
87
|
-
conn.get('http://example.com/timeout')
|
88
|
-
end
|
89
|
-
assert_equal 0, trace.size
|
90
|
-
end
|
91
|
-
|
92
|
-
def test_preserves_request_with_query_params
|
93
|
-
trace = []
|
94
|
-
stub_request(:get, 'http://example.com/search').with(query: { 'q' => 'test', 'page' => '2' }).to_return(status: 200)
|
95
|
-
conn =
|
96
|
-
Faraday.new do |f|
|
97
|
-
f.use Fbe::Middleware::Trace, trace
|
98
|
-
f.adapter :net_http
|
99
|
-
end
|
100
|
-
conn.get('http://example.com/search?q=test&page=2')
|
101
|
-
assert_equal 1, trace.size
|
102
|
-
url = trace.first[:url]
|
103
|
-
assert url.start_with?('http://example.com/search?')
|
104
|
-
assert_includes url, 'q=test'
|
105
|
-
assert_includes url, 'page=2'
|
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
|
168
|
-
end
|