zache 0.15.0 → 0.15.2
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 +5 -4
- data/Gemfile.lock +46 -32
- data/README.md +36 -19
- data/REUSE.toml +12 -7
- data/Rakefile +6 -1
- data/lib/zache.rb +129 -55
- data/zache.gemspec +2 -2
- metadata +3 -21
- data/.0pdd.yml +0 -12
- data/.github/workflows/actionlint.yml +0 -25
- data/.github/workflows/codecov.yml +0 -25
- data/.github/workflows/copyrights.yml +0 -15
- data/.github/workflows/license.yml +0 -42
- data/.github/workflows/markdown-lint.yml +0 -23
- data/.github/workflows/pdd.yml +0 -19
- data/.github/workflows/rake.yml +0 -28
- data/.github/workflows/reuse.yml +0 -19
- data/.github/workflows/xcop.yml +0 -21
- data/.github/workflows/yamllint.yml +0 -19
- data/.gitignore +0 -10
- data/.pdd +0 -5
- data/.rubocop.yml +0 -40
- data/.rultor.yml +0 -26
- data/renovate.json +0 -6
- data/test/test__helper.rb +0 -31
- data/test/test_zache.rb +0 -311
data/test/test_zache.rb
DELETED
|
@@ -1,311 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2018-2025 Yegor Bugayenko
|
|
4
|
-
# SPDX-License-Identifier: MIT
|
|
5
|
-
|
|
6
|
-
require 'concurrent'
|
|
7
|
-
require 'minitest/autorun'
|
|
8
|
-
require 'securerandom'
|
|
9
|
-
require 'threads'
|
|
10
|
-
require 'timeout'
|
|
11
|
-
require_relative '../lib/zache'
|
|
12
|
-
require_relative 'test__helper'
|
|
13
|
-
|
|
14
|
-
Thread.report_on_exception = true
|
|
15
|
-
|
|
16
|
-
# Cache test.
|
|
17
|
-
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
18
|
-
# Copyright:: Copyright (c) 2018-2025 Yegor Bugayenko
|
|
19
|
-
# License:: MIT
|
|
20
|
-
class ZacheTest < Minitest::Test
|
|
21
|
-
def test_caches
|
|
22
|
-
z = Zache.new(sync: false)
|
|
23
|
-
first = z.get(:hey, lifetime: 5) { rand }
|
|
24
|
-
second = z.get(:hey) { rand }
|
|
25
|
-
assert_equal(first, second)
|
|
26
|
-
assert_equal(1, z.size)
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def test_caches_and_expires
|
|
30
|
-
z = Zache.new
|
|
31
|
-
first = z.get(:hey, lifetime: 0.01) { rand }
|
|
32
|
-
sleep 0.1
|
|
33
|
-
second = z.get(:hey) { rand }
|
|
34
|
-
refute_equal(first, second)
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def test_calculates_age
|
|
38
|
-
z = Zache.new
|
|
39
|
-
z.get(:hey) { rand }
|
|
40
|
-
sleep 0.1
|
|
41
|
-
assert_operator(z.mtime(:hey), :<, Time.now - 0.05)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def test_caches_in_threads
|
|
45
|
-
z = Zache.new
|
|
46
|
-
Threads.new(10).assert(100) do
|
|
47
|
-
z.get(:hey, lifetime: 0.0001) { rand }
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def test_key_exists
|
|
52
|
-
z = Zache.new
|
|
53
|
-
z.get(:hey) { rand }
|
|
54
|
-
exists_result = z.exists?(:hey)
|
|
55
|
-
not_exists_result = z.exists?(:bye)
|
|
56
|
-
assert(exists_result)
|
|
57
|
-
refute(not_exists_result)
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def test_put_and_exists
|
|
61
|
-
z = Zache.new
|
|
62
|
-
z.put(:hey, 'hello', lifetime: 0.1)
|
|
63
|
-
sleep 0.2
|
|
64
|
-
refute(z.exists?(:hey))
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def test_remove_key
|
|
68
|
-
z = Zache.new
|
|
69
|
-
z.get(:hey) { rand }
|
|
70
|
-
z.get(:wey) { rand }
|
|
71
|
-
assert(z.exists?(:hey))
|
|
72
|
-
assert(z.exists?(:wey))
|
|
73
|
-
z.remove(:hey)
|
|
74
|
-
refute(z.exists?(:hey))
|
|
75
|
-
assert(z.exists?(:wey))
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def test_remove_by_block
|
|
79
|
-
z = Zache.new
|
|
80
|
-
z.get('first') { rand }
|
|
81
|
-
z.get('second') { rand }
|
|
82
|
-
z.remove_by { |k| k == 'first' }
|
|
83
|
-
refute(z.exists?('first'))
|
|
84
|
-
assert(z.exists?('second'))
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def test_remove_key_with_sync_false
|
|
88
|
-
z = Zache.new(sync: false)
|
|
89
|
-
z.get(:hey) { rand }
|
|
90
|
-
z.get(:wey) { rand }
|
|
91
|
-
assert(z.exists?(:hey))
|
|
92
|
-
assert(z.exists?(:wey))
|
|
93
|
-
z.remove(:hey)
|
|
94
|
-
refute(z.exists?(:hey))
|
|
95
|
-
assert(z.exists?(:wey))
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
def test_clean_with_threads
|
|
99
|
-
z = Zache.new
|
|
100
|
-
Threads.new(300).assert(3000) do
|
|
101
|
-
z.get(:hey) { rand }
|
|
102
|
-
z.get(:bye, lifetime: 0.01) { rand }
|
|
103
|
-
sleep 0.1
|
|
104
|
-
z.clean
|
|
105
|
-
end
|
|
106
|
-
assert(z.exists?(:hey))
|
|
107
|
-
refute(z.exists?(:bye))
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
def test_clean
|
|
111
|
-
z = Zache.new
|
|
112
|
-
z.get(:hey) { rand }
|
|
113
|
-
z.get(:bye, lifetime: 0.01) { rand }
|
|
114
|
-
sleep 0.1
|
|
115
|
-
z.clean
|
|
116
|
-
assert(z.exists?(:hey))
|
|
117
|
-
refute(z.exists?(:bye))
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
def test_clean_size
|
|
121
|
-
z = Zache.new
|
|
122
|
-
z.get(:hey, lifetime: 0.01) { rand }
|
|
123
|
-
sleep 0.1
|
|
124
|
-
z.clean
|
|
125
|
-
assert_empty(z)
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
def test_clean_with_sync_false
|
|
129
|
-
z = Zache.new(sync: false)
|
|
130
|
-
z.get(:hey) { rand }
|
|
131
|
-
z.get(:bye, lifetime: 0.01) { rand }
|
|
132
|
-
sleep 0.1
|
|
133
|
-
z.clean
|
|
134
|
-
assert(z.exists?(:hey))
|
|
135
|
-
refute(z.exists?(:bye))
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
def test_remove_absent_key
|
|
139
|
-
z = Zache.new
|
|
140
|
-
z.remove(:hey)
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
def test_check_and_remove
|
|
144
|
-
z = Zache.new
|
|
145
|
-
z.get(:hey, lifetime: 0) { rand }
|
|
146
|
-
refute(z.exists?(:hey))
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
def test_remove_all_with_threads
|
|
150
|
-
z = Zache.new
|
|
151
|
-
Threads.new(10).assert(100) do |i|
|
|
152
|
-
z.get(:"hey#{i}") { rand }
|
|
153
|
-
assert(z.exists?(:"hey#{i}"))
|
|
154
|
-
z.remove_all
|
|
155
|
-
end
|
|
156
|
-
10.times do |i|
|
|
157
|
-
refute(z.exists?(:"hey#{i}"))
|
|
158
|
-
end
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
def test_remove_all_with_sync
|
|
162
|
-
z = Zache.new
|
|
163
|
-
z.get(:hey) { rand }
|
|
164
|
-
z.get(:bye) { rand }
|
|
165
|
-
z.remove_all
|
|
166
|
-
refute(z.exists?(:hey))
|
|
167
|
-
refute(z.exists?(:bye))
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
def test_remove_all_without_sync
|
|
171
|
-
z = Zache.new(sync: false)
|
|
172
|
-
z.get(:hey) { rand }
|
|
173
|
-
z.get(:bye) { rand }
|
|
174
|
-
z.remove_all
|
|
175
|
-
refute(z.exists?(:hey))
|
|
176
|
-
refute(z.exists?(:bye))
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
def test_puts_something_in
|
|
180
|
-
z = Zache.new(sync: false)
|
|
181
|
-
z.get(:hey) { rand }
|
|
182
|
-
z.put(:hey, 123)
|
|
183
|
-
assert_equal(123, z.get(:hey))
|
|
184
|
-
end
|
|
185
|
-
|
|
186
|
-
def test_sync_zache_is_not_reentrant
|
|
187
|
-
z = Zache.new
|
|
188
|
-
assert_raises ThreadError do
|
|
189
|
-
z.get(:first) { z.get(:first) { 1 } }
|
|
190
|
-
end
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
def test_sync_zache_is_reentrant_for_different_keys
|
|
194
|
-
z = Zache.new
|
|
195
|
-
z.get(:first) { z.get(:second) { 1 } }
|
|
196
|
-
end
|
|
197
|
-
|
|
198
|
-
def test_calculates_only_once
|
|
199
|
-
z = Zache.new
|
|
200
|
-
long = Thread.start do
|
|
201
|
-
z.get(:x) do
|
|
202
|
-
sleep 0.5
|
|
203
|
-
'first'
|
|
204
|
-
end
|
|
205
|
-
end
|
|
206
|
-
sleep 0.1
|
|
207
|
-
assert(z.locked?(:x))
|
|
208
|
-
z.get(:x) { 'second' }
|
|
209
|
-
refute(z.locked?(:x))
|
|
210
|
-
long.kill
|
|
211
|
-
end
|
|
212
|
-
|
|
213
|
-
def test_checks_locked_status_from_inside
|
|
214
|
-
z = Zache.new
|
|
215
|
-
z.get(:x) do
|
|
216
|
-
assert(z.locked?(:x))
|
|
217
|
-
'done'
|
|
218
|
-
end
|
|
219
|
-
refute(z.locked?(:x))
|
|
220
|
-
end
|
|
221
|
-
|
|
222
|
-
def test_returns_dirty_result
|
|
223
|
-
z = Zache.new(dirty: true)
|
|
224
|
-
z.get(:x, lifetime: 0) { 1 }
|
|
225
|
-
long = Thread.start do
|
|
226
|
-
z.get(:x) do
|
|
227
|
-
sleep 1000
|
|
228
|
-
2
|
|
229
|
-
end
|
|
230
|
-
end
|
|
231
|
-
sleep 0.1
|
|
232
|
-
Timeout.timeout(1) do
|
|
233
|
-
assert(z.exists?(:x))
|
|
234
|
-
assert(z.expired?(:x))
|
|
235
|
-
assert_equal(1, z.get(:x))
|
|
236
|
-
assert_equal(1, z.get(:x) { 2 })
|
|
237
|
-
end
|
|
238
|
-
long.kill
|
|
239
|
-
end
|
|
240
|
-
|
|
241
|
-
def test_returns_dirty_result_when_not_locked
|
|
242
|
-
z = Zache.new(dirty: true)
|
|
243
|
-
z.get(:x, lifetime: 0) { 1 }
|
|
244
|
-
assert(z.exists?(:x))
|
|
245
|
-
assert_equal(1, z.get(:x))
|
|
246
|
-
assert_equal(2, z.get(:x) { 2 })
|
|
247
|
-
end
|
|
248
|
-
|
|
249
|
-
def test_fetches_multiple_keys_in_many_threads_in_dirty_mode
|
|
250
|
-
z = Zache.new(dirty: true)
|
|
251
|
-
set = Concurrent::Set.new
|
|
252
|
-
threads = 50
|
|
253
|
-
barrier = Concurrent::CyclicBarrier.new(threads)
|
|
254
|
-
Threads.new(threads).assert(threads * 2) do |i|
|
|
255
|
-
barrier.wait if i < threads
|
|
256
|
-
set << z.get(i, lifetime: 0.001) { i }
|
|
257
|
-
end
|
|
258
|
-
assert_equal(threads, set.size)
|
|
259
|
-
end
|
|
260
|
-
|
|
261
|
-
def test_fetches_multiple_keys_in_many_threads
|
|
262
|
-
z = Zache.new
|
|
263
|
-
set = Concurrent::Set.new
|
|
264
|
-
threads = 50
|
|
265
|
-
barrier = Concurrent::CyclicBarrier.new(threads)
|
|
266
|
-
Threads.new(threads).assert(threads * 2) do |i|
|
|
267
|
-
barrier.wait if i < threads
|
|
268
|
-
set << z.get(i) { i }
|
|
269
|
-
end
|
|
270
|
-
assert_equal(threads, set.size)
|
|
271
|
-
end
|
|
272
|
-
|
|
273
|
-
def test_fake_class_works
|
|
274
|
-
z = Zache::Fake.new
|
|
275
|
-
assert_equal(1, z.get(:x) { 1 })
|
|
276
|
-
end
|
|
277
|
-
|
|
278
|
-
def test_rethrows
|
|
279
|
-
z = Zache.new
|
|
280
|
-
assert_raises RuntimeError do
|
|
281
|
-
z.get(:hey) { raise 'intentional' }
|
|
282
|
-
end
|
|
283
|
-
end
|
|
284
|
-
|
|
285
|
-
def test_returns_placeholder_in_eager_mode
|
|
286
|
-
z = Zache.new
|
|
287
|
-
a = z.get(:me, placeholder: 42, eager: true) do
|
|
288
|
-
sleep 0.1
|
|
289
|
-
43
|
|
290
|
-
end
|
|
291
|
-
assert_equal(42, a)
|
|
292
|
-
sleep 0.2
|
|
293
|
-
b = z.get(:me)
|
|
294
|
-
assert_equal(43, b)
|
|
295
|
-
end
|
|
296
|
-
|
|
297
|
-
def test_returns_placeholder_and_releases_lock
|
|
298
|
-
z = Zache.new
|
|
299
|
-
z.get(:slow, placeholder: 42, eager: true) do
|
|
300
|
-
sleep 9999
|
|
301
|
-
end
|
|
302
|
-
sleep 0.1
|
|
303
|
-
assert_equal(555, z.get(:fast) { 555 })
|
|
304
|
-
end
|
|
305
|
-
|
|
306
|
-
private
|
|
307
|
-
|
|
308
|
-
def rand
|
|
309
|
-
SecureRandom.uuid
|
|
310
|
-
end
|
|
311
|
-
end
|