test_transactions.py 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. #!/usr/bin/env python3
  2. """
  3. Test suite for CDK FFI wallet operations
  4. """
  5. import asyncio
  6. import os
  7. import sys
  8. import tempfile
  9. from pathlib import Path
  10. # Setup paths before importing cdk_ffi
  11. repo_root = Path(__file__).parent.parent.parent.parent
  12. bindings_path = repo_root / "target" / "bindings" / "python"
  13. lib_path = repo_root / "target" / "release"
  14. # Copy the library to the bindings directory so Python can find it
  15. import shutil
  16. lib_file = "libcdk_ffi.dylib" if sys.platform == "darwin" else "libcdk_ffi.so"
  17. src_lib = lib_path / lib_file
  18. dst_lib = bindings_path / lib_file
  19. if src_lib.exists() and not dst_lib.exists():
  20. shutil.copy2(src_lib, dst_lib)
  21. # Add target/bindings/python to path to load cdk_ffi module
  22. sys.path.insert(0, str(bindings_path))
  23. import cdk_ffi
  24. async def test_wallet_creation():
  25. """Test creating a wallet with SQLite backend"""
  26. print("\n=== Test: Wallet Creation ===")
  27. with tempfile.NamedTemporaryFile(suffix=".db", delete=False) as tmp:
  28. db_path = tmp.name
  29. try:
  30. backend = cdk_ffi.WalletDbBackend.SQLITE(path=db_path)
  31. db = cdk_ffi.create_wallet_db(backend)
  32. print("✓ Wallet database created")
  33. # Verify database is accessible by querying quotes
  34. mint_quotes = await db.get_mint_quotes()
  35. assert isinstance(mint_quotes, list), "get_mint_quotes should return a list"
  36. print("✓ Wallet database accessible")
  37. print("✓ Test passed: Wallet creation works")
  38. finally:
  39. if os.path.exists(db_path):
  40. os.unlink(db_path)
  41. async def test_wallet_mint_management():
  42. """Test adding and querying mints"""
  43. print("\n=== Test: Wallet Mint Management ===")
  44. with tempfile.NamedTemporaryFile(suffix=".db", delete=False) as tmp:
  45. db_path = tmp.name
  46. try:
  47. backend = cdk_ffi.WalletDbBackend.SQLITE(path=db_path)
  48. db = cdk_ffi.create_wallet_db(backend)
  49. mint_url = cdk_ffi.MintUrl(url="https://testmint.example.com")
  50. # Add mint
  51. await db.add_mint(mint_url, None)
  52. print("✓ Added mint to wallet")
  53. # Get specific mint (verifies it was added)
  54. await db.get_mint(mint_url)
  55. print("✓ Retrieved mint from database")
  56. # Remove mint
  57. await db.remove_mint(mint_url)
  58. print("✓ Removed mint from wallet")
  59. # Verify removal
  60. mint_info_after = await db.get_mint(mint_url)
  61. assert mint_info_after is None, "Mint should be removed"
  62. print("✓ Verified mint removal")
  63. print("✓ Test passed: Mint management works")
  64. finally:
  65. if os.path.exists(db_path):
  66. os.unlink(db_path)
  67. async def test_wallet_keyset_management():
  68. """Test adding and querying keysets"""
  69. print("\n=== Test: Wallet Keyset Management ===")
  70. with tempfile.NamedTemporaryFile(suffix=".db", delete=False) as tmp:
  71. db_path = tmp.name
  72. try:
  73. backend = cdk_ffi.WalletDbBackend.SQLITE(path=db_path)
  74. db = cdk_ffi.create_wallet_db(backend)
  75. mint_url = cdk_ffi.MintUrl(url="https://testmint.example.com")
  76. keyset_id = cdk_ffi.Id(hex="004146bdf4a9afab")
  77. # Add mint first (foreign key requirement)
  78. await db.add_mint(mint_url, None)
  79. print("✓ Added mint")
  80. # Add keyset
  81. keyset_info = cdk_ffi.KeySetInfo(
  82. id=keyset_id.hex,
  83. unit=cdk_ffi.CurrencyUnit.SAT(),
  84. active=True,
  85. input_fee_ppk=0
  86. )
  87. await db.add_mint_keysets(mint_url, [keyset_info])
  88. print("✓ Added keyset")
  89. # Query keyset by ID
  90. keyset = await db.get_keyset_by_id(keyset_id)
  91. assert keyset is not None, "Keyset should exist"
  92. assert keyset.id == keyset_id.hex, "Keyset ID should match"
  93. print(f"✓ Retrieved keyset: {keyset.id}")
  94. # Query keysets for mint
  95. keysets = await db.get_mint_keysets(mint_url)
  96. assert keysets is not None and len(keysets) > 0, "Should have keysets for mint"
  97. print(f"✓ Retrieved {len(keysets)} keyset(s) for mint")
  98. print("✓ Test passed: Keyset management works")
  99. finally:
  100. if os.path.exists(db_path):
  101. os.unlink(db_path)
  102. async def test_wallet_keyset_counter():
  103. """Test keyset counter operations"""
  104. print("\n=== Test: Wallet Keyset Counter ===")
  105. with tempfile.NamedTemporaryFile(suffix=".db", delete=False) as tmp:
  106. db_path = tmp.name
  107. try:
  108. backend = cdk_ffi.WalletDbBackend.SQLITE(path=db_path)
  109. db = cdk_ffi.create_wallet_db(backend)
  110. mint_url = cdk_ffi.MintUrl(url="https://testmint.example.com")
  111. keyset_id = cdk_ffi.Id(hex="004146bdf4a9afab")
  112. # Setup mint and keyset
  113. await db.add_mint(mint_url, None)
  114. keyset_info = cdk_ffi.KeySetInfo(
  115. id=keyset_id.hex,
  116. unit=cdk_ffi.CurrencyUnit.SAT(),
  117. active=True,
  118. input_fee_ppk=0
  119. )
  120. await db.add_mint_keysets(mint_url, [keyset_info])
  121. print("✓ Setup complete")
  122. # Increment counter
  123. counter1 = await db.increment_keyset_counter(keyset_id, 1)
  124. print(f"✓ Counter after +1: {counter1}")
  125. assert counter1 == 1, f"Expected counter 1, got {counter1}"
  126. # Increment again
  127. counter2 = await db.increment_keyset_counter(keyset_id, 5)
  128. print(f"✓ Counter after +5: {counter2}")
  129. assert counter2 == 6, f"Expected counter 6, got {counter2}"
  130. # Read current value (increment by 0)
  131. counter3 = await db.increment_keyset_counter(keyset_id, 0)
  132. print(f"✓ Current counter: {counter3}")
  133. assert counter3 == 6, f"Expected counter 6, got {counter3}"
  134. print("✓ Test passed: Keyset counter works")
  135. finally:
  136. if os.path.exists(db_path):
  137. os.unlink(db_path)
  138. async def test_wallet_quotes():
  139. """Test mint and melt quote operations"""
  140. print("\n=== Test: Wallet Quote Operations ===")
  141. with tempfile.NamedTemporaryFile(suffix=".db", delete=False) as tmp:
  142. db_path = tmp.name
  143. try:
  144. backend = cdk_ffi.WalletDbBackend.SQLITE(path=db_path)
  145. db = cdk_ffi.create_wallet_db(backend)
  146. mint_url = cdk_ffi.MintUrl(url="https://testmint.example.com")
  147. # Add mint first
  148. await db.add_mint(mint_url, None)
  149. print("✓ Added mint")
  150. # Query mint quotes (should be empty initially)
  151. mint_quotes = await db.get_mint_quotes()
  152. assert isinstance(mint_quotes, list), "get_mint_quotes should return a list"
  153. print(f"✓ Retrieved {len(mint_quotes)} mint quote(s)")
  154. # Query melt quotes (should be empty initially)
  155. melt_quotes = await db.get_melt_quotes()
  156. assert isinstance(melt_quotes, list), "get_melt_quotes should return a list"
  157. print(f"✓ Retrieved {len(melt_quotes)} melt quote(s)")
  158. print("✓ Test passed: Quote operations work")
  159. finally:
  160. if os.path.exists(db_path):
  161. os.unlink(db_path)
  162. async def test_wallet_proofs_by_ys():
  163. """Test retrieving proofs by Y values"""
  164. print("\n=== Test: Wallet Get Proofs by Y Values ===")
  165. with tempfile.NamedTemporaryFile(suffix=".db", delete=False) as tmp:
  166. db_path = tmp.name
  167. try:
  168. backend = cdk_ffi.WalletDbBackend.SQLITE(path=db_path)
  169. db = cdk_ffi.create_wallet_db(backend)
  170. # Test with empty list
  171. proofs = await db.get_proofs_by_ys([])
  172. assert len(proofs) == 0, f"Expected 0 proofs, got {len(proofs)}"
  173. print("✓ get_proofs_by_ys returns empty for empty input")
  174. print("✓ Test passed: get_proofs_by_ys works")
  175. finally:
  176. if os.path.exists(db_path):
  177. os.unlink(db_path)
  178. async def main():
  179. """Run all tests"""
  180. print("Starting CDK FFI Wallet Tests")
  181. print("=" * 50)
  182. tests = [
  183. ("Wallet Creation", test_wallet_creation),
  184. ("Wallet Mint Management", test_wallet_mint_management),
  185. ("Wallet Keyset Management", test_wallet_keyset_management),
  186. ("Wallet Keyset Counter", test_wallet_keyset_counter),
  187. ("Wallet Quote Operations", test_wallet_quotes),
  188. ("Wallet Get Proofs by Y Values", test_wallet_proofs_by_ys),
  189. ]
  190. passed = 0
  191. failed = 0
  192. for test_name, test_func in tests:
  193. try:
  194. await test_func()
  195. passed += 1
  196. except Exception as e:
  197. failed += 1
  198. print(f"\n✗ Test failed: {test_name}")
  199. print(f"Error: {e}")
  200. import traceback
  201. traceback.print_exc()
  202. print("\n" + "=" * 50)
  203. print(f"Test Results: {passed} passed, {failed} failed")
  204. print("=" * 50)
  205. return 0 if failed == 0 else 1
  206. if __name__ == "__main__":
  207. exit_code = asyncio.run(main())
  208. sys.exit(exit_code)