Ver Fonte

tests: run py kv test in ci (#1566)

* tests: run py kv test in ci

* fix: python bindings tests
tsk há 2 dias atrás
pai
commit
95f87d3d08
3 ficheiros alterados com 36 adições e 259 exclusões
  1. 34 259
      crates/cdk-ffi/tests/test_kvstore.py
  2. 1 0
      crates/cdk/src/wallet/proofs.rs
  3. 1 0
      flake.nix

+ 34 - 259
crates/cdk-ffi/tests/test_kvstore.py

@@ -3,13 +3,14 @@
 Test suite for CDK FFI Key-Value Store operations
 
 Tests the KVStore trait functionality exposed through the FFI bindings,
-including read, write, list, and remove operations with transaction support.
+including read, write, list, and remove operations.
 """
 
 import asyncio
 import os
 import sys
 import tempfile
+import shutil
 from pathlib import Path
 
 # Setup paths before importing cdk_ffi
@@ -17,9 +18,6 @@ repo_root = Path(__file__).parent.parent.parent.parent
 bindings_path = repo_root / "target" / "bindings" / "python"
 lib_path = repo_root / "target" / "release"
 
-# Copy the library to the bindings directory so Python can find it
-import shutil
-
 lib_file = "libcdk_ffi.dylib" if sys.platform == "darwin" else "libcdk_ffi.so"
 src_lib = lib_path / lib_file
 dst_lib = bindings_path / lib_file
@@ -59,17 +57,13 @@ async def test_kv_write_and_read():
     db, db_path = create_test_db()
 
     try:
-        # Write a value using KV transaction
-        kv_tx = await db.begin_db_transaction()
+        # Write a value
         test_data = b"Hello, KVStore!"
-        await kv_tx.kv_write("app", "config", "greeting", test_data)
-        await kv_tx.commit()
+        await db.kv_write("app", "config", "greeting", test_data)
         print("  Written value to KV store")
 
-        # Read it back using a new transaction
-        kv_tx2 = await db.begin_db_transaction()
-        result = await kv_tx2.kv_read("app", "config", "greeting")
-        await kv_tx2.rollback()
+        # Read it back
+        result = await db.kv_read("app", "config", "greeting")
 
         assert result is not None, "Expected to read back the value"
         assert bytes(result) == test_data, f"Expected {test_data}, got {bytes(result)}"
@@ -88,9 +82,7 @@ async def test_kv_read_nonexistent():
     db, db_path = create_test_db()
 
     try:
-        kv_tx = await db.begin_db_transaction()
-        result = await kv_tx.kv_read("nonexistent", "namespace", "key")
-        await kv_tx.rollback()
+        result = await db.kv_read("nonexistent", "namespace", "key")
 
         assert result is None, f"Expected None for nonexistent key, got {result}"
         print("  Correctly returns None for nonexistent key")
@@ -109,21 +101,15 @@ async def test_kv_overwrite():
 
     try:
         # Write initial value
-        kv_tx = await db.begin_db_transaction()
-        await kv_tx.kv_write("app", "data", "counter", b"1")
-        await kv_tx.commit()
+        await db.kv_write("app", "data", "counter", b"1")
         print("  Written initial value")
 
         # Overwrite with new value
-        kv_tx2 = await db.begin_db_transaction()
-        await kv_tx2.kv_write("app", "data", "counter", b"42")
-        await kv_tx2.commit()
+        await db.kv_write("app", "data", "counter", b"42")
         print("  Overwrote with new value")
 
         # Read back
-        kv_tx3 = await db.begin_db_transaction()
-        result = await kv_tx3.kv_read("app", "data", "counter")
-        await kv_tx3.rollback()
+        result = await db.kv_read("app", "data", "counter")
 
         assert result is not None, "Expected to read back the value"
         assert bytes(result) == b"42", f"Expected b'42', got {bytes(result)}"
@@ -143,28 +129,20 @@ async def test_kv_remove():
 
     try:
         # Write a value
-        kv_tx = await db.begin_db_transaction()
-        await kv_tx.kv_write("app", "temp", "to_delete", b"delete me")
-        await kv_tx.commit()
+        await db.kv_write("app", "temp", "to_delete", b"delete me")
         print("  Written value to delete")
 
         # Verify it exists
-        kv_tx2 = await db.begin_db_transaction()
-        result = await kv_tx2.kv_read("app", "temp", "to_delete")
-        await kv_tx2.rollback()
+        result = await db.kv_read("app", "temp", "to_delete")
         assert result is not None, "Value should exist before removal"
         print("  Verified value exists")
 
         # Remove it
-        kv_tx3 = await db.begin_db_transaction()
-        await kv_tx3.kv_remove("app", "temp", "to_delete")
-        await kv_tx3.commit()
+        await db.kv_remove("app", "temp", "to_delete")
         print("  Removed value")
 
         # Verify it's gone
-        kv_tx4 = await db.begin_db_transaction()
-        result_after = await kv_tx4.kv_read("app", "temp", "to_delete")
-        await kv_tx4.rollback()
+        result_after = await db.kv_read("app", "temp", "to_delete")
 
         assert result_after is None, f"Expected None after removal, got {result_after}"
         print("  Verified value is removed")
@@ -183,18 +161,14 @@ async def test_kv_list_keys():
 
     try:
         # Write multiple keys
-        kv_tx = await db.begin_db_transaction()
-        await kv_tx.kv_write("myapp", "settings", "theme", b"dark")
-        await kv_tx.kv_write("myapp", "settings", "language", b"en")
-        await kv_tx.kv_write("myapp", "settings", "timezone", b"UTC")
-        await kv_tx.kv_write("myapp", "other", "unrelated", b"data")
-        await kv_tx.commit()
+        await db.kv_write("myapp", "settings", "theme", b"dark")
+        await db.kv_write("myapp", "settings", "language", b"en")
+        await db.kv_write("myapp", "settings", "timezone", b"UTC")
+        await db.kv_write("myapp", "other", "unrelated", b"data")
         print("  Written multiple keys")
 
         # List keys in the settings namespace
-        kv_tx2 = await db.begin_db_transaction()
-        keys = await kv_tx2.kv_list("myapp", "settings")
-        await kv_tx2.rollback()
+        keys = await db.kv_list("myapp", "settings")
 
         assert len(keys) == 3, f"Expected 3 keys, got {len(keys)}"
         assert "theme" in keys, "Expected 'theme' in keys"
@@ -216,9 +190,7 @@ async def test_kv_list_empty_namespace():
     db, db_path = create_test_db()
 
     try:
-        kv_tx = await db.begin_db_transaction()
-        keys = await kv_tx.kv_list("nonexistent", "namespace")
-        await kv_tx.rollback()
+        keys = await db.kv_list("nonexistent", "namespace")
 
         assert isinstance(keys, list), "Expected a list"
         assert len(keys) == 0, f"Expected empty list, got {keys}"
@@ -230,141 +202,6 @@ async def test_kv_list_empty_namespace():
         cleanup_db(db_path)
 
 
-# Transaction Tests
-
-async def test_kv_transaction_commit():
-    """Test that KV changes persist after commit"""
-    print("\n=== Test: KV Transaction Commit ===")
-
-    db, db_path = create_test_db()
-
-    try:
-        # Write and commit
-        kv_tx = await db.begin_db_transaction()
-        await kv_tx.kv_write("test", "commit", "key1", b"committed")
-        await kv_tx.commit()
-        print("  Written and committed")
-
-        # Verify in new transaction
-        kv_tx2 = await db.begin_db_transaction()
-        result = await kv_tx2.kv_read("test", "commit", "key1")
-        await kv_tx2.rollback()
-
-        assert result is not None, "Value should persist after commit"
-        assert bytes(result) == b"committed", f"Expected b'committed', got {bytes(result)}"
-        print("  Value persists after commit")
-
-        print("  Test passed: KV transaction commit works")
-
-    finally:
-        cleanup_db(db_path)
-
-
-async def test_kv_transaction_rollback():
-    """Test that KV changes are reverted after rollback"""
-    print("\n=== Test: KV Transaction Rollback ===")
-
-    db, db_path = create_test_db()
-
-    try:
-        # Write and rollback
-        kv_tx = await db.begin_db_transaction()
-        await kv_tx.kv_write("test", "rollback", "key1", b"should_not_persist")
-        await kv_tx.rollback()
-        print("  Written and rolled back")
-
-        # Verify not persisted
-        kv_tx2 = await db.begin_db_transaction()
-        result = await kv_tx2.kv_read("test", "rollback", "key1")
-        await kv_tx2.rollback()
-
-        assert result is None, f"Value should not persist after rollback, got {bytes(result) if result else None}"
-        print("  Value not persisted after rollback")
-
-        print("  Test passed: KV transaction rollback works")
-
-    finally:
-        cleanup_db(db_path)
-
-
-async def test_kv_transaction_atomicity():
-    """Test that multiple operations in a transaction are atomic"""
-    print("\n=== Test: KV Transaction Atomicity ===")
-
-    db, db_path = create_test_db()
-
-    try:
-        # Perform multiple writes in one transaction
-        kv_tx = await db.begin_db_transaction()
-        await kv_tx.kv_write("atomic", "test", "key1", b"value1")
-        await kv_tx.kv_write("atomic", "test", "key2", b"value2")
-        await kv_tx.kv_write("atomic", "test", "key3", b"value3")
-
-        # Read within same transaction (should see uncommitted values)
-        keys_before = await kv_tx.kv_list("atomic", "test")
-        print(f"  Keys within transaction: {keys_before}")
-
-        # Rollback all
-        await kv_tx.rollback()
-        print("  Rolled back transaction")
-
-        # Verify none persisted
-        kv_tx2 = await db.begin_db_transaction()
-        keys_after = await kv_tx2.kv_list("atomic", "test")
-        await kv_tx2.rollback()
-
-        assert len(keys_after) == 0, f"Expected no keys after rollback, got {keys_after}"
-        print("  No keys persisted after rollback")
-
-        # Now do the same but commit
-        kv_tx3 = await db.begin_db_transaction()
-        await kv_tx3.kv_write("atomic", "test", "key1", b"value1")
-        await kv_tx3.kv_write("atomic", "test", "key2", b"value2")
-        await kv_tx3.kv_write("atomic", "test", "key3", b"value3")
-        await kv_tx3.commit()
-        print("  Committed transaction with 3 keys")
-
-        # Verify all persisted
-        kv_tx4 = await db.begin_db_transaction()
-        keys_final = await kv_tx4.kv_list("atomic", "test")
-        await kv_tx4.rollback()
-
-        assert len(keys_final) == 3, f"Expected 3 keys after commit, got {len(keys_final)}"
-        print(f"  All 3 keys persisted: {keys_final}")
-
-        print("  Test passed: KV transaction atomicity works")
-
-    finally:
-        cleanup_db(db_path)
-
-
-async def test_kv_read_within_transaction():
-    """Test reading values within the same transaction they were written"""
-    print("\n=== Test: KV Read Within Transaction ===")
-
-    db, db_path = create_test_db()
-
-    try:
-        kv_tx = await db.begin_db_transaction()
-
-        # Write a value
-        await kv_tx.kv_write("intra", "tx", "mykey", b"myvalue")
-
-        # Read it back in same transaction
-        result = await kv_tx.kv_read("intra", "tx", "mykey")
-
-        assert result is not None, "Should be able to read uncommitted value in same tx"
-        assert bytes(result) == b"myvalue", f"Expected b'myvalue', got {bytes(result)}"
-        print("  Can read uncommitted value within transaction")
-
-        await kv_tx.rollback()
-
-        print("  Test passed: KV read within transaction works")
-
-    finally:
-        cleanup_db(db_path)
-
-
 # Namespace Isolation Tests
 
 async def test_kv_namespace_isolation():
@@ -375,21 +212,15 @@ async def test_kv_namespace_isolation():
 
     try:
         # Write same key in different namespaces
-        kv_tx = await db.begin_db_transaction()
-        await kv_tx.kv_write("app1", "config", "key", b"app1_value")
-        await kv_tx.kv_write("app2", "config", "key", b"app2_value")
-        await kv_tx.kv_write("app1", "other", "key", b"app1_other_value")
-        await kv_tx.commit()
+        await db.kv_write("app1", "config", "key", b"app1_value")
+        await db.kv_write("app2", "config", "key", b"app2_value")
+        await db.kv_write("app1", "other", "key", b"app1_other_value")
         print("  Written same key in different namespaces")
 
         # Read from each namespace
-        kv_tx2 = await db.begin_db_transaction()
-
-        result1 = await kv_tx2.kv_read("app1", "config", "key")
-        result2 = await kv_tx2.kv_read("app2", "config", "key")
-        result3 = await kv_tx2.kv_read("app1", "other", "key")
-
-        await kv_tx2.rollback()
+        result1 = await db.kv_read("app1", "config", "key")
+        result2 = await db.kv_read("app2", "config", "key")
+        result3 = await db.kv_read("app1", "other", "key")
 
         assert bytes(result1) == b"app1_value", f"Expected b'app1_value', got {bytes(result1)}"
         assert bytes(result2) == b"app2_value", f"Expected b'app2_value', got {bytes(result2)}"
@@ -420,21 +251,17 @@ async def test_kv_binary_data():
             ("random_binary", bytes([0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE])),
         ]
 
-        kv_tx = await db.begin_db_transaction()
         for name, data in test_cases:
-            await kv_tx.kv_write("binary", "test", name, data)
-        await kv_tx.commit()
+            await db.kv_write("binary", "test", name, data)
         print(f"  Written {len(test_cases)} binary test cases")
 
         # Read back and verify
-        kv_tx2 = await db.begin_db_transaction()
         for name, expected_data in test_cases:
-            result = await kv_tx2.kv_read("binary", "test", name)
+            result = await db.kv_read("binary", "test", name)
             assert result is not None, f"Expected data for {name}"
             actual_data = bytes(result)
             assert actual_data == expected_data, f"Mismatch for {name}: expected {expected_data!r}, got {actual_data!r}"
             print(f"    '{name}': OK ({len(actual_data)} bytes)")
-        await kv_tx2.rollback()
 
         print("  Test passed: KV binary data works")
 
@@ -452,15 +279,11 @@ async def test_kv_large_value():
         # Create a 1MB value
         large_data = bytes([i % 256 for i in range(1024 * 1024)])
 
-        kv_tx = await db.begin_db_transaction()
-        await kv_tx.kv_write("large", "data", "megabyte", large_data)
-        await kv_tx.commit()
+        await db.kv_write("large", "data", "megabyte", large_data)
         print(f"  Written {len(large_data)} bytes")
 
         # Read back
-        kv_tx2 = await db.begin_db_transaction()
-        result = await kv_tx2.kv_read("large", "data", "megabyte")
-        await kv_tx2.rollback()
+        result = await db.kv_read("large", "data", "megabyte")
 
         assert result is not None, "Expected to read large value"
         result_bytes = bytes(result)
@@ -493,17 +316,12 @@ async def test_kv_special_key_names():
             "empty_value",
         ]
 
-        kv_tx = await db.begin_db_transaction()
         for i, key in enumerate(special_keys):
-            print(key)
-            await kv_tx.kv_write("special", "keys", key, f"value_{i}".encode())
-        await kv_tx.commit()
+            await db.kv_write("special", "keys", key, f"value_{i}".encode())
         print(f"  Written {len(special_keys)} special keys")
 
         # List and verify
-        kv_tx2 = await db.begin_db_transaction()
-        keys = await kv_tx2.kv_list("special", "keys")
-        await kv_tx2.rollback()
+        keys = await db.kv_list("special", "keys")
 
         assert len(keys) == len(special_keys), f"Expected {len(special_keys)} keys, got {len(keys)}"
         for key in special_keys:
@@ -516,38 +334,6 @@ async def test_kv_special_key_names():
         cleanup_db(db_path)
 
 
-# Database Read Method Tests
-
-async def test_kv_database_read_methods():
-    """Test kv_read and kv_list methods on the database object (not transaction)"""
-    print("\n=== Test: KV Database Read Methods ===")
-
-    db, db_path = create_test_db()
-
-    try:
-        # Write some data first
-        kv_tx = await db.begin_db_transaction()
-        await kv_tx.kv_write("dbread", "test", "key1", b"value1")
-        await kv_tx.kv_write("dbread", "test", "key2", b"value2")
-        await kv_tx.commit()
-        print("  Written test data")
-
-        # Read back using database-level kv_read (not transaction)
-        result = await db.kv_read("dbread", "test", "key1")
-        assert result is not None, "Expected to read key1"
-        assert bytes(result) == b"value1", f"Expected b'value1', got {bytes(result)}"
-        print("  db.kv_read() works")
-
-        keys = await db.kv_list("dbread", "test")
-        assert len(keys) == 2, f"Expected 2 keys, got {len(keys)}"
-        print(f"  db.kv_list() works: {keys}")
-
-        print("  Test passed: KV database read methods work")
-
-    finally:
-        cleanup_db(db_path)
-
-
 # Persistence Test
 
 async def test_kv_persistence_across_instances():
@@ -563,9 +349,7 @@ async def test_kv_persistence_across_instances():
         backend = cdk_ffi.WalletDbBackend.SQLITE(path=db_path)
         db1 = cdk_ffi.create_wallet_db(backend)
 
-        kv_tx = await db1.begin_db_transaction()
-        await kv_tx.kv_write("persist", "test", "mykey", b"persistent_value")
-        await kv_tx.commit()
+        await db1.kv_write("persist", "test", "mykey", b"persistent_value")
         print("  Written and committed with first db instance")
 
         # Delete reference to first db (simulating closing)
@@ -577,9 +361,7 @@ async def test_kv_persistence_across_instances():
         backend2 = cdk_ffi.WalletDbBackend.SQLITE(path=db_path)
         db2 = cdk_ffi.create_wallet_db(backend2)
 
-        kv_tx2 = await db2.begin_db_transaction()
-        result = await kv_tx2.kv_read("persist", "test", "mykey")
-        await kv_tx2.rollback()
+        result = await db2.kv_read("persist", "test", "mykey")
 
         assert result is not None, "Data should persist across db instances"
         assert bytes(result) == b"persistent_value", f"Expected b'persistent_value', got {bytes(result)}"
@@ -605,19 +387,12 @@ async def main():
         ("KV Remove", test_kv_remove),
         ("KV List Keys", test_kv_list_keys),
         ("KV List Empty Namespace", test_kv_list_empty_namespace),
-        # Transaction tests
-        ("KV Transaction Commit", test_kv_transaction_commit),
-        ("KV Transaction Rollback", test_kv_transaction_rollback),
-        ("KV Transaction Atomicity", test_kv_transaction_atomicity),
-        ("KV Read Within Transaction", test_kv_read_within_transaction),
         # Namespace tests
         ("KV Namespace Isolation", test_kv_namespace_isolation),
         # Data tests
         ("KV Binary Data", test_kv_binary_data),
         ("KV Large Value", test_kv_large_value),
         ("KV Special Key Names", test_kv_special_key_names),
-        # Database methods
-        ("KV Database Read Methods", test_kv_database_read_methods),
         # Persistence
         ("KV Persistence Across Instances", test_kv_persistence_across_instances),
     ]

+ 1 - 0
crates/cdk/src/wallet/proofs.rs

@@ -93,6 +93,7 @@ impl Wallet {
 
         self.swap(None, SplitTarget::default(), unspent, None, false)
             .await?;
+
         let _ = self
             .localstore
             .remove_transaction(transaction_id)

+ 1 - 0
flake.nix

@@ -281,6 +281,7 @@
 
             # Run Python tests
             python3 crates/cdk-ffi/tests/test_transactions.py
+            python3 crates/cdk-ffi/tests/test_kvstore.py
           '';
           installPhaseCommand = "mkdir -p $out";
         });