fbe 0.19.2 → 0.20.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/Gemfile +1 -0
- data/Gemfile.lock +4 -2
- data/lib/fbe/middleware/sqlite_store.rb +59 -32
- data/lib/fbe/octo.rb +16 -8
- data/lib/fbe.rb +1 -1
- data/test/fbe/middleware/test_sqlite_store.rb +171 -14
- data/test/fbe/test_octo.rb +46 -2
- data/test/test__helper.rb +1 -0
- 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: 8c33c559724c991d4aabc2ad9c097170e53de0002e362dcfadfe956d77eed7ec
|
4
|
+
data.tar.gz: 787dbc8ce12ebacbd0b96cd8174ced19aa11665f29d3d410fb93c397dbb80d87
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ca43bc96f5c8f426a72fb3ab722684d36b67613526b9d2e1be175abae03581c4fc0318314e92628c9064d2c7ba8637814ed950e349ba86b64caedc768619be8f
|
7
|
+
data.tar.gz: 81d737f13af364095e871df44000f6293d1c062929d7f859cd3836d23c3cf602a1362a9653fd739f1726c4d1004e0bad1806e3cb3fde23dc4aef081e39dfbd6a
|
data/Gemfile
CHANGED
@@ -8,6 +8,7 @@ gemspec
|
|
8
8
|
|
9
9
|
gem 'minitest', '~>5.25', require: false
|
10
10
|
gem 'minitest-reporters', '~>1.7', require: false
|
11
|
+
gem 'minitest-stub-const', '~>0.6', require: false
|
11
12
|
gem 'os', '~>1.1', require: false
|
12
13
|
gem 'qbash', '~>0.4', require: false
|
13
14
|
gem 'rake', '~>13.3', require: false
|
data/Gemfile.lock
CHANGED
@@ -143,6 +143,7 @@ GEM
|
|
143
143
|
builder
|
144
144
|
minitest (>= 5.0)
|
145
145
|
ruby-progressbar
|
146
|
+
minitest-stub-const (0.6)
|
146
147
|
moments (0.3.0)
|
147
148
|
multipart-post (2.4.1)
|
148
149
|
net-http (0.6.0)
|
@@ -179,7 +180,7 @@ GEM
|
|
179
180
|
regexp_parser (2.10.0)
|
180
181
|
retries (0.0.5)
|
181
182
|
rexml (3.4.1)
|
182
|
-
rubocop (1.76.
|
183
|
+
rubocop (1.76.1)
|
183
184
|
json (~> 2.3)
|
184
185
|
language_server-protocol (~> 3.17.0.2)
|
185
186
|
lint_roller (~> 1.1.0)
|
@@ -190,7 +191,7 @@ GEM
|
|
190
191
|
rubocop-ast (>= 1.45.0, < 2.0)
|
191
192
|
ruby-progressbar (~> 1.7)
|
192
193
|
unicode-display_width (>= 2.4.0, < 4.0)
|
193
|
-
rubocop-ast (1.45.
|
194
|
+
rubocop-ast (1.45.1)
|
194
195
|
parser (>= 3.3.7.2)
|
195
196
|
prism (~> 1.4)
|
196
197
|
rubocop-minitest (0.38.1)
|
@@ -258,6 +259,7 @@ DEPENDENCIES
|
|
258
259
|
fbe!
|
259
260
|
minitest (~> 5.25)
|
260
261
|
minitest-reporters (~> 1.7)
|
262
|
+
minitest-stub-const (~> 0.6)
|
261
263
|
os (~> 1.1)
|
262
264
|
qbash (~> 0.4)
|
263
265
|
rake (~> 13.3)
|
@@ -3,6 +3,7 @@
|
|
3
3
|
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Zerocracy
|
4
4
|
# SPDX-License-Identifier: MIT
|
5
5
|
|
6
|
+
require 'time'
|
6
7
|
require 'json'
|
7
8
|
require 'sqlite3'
|
8
9
|
require_relative '../../fbe'
|
@@ -16,18 +17,20 @@ require_relative '../../fbe/middleware'
|
|
16
17
|
class Fbe::Middleware::SqliteStore
|
17
18
|
attr_reader :path
|
18
19
|
|
19
|
-
def initialize(path)
|
20
|
+
def initialize(path, version)
|
20
21
|
raise ArgumentError, 'Database path cannot be nil or empty' if path.nil? || path.empty?
|
21
22
|
dir = File.dirname(path)
|
22
23
|
raise ArgumentError, "Directory #{dir} does not exist" unless File.directory?(dir)
|
24
|
+
raise ArgumentError, 'Version cannot be nil or empty' if version.nil? || version.empty?
|
23
25
|
@path = File.absolute_path(path)
|
24
|
-
|
25
|
-
prepare
|
26
|
-
at_exit { close }
|
26
|
+
@version = version
|
27
27
|
end
|
28
28
|
|
29
29
|
def read(key)
|
30
|
-
value = perform
|
30
|
+
value = perform do |t|
|
31
|
+
t.execute('UPDATE cache SET touched_at = ?2 WHERE key = ?1;', [key, Time.now.utc.iso8601])
|
32
|
+
t.execute('SELECT value FROM cache WHERE key = ? LIMIT 1;', [key])
|
33
|
+
end.dig(0, 0)
|
31
34
|
JSON.parse(value) if value
|
32
35
|
end
|
33
36
|
|
@@ -37,40 +40,27 @@ class Fbe::Middleware::SqliteStore
|
|
37
40
|
end
|
38
41
|
|
39
42
|
def write(key, value)
|
43
|
+
return if value.is_a?(Array) && value.any? do |vv|
|
44
|
+
req = JSON.parse(vv[0])
|
45
|
+
req['url'].include?('?') || req['method'] != 'get'
|
46
|
+
end
|
40
47
|
value = JSON.dump(value)
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
48
|
+
return if value.bytesize > 10_000
|
49
|
+
perform do |t|
|
50
|
+
t.execute(<<~SQL, [key, value, Time.now.utc.iso8601])
|
51
|
+
INSERT INTO cache(key, value, touched_at) VALUES(?1, ?2, ?3)
|
52
|
+
ON CONFLICT(key) DO UPDATE SET value = ?2, touched_at = ?3
|
45
53
|
SQL
|
46
54
|
end
|
47
55
|
nil
|
48
56
|
end
|
49
57
|
|
50
|
-
def open
|
51
|
-
return if @db
|
52
|
-
@db = SQLite3::Database.new(@path)
|
53
|
-
end
|
54
|
-
|
55
|
-
def prepare
|
56
|
-
perform do |tdb|
|
57
|
-
tdb.execute 'CREATE TABLE IF NOT EXISTS cache(key TEXT UNIQUE NOT NULL, value TEXT);'
|
58
|
-
tdb.execute 'CREATE INDEX IF NOT EXISTS key_idx ON cache(key);'
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def close
|
63
|
-
return if !@db || @db.closed?
|
64
|
-
@db.close
|
65
|
-
@db = nil
|
66
|
-
end
|
67
|
-
|
68
58
|
def clear
|
69
|
-
perform
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
59
|
+
perform do |t|
|
60
|
+
t.execute 'DELETE FROM cache;'
|
61
|
+
t.execute "UPDATE meta SET value = ? WHERE key = 'version';", [@version]
|
62
|
+
end
|
63
|
+
@db.execute 'VACUUM;'
|
74
64
|
end
|
75
65
|
|
76
66
|
def all
|
@@ -80,6 +70,43 @@ class Fbe::Middleware::SqliteStore
|
|
80
70
|
private
|
81
71
|
|
82
72
|
def perform(&)
|
73
|
+
@db ||=
|
74
|
+
SQLite3::Database.new(@path).tap do |d|
|
75
|
+
d.transaction do |t|
|
76
|
+
t.execute <<~SQL
|
77
|
+
CREATE TABLE IF NOT EXISTS cache(
|
78
|
+
key TEXT UNIQUE NOT NULL, value TEXT, touched_at TEXT NOT NULL
|
79
|
+
);
|
80
|
+
SQL
|
81
|
+
t.execute 'CREATE INDEX IF NOT EXISTS cache_key_idx ON cache(key);'
|
82
|
+
t.execute 'CREATE INDEX IF NOT EXISTS cache_touched_at_idx ON cache(touched_at);'
|
83
|
+
t.execute 'CREATE TABLE IF NOT EXISTS meta(key TEXT UNIQUE NOT NULL, value TEXT);'
|
84
|
+
t.execute 'CREATE INDEX IF NOT EXISTS meta_key_idx ON meta(key);'
|
85
|
+
t.execute "INSERT INTO meta(key, value) VALUES('version', ?) ON CONFLICT(key) DO NOTHING;", [@version]
|
86
|
+
end
|
87
|
+
if d.execute("SELECT value FROM meta WHERE key = 'version' LIMIT 1;").dig(0, 0) != @version
|
88
|
+
d.transaction do |t|
|
89
|
+
t.execute 'DELETE FROM cache;'
|
90
|
+
t.execute "UPDATE meta SET value = ? WHERE key = 'version';", [@version]
|
91
|
+
end
|
92
|
+
d.execute 'VACUUM;'
|
93
|
+
end
|
94
|
+
if File.size(@path) > 10 * 1024 * 1024
|
95
|
+
while d.execute(<<~SQL).dig(0, 0) > 10 * 1024 * 1024
|
96
|
+
SELECT (page_count - freelist_count) * page_size AS size
|
97
|
+
FROM pragma_page_count(), pragma_freelist_count(), pragma_page_size();
|
98
|
+
SQL
|
99
|
+
d.transaction do |t|
|
100
|
+
t.execute <<~SQL
|
101
|
+
DELETE FROM cache
|
102
|
+
WHERE key IN (SELECT key FROM cache ORDER BY touched_at LIMIT 50)
|
103
|
+
SQL
|
104
|
+
end
|
105
|
+
end
|
106
|
+
d.execute 'VACUUM;'
|
107
|
+
end
|
108
|
+
at_exit { @db&.close }
|
109
|
+
end
|
83
110
|
@db.transaction(&)
|
84
111
|
end
|
85
112
|
end
|
data/lib/fbe/octo.rb
CHANGED
@@ -76,16 +76,24 @@ def Fbe.octo(options: $options, global: $global, loog: $loog)
|
|
76
76
|
methods: [:get],
|
77
77
|
backoff_factor: 2
|
78
78
|
)
|
79
|
-
serializer = Marshal
|
80
79
|
if options.sqlite_cache
|
81
|
-
store = Fbe::Middleware::SqliteStore.new(options.sqlite_cache)
|
82
|
-
|
83
|
-
|
80
|
+
store = Fbe::Middleware::SqliteStore.new(options.sqlite_cache, Fbe::VERSION)
|
81
|
+
loog.info(
|
82
|
+
"Using HTTP cache in SQLite file: #{store.path} (" \
|
83
|
+
"#{File.exist?(store.path) ? "#{File.size(store.path)} bytes" : 'file is absent'}" \
|
84
|
+
')'
|
85
|
+
)
|
86
|
+
builder.use(
|
87
|
+
Faraday::HttpCache,
|
88
|
+
store:, serializer: JSON, shared_cache: false, logger: Loog::NULL
|
89
|
+
)
|
90
|
+
else
|
91
|
+
loog.info("No HTTP cache in SQLite file, because 'sqlite_cache' option is not provided")
|
92
|
+
builder.use(
|
93
|
+
Faraday::HttpCache,
|
94
|
+
serializer: Marshal, shared_cache: false, logger: Loog::NULL
|
95
|
+
)
|
84
96
|
end
|
85
|
-
builder.use(
|
86
|
-
Faraday::HttpCache,
|
87
|
-
store: store, serializer: serializer, shared_cache: false, logger: Loog::NULL
|
88
|
-
)
|
89
97
|
builder.use(Octokit::Response::RaiseError)
|
90
98
|
builder.use(Faraday::Response::Logger, loog, formatter: Fbe::Middleware::Formatter)
|
91
99
|
builder.use(Fbe::Middleware::Trace, trace)
|
data/lib/fbe.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Zerocracy
|
4
4
|
# SPDX-License-Identifier: MIT
|
5
5
|
|
6
|
+
require 'qbash'
|
6
7
|
require_relative '../../test__helper'
|
7
8
|
require_relative '../../../lib/fbe/middleware'
|
8
9
|
require_relative '../../../lib/fbe/middleware/sqlite_store'
|
@@ -12,24 +13,180 @@ require_relative '../../../lib/fbe/middleware/sqlite_store'
|
|
12
13
|
# Copyright:: Copyright (c) 2024-2025 Zerocracy
|
13
14
|
# License:: MIT
|
14
15
|
class SqliteStoreTest < Fbe::Test
|
15
|
-
def
|
16
|
-
|
17
|
-
store = Fbe::Middleware::SqliteStore.new(
|
18
|
-
|
19
|
-
assert_nil(store.
|
20
|
-
assert_nil(store.
|
21
|
-
|
22
|
-
assert_nil(store.write(
|
23
|
-
assert_equal(
|
24
|
-
|
25
|
-
assert_nil(store.
|
16
|
+
def test_simple_caching_algorithm
|
17
|
+
with_tmpfile('x.db') do |f|
|
18
|
+
store = Fbe::Middleware::SqliteStore.new(f, '0.0.0')
|
19
|
+
k = 'some-key'
|
20
|
+
assert_nil(store.read(k))
|
21
|
+
assert_nil(store.delete(k))
|
22
|
+
v1 = 'first value to save'
|
23
|
+
assert_nil(store.write(k, v1))
|
24
|
+
assert_equal(v1, store.read(k))
|
25
|
+
v2 = 'another value to save'
|
26
|
+
assert_nil(store.write(k, v2))
|
27
|
+
assert_equal(v2, store.read(k))
|
28
|
+
assert_nil(store.delete(k))
|
29
|
+
assert_nil(store.read(k))
|
30
|
+
assert_path_exists(f)
|
26
31
|
end
|
27
32
|
end
|
28
33
|
|
29
|
-
def
|
30
|
-
|
31
|
-
store = Fbe::Middleware::SqliteStore.new(
|
34
|
+
def test_returns_empty_list
|
35
|
+
with_tmpfile('b.db') do |f|
|
36
|
+
store = Fbe::Middleware::SqliteStore.new(f, '0.0.0')
|
37
|
+
assert_empty(store.all)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_clear_all_keys
|
42
|
+
with_tmpfile('a.db') do |f|
|
43
|
+
store = Fbe::Middleware::SqliteStore.new(f, '0.0.0')
|
44
|
+
k = 'a key'
|
45
|
+
store.write(k, 'some value')
|
46
|
+
store.clear
|
47
|
+
assert_empty(store.all)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_empty_all_if_not_written
|
52
|
+
with_tmpfile do |f|
|
53
|
+
store = Fbe::Middleware::SqliteStore.new(f, '0.0.0')
|
32
54
|
assert_empty(store.all)
|
33
55
|
end
|
34
56
|
end
|
57
|
+
|
58
|
+
def test_wrong_db_path
|
59
|
+
assert_raises(ArgumentError) do
|
60
|
+
Fbe::Middleware::SqliteStore.new(nil, '0.0.0').read('my_key')
|
61
|
+
end
|
62
|
+
assert_raises(ArgumentError) do
|
63
|
+
Fbe::Middleware::SqliteStore.new('', '0.0.0').read('my_key')
|
64
|
+
end
|
65
|
+
assert_raises(ArgumentError) do
|
66
|
+
Fbe::Middleware::SqliteStore.new('/fakepath/fakefolder/test.db', '0.0.0').read('my_key')
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_not_db_file
|
71
|
+
with_tmpfile do |f|
|
72
|
+
File.binwrite(f, Array.new(20) { rand(0..255) }.pack('C*'))
|
73
|
+
ex =
|
74
|
+
assert_raises(SQLite3::NotADatabaseException) do
|
75
|
+
Fbe::Middleware::SqliteStore.new(f, '0.0.0').read('my_key')
|
76
|
+
end
|
77
|
+
assert_match('file is not a database', ex.message)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_defer_db_close_callback
|
82
|
+
txt = <<~RUBY
|
83
|
+
require 'tempfile'
|
84
|
+
require 'sqlite3'
|
85
|
+
require 'fbe/middleware/sqlite_store'
|
86
|
+
|
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
|
+
|
96
|
+
Tempfile.open('test.db') do |f|
|
97
|
+
Fbe::Middleware::SqliteStore.new(f.path, '0.0.0').then do |s|
|
98
|
+
s.write('my_key', 'my_value')
|
99
|
+
s.read('my_key')
|
100
|
+
end
|
101
|
+
end
|
102
|
+
RUBY
|
103
|
+
out =
|
104
|
+
qbash(
|
105
|
+
'bundle exec ruby ' \
|
106
|
+
"-I#{Shellwords.escape(File.expand_path('../../../lib', __dir__))} " \
|
107
|
+
"-e #{Shellwords.escape(txt)} 2>&1"
|
108
|
+
)
|
109
|
+
assert_match('closed sqlite after process exit', out)
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_different_versions
|
113
|
+
with_tmpfile('d.db') do |f|
|
114
|
+
Fbe::Middleware::SqliteStore.new(f, '0.0.1').then do |store|
|
115
|
+
store.write('kkk1', 'some value')
|
116
|
+
store.write('kkk2', 'another value')
|
117
|
+
end
|
118
|
+
Fbe::Middleware::SqliteStore.new(f, '0.0.1').then do |store|
|
119
|
+
assert_equal('some value', store.read('kkk1'))
|
120
|
+
assert_equal('another value', store.read('kkk2'))
|
121
|
+
end
|
122
|
+
Fbe::Middleware::SqliteStore.new(f, '0.0.2').then do |store|
|
123
|
+
assert_nil(store.read('kkk1'))
|
124
|
+
assert_nil(store.read('kkk2'))
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_initialize_wrong_version
|
130
|
+
with_tmpfile('e.db') do |f|
|
131
|
+
msg = 'Version cannot be nil or empty'
|
132
|
+
assert_raises(ArgumentError) { Fbe::Middleware::SqliteStore.new(f, nil) }.then do |ex|
|
133
|
+
assert_match(msg, ex.message)
|
134
|
+
end
|
135
|
+
assert_raises(ArgumentError) { Fbe::Middleware::SqliteStore.new(f, '') }.then do |ex|
|
136
|
+
assert_match(msg, ex.message)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_skip_write_if_value_more_then_10k_bytes
|
142
|
+
with_tmpfile('a.db') do |f|
|
143
|
+
Fbe::Middleware::SqliteStore.new(f, '0.0.1').then do |store|
|
144
|
+
store.write('a', 'a' * 9_997)
|
145
|
+
store.write('b', 'b' * 9_998)
|
146
|
+
store.write('c', 'c' * 9_999)
|
147
|
+
store.write('d', 'd' * 10_000)
|
148
|
+
assert_equal('a' * 9_997, store.read('a'))
|
149
|
+
assert_equal('b' * 9_998, store.read('b'))
|
150
|
+
assert_nil(store.read('c'))
|
151
|
+
assert_nil(store.read('d'))
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def test_shrink_cache_if_more_then_10_mb
|
157
|
+
with_tmpfile('large.db') do |f|
|
158
|
+
Fbe::Middleware::SqliteStore.new(f, '0.0.1').then do |store|
|
159
|
+
key = 'aaa'
|
160
|
+
alpha = ('a'..'z').to_a
|
161
|
+
store.write('a', 'aa')
|
162
|
+
Time.stub(:now, (Time.now - (5 * 60 * 60)).round) do
|
163
|
+
store.write('b', 'bb')
|
164
|
+
store.write('c', 'cc')
|
165
|
+
end
|
166
|
+
assert_equal('cc', store.read('c'))
|
167
|
+
Time.stub(:now, rand((Time.now - (5 * 60 * 60))..Time.now).round) do
|
168
|
+
10_240.times do
|
169
|
+
value = alpha.sample * rand(1024..2048)
|
170
|
+
store.write(key, value)
|
171
|
+
key = key.next
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
assert_operator(File.size(f), :>, 10 * 1024 * 1024)
|
176
|
+
Fbe::Middleware::SqliteStore.new(f, '0.0.1').then do |store|
|
177
|
+
assert_equal('aa', store.read('a'))
|
178
|
+
assert_nil(store.read('b'))
|
179
|
+
assert_equal('cc', store.read('c'))
|
180
|
+
assert_operator(File.size(f), :<=, 10 * 1024 * 1024)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
private
|
186
|
+
|
187
|
+
def with_tmpfile(name = 'test.db', &)
|
188
|
+
Dir.mktmpdir do |dir|
|
189
|
+
yield File.expand_path(name, dir)
|
190
|
+
end
|
191
|
+
end
|
35
192
|
end
|
data/test/fbe/test_octo.rb
CHANGED
@@ -256,7 +256,10 @@ class TestOcto < Fbe::Test
|
|
256
256
|
end
|
257
257
|
|
258
258
|
def test_reads_quota
|
259
|
-
WebMock.
|
259
|
+
WebMock.disable_net_connect!
|
260
|
+
stub_request(:get, 'https://api.github.com/rate_limit').to_return(
|
261
|
+
{ body: '{}', headers: { 'X-RateLimit-Remaining' => '222' } }
|
262
|
+
)
|
260
263
|
o = Fbe.octo(loog: Loog::VERBOSE, global: {}, options: Judges::Options.new({ 'github_api_pause' => 0.01 }))
|
261
264
|
refute_nil(o.off_quota?)
|
262
265
|
end
|
@@ -365,7 +368,7 @@ class TestOcto < Fbe::Test
|
|
365
368
|
assert_includes second_output, 'GitHub API trace is empty'
|
366
369
|
end
|
367
370
|
|
368
|
-
def
|
371
|
+
def test_works_via_sqlite_store
|
369
372
|
WebMock.disable_net_connect!
|
370
373
|
Dir.mktmpdir do |dir|
|
371
374
|
global = {}
|
@@ -402,4 +405,45 @@ class TestOcto < Fbe::Test
|
|
402
405
|
assert_path_exists(file)
|
403
406
|
end
|
404
407
|
end
|
408
|
+
|
409
|
+
def test_sqlite_store_for_use_in_different_versions
|
410
|
+
WebMock.disable_net_connect!
|
411
|
+
Dir.mktmpdir do |dir|
|
412
|
+
global = {}
|
413
|
+
stub =
|
414
|
+
stub_request(:get, 'https://api.github.com/user/42')
|
415
|
+
.to_return(
|
416
|
+
status: 200,
|
417
|
+
body: { login: 'user1' }.to_json,
|
418
|
+
headers: {
|
419
|
+
'Content-Type' => 'application/json',
|
420
|
+
'Cache-Control' => 'public, max-age=60, s-maxage=60',
|
421
|
+
'Etag' => 'W/"2ff9dd4c3153f006830b2b8b721f6a4bb400a1eb81a2e1fa0a3b846ad349b9ec"',
|
422
|
+
'Last-Modified' => 'Wed, 01 May 2025 20:00:00 GMT'
|
423
|
+
}
|
424
|
+
)
|
425
|
+
sqlite_cache = File.expand_path('test.db', dir)
|
426
|
+
Fbe.stub_const(:VERSION, '0.0.1') do
|
427
|
+
o = Fbe.octo(loog: Loog::NULL, global:, options: Judges::Options.new({ 'sqlite_cache' => sqlite_cache }))
|
428
|
+
assert_equal('user1', o.user_name_by_id(42))
|
429
|
+
end
|
430
|
+
WebMock.remove_request_stub(stub)
|
431
|
+
stub_request(:get, 'https://api.github.com/user/42')
|
432
|
+
.to_return(
|
433
|
+
status: 200,
|
434
|
+
body: { login: 'user2' }.to_json,
|
435
|
+
headers: {
|
436
|
+
'Content-Type' => 'application/json',
|
437
|
+
'Cache-Control' => 'public, max-age=60, s-maxage=60',
|
438
|
+
'Etag' => 'W/"2ff9dd4c3153f006830b2b8b721f6a4bb400a1eb81a2e1fa0a3b846ad349b9ec"',
|
439
|
+
'Last-Modified' => 'Wed, 01 May 2025 20:00:00 GMT'
|
440
|
+
}
|
441
|
+
)
|
442
|
+
global = {}
|
443
|
+
Fbe.stub_const(:VERSION, '0.0.2') do
|
444
|
+
o = Fbe.octo(loog: Loog::NULL, global:, options: Judges::Options.new({ 'sqlite_cache' => sqlite_cache }))
|
445
|
+
assert_equal('user2', o.user_name_by_id(42))
|
446
|
+
end
|
447
|
+
end
|
448
|
+
end
|
405
449
|
end
|
data/test/test__helper.rb
CHANGED