feat: migrate tests to use centralized aitbc package utilities
Some checks failed
Python Tests / test-python (push) Failing after 43s
Some checks failed
Python Tests / test-python (push) Failing after 43s
- Migrate HTTP client usage from requests to aitbc.AITBCHTTPClient in test files - Update conftest.py to use aitbc path utilities (get_data_path, get_log_path) - Update test_model_validation.py to use aitbc validators (validate_address, validate_hash) - Skip HTML scraping files that require raw requests (verify_toggle_removed.py) - Migrated files: test_payment_integration.py, test_cross_node_blockchain.py, verify_transactions_fixed.py, test_tx_import.py, test_simple_import.py, test_minimal.py, test_block_import_complete.py
This commit is contained in:
@@ -12,6 +12,12 @@ from unittest.mock import Mock
|
|||||||
project_root = Path(__file__).parent.parent
|
project_root = Path(__file__).parent.parent
|
||||||
sys.path.insert(0, str(project_root))
|
sys.path.insert(0, str(project_root))
|
||||||
|
|
||||||
|
# Add aitbc package to sys.path for centralized utilities
|
||||||
|
sys.path.insert(0, str(project_root / "aitbc"))
|
||||||
|
|
||||||
|
# Import aitbc utilities for conftest
|
||||||
|
from aitbc import get_data_path, get_log_path
|
||||||
|
|
||||||
# Add necessary source paths
|
# Add necessary source paths
|
||||||
sys.path.insert(0, str(project_root / "packages" / "py" / "aitbc-core" / "src"))
|
sys.path.insert(0, str(project_root / "packages" / "py" / "aitbc-core" / "src"))
|
||||||
sys.path.insert(0, str(project_root / "packages" / "py" / "aitbc-crypto" / "src"))
|
sys.path.insert(0, str(project_root / "packages" / "py" / "aitbc-crypto" / "src"))
|
||||||
@@ -44,8 +50,9 @@ sys.path.insert(0, str(project_root / "apps" / "coordinator-api"))
|
|||||||
|
|
||||||
# Set up test environment
|
# Set up test environment
|
||||||
os.environ["TEST_MODE"] = "true"
|
os.environ["TEST_MODE"] = "true"
|
||||||
os.environ["AUDIT_LOG_DIR"] = str(project_root / "logs" / "audit")
|
os.environ["AUDIT_LOG_DIR"] = str(get_log_path() / "audit")
|
||||||
os.environ["TEST_DATABASE_URL"] = "sqlite:///:memory:"
|
os.environ["TEST_DATABASE_URL"] = "sqlite:///:memory:"
|
||||||
|
os.environ["DATA_DIR"] = str(get_data_path())
|
||||||
|
|
||||||
# Mock missing optional dependencies
|
# Mock missing optional dependencies
|
||||||
sys.modules['slowapi'] = Mock()
|
sys.modules['slowapi'] = Mock()
|
||||||
|
|||||||
@@ -19,14 +19,13 @@ def compute_block_hash(height, parent_hash, timestamp):
|
|||||||
|
|
||||||
def test_block_import():
|
def test_block_import():
|
||||||
"""Test the block import endpoint with various scenarios"""
|
"""Test the block import endpoint with various scenarios"""
|
||||||
import requests
|
|
||||||
|
|
||||||
print("Testing Block Import Endpoint")
|
print("Testing Block Import Endpoint")
|
||||||
print("=" * 50)
|
print("=" * 50)
|
||||||
|
|
||||||
# Get current head to work with existing blockchain
|
# Get current head to work with existing blockchain
|
||||||
response = requests.get(f"{BASE_URL}/head")
|
client = AITBCHTTPClient()
|
||||||
head = response.json()
|
head = client.get(f"{BASE_URL}/head")
|
||||||
print(f"Current head: height={head['height']}, hash={head['hash']}")
|
print(f"Current head: height={head['height']}, hash={head['hash']}")
|
||||||
|
|
||||||
# Use very high heights to avoid conflicts with existing chain
|
# Use very high heights to avoid conflicts with existing chain
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ Tests all functionality including validation, conflicts, and transaction import
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
import hashlib
|
import hashlib
|
||||||
import requests
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from aitbc import AITBCHTTPClient
|
||||||
|
|
||||||
BASE_URL = "https://aitbc.bubuit.net/rpc"
|
BASE_URL = "https://aitbc.bubuit.net/rpc"
|
||||||
CHAIN_ID = "ait-mainnet"
|
CHAIN_ID = "ait-mainnet"
|
||||||
@@ -25,10 +25,11 @@ def test_block_import_complete():
|
|||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
|
|
||||||
results = []
|
results = []
|
||||||
|
client = AITBCHTTPClient()
|
||||||
|
|
||||||
# Test 1: Invalid height (0)
|
# Test 1: Invalid height (0)
|
||||||
print("\n[TEST 1] Invalid height (0)...")
|
print("\n[TEST 1] Invalid height (0)...")
|
||||||
response = requests.post(
|
response = client.post(
|
||||||
f"{BASE_URL}/importBlock",
|
f"{BASE_URL}/importBlock",
|
||||||
json={
|
json={
|
||||||
"height": 0,
|
"height": 0,
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ Cross-node blockchain feature tests
|
|||||||
Tests new blockchain features across aitbc and aitbc1 nodes
|
Tests new blockchain features across aitbc and aitbc1 nodes
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import requests
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import subprocess
|
import subprocess
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import time
|
import time
|
||||||
|
from aitbc import AITBCHTTPClient, NetworkErroration
|
||||||
|
|
||||||
# Test configuration
|
# Test configuration
|
||||||
NODES = {
|
NODES = {
|
||||||
@@ -35,12 +35,11 @@ def compute_block_hash(height, parent_hash, timestamp):
|
|||||||
|
|
||||||
def get_node_head(node_key):
|
def get_node_head(node_key):
|
||||||
"""Get the current head block from a node"""
|
"""Get the current head block from a node"""
|
||||||
url = f"{NODES[node_key]['rpc_url']}/head"
|
client = AITBCHTTPClient(timeout=10)
|
||||||
try:
|
try:
|
||||||
response = requests.get(url, timeout=10)
|
url = f"{NODES[node_key]['rpc_url']}/head"
|
||||||
response.raise_for_status()
|
return client.get(url)
|
||||||
return response.json()
|
except NetworkError as e:
|
||||||
except Exception as e:
|
|
||||||
print(f"Error getting head from {node_key}: {e}")
|
print(f"Error getting head from {node_key}: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -120,24 +119,27 @@ def test_cross_node_block_sync():
|
|||||||
timestamp = datetime.utcnow().isoformat() + "Z"
|
timestamp = datetime.utcnow().isoformat() + "Z"
|
||||||
valid_hash = compute_block_hash(height, parent_hash, timestamp)
|
valid_hash = compute_block_hash(height, parent_hash, timestamp)
|
||||||
|
|
||||||
response = requests.post(
|
client = AITBCHTTPClient(timeout=10)
|
||||||
f"{NODES['aitbc']['rpc_url']}/importBlock",
|
try:
|
||||||
json={
|
result = client.post(
|
||||||
"height": height,
|
f"{NODES['aitbc']['rpc_url']}/importBlock",
|
||||||
"hash": valid_hash,
|
json={
|
||||||
"parent_hash": parent_hash,
|
"height": height,
|
||||||
"proposer": "cross-node-test",
|
"hash": valid_hash,
|
||||||
"timestamp": timestamp,
|
"parent_hash": parent_hash,
|
||||||
"tx_count": 0,
|
"proposer": "cross-node-test",
|
||||||
"chain_id": CHAIN_ID
|
"timestamp": timestamp,
|
||||||
}
|
"tx_count": 0,
|
||||||
)
|
"chain_id": CHAIN_ID
|
||||||
|
}
|
||||||
if response.status_code == 200 and response.json().get("success"):
|
)
|
||||||
print(f"✅ Block imported on aitbc: height={height}, hash={valid_hash}")
|
if result.get("success"):
|
||||||
else:
|
print(f"✅ Block imported on aitbc: height={height}, hash={valid_hash}")
|
||||||
print(f"❌ Failed to import block on aitbc: {response.status_code}")
|
else:
|
||||||
print(f"Response: {response.text}")
|
print(f"❌ Failed to import block on aitbc")
|
||||||
|
return False
|
||||||
|
except NetworkError as e:
|
||||||
|
print(f"❌ Failed to import block on aitbc: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Wait for gossip propagation
|
# Wait for gossip propagation
|
||||||
@@ -151,9 +153,8 @@ def test_cross_node_block_sync():
|
|||||||
|
|
||||||
# Try to get the specific block from aitbc1
|
# Try to get the specific block from aitbc1
|
||||||
try:
|
try:
|
||||||
response = requests.get(f"{NODES['aitbc1']['rpc_url']}/blocks/{height}", timeout=10)
|
block_data = AITBCHTTPClient(timeout=10).get(f"{NODES['aitbc1']['rpc_url']}/blocks/{height}")
|
||||||
if response.status_code == 200:
|
if block_data:
|
||||||
block_data = response.json()
|
|
||||||
print(f"✅ Block synced to aitbc1: height={block_data.get('height')}, hash={block_data.get('hash')}")
|
print(f"✅ Block synced to aitbc1: height={block_data.get('height')}, hash={block_data.get('hash')}")
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
@@ -175,13 +176,12 @@ def test_cross_node_block_range():
|
|||||||
for node_key in NODES:
|
for node_key in NODES:
|
||||||
url = f"{NODES[node_key]['rpc_url']}/blocks-range"
|
url = f"{NODES[node_key]['rpc_url']}/blocks-range"
|
||||||
try:
|
try:
|
||||||
response = requests.get(url, params={"start": 0, "end": 5}, timeout=10)
|
response = AITBCHTTPClient(timeout=10).get(url, params={"start": 0, "end": 5})
|
||||||
response.raise_for_status()
|
blocks = response.get("blocks", []) if response else []
|
||||||
blocks = response.json().get("blocks", [])
|
|
||||||
print(f"{NODES[node_key]['name']}: returned {len(blocks)} blocks in range 0-5")
|
print(f"{NODES[node_key]['name']}: returned {len(blocks)} blocks in range 0-5")
|
||||||
assert len(blocks) >= 1, \
|
assert len(blocks) >= 1, \
|
||||||
f"Node {node_key} returned no blocks"
|
f"Node {node_key} returned no blocks"
|
||||||
except Exception as e:
|
except NetworkError as e:
|
||||||
print(f"❌ Error getting block range from {node_key}: {e}")
|
print(f"❌ Error getting block range from {node_key}: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -195,15 +195,13 @@ def test_cross_node_connectivity():
|
|||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
|
|
||||||
for node_key in NODES:
|
for node_key in NODES:
|
||||||
url = f"{NODES[node_key]['rpc_url']}/head"
|
client = AITBCHTTPClient(timeout=10)
|
||||||
try:
|
try:
|
||||||
response = requests.get(url, timeout=10)
|
head = client.get(f"{NODES[node_key]['rpc_url']}/head")
|
||||||
response.raise_for_status()
|
|
||||||
head = response.json()
|
|
||||||
print(f"{NODES[node_key]['name']}: reachable, height={head.get('height')}")
|
print(f"{NODES[node_key]['name']}: reachable, height={head.get('height')}")
|
||||||
assert head.get("height") is not None, \
|
assert head.get("height") is not None, \
|
||||||
f"Node {node_key} did not return valid head"
|
f"Node {node_key} did not return valid head"
|
||||||
except Exception as e:
|
except NetworkError as e:
|
||||||
print(f"❌ Error connecting to {node_key}: {e}")
|
print(f"❌ Error connecting to {node_key}: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ Minimal test to debug transaction import
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
import hashlib
|
import hashlib
|
||||||
import requests
|
from aitbc import AITBCHTTPClient, NetworkError
|
||||||
|
|
||||||
BASE_URL = "https://aitbc.bubuit.net/rpc"
|
BASE_URL = "https://aitbc.bubuit.net/rpc"
|
||||||
CHAIN_ID = "ait-mainnet"
|
CHAIN_ID = "ait-mainnet"
|
||||||
@@ -19,8 +19,8 @@ def test_minimal():
|
|||||||
"""Test with minimal data"""
|
"""Test with minimal data"""
|
||||||
|
|
||||||
# Get current head
|
# Get current head
|
||||||
response = requests.get(f"{BASE_URL}/head")
|
client = AITBCHTTPClient()
|
||||||
head = response.json()
|
head = client.get(f"{BASE_URL}/head")
|
||||||
|
|
||||||
# Create a new block
|
# Create a new block
|
||||||
height = head["height"] + 1
|
height = head["height"] + 1
|
||||||
@@ -58,9 +58,8 @@ def test_minimal():
|
|||||||
test_block["transactions"] = [{"tx_hash": "0xtest", "sender": "0xtest", "recipient": "0xtest", "payload": {}}]
|
test_block["transactions"] = [{"tx_hash": "0xtest", "sender": "0xtest", "recipient": "0xtest", "payload": {}}]
|
||||||
|
|
||||||
print("\nTesting with one transaction...")
|
print("\nTesting with one transaction...")
|
||||||
response = requests.post(f"{BASE_URL}/importBlock", json=test_block)
|
response = client.post(f"{BASE_URL}/importBlock", json=test_block)
|
||||||
print(f"Status: {response.status_code}")
|
print(f"Response: {response}")
|
||||||
print(f"Response: {response.json()}")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
test_minimal()
|
test_minimal()
|
||||||
|
|||||||
@@ -41,6 +41,14 @@ test_data = {
|
|||||||
print("Test data:")
|
print("Test data:")
|
||||||
print(test_data)
|
print(test_data)
|
||||||
|
|
||||||
|
# Validate address and hash using aitbc validators
|
||||||
|
try:
|
||||||
|
validate_address(test_data["proposer"])
|
||||||
|
validate_hash(test_data["hash"])
|
||||||
|
print("✅ Address and hash validation passed")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"⚠️ Validation warning: {e}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
request = BlockImportRequest(**test_data)
|
request = BlockImportRequest(**test_data)
|
||||||
print("\n✅ Request validated successfully!")
|
print("\n✅ Request validated successfully!")
|
||||||
|
|||||||
@@ -7,13 +7,12 @@ Tests job creation with payments, escrow, release, and refund flows
|
|||||||
import asyncio
|
import asyncio
|
||||||
import httpx
|
import httpx
|
||||||
import json
|
import json
|
||||||
import logging
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Dict, Any
|
from typing import Dict, Any
|
||||||
|
from aitbc import get_logger
|
||||||
|
|
||||||
# Configure logging
|
# Configure logging
|
||||||
logging.basicConfig(level=logging.INFO)
|
logger = get_logger(__name__)
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
# Configuration
|
# Configuration
|
||||||
COORDINATOR_URL = "https://aitbc.bubuit.net/api"
|
COORDINATOR_URL = "https://aitbc.bubuit.net/api"
|
||||||
@@ -22,7 +21,7 @@ MINER_KEY = "${MINER_API_KEY}"
|
|||||||
|
|
||||||
class PaymentIntegrationTest:
|
class PaymentIntegrationTest:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.client = httpx.Client(timeout=30.0)
|
self.client = AITBCHTTPClient(timeout=30.0)
|
||||||
self.job_id = None
|
self.job_id = None
|
||||||
self.payment_id = None
|
self.payment_id = None
|
||||||
|
|
||||||
|
|||||||
@@ -7,13 +7,12 @@ Tests job creation with payments, escrow, release, and refund flows
|
|||||||
import asyncio
|
import asyncio
|
||||||
import httpx
|
import httpx
|
||||||
import json
|
import json
|
||||||
import logging
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Dict, Any
|
from typing import Dict, Any
|
||||||
|
from aitbc import get_logger
|
||||||
|
|
||||||
# Configure logging
|
# Configure logging
|
||||||
logging.basicConfig(level=logging.INFO)
|
logger = get_logger(__name__)
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
# Configuration - Using localhost as we're testing from the server
|
# Configuration - Using localhost as we're testing from the server
|
||||||
COORDINATOR_URL = "http://127.0.0.1:8000/v1"
|
COORDINATOR_URL = "http://127.0.0.1:8000/v1"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ Simple test for block import endpoint without transactions
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
import hashlib
|
import hashlib
|
||||||
import requests
|
from aitbc import AITBCHTTPClient, NetworkError
|
||||||
|
|
||||||
BASE_URL = "https://aitbc.bubuit.net/rpc"
|
BASE_URL = "https://aitbc.bubuit.net/rpc"
|
||||||
CHAIN_ID = "ait-mainnet"
|
CHAIN_ID = "ait-mainnet"
|
||||||
@@ -22,8 +22,8 @@ def test_simple_block_import():
|
|||||||
print("=" * 40)
|
print("=" * 40)
|
||||||
|
|
||||||
# Get current head
|
# Get current head
|
||||||
response = requests.get(f"{BASE_URL}/head")
|
client = AITBCHTTPClient()
|
||||||
head = response.json()
|
head = client.get(f"{BASE_URL}/head")
|
||||||
print(f"Current head: height={head['height']}, hash={head['hash']}")
|
print(f"Current head: height={head['height']}, hash={head['hash']}")
|
||||||
|
|
||||||
# Create a new block
|
# Create a new block
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ Test transaction import specifically
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
import hashlib
|
import hashlib
|
||||||
import requests
|
from aitbc import AITBCHTTPClient, NetworkError
|
||||||
|
|
||||||
BASE_URL = "https://aitbc.bubuit.net/rpc"
|
BASE_URL = "https://aitbc.bubuit.net/rpc"
|
||||||
CHAIN_ID = "ait-mainnet"
|
CHAIN_ID = "ait-mainnet"
|
||||||
@@ -22,8 +22,8 @@ def test_transaction_import():
|
|||||||
print("=" * 40)
|
print("=" * 40)
|
||||||
|
|
||||||
# Get current head
|
# Get current head
|
||||||
response = requests.get(f"{BASE_URL}/head")
|
client = AITBCHTTPClient()
|
||||||
head = response.json()
|
head = client.get(f"{BASE_URL}/head")
|
||||||
print(f"Current head: height={head['height']}")
|
print(f"Current head: height={head['height']}")
|
||||||
|
|
||||||
# Create a new block with one transaction
|
# Create a new block with one transaction
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
Verify that the data mode toggle button is removed from the explorer
|
Verify that the data mode toggle button is removed from the explorer
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import requests
|
|
||||||
import re
|
import re
|
||||||
|
import requests
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
print("🔍 Verifying Data Mode Toggle is Removed")
|
print("🔍 Verifying Data Mode Toggle is Removed")
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
Verify that transactions are now showing properly on the explorer
|
Verify that transactions are now showing properly on the explorer
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import requests
|
from aitbc import AITBCHTTPClient, NetworkError
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
print("🔍 Verifying Transactions Display on AITBC Explorer")
|
print("🔍 Verifying Transactions Display on AITBC Explorer")
|
||||||
@@ -12,9 +12,9 @@ def main():
|
|||||||
# Check API
|
# Check API
|
||||||
print("\n1. API Check:")
|
print("\n1. API Check:")
|
||||||
try:
|
try:
|
||||||
response = requests.get("https://aitbc.bubuit.net/api/explorer/transactions")
|
client = AITBCHTTPClient()
|
||||||
if response.status_code == 200:
|
data = client.get("https://aitbc.bubuit.net/api/explorer/transactions")
|
||||||
data = response.json()
|
if data:
|
||||||
print(f" ✅ API returns {len(data['items'])} transactions")
|
print(f" ✅ API returns {len(data['items'])} transactions")
|
||||||
|
|
||||||
# Count by status
|
# Count by status
|
||||||
@@ -27,8 +27,8 @@ def main():
|
|||||||
for status, count in status_counts.items():
|
for status, count in status_counts.items():
|
||||||
print(f" • {status}: {count}")
|
print(f" • {status}: {count}")
|
||||||
else:
|
else:
|
||||||
print(f" ❌ API failed: {response.status_code}")
|
print(f" ❌ API failed")
|
||||||
except Exception as e:
|
except NetworkError as e:
|
||||||
print(f" ❌ Error: {e}")
|
print(f" ❌ Error: {e}")
|
||||||
|
|
||||||
# Check main explorer page
|
# Check main explorer page
|
||||||
|
|||||||
Reference in New Issue
Block a user