refactor: consolidate blockchain explorer into single app and update backup ignore patterns
- Remove standalone explorer-web app (README, HTML, package files) - Add /web endpoint to blockchain-explorer for web interface access - Update .gitignore to exclude application backup archives (*.tar.gz, *.zip) - Add backup documentation files to .gitignore (BACKUP_INDEX.md, README.md) - Consolidate explorer functionality into main blockchain-explorer application
This commit is contained in:
404
apps/wallet/tests/test_multichain.py
Normal file
404
apps/wallet/tests/test_multichain.py
Normal file
@@ -0,0 +1,404 @@
|
||||
"""
|
||||
Multi-Chain Wallet Daemon Tests
|
||||
|
||||
Tests for multi-chain functionality including chain management,
|
||||
chain-specific wallet operations, and cross-chain migrations.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
import tempfile
|
||||
import json
|
||||
from pathlib import Path
|
||||
from unittest.mock import Mock, patch
|
||||
from datetime import datetime
|
||||
|
||||
from app.chain.manager import ChainManager, ChainConfig, ChainStatus
|
||||
from app.chain.multichain_ledger import MultiChainLedgerAdapter, ChainWalletMetadata
|
||||
from app.chain.chain_aware_wallet_service import ChainAwareWalletService
|
||||
|
||||
|
||||
class TestChainManager:
|
||||
"""Test the chain manager functionality"""
|
||||
|
||||
def setup_method(self):
|
||||
"""Set up test environment"""
|
||||
self.temp_dir = Path(tempfile.mkdtemp())
|
||||
self.config_path = self.temp_dir / "test_chains.json"
|
||||
self.chain_manager = ChainManager(self.config_path)
|
||||
|
||||
def teardown_method(self):
|
||||
"""Clean up test environment"""
|
||||
import shutil
|
||||
shutil.rmtree(self.temp_dir)
|
||||
|
||||
def test_create_default_chain(self):
|
||||
"""Test default chain creation"""
|
||||
assert len(self.chain_manager.chains) == 1
|
||||
assert "ait-devnet" in self.chain_manager.chains
|
||||
assert self.chain_manager.default_chain_id == "ait-devnet"
|
||||
|
||||
def test_add_chain(self):
|
||||
"""Test adding a new chain"""
|
||||
chain_config = ChainConfig(
|
||||
chain_id="test-chain",
|
||||
name="Test Chain",
|
||||
coordinator_url="http://localhost:8001",
|
||||
coordinator_api_key="test-key"
|
||||
)
|
||||
|
||||
success = self.chain_manager.add_chain(chain_config)
|
||||
assert success is True
|
||||
assert "test-chain" in self.chain_manager.chains
|
||||
assert len(self.chain_manager.chains) == 2
|
||||
|
||||
def test_add_duplicate_chain(self):
|
||||
"""Test adding a duplicate chain"""
|
||||
chain_config = ChainConfig(
|
||||
chain_id="ait-devnet", # Already exists
|
||||
name="Duplicate Chain",
|
||||
coordinator_url="http://localhost:8001",
|
||||
coordinator_api_key="test-key"
|
||||
)
|
||||
|
||||
success = self.chain_manager.add_chain(chain_config)
|
||||
assert success is False
|
||||
assert len(self.chain_manager.chains) == 1
|
||||
|
||||
def test_remove_chain(self):
|
||||
"""Test removing a chain"""
|
||||
# First add a test chain
|
||||
chain_config = ChainConfig(
|
||||
chain_id="test-chain",
|
||||
name="Test Chain",
|
||||
coordinator_url="http://localhost:8001",
|
||||
coordinator_api_key="test-key"
|
||||
)
|
||||
self.chain_manager.add_chain(chain_config)
|
||||
|
||||
# Remove it
|
||||
success = self.chain_manager.remove_chain("test-chain")
|
||||
assert success is True
|
||||
assert "test-chain" not in self.chain_manager.chains
|
||||
assert len(self.chain_manager.chains) == 1
|
||||
|
||||
def test_remove_default_chain(self):
|
||||
"""Test removing the default chain (should fail)"""
|
||||
success = self.chain_manager.remove_chain("ait-devnet")
|
||||
assert success is False
|
||||
assert "ait-devnet" in self.chain_manager.chains
|
||||
|
||||
def test_set_default_chain(self):
|
||||
"""Test setting default chain"""
|
||||
# Add a test chain first
|
||||
chain_config = ChainConfig(
|
||||
chain_id="test-chain",
|
||||
name="Test Chain",
|
||||
coordinator_url="http://localhost:8001",
|
||||
coordinator_api_key="test-key"
|
||||
)
|
||||
self.chain_manager.add_chain(chain_config)
|
||||
|
||||
# Set as default
|
||||
success = self.chain_manager.set_default_chain("test-chain")
|
||||
assert success is True
|
||||
assert self.chain_manager.default_chain_id == "test-chain"
|
||||
|
||||
def test_validate_chain_id(self):
|
||||
"""Test chain ID validation"""
|
||||
# Valid active chain
|
||||
assert self.chain_manager.validate_chain_id("ait-devnet") is True
|
||||
|
||||
# Invalid chain
|
||||
assert self.chain_manager.validate_chain_id("nonexistent") is False
|
||||
|
||||
# Add inactive chain
|
||||
chain_config = ChainConfig(
|
||||
chain_id="inactive-chain",
|
||||
name="Inactive Chain",
|
||||
coordinator_url="http://localhost:8001",
|
||||
coordinator_api_key="test-key",
|
||||
status=ChainStatus.INACTIVE
|
||||
)
|
||||
self.chain_manager.add_chain(chain_config)
|
||||
|
||||
# Inactive chain should be invalid
|
||||
assert self.chain_manager.validate_chain_id("inactive-chain") is False
|
||||
|
||||
def test_get_chain_stats(self):
|
||||
"""Test getting chain statistics"""
|
||||
stats = self.chain_manager.get_chain_stats()
|
||||
|
||||
assert stats["total_chains"] == 1
|
||||
assert stats["active_chains"] == 1
|
||||
assert stats["default_chain"] == "ait-devnet"
|
||||
assert len(stats["chain_list"]) == 1
|
||||
|
||||
|
||||
class TestMultiChainLedger:
|
||||
"""Test the multi-chain ledger adapter"""
|
||||
|
||||
def setup_method(self):
|
||||
"""Set up test environment"""
|
||||
self.temp_dir = Path(tempfile.mkdtemp())
|
||||
self.chain_manager = ChainManager(self.temp_dir / "chains.json")
|
||||
self.ledger = MultiChainLedgerAdapter(self.chain_manager, self.temp_dir)
|
||||
|
||||
def teardown_method(self):
|
||||
"""Clean up test environment"""
|
||||
import shutil
|
||||
shutil.rmtree(self.temp_dir)
|
||||
|
||||
def test_create_wallet(self):
|
||||
"""Test creating a wallet in a specific chain"""
|
||||
success = self.ledger.create_wallet(
|
||||
chain_id="ait-devnet",
|
||||
wallet_id="test-wallet",
|
||||
public_key="test-public-key",
|
||||
address="test-address"
|
||||
)
|
||||
|
||||
assert success is True
|
||||
|
||||
# Verify wallet exists
|
||||
wallet = self.ledger.get_wallet("ait-devnet", "test-wallet")
|
||||
assert wallet is not None
|
||||
assert wallet.wallet_id == "test-wallet"
|
||||
assert wallet.chain_id == "ait-devnet"
|
||||
assert wallet.public_key == "test-public-key"
|
||||
|
||||
def test_create_wallet_invalid_chain(self):
|
||||
"""Test creating wallet in invalid chain"""
|
||||
success = self.ledger.create_wallet(
|
||||
chain_id="invalid-chain",
|
||||
wallet_id="test-wallet",
|
||||
public_key="test-public-key"
|
||||
)
|
||||
|
||||
assert success is False
|
||||
|
||||
def test_list_wallets(self):
|
||||
"""Test listing wallets"""
|
||||
# Create multiple wallets
|
||||
self.ledger.create_wallet("ait-devnet", "wallet1", "pub1")
|
||||
self.ledger.create_wallet("ait-devnet", "wallet2", "pub2")
|
||||
|
||||
wallets = self.ledger.list_wallets("ait-devnet")
|
||||
assert len(wallets) == 2
|
||||
wallet_ids = [wallet.wallet_id for wallet in wallets]
|
||||
assert "wallet1" in wallet_ids
|
||||
assert "wallet2" in wallet_ids
|
||||
|
||||
def test_record_event(self):
|
||||
"""Test recording events"""
|
||||
success = self.ledger.record_event(
|
||||
chain_id="ait-devnet",
|
||||
wallet_id="test-wallet",
|
||||
event_type="test-event",
|
||||
data={"test": "data"}
|
||||
)
|
||||
|
||||
assert success is True
|
||||
|
||||
# Get events
|
||||
events = self.ledger.get_wallet_events("ait-devnet", "test-wallet")
|
||||
assert len(events) == 1
|
||||
assert events[0].event_type == "test-event"
|
||||
assert events[0].data["test"] == "data"
|
||||
|
||||
def test_get_chain_stats(self):
|
||||
"""Test getting chain statistics"""
|
||||
# Create a wallet first
|
||||
self.ledger.create_wallet("ait-devnet", "test-wallet", "test-pub")
|
||||
|
||||
stats = self.ledger.get_chain_stats("ait-devnet")
|
||||
assert stats["chain_id"] == "ait-devnet"
|
||||
assert stats["wallet_count"] == 1
|
||||
assert "database_path" in stats
|
||||
|
||||
|
||||
class TestChainAwareWalletService:
|
||||
"""Test the chain-aware wallet service"""
|
||||
|
||||
def setup_method(self):
|
||||
"""Set up test environment"""
|
||||
self.temp_dir = Path(tempfile.mkdtemp())
|
||||
self.chain_manager = ChainManager(self.temp_dir / "chains.json")
|
||||
self.ledger = MultiChainLedgerAdapter(self.chain_manager, self.temp_dir)
|
||||
|
||||
# Mock keystore service
|
||||
with patch('app.chain.chain_aware_wallet_service.PersistentKeystoreService') as mock_keystore:
|
||||
self.mock_keystore = mock_keystore.return_value
|
||||
self.mock_keystore.create_wallet.return_value = Mock(
|
||||
public_key="test-pub-key",
|
||||
metadata={}
|
||||
)
|
||||
self.mock_keystore.sign_message.return_value = b"test-signature"
|
||||
self.mock_keystore.unlock_wallet.return_value = True
|
||||
self.mock_keystore.lock_wallet.return_value = True
|
||||
|
||||
self.wallet_service = ChainAwareWalletService(self.chain_manager, self.ledger)
|
||||
|
||||
def teardown_method(self):
|
||||
"""Clean up test environment"""
|
||||
import shutil
|
||||
shutil.rmtree(self.temp_dir)
|
||||
|
||||
def test_create_wallet(self):
|
||||
"""Test creating a wallet in a specific chain"""
|
||||
wallet = self.wallet_service.create_wallet(
|
||||
chain_id="ait-devnet",
|
||||
wallet_id="test-wallet",
|
||||
password="test-password"
|
||||
)
|
||||
|
||||
assert wallet is not None
|
||||
assert wallet.wallet_id == "test-wallet"
|
||||
assert wallet.chain_id == "ait-devnet"
|
||||
assert wallet.public_key == "test-pub-key"
|
||||
|
||||
def test_create_wallet_invalid_chain(self):
|
||||
"""Test creating wallet in invalid chain"""
|
||||
wallet = self.wallet_service.create_wallet(
|
||||
chain_id="invalid-chain",
|
||||
wallet_id="test-wallet",
|
||||
password="test-password"
|
||||
)
|
||||
|
||||
assert wallet is None
|
||||
|
||||
def test_sign_message(self):
|
||||
"""Test signing a message"""
|
||||
# First create a wallet
|
||||
self.wallet_service.create_wallet("ait-devnet", "test-wallet", "test-password")
|
||||
|
||||
signature = self.wallet_service.sign_message(
|
||||
chain_id="ait-devnet",
|
||||
wallet_id="test-wallet",
|
||||
password="test-password",
|
||||
message=b"test message"
|
||||
)
|
||||
|
||||
assert signature == "test-signature" # Mocked signature
|
||||
|
||||
def test_unlock_wallet(self):
|
||||
"""Test unlocking a wallet"""
|
||||
# First create a wallet
|
||||
self.wallet_service.create_wallet("ait-devnet", "test-wallet", "test-password")
|
||||
|
||||
success = self.wallet_service.unlock_wallet(
|
||||
chain_id="ait-devnet",
|
||||
wallet_id="test-wallet",
|
||||
password="test-password"
|
||||
)
|
||||
|
||||
assert success is True
|
||||
|
||||
def test_list_wallets(self):
|
||||
"""Test listing wallets"""
|
||||
# Create wallets in different chains
|
||||
self.wallet_service.create_wallet("ait-devnet", "wallet1", "password1")
|
||||
|
||||
# Add another chain
|
||||
chain_config = ChainConfig(
|
||||
chain_id="test-chain",
|
||||
name="Test Chain",
|
||||
coordinator_url="http://localhost:8001",
|
||||
coordinator_api_key="test-key"
|
||||
)
|
||||
self.chain_manager.add_chain(chain_config)
|
||||
|
||||
# Create wallet in new chain
|
||||
self.wallet_service.create_wallet("test-chain", "wallet2", "password2")
|
||||
|
||||
# List all wallets
|
||||
all_wallets = self.wallet_service.list_wallets()
|
||||
assert len(all_wallets) == 2
|
||||
|
||||
# List specific chain wallets
|
||||
devnet_wallets = self.wallet_service.list_wallets("ait-devnet")
|
||||
assert len(devnet_wallets) == 1
|
||||
assert devnet_wallets[0].wallet_id == "wallet1"
|
||||
|
||||
def test_get_chain_wallet_stats(self):
|
||||
"""Test getting chain wallet statistics"""
|
||||
# Create a wallet
|
||||
self.wallet_service.create_wallet("ait-devnet", "test-wallet", "test-password")
|
||||
|
||||
stats = self.wallet_service.get_chain_wallet_stats("ait-devnet")
|
||||
assert stats["chain_id"] == "ait-devnet"
|
||||
assert "ledger_stats" in stats
|
||||
assert "keystore_stats" in stats
|
||||
|
||||
|
||||
class TestMultiChainIntegration:
|
||||
"""Integration tests for multi-chain functionality"""
|
||||
|
||||
def setup_method(self):
|
||||
"""Set up test environment"""
|
||||
self.temp_dir = Path(tempfile.mkdtemp())
|
||||
self.chain_manager = ChainManager(self.temp_dir / "chains.json")
|
||||
self.ledger = MultiChainLedgerAdapter(self.chain_manager, self.temp_dir)
|
||||
|
||||
# Add a second chain
|
||||
chain_config = ChainConfig(
|
||||
chain_id="test-chain",
|
||||
name="Test Chain",
|
||||
coordinator_url="http://localhost:8001",
|
||||
coordinator_api_key="test-key"
|
||||
)
|
||||
self.chain_manager.add_chain(chain_config)
|
||||
|
||||
def teardown_method(self):
|
||||
"""Clean up test environment"""
|
||||
import shutil
|
||||
shutil.rmtree(self.temp_dir)
|
||||
|
||||
def test_cross_chain_wallet_isolation(self):
|
||||
"""Test that wallets are properly isolated between chains"""
|
||||
# Create wallet with same ID in different chains
|
||||
self.ledger.create_wallet("ait-devnet", "same-wallet", "pub1", "addr1")
|
||||
self.ledger.create_wallet("test-chain", "same-wallet", "pub2", "addr2")
|
||||
|
||||
# Verify they are different
|
||||
wallet1 = self.ledger.get_wallet("ait-devnet", "same-wallet")
|
||||
wallet2 = self.ledger.get_wallet("test-chain", "same-wallet")
|
||||
|
||||
assert wallet1.chain_id == "ait-devnet"
|
||||
assert wallet2.chain_id == "test-chain"
|
||||
assert wallet1.public_key != wallet2.public_key
|
||||
assert wallet1.address != wallet2.address
|
||||
|
||||
def test_chain_specific_events(self):
|
||||
"""Test that events are chain-specific"""
|
||||
# Create wallets in different chains
|
||||
self.ledger.create_wallet("ait-devnet", "wallet1", "pub1")
|
||||
self.ledger.create_wallet("test-chain", "wallet2", "pub2")
|
||||
|
||||
# Record events
|
||||
self.ledger.record_event("ait-devnet", "wallet1", "event1", {"chain": "devnet"})
|
||||
self.ledger.record_event("test-chain", "wallet2", "event2", {"chain": "test"})
|
||||
|
||||
# Verify events are chain-specific
|
||||
events1 = self.ledger.get_wallet_events("ait-devnet", "wallet1")
|
||||
events2 = self.ledger.get_wallet_events("test-chain", "wallet2")
|
||||
|
||||
assert len(events1) == 1
|
||||
assert len(events2) == 1
|
||||
assert events1[0].data["chain"] == "devnet"
|
||||
assert events2[0].data["chain"] == "test"
|
||||
|
||||
def test_all_chain_stats(self):
|
||||
"""Test getting statistics for all chains"""
|
||||
# Create wallets in different chains
|
||||
self.ledger.create_wallet("ait-devnet", "wallet1", "pub1")
|
||||
self.ledger.create_wallet("test-chain", "wallet2", "pub2")
|
||||
|
||||
stats = self.ledger.get_all_chain_stats()
|
||||
assert stats["total_chains"] == 2
|
||||
assert stats["total_wallets"] == 2
|
||||
assert "ait-devnet" in stats["chain_stats"]
|
||||
assert "test-chain" in stats["chain_stats"]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pytest.main([__file__])
|
||||
Reference in New Issue
Block a user