Skip to content

Commit 5e56742

Browse files
authored
Merge pull request #1378 from KeaxD/IoSet-webdber
More tests for Webdb methods + fix typos
2 parents bc39642 + 663ee44 commit 5e56742

2 files changed

Lines changed: 227 additions & 7 deletions

File tree

src/keri/db/webdbing.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1459,8 +1459,8 @@ def putOnIoSetVals(self, db, key, *, on=0, vals=None, sep=b'.'):
14591459
sep (bytes): separator character for split
14601460
14611461
Set of values at a given effective key preserve insertion order.
1462-
Because lmdb is lexocographic an insertion ordering suffix is appended to
1463-
all keys that makes lexocographic order the same as insertion order.
1462+
Because lmdb is lexicographic an insertion ordering suffix is appended to
1463+
all keys that makes lexicographic order the same as insertion order.
14641464
14651465
Suffix is 33 characters long consisting of sep '.' followed by 32 char
14661466
hex string for essentially unlimited number of values in each set
@@ -1501,8 +1501,8 @@ def pinOnIoSetVals(self, db, key, *, on=0, vals=None, sep=b'.'):
15011501
Assumes DB opened with dupsort=False
15021502
15031503
Set of values at a given effective key preserve insertion order.
1504-
Because lmdb is lexocographic an insertion ordering suffix is appended to
1505-
all keys that makes lexocographic order the same as insertion order.
1504+
Because lmdb is lexicographic an insertion ordering suffix is appended to
1505+
all keys that makes lexicographic order the same as insertion order.
15061506
15071507
Suffix is 33 characters long consisting of sep '.' followed by 32 char
15081508
hex string for essentially unlimited number of values in each set
@@ -1627,7 +1627,7 @@ def addOnIoSetVal(self, db, key, *, on=0, val=None, sep=b'.'):
16271627
def getOnIoSetItemIter(self, db, key, *, on=0, ion=0, sep=b'.'):
16281628
"""Get iterator of all set vals at onkey = key + sep + on in db starting
16291629
at insertion order ion within set This provides ordinal ordering of
1630-
keys and inserion ordering of set vals.
1630+
keys and insertion ordering of set vals.
16311631
When key is empty then returns empty iterator
16321632
16331633
Returns:
@@ -2028,7 +2028,7 @@ def getOnAllIoSetItemBackIter(self, db, key=b"", on=None, *, sep=b'.'):
20282028
Raises StopIterationError when done or when key empty or None
20292029
20302030
Backwards means decreasing numerical value of ion, for each on and
2031-
decreasing numerical value on for each key and decreasing lexocographic
2031+
decreasing numerical value on for each key and decreasing lexicographic
20322032
order of each key.
20332033
20342034
Returns:
@@ -2098,7 +2098,7 @@ def getOnAllIoSetLastItemBackIter(self, db, key=b"", on=None, *, sep=b'.'):
20982098
Raises StopIterationError when done or when key empty or None
20992099
21002100
Backwards means decreasing numerical value of each ion, for each on and
2101-
decreasing numerical value of each on for each key and decreasing lexocographic
2101+
decreasing numerical value of each on for each key and decreasing lexicographic
21022102
value of each key.
21032103
21042104
Returns:

tests/db/test_webdbing.py

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,71 @@ async def _go():
482482
asyncio.run(_go())
483483

484484

485+
486+
def test_close():
487+
"""Test WebDBer.close() behavior with and without clear=True."""
488+
async def _go():
489+
backend = FakeStorageBackend()
490+
491+
# --- 1. close(clear=False) preserves items and dirty flags ---
492+
dber, _ = await _open_fake_dber(
493+
name="close-test",
494+
stores=["vals."],
495+
clear=True,
496+
backend=backend,
497+
)
498+
sdb = dber.env.open_db(key=b"vals.")
499+
500+
# Add some data
501+
assert dber.putVal(sdb, b"a.1", b"wow") is True
502+
assert dber.putVal(sdb, b"a.2", b"wee") is True
503+
assert dber.putVal(sdb, b"b.1", b"woo") is True
504+
505+
dber.close(clear=False)
506+
507+
# Stores removed from dber
508+
assert dber._stores == {}
509+
assert dber.stores == []
510+
assert sdb.dirty == True
511+
512+
# Original SubDb values unchanged
513+
assert list(dber.getTopItemIter(sdb)) == [
514+
(b"a.1", b"wow"), (b"a.2", b"wee"), (b"b.1", b"woo"),
515+
]
516+
517+
# 2. close(clear=True) clears items
518+
dber2, _ = await _open_fake_dber(
519+
name="close-test-2",
520+
stores=["vals."],
521+
clear=True,
522+
backend=backend,
523+
)
524+
sdb2 = dber2.env.open_db(key=b"vals.")
525+
526+
# Add some data
527+
assert dber2.putVal(sdb2, b"a.1", b"wow") is True
528+
assert dber2.putVal(sdb2, b"a.2", b"wee") is True
529+
assert dber2.putVal(sdb2, b"b.1", b"woo") is True
530+
531+
dber2.close(clear=True)
532+
533+
# Stores removed from dber2
534+
assert dber2._stores == {}
535+
assert dber2.stores == []
536+
assert sdb.dirty == True
537+
538+
# Items cleared
539+
assert list(dber2.getTopItemIter(sdb2)) == []
540+
541+
542+
# 3. close() is idempotent
543+
dber2.close()
544+
assert dber2._stores == {}
545+
assert dber2.stores == []
546+
547+
asyncio.run(_go())
548+
549+
485550
@pytest.mark.skip(reason="Requires hio>=0.7.20 Doist.ado() for async task integration")
486551
def test_flush_with_hio_ado():
487552
"""Test flush completion under hio Doist.ado() scheduling."""
@@ -3758,6 +3823,161 @@ async def _go():
37583823
# on=0 entries should still exist
37593824
assert dber.cntOnIoSet(db, key1, on=0) == 4
37603825

3826+
3827+
# more tests
3828+
assert dber.remOnAllIoSet(db) == True
3829+
assert [item for item in dber.getOnIoSetItemIter(db, b'A')] == []
3830+
# test pinOnIoSetVals
3831+
vals0 = ["z", "m", "x", "a"]
3832+
vals1 = ["w", "n", "y", "d"]
3833+
keyA = b'A'
3834+
keyB = b'B'
3835+
assert dber.putOnIoSetVals(db, keyA) == False
3836+
assert dber.pinOnIoSetVals(db, key='',vals=vals0) == False # empty keyA no-op
3837+
assert dber.pinOnIoSetVals(db, key=None ,vals=vals0) == False # None keyA no-op
3838+
assert dber.pinOnIoSetVals(db, key=None ,vals='') == False # empty vals no-op
3839+
assert dber.pinOnIoSetVals(db, key=None ,vals=None) == False # None vals no-op
3840+
3841+
assert dber.putOnIoSetVals(db, keyA, vals=vals0) == True
3842+
assert list(dber.getOnIoSetItemIter(db, keyA)) == [(keyA, 0, "z"),
3843+
(keyA, 0, "m"),
3844+
(keyA, 0, "x"),
3845+
(keyA, 0, "a")]
3846+
assert dber.pinOnIoSetVals(db, keyA, vals=vals0) == True # pinning same vals still returns True
3847+
assert list(dber.getOnIoSetItemIter(db, keyA)) == [(keyA, 0, "z"),
3848+
(keyA, 0, "m"),
3849+
(keyA, 0, "x"),
3850+
(keyA, 0, "a")]
3851+
assert dber.pinOnIoSetVals(db, keyB, vals=vals1) == True # pinning vals1 to a different keyB doesn't affect keyA's values
3852+
assert list(dber.getOnIoSetItemIter(db, keyA)) == [(keyA, 0, "z"),
3853+
(keyA, 0, "m"),
3854+
(keyA, 0, "x"),
3855+
(keyA, 0, "a")]
3856+
assert list(dber.getOnIoSetItemIter(db, keyB)) == [(keyB, 0, "w"), # vals0 replaced by vals1
3857+
(keyB, 0, "n"),
3858+
(keyB, 0, "y"),
3859+
(keyB, 0, "d")]
3860+
3861+
assert dber.pinOnIoSetVals(db, keyA, vals=vals1) == True # default on=0 so vals0 replaced by vals1
3862+
assert list(dber.getOnIoSetItemIter(db, keyA)) == [(keyA, 0, "w"), # vals0 replaced by vals1
3863+
(keyA, 0, "n"),
3864+
(keyA, 0, "y"),
3865+
(keyA, 0, "d")]
3866+
3867+
assert dber.pinOnIoSetVals(db, keyA, on=1, vals=vals1) == True # pinning on=1 vals1 should not affect on=0 vals1 so should add on=1 vals1
3868+
assert list(dber.getOnIoSetItemIter(db, keyA)) == [(keyA, 0, "w"),
3869+
(keyA, 0, "n"),
3870+
(keyA, 0, "y"),
3871+
(keyA, 0, "d")]
3872+
assert list(dber.getOnIoSetItemIter(db, keyA, on=1)) == [(keyA, 1, "w"),
3873+
(keyA, 1, "n"),
3874+
(keyA, 1, "y"),
3875+
(keyA, 1, "d")]
3876+
3877+
assert dber.pinOnIoSetVals(db, keyA, on=4, vals=vals1) == True # gaps between on values is allowed
3878+
assert list(dber.getOnIoSetItemIter(db, keyA, on=4)) == [(keyA, 4, "w"),
3879+
(keyA, 4, "n"),
3880+
(keyA, 4, "y"),
3881+
(keyA, 4, "d")]
3882+
3883+
assert list(dber.getOnAllIoSetItemIter(db, keyA)) == [
3884+
(keyA, 0, "w"),
3885+
(keyA, 0, "n"),
3886+
(keyA, 0, "y"),
3887+
(keyA, 0, "d"),
3888+
(keyA, 1, "w"),
3889+
(keyA, 1, "n"),
3890+
(keyA, 1, "y"),
3891+
(keyA, 1, "d"),
3892+
(keyA, 4, "w"),
3893+
(keyA, 4, "n"),
3894+
(keyA, 4, "y"),
3895+
(keyA, 4, "d")]
3896+
3897+
assert dber.remOnAllIoSet(db) == True
3898+
assert [item for item in dber.getOnIoSetItemIter(db, b'A')] == []
3899+
3900+
3901+
# test getOnTopIoSetItemIter
3902+
vals0 = ["z", "m", "x", "a"]
3903+
vals1 = ["w", "n", "y", "d"]
3904+
keyA = b'A'
3905+
keyB = b'B'
3906+
3907+
assert list(dber.getOnTopIoSetItemIter(db)) == [] # empty db
3908+
assert dber.putOnIoSetVals(db, keyA, vals=vals0) == True
3909+
assert list(dber.getOnTopIoSetItemIter(db, keyA)) == [(keyA, 0, "z"),
3910+
(keyA, 0, "m"),
3911+
(keyA, 0, "x"),
3912+
(keyA, 0, "a")]
3913+
assert dber.putOnIoSetVals(db, keyB, vals=vals1) == True
3914+
assert list(dber.getOnTopIoSetItemIter(db, keyB)) == [(keyB, 0, "w"),
3915+
(keyB, 0, "n"),
3916+
(keyB, 0, "y"),
3917+
(keyB, 0, "d")]
3918+
3919+
itemsA = list(dber.getOnTopIoSetItemIter(db, keyA))
3920+
assert itemsA == [
3921+
(keyA, 0, "z"),
3922+
(keyA, 0, "m"),
3923+
(keyA, 0, "x"),
3924+
(keyA, 0, "a"),
3925+
]
3926+
3927+
itemsB = list(dber.getOnTopIoSetItemIter(db, keyB))
3928+
assert itemsB == [
3929+
(keyB, 0, "w"),
3930+
(keyB, 0, "n"),
3931+
(keyB, 0, "y"),
3932+
(keyB, 0, "d"),
3933+
]
3934+
3935+
itemsAll = list(dber.getOnTopIoSetItemIter(db, top=b""))
3936+
assert itemsAll == [
3937+
(keyA, 0, "z"), (keyA, 0, "m"), (keyA, 0, "x"), (keyA, 0, "a"),
3938+
(keyB, 0, "w"), (keyB, 0, "n"), (keyB, 0, "y"), (keyB, 0, "d"),
3939+
]
3940+
3941+
# Add additional branches under A*
3942+
keyA1 = b"A1"
3943+
keyA2 = b"A2"
3944+
3945+
valsA1 = ["p", "q"]
3946+
valsA2 = ["r"]
3947+
3948+
assert dber.putOnIoSetVals(db, keyA1, vals=valsA1) is True
3949+
assert dber.putOnIoSetVals(db, keyA2, vals=valsA2) is True
3950+
3951+
# top=b"A" should match A, A1, A2 (because all start with b"A")
3952+
itemsAstar = list(dber.getOnTopIoSetItemIter(db, top=b"A"))
3953+
3954+
assert itemsAstar == [
3955+
# A branch
3956+
(keyA, 0, "z"), (keyA, 0, "m"), (keyA, 0, "x"), (keyA, 0, "a"),
3957+
# A1 branch
3958+
(keyA1, 0, "p"), (keyA1, 0, "q"),
3959+
# A2 branch
3960+
(keyA2, 0, "r"),
3961+
]
3962+
3963+
# top=b"A1" should match ONLY A1 branch
3964+
itemsA1 = list(dber.getOnTopIoSetItemIter(db, top=b"A1"))
3965+
assert itemsA1 == [
3966+
(keyA1, 0, "p"),
3967+
(keyA1, 0, "q"),
3968+
]
3969+
3970+
# top=b"A2" should match ONLY A2 branch
3971+
itemsA2 = list(dber.getOnTopIoSetItemIter(db, top=b"A2"))
3972+
assert itemsA2 == [
3973+
(keyA2, 0, "r"),
3974+
]
3975+
assert list(dber.getOnTopIoSetItemIter(db)) == [
3976+
(keyA, 0, "z"), (keyA, 0, "m"), (keyA, 0, "x"), (keyA, 0, "a"),
3977+
(keyA1, 0, "p"), (keyA1, 0, "q"), (keyA2, 0, "r"), (keyB, 0, "w"),
3978+
(keyB, 0, "n"), (keyB, 0, "y"), (keyB, 0, "d"),
3979+
] # empty top returns whole db, keyA1 and keyA2 are in correct order under keyA and before keyB
3980+
37613981
asyncio.run(_go())
37623982

37633983

0 commit comments

Comments
 (0)