factbase 0.15.0 → 0.15.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 +4 -4
- data/Gemfile.lock +5 -5
- data/factbase.gemspec +4 -4
- data/lib/factbase/fact.rb +1 -1
- data/lib/factbase/fact_as_yaml.rb +10 -1
- data/lib/factbase/indexed/indexed_term.rb +6 -1
- data/lib/factbase/version.rb +1 -1
- metadata +7 -87
- data/.0pdd.yml +0 -8
- data/.gitattributes +0 -7
- data/.github/publish-benchmark.sh +0 -24
- data/.github/workflows/actionlint.yml +0 -25
- data/.github/workflows/benchmark.yml +0 -36
- data/.github/workflows/codecov.yml +0 -27
- data/.github/workflows/copyrights.yml +0 -19
- 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/typos.yml +0 -19
- data/.github/workflows/xcop.yml +0 -19
- data/.github/workflows/yamllint.yml +0 -19
- data/.gitignore +0 -11
- data/.pdd +0 -7
- data/.rubocop.yml +0 -51
- data/.rultor.yml +0 -27
- data/benchmark/bench_factbase.rb +0 -61
- data/benchmark/bench_large_query.rb +0 -128
- data/benchmark/bench_query.rb +0 -57
- data/benchmark/bench_taped.rb +0 -33
- data/fixtures/stories/agg.yml +0 -17
- data/fixtures/stories/always.yml +0 -16
- data/fixtures/stories/and.yml +0 -19
- data/fixtures/stories/as.yml +0 -16
- data/fixtures/stories/count.yml +0 -18
- data/fixtures/stories/empty.yml +0 -23
- data/fixtures/stories/eq.yml +0 -30
- data/fixtures/stories/gt.yml +0 -18
- data/fixtures/stories/join.yml +0 -22
- data/fixtures/stories/max.yml +0 -14
- data/fixtures/stories/min.yml +0 -14
- data/fixtures/stories/nth.yml +0 -14
- data/fixtures/stories/one.yml +0 -14
- data/fixtures/stories/or.yml +0 -18
- data/fixtures/stories/sprintf.yml +0 -12
- data/fixtures/stories/sum.yml +0 -14
- data/fixtures/stories/unique.yml +0 -30
- data/renovate.json +0 -6
- data/test/factbase/cached/test_cached_factbase.rb +0 -44
- data/test/factbase/cached/test_cached_query.rb +0 -100
- data/test/factbase/indexed/test_indexed_fact.rb +0 -23
- data/test/factbase/indexed/test_indexed_factbase.rb +0 -96
- data/test/factbase/indexed/test_indexed_query.rb +0 -208
- data/test/factbase/indexed/test_indexed_term.rb +0 -140
- data/test/factbase/sync/test_sync_factbase.rb +0 -22
- data/test/factbase/sync/test_sync_query.rb +0 -30
- data/test/factbase/terms/test_aggregates.rb +0 -63
- data/test/factbase/terms/test_aliases.rb +0 -58
- data/test/factbase/terms/test_casting.rb +0 -33
- data/test/factbase/terms/test_debug.rb +0 -111
- data/test/factbase/terms/test_defn.rb +0 -48
- data/test/factbase/terms/test_logical.rb +0 -57
- data/test/factbase/terms/test_math.rb +0 -122
- data/test/factbase/terms/test_meta.rb +0 -70
- data/test/factbase/terms/test_ordering.rb +0 -44
- data/test/factbase/terms/test_strings.rb +0 -36
- data/test/factbase/terms/test_system.rb +0 -31
- data/test/factbase/test_accum.rb +0 -74
- data/test/factbase/test_churn.rb +0 -41
- data/test/factbase/test_fact.rb +0 -108
- data/test/factbase/test_fact_as_yaml.rb +0 -77
- data/test/factbase/test_flatten.rb +0 -28
- data/test/factbase/test_impatient.rb +0 -176
- data/test/factbase/test_inv.rb +0 -44
- data/test/factbase/test_logged.rb +0 -155
- data/test/factbase/test_pre.rb +0 -35
- data/test/factbase/test_query.rb +0 -445
- data/test/factbase/test_rules.rb +0 -128
- data/test/factbase/test_syntax.rb +0 -166
- data/test/factbase/test_tallied.rb +0 -81
- data/test/factbase/test_taped.rb +0 -72
- data/test/factbase/test_tee.rb +0 -85
- data/test/factbase/test_term.rb +0 -87
- data/test/factbase/test_to_json.rb +0 -35
- data/test/factbase/test_to_xml.rb +0 -89
- data/test/factbase/test_to_yaml.rb +0 -39
- data/test/test__helper.rb +0 -41
- data/test/test_factbase.rb +0 -509
data/test/test_factbase.rb
DELETED
@@ -1,509 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
4
|
-
# SPDX-License-Identifier: MIT
|
5
|
-
|
6
|
-
require 'loog'
|
7
|
-
require 'threads'
|
8
|
-
require_relative '../lib/factbase'
|
9
|
-
require_relative '../lib/factbase/inv'
|
10
|
-
require_relative '../lib/factbase/logged'
|
11
|
-
require_relative '../lib/factbase/pre'
|
12
|
-
require_relative '../lib/factbase/rules'
|
13
|
-
require_relative 'test__helper'
|
14
|
-
|
15
|
-
# Factbase main module test.
|
16
|
-
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
17
|
-
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
|
18
|
-
# License:: MIT
|
19
|
-
class TestFactbase < Factbase::Test
|
20
|
-
def test_injects_data_correctly
|
21
|
-
maps = []
|
22
|
-
fb = Factbase.new(maps)
|
23
|
-
fb.insert
|
24
|
-
f = fb.insert
|
25
|
-
f.foo = 1
|
26
|
-
f.bar = 2
|
27
|
-
f.bar = 3
|
28
|
-
assert_equal(2, maps.size)
|
29
|
-
assert_equal(0, maps[0].size)
|
30
|
-
assert_equal(2, maps[1].size)
|
31
|
-
assert_equal([1], maps[1]['foo'])
|
32
|
-
assert_equal([2, 3], maps[1]['bar'])
|
33
|
-
end
|
34
|
-
|
35
|
-
def test_query_many_times
|
36
|
-
fb = Factbase.new
|
37
|
-
total = 5
|
38
|
-
total.times { fb.insert }
|
39
|
-
total.times do
|
40
|
-
assert_equal(5, fb.query('(always)').each.to_a.size)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def test_converts_query_to_term
|
45
|
-
fb = Factbase.new
|
46
|
-
term = fb.to_term('(eq foo 42)')
|
47
|
-
assert_equal('(eq foo 42)', term.to_s)
|
48
|
-
end
|
49
|
-
|
50
|
-
def test_simple_setting
|
51
|
-
fb = Factbase.new
|
52
|
-
fb.insert
|
53
|
-
fb.insert.bar = 88
|
54
|
-
found = 0
|
55
|
-
fb.query('(exists bar)').each do |f|
|
56
|
-
assert_predicate(f.bar, :positive?)
|
57
|
-
f.foo = 42
|
58
|
-
assert_equal(42, f.foo)
|
59
|
-
found += 1
|
60
|
-
end
|
61
|
-
assert_equal(1, found)
|
62
|
-
assert_equal(2, fb.size)
|
63
|
-
end
|
64
|
-
|
65
|
-
def test_modify_via_query
|
66
|
-
fb = Factbase.new
|
67
|
-
fb.insert.bar = 1
|
68
|
-
fb.query('(exists bar)').each do |f|
|
69
|
-
f.bar = 42
|
70
|
-
assert_equal(2, f['bar'].size)
|
71
|
-
end
|
72
|
-
found = 0
|
73
|
-
fb.query('(always)').each do |f|
|
74
|
-
assert_equal(2, f['bar'].size)
|
75
|
-
found += 1
|
76
|
-
end
|
77
|
-
assert_equal(1, found)
|
78
|
-
assert_equal(2, fb.query('(always)').each.to_a[0]['bar'].size)
|
79
|
-
end
|
80
|
-
|
81
|
-
def test_serialize_and_deserialize
|
82
|
-
f1 = Factbase.new
|
83
|
-
f2 = Factbase.new
|
84
|
-
f1.insert.foo = 42
|
85
|
-
Tempfile.open do |f|
|
86
|
-
File.binwrite(f.path, f1.export)
|
87
|
-
f2.import(File.binread(f.path))
|
88
|
-
end
|
89
|
-
assert_equal(1, f2.query('(eq foo 42)').each.to_a.size)
|
90
|
-
end
|
91
|
-
|
92
|
-
def test_reads_from_empty_file
|
93
|
-
fb = Factbase.new
|
94
|
-
Tempfile.open do |f|
|
95
|
-
File.binwrite(f.path, '')
|
96
|
-
assert_includes(
|
97
|
-
assert_raises(StandardError) do
|
98
|
-
fb.import(File.binread(f.path))
|
99
|
-
end.message, 'cannot load a factbase'
|
100
|
-
)
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
def test_empty_or_not
|
105
|
-
fb = Factbase.new
|
106
|
-
assert_equal(0, fb.size)
|
107
|
-
fb.insert
|
108
|
-
assert_equal(1, fb.size)
|
109
|
-
end
|
110
|
-
|
111
|
-
def test_txn_returns_boolean
|
112
|
-
fb = Factbase.new
|
113
|
-
assert_equal(1, fb.txn(&:insert).to_i)
|
114
|
-
assert_equal(1, fb.txn { |fbt| fbt.insert.bar = 42 }.to_i)
|
115
|
-
assert_equal(0, fb.txn { |fbt| fbt.query('(always)').each.to_a }.to_i)
|
116
|
-
assert_equal(2, fb.txn { |fbt| fbt.query('(always)').each { |f| f.hello = 33 } }.to_i)
|
117
|
-
assert_equal(1, fb.txn { |fbt| fbt.query('(always)').each.to_a[0].zzz = 33 }.to_i)
|
118
|
-
end
|
119
|
-
|
120
|
-
def test_appends_in_txn
|
121
|
-
fb = Factbase.new
|
122
|
-
fb.insert.foo = 443
|
123
|
-
assert(fb.txn { |fbt| fbt.query('(always)').each { |f| f.hello = 33 } })
|
124
|
-
end
|
125
|
-
|
126
|
-
def test_run_txn
|
127
|
-
fb = Factbase.new
|
128
|
-
fb.txn do |fbt|
|
129
|
-
fbt.insert.bar = 42
|
130
|
-
fbt.insert.z = 42
|
131
|
-
end
|
132
|
-
assert_equal(2, fb.size)
|
133
|
-
assert_includes(
|
134
|
-
assert_raises(StandardError) do
|
135
|
-
fb.txn do |fbt|
|
136
|
-
fbt.insert.foo = 42
|
137
|
-
raise 'intentionally'
|
138
|
-
end
|
139
|
-
end.message, 'intentionally'
|
140
|
-
)
|
141
|
-
assert_equal(2, fb.size)
|
142
|
-
end
|
143
|
-
|
144
|
-
def test_deals_with_arrays_in_txn
|
145
|
-
fb = Factbase.new
|
146
|
-
n = fb.insert
|
147
|
-
n.foo = 1
|
148
|
-
n.foo = 2
|
149
|
-
fb.txn do |fbt|
|
150
|
-
f = fbt.query('(gt foo 0)').each.to_a.first
|
151
|
-
assert_equal(1, f.foo)
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
def test_run_txn_via_query
|
156
|
-
fb = Factbase.new
|
157
|
-
fb.insert.foo = 1
|
158
|
-
assert(
|
159
|
-
fb.txn do |fbt|
|
160
|
-
fbt.query('(always)').each { |f| f.foo = 42 }
|
161
|
-
end
|
162
|
-
)
|
163
|
-
assert_equal([1, 42], fb.query('(always)').each.to_a[0]['foo'])
|
164
|
-
end
|
165
|
-
|
166
|
-
def test_run_txn_with_inv
|
167
|
-
fb = Factbase::Inv.new(Factbase.new) { |_p, v| throw 'oops' if v == 42 }
|
168
|
-
fb.insert.bar = 3
|
169
|
-
fb.insert.foo = 5
|
170
|
-
assert_equal(2, fb.size)
|
171
|
-
assert_includes(
|
172
|
-
assert_raises(StandardError) do
|
173
|
-
fb.txn do |fbt|
|
174
|
-
fbt.insert.foo = 42
|
175
|
-
end
|
176
|
-
end.message, 'oops'
|
177
|
-
)
|
178
|
-
assert_equal(2, fb.size)
|
179
|
-
end
|
180
|
-
|
181
|
-
def test_all_decorators
|
182
|
-
[
|
183
|
-
Factbase::Rules.new(Factbase.new, '(always)'),
|
184
|
-
Factbase::Inv.new(Factbase.new) { |_, _| true },
|
185
|
-
Factbase::Pre.new(Factbase.new) { |_| true },
|
186
|
-
Factbase::Logged.new(Factbase.new, Loog::NULL)
|
187
|
-
].each do |d|
|
188
|
-
f = d.insert
|
189
|
-
f.foo = 42
|
190
|
-
d.txn do |fbt|
|
191
|
-
fbt.insert.bar = 455
|
192
|
-
end
|
193
|
-
assert_raises(StandardError) do
|
194
|
-
d.txn do |fbt|
|
195
|
-
fbt.insert
|
196
|
-
raise 'oops'
|
197
|
-
end
|
198
|
-
end
|
199
|
-
d.import(d.export)
|
200
|
-
assert_equal(4, d.size)
|
201
|
-
assert_equal(4, d.query('(always)').each.to_a.size)
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
def test_txn_inside_query
|
206
|
-
fb = Factbase.new
|
207
|
-
fact = fb.insert
|
208
|
-
fact.foo = 42
|
209
|
-
fact.foo = 555
|
210
|
-
fb.query('(exists foo)').each do |f|
|
211
|
-
fb.txn do |fbt|
|
212
|
-
assert_equal(42, fb.query('(always)').each.to_a.first.foo)
|
213
|
-
assert_equal(42, fb.query('(always)').each.to_a.first['foo'].first)
|
214
|
-
fbt.insert.bar = 33
|
215
|
-
end
|
216
|
-
f.xyz = 1
|
217
|
-
end
|
218
|
-
assert_equal(1, fb.query('(exists xyz)').each.to_a.size)
|
219
|
-
end
|
220
|
-
|
221
|
-
def test_evals_complex_txn
|
222
|
-
fb = Factbase.new
|
223
|
-
n = fb.insert
|
224
|
-
n.foo = 42
|
225
|
-
n.bar = 555
|
226
|
-
fb.txn do |fbt|
|
227
|
-
fbt.insert.foo = 333
|
228
|
-
fbt.insert.bar = 333
|
229
|
-
fbt.query('(eq bar 555)').delete!
|
230
|
-
fbt.insert.bar = 555
|
231
|
-
fbt.query('(eq bar 777)').delete! # nothing to be deleted
|
232
|
-
n1 = fbt.insert
|
233
|
-
n1.bar = 9
|
234
|
-
n1.bar = 99
|
235
|
-
end
|
236
|
-
assert_equal(4, fb.query('(always)').each.to_a.size)
|
237
|
-
end
|
238
|
-
|
239
|
-
def test_txn_with_rollback
|
240
|
-
fb = Factbase.new
|
241
|
-
n = fb.insert
|
242
|
-
n.bar = 55
|
243
|
-
modified =
|
244
|
-
fb.txn do |fbt|
|
245
|
-
fbt.insert.bar = 33
|
246
|
-
fbt.query('(eq bar 55)').each.to_a.first.boom = 44
|
247
|
-
raise Factbase::Rollback
|
248
|
-
end
|
249
|
-
assert_equal(0, modified.to_i)
|
250
|
-
assert_equal(1, fb.query('(always)').each.to_a.size)
|
251
|
-
assert_equal(0, fb.query('(exists boom)').each.to_a.size)
|
252
|
-
end
|
253
|
-
|
254
|
-
def test_modifies_existing_fact_in_txn
|
255
|
-
fb = Factbase.new
|
256
|
-
n = fb.insert
|
257
|
-
n.foo = 1
|
258
|
-
fb.txn do |fbt|
|
259
|
-
f = fbt.query('(always)').each.to_a.first
|
260
|
-
f.bar = 2
|
261
|
-
end
|
262
|
-
assert_equal(1, fb.query('(eq foo 1)').each.to_a.size)
|
263
|
-
end
|
264
|
-
|
265
|
-
def test_simple_concurrent_inserts
|
266
|
-
fb = Factbase.new
|
267
|
-
t = Concurrent.processor_count * 20
|
268
|
-
Threads.new(t).assert do
|
269
|
-
fb.insert
|
270
|
-
end
|
271
|
-
assert_equal(t, fb.size)
|
272
|
-
end
|
273
|
-
|
274
|
-
def test_simple_concurrent_inserts_in_txns
|
275
|
-
fb = Factbase.new
|
276
|
-
t = Concurrent.processor_count * 7
|
277
|
-
mul = 23
|
278
|
-
Threads.new(t).assert do
|
279
|
-
assert(
|
280
|
-
fb.txn do |fbt|
|
281
|
-
mul.times do |m|
|
282
|
-
fbt.insert.foo = m
|
283
|
-
end
|
284
|
-
end
|
285
|
-
)
|
286
|
-
end
|
287
|
-
assert_equal(t * mul, fb.size)
|
288
|
-
end
|
289
|
-
|
290
|
-
def test_simple_concurrent_inserts_in_txns_with_sleep
|
291
|
-
fb = Factbase.new
|
292
|
-
t = Concurrent.processor_count * 13
|
293
|
-
mul = 53
|
294
|
-
Threads.new(t).assert do
|
295
|
-
assert(
|
296
|
-
fb.txn do |fbt|
|
297
|
-
sleep(0.01)
|
298
|
-
mul.times do |m|
|
299
|
-
fbt.insert.foo = m
|
300
|
-
end
|
301
|
-
end
|
302
|
-
)
|
303
|
-
end
|
304
|
-
assert_equal(t * mul, fb.size)
|
305
|
-
end
|
306
|
-
|
307
|
-
def test_concurrent_inserts
|
308
|
-
fb = Factbase.new
|
309
|
-
t = Concurrent.processor_count * 20
|
310
|
-
Threads.new(t).assert do
|
311
|
-
fact = fb.insert
|
312
|
-
fact.foo = 42
|
313
|
-
fact.bar = 49
|
314
|
-
fact.value = fact.foo * fact.bar
|
315
|
-
end
|
316
|
-
assert_equal(t, fb.size)
|
317
|
-
assert_equal(t, fb.query('(eq foo 42)').each.to_a.size)
|
318
|
-
assert_equal(t, fb.query('(eq bar 49)').each.to_a.size)
|
319
|
-
assert_equal(t, fb.query("(eq value #{42 * 49})").each.to_a.size)
|
320
|
-
end
|
321
|
-
|
322
|
-
def test_different_values_when_concurrent_inserts
|
323
|
-
fb = Factbase.new
|
324
|
-
t = Concurrent.processor_count * 16
|
325
|
-
Threads.new(t).assert do |i|
|
326
|
-
fb.insert.foo = i
|
327
|
-
end
|
328
|
-
assert_equal(t, fb.size)
|
329
|
-
Threads.new(t) do |i|
|
330
|
-
f = fb.query("(eq foo #{i})").each.to_a
|
331
|
-
assert_equal(1, f.count)
|
332
|
-
assert_equal(i, f.first.foo)
|
333
|
-
end
|
334
|
-
end
|
335
|
-
|
336
|
-
# @todo #98:1h I assumed that the test `test_different_properties_when_concurrent_inserts` would be passed.
|
337
|
-
# I see like this:
|
338
|
-
# ```
|
339
|
-
# [2024-08-22 21:14:53.962] ERROR -- Expected: 1
|
340
|
-
# Actual: 0: nil
|
341
|
-
# [2024-08-22 21:14:53.962] ERROR -- Expected: 1
|
342
|
-
# Actual: 0: nil
|
343
|
-
# test_different_properties_when_concurrent_inserts ERROR (0.01s)
|
344
|
-
# Minitest::UnexpectedError: RuntimeError: Only 0 out of 5 threads completed successfully
|
345
|
-
# /home/suban/.rbenv/versions/3.3.4/lib/ruby/gems/3.3.0/gems/threads-0.4.0/lib/threads.rb:73:in `assert'
|
346
|
-
# test/test_factbase.rb:265:in `test_different_properties_when_concurrent_inserts'
|
347
|
-
# ```
|
348
|
-
def test_different_properties_when_concurrent_inserts
|
349
|
-
skip('Does not work')
|
350
|
-
fb = Factbase.new
|
351
|
-
Threads.new(5).assert do |i|
|
352
|
-
fb.insert.send(:"prop_#{i}=", i)
|
353
|
-
end
|
354
|
-
assert_equal(5, fb.size)
|
355
|
-
Threads.new(5).assert do |i|
|
356
|
-
prop = "prop_#{i}"
|
357
|
-
f = fb.query("(eq #{prop} #{i})").each.to_a
|
358
|
-
assert_equal(1, f.count)
|
359
|
-
assert_equal(i, f.first.send(prop.to_sym))
|
360
|
-
end
|
361
|
-
end
|
362
|
-
|
363
|
-
# @todo #98:1h I assumed that the test `test_concurrent_transactions_inserts` would be passed.
|
364
|
-
# I see like this:
|
365
|
-
# ```
|
366
|
-
# Expected: 100
|
367
|
-
# Actual: 99
|
368
|
-
# D:/a/factbase/factbase/test/test_factbase.rb:281:in `test_concurrent_transactions_inserts'
|
369
|
-
# ```
|
370
|
-
# See details here https://github.com/yegor256/factbase/actions/runs/10492255419/job/29068637032
|
371
|
-
def test_concurrent_transactions_inserts
|
372
|
-
skip('Does not work')
|
373
|
-
t = Concurrent.processor_count * 19
|
374
|
-
fb = Factbase.new
|
375
|
-
Threads.new(t).assert do |i|
|
376
|
-
fb.txn do |fbt|
|
377
|
-
fact = fbt.insert
|
378
|
-
fact.thread_id = i
|
379
|
-
end
|
380
|
-
end
|
381
|
-
assert_equal(t, fb.size)
|
382
|
-
assert_equal(t, fb.query('(exists thread_id)').each.to_a.size)
|
383
|
-
end
|
384
|
-
|
385
|
-
def test_concurrent_transactions_with_rollbacks
|
386
|
-
fb = Factbase.new
|
387
|
-
Threads.new.assert do |i|
|
388
|
-
fb.txn do |fbt|
|
389
|
-
fact = fbt.insert
|
390
|
-
fact.thread_id = i
|
391
|
-
raise Factbase::Rollback
|
392
|
-
end
|
393
|
-
end
|
394
|
-
assert_equal(0, fb.size)
|
395
|
-
end
|
396
|
-
|
397
|
-
def test_concurrent_transactions_successful
|
398
|
-
fb = Factbase.new
|
399
|
-
t = Concurrent.processor_count * 17
|
400
|
-
Threads.new(t).assert do |i|
|
401
|
-
fb.txn do |fbt|
|
402
|
-
fact = fbt.insert
|
403
|
-
fact.thread_id = i
|
404
|
-
fact.value = i * 10
|
405
|
-
end
|
406
|
-
end
|
407
|
-
facts = fb.query('(exists thread_id)').each.to_a
|
408
|
-
assert_equal(t, facts.size)
|
409
|
-
facts.each do |fact|
|
410
|
-
assert_equal(fact.value, fact.thread_id * 10)
|
411
|
-
end
|
412
|
-
end
|
413
|
-
|
414
|
-
# @todo #98:1h I assumed that the test `test_concurrent_queries` would be passed.
|
415
|
-
# I see like this:
|
416
|
-
# ```
|
417
|
-
# [2024-08-22 17:40:19.224] ERROR -- Expected: [0, 1]
|
418
|
-
# Actual: [0, 0]: nil
|
419
|
-
# [2024-08-22 17:40:19.224] ERROR -- Expected: [0, 1]
|
420
|
-
# Actual: [0, 0]: nil
|
421
|
-
# test_concurrent_queries ERROR (0.00s)
|
422
|
-
# Minitest::UnexpectedError: RuntimeError: Only 0 out of 2 threads completed successfully
|
423
|
-
# /home/suban/.rbenv/versions/3.3.4/lib/ruby/gems/3.3.0/gems/threads-0.4.0/lib/threads.rb:73:in `assert'
|
424
|
-
# test/test_factbase.rb:329:in `test_concurrent_queries'
|
425
|
-
# ```
|
426
|
-
def test_concurrent_queries
|
427
|
-
skip('Does not work')
|
428
|
-
fb = Factbase.new
|
429
|
-
Threads.new(2).assert do |i|
|
430
|
-
fact = fb.insert
|
431
|
-
fact.thread_id = i
|
432
|
-
fact.value = i * 10
|
433
|
-
end
|
434
|
-
Threads.new(2).assert do
|
435
|
-
results = fb.query('(exists thread_id)').each.to_a
|
436
|
-
assert_equal(2, results.size)
|
437
|
-
thread_ids = results.map(&:thread_id)
|
438
|
-
assert_equal((0..1).to_a, thread_ids.sort)
|
439
|
-
end
|
440
|
-
end
|
441
|
-
|
442
|
-
def test_export_import_concurrent
|
443
|
-
fb = Factbase.new
|
444
|
-
Threads.new(100).assert do
|
445
|
-
fact = fb.insert
|
446
|
-
fact.value = 42
|
447
|
-
end
|
448
|
-
Threads.new(5).assert do
|
449
|
-
new_fb = Factbase.new
|
450
|
-
new_fb.import(fb.export)
|
451
|
-
assert_equal(fb.size, new_fb.size)
|
452
|
-
facts = fb.query('(eq value 42)').each.to_a
|
453
|
-
assert_equal(100, facts.size)
|
454
|
-
facts.each do |fact|
|
455
|
-
new_fact = new_fb.query("(eq value #{fact.value})").each.to_a.first
|
456
|
-
assert_equal(fact.value, new_fact.value)
|
457
|
-
end
|
458
|
-
end
|
459
|
-
end
|
460
|
-
|
461
|
-
def test_dup_concurrent
|
462
|
-
fb = Factbase.new
|
463
|
-
mutex = Mutex.new
|
464
|
-
Threads.new(100).assert do
|
465
|
-
fact = fb.insert
|
466
|
-
fact.foo = 42
|
467
|
-
end
|
468
|
-
fbs = []
|
469
|
-
Threads.new(100).assert do
|
470
|
-
mutex.synchronize do
|
471
|
-
fbs << fb.dup
|
472
|
-
end
|
473
|
-
end
|
474
|
-
assert_equal(100, fbs.size)
|
475
|
-
fbs.each do |factbase|
|
476
|
-
assert_equal(100, factbase.query('(eq foo 42)').each.to_a.size)
|
477
|
-
end
|
478
|
-
end
|
479
|
-
|
480
|
-
def test_commits_on_exit_by_throw
|
481
|
-
fb = Factbase.new
|
482
|
-
fb.txn do |fbt|
|
483
|
-
fbt.insert.foo = 1
|
484
|
-
throw :commit
|
485
|
-
end
|
486
|
-
assert_equal(1, fb.size)
|
487
|
-
end
|
488
|
-
|
489
|
-
def test_rolls_back
|
490
|
-
fb = Factbase.new
|
491
|
-
fb.txn do |fbt|
|
492
|
-
fbt.insert.foo = 1
|
493
|
-
throw :rollback
|
494
|
-
end
|
495
|
-
assert_equal(0, fb.size)
|
496
|
-
end
|
497
|
-
|
498
|
-
def test_get_raise_for_empty_fact
|
499
|
-
fb = Factbase.new
|
500
|
-
fb.txn do |fbt|
|
501
|
-
f = fbt.insert
|
502
|
-
f.foo = 123
|
503
|
-
f = fbt.query('(always)').each.to_a.first
|
504
|
-
assert_equal(123, f.foo)
|
505
|
-
ex = assert_raises(RuntimeError) { f.bar }
|
506
|
-
assert_equal("Can't find 'bar' attribute out of [foo]", ex.message)
|
507
|
-
end
|
508
|
-
end
|
509
|
-
end
|