Skip to content

Commit d1e0cda

Browse files
committed
test: add comprehensive testing for TierStore
This commit adds unit, integration, and FFI tests for the TierStore implementation: - Unit tests for TierStore core functionality - Integration tests for nodes built with tiered storage - Python FFI tests for foreign key-value store
1 parent cc930ed commit d1e0cda

File tree

9 files changed

+947
-231
lines changed

9 files changed

+947
-231
lines changed

benches/payments.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ fn payment_benchmark(c: &mut Criterion) {
127127
true,
128128
false,
129129
common::TestStoreType::Sqlite,
130+
common::TestStoreType::Sqlite,
130131
);
131132

132133
let runtime =
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
import threading
2+
3+
from abc import ABC, abstractmethod
4+
from typing import List
5+
6+
from ldk_node import IoError
7+
8+
class AbstractKvStore(ABC):
9+
@abstractmethod
10+
async def read_async(self, primary_namespace: "str",secondary_namespace: "str",key: "str") -> "typing.List[int]":
11+
pass
12+
13+
@abstractmethod
14+
async def write_async(self, primary_namespace: "str",secondary_namespace: "str",key: "str",buf: "typing.List[int]") -> None:
15+
pass
16+
17+
@abstractmethod
18+
async def remove_async(self, primary_namespace: "str",secondary_namespace: "str",key: "str",lazy: "bool") -> None:
19+
pass
20+
21+
@abstractmethod
22+
async def list_async(self, primary_namespace: "str",secondary_namespace: "str") -> "typing.List[str]":
23+
pass
24+
25+
@abstractmethod
26+
def read(self, primary_namespace: "str",secondary_namespace: "str",key: "str") -> "typing.List[int]":
27+
pass
28+
29+
@abstractmethod
30+
def write(self, primary_namespace: "str",secondary_namespace: "str",key: "str",buf: "typing.List[int]") -> None:
31+
pass
32+
33+
@abstractmethod
34+
def remove(self, primary_namespace: "str",secondary_namespace: "str",key: "str",lazy: "bool") -> None:
35+
pass
36+
37+
@abstractmethod
38+
def list(self, primary_namespace: "str",secondary_namespace: "str") -> "typing.List[str]":
39+
pass
40+
41+
class TestKvStore(AbstractKvStore):
42+
def __init__(self, name: str):
43+
self.name = name
44+
# Storage structure: {(primary_ns, secondary_ns): {key: [bytes]}}
45+
self.storage = {}
46+
self._lock = threading.Lock()
47+
48+
def dump(self):
49+
print(f"\n[{self.name}] Store contents:")
50+
for (primary_ns, secondary_ns), keys_dict in self.storage.items():
51+
print(f" Namespace: ({primary_ns!r}, {secondary_ns!r})")
52+
for key, data in keys_dict.items():
53+
print(f" Key: {key!r} -> {len(data)} bytes")
54+
# Optionally show first few bytes
55+
preview = data[:20] if len(data) > 20 else data
56+
print(f" Data preview: {preview}...")
57+
58+
def read(self, primary_namespace: str, secondary_namespace: str, key: str) -> List[int]:
59+
with self._lock:
60+
print(f"[{self.name}] READ: {primary_namespace}/{secondary_namespace}/{key}")
61+
namespace_key = (primary_namespace, secondary_namespace)
62+
63+
if namespace_key not in self.storage:
64+
print(f" -> namespace not found, keys: {list(self.storage.keys())}")
65+
raise IoError.NotFound(f"Namespace not found: {primary_namespace}/{secondary_namespace}")
66+
67+
if key not in self.storage[namespace_key]:
68+
print(f" -> key not found, keys: {list(self.storage[namespace_key].keys())}")
69+
raise IoError.NotFound(f"Key not found: {key}")
70+
71+
data = self.storage[namespace_key][key]
72+
print(f" -> returning {len(data)} bytes")
73+
return data
74+
75+
def write(self, primary_namespace: str, secondary_namespace: str, key: str, buf: List[int]) -> None:
76+
with self._lock:
77+
namespace_key = (primary_namespace, secondary_namespace)
78+
if namespace_key not in self.storage:
79+
self.storage[namespace_key] = {}
80+
81+
self.storage[namespace_key][key] = buf.copy()
82+
83+
def remove(self, primary_namespace: str, secondary_namespace: str, key: str, lazy: bool) -> None:
84+
with self._lock:
85+
namespace_key = (primary_namespace, secondary_namespace)
86+
if namespace_key not in self.storage:
87+
raise IoError.NotFound(f"Namespace not found: {primary_namespace}/{secondary_namespace}")
88+
89+
if key not in self.storage[namespace_key]:
90+
raise IoError.NotFound(f"Key not found: {key}")
91+
92+
del self.storage[namespace_key][key]
93+
94+
if not self.storage[namespace_key]:
95+
del self.storage[namespace_key]
96+
97+
def list(self, primary_namespace: str, secondary_namespace: str) -> List[str]:
98+
with self._lock:
99+
namespace_key = (primary_namespace, secondary_namespace)
100+
if namespace_key in self.storage:
101+
return list(self.storage[namespace_key].keys())
102+
return []
103+
104+
async def read_async(self, primary_namespace: str, secondary_namespace: str, key: str) -> List[int]:
105+
return self.read(primary_namespace, secondary_namespace, key)
106+
107+
async def write_async(self, primary_namespace: str, secondary_namespace: str, key: str, buf: List[int]) -> None:
108+
self.write(primary_namespace, secondary_namespace, key, buf)
109+
110+
async def remove_async(self, primary_namespace: str, secondary_namespace: str, key: str, lazy: bool) -> None:
111+
self.remove(primary_namespace, secondary_namespace, key, lazy)
112+
113+
async def list_async(self, primary_namespace: str, secondary_namespace: str) -> List[str]:
114+
return self.list(primary_namespace, secondary_namespace)
115+

0 commit comments

Comments
 (0)