Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,6 @@ __pycache__/

# Intellij IDEA files
.idea/
tests/.env
htmlcov/
.coverage
372 changes: 368 additions & 4 deletions poetry.lock

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ websocket-client = "^1.7.0"
jsonschema = "^4.22.0"
pydantic-settings = "^2.0"

[tool.poetry.group.dev.dependencies]
pytest = "^8.3.4"
pytest-cov = "^6.0.0"
pytest-asyncio = "^0.24.0"
pytest-mock = "^3.14.0"
pytest-env = "^1.1.5"
pytest-timeout = "^2.3.1"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
59 changes: 59 additions & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
[pytest]
# Test discovery patterns
python_files = test_*.py *_test.py
python_classes = Test*
python_functions = test_*

# Test paths
testpaths = tests

# Output options
addopts =
# Verbose output
-v
# Show summary of all test types (failed, error, skipped, xfailed, xpassed)
-ra
# Show local variables in tracebacks
--showlocals
# Strict markers - require all markers to be registered
--strict-markers
# Strict config - raise errors on unknown config options
--strict-config
# Coverage options (uncomment when you want coverage reports)
# --cov=virtuals_acp
# --cov-report=html
# --cov-report=term-missing
# --cov-branch
# Disable warnings summary (uncomment to see warnings)
# --disable-warnings

# Asyncio configuration
asyncio_mode = auto
asyncio_default_fixture_loop_scope = function

# Timeout for tests (in seconds) - prevents tests from hanging
timeout = 300

# Markers - register custom markers here
markers =
unit: Unit tests
integration: Integration tests
slow: Tests that take a long time to run
requires_network: Tests that require network connectivity
requires_blockchain: Tests that require blockchain connectivity
smoke: Smoke tests for basic functionality

# Logging
log_cli = false
log_cli_level = INFO
log_cli_format = %(asctime)s [%(levelname)8s] %(message)s
log_cli_date_format = %Y-%m-%d %H:%M:%S

# Minimum Python version
minversion = 7.0

# Filter warnings
filterwarnings =
error
ignore::UserWarning
ignore::DeprecationWarning
11 changes: 11 additions & 0 deletions tests/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# General Variables
WHITELISTED_WALLET_ADDRESS=<YOUR_WHITELISTED_WALLET_ADDRESS>
WHITELISTED_WALLET_PRIVATE_KEY=<YOUR_WHITELISTED_PRIVATE_KEY>

# Seller Agent Variables
SELLER_ENTITY_ID=<YOUR_SELLER_ENTITY_ID>
SELLER_AGENT_WALLET_ADDRESS=<YOUR_SELLER_AGENT_WALLET_ADDRESS>

# Buyer Agent Variables
BUYER_ENTITY_ID=<YOUR_BUYER_ENTITY_ID>
BUYER_AGENT_WALLET_ADDRESS=<YOUR_BUYER_AGENT_WALLET_ADDRESS>
22 changes: 22 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import os
from pathlib import Path
import pytest


# Load .env file from tests directory if it exists
def pytest_configure(config):
"""Load environment variables from tests/.env before running tests"""
env_file = Path(__file__).parent / ".env"
if env_file.exists():
print(f"\n✅ Loading environment variables from {env_file}")
with open(env_file) as f:
for line in f:
line = line.strip()
# Skip comments and empty lines
if line and not line.startswith('#'):
if '=' in line:
key, value = line.split('=', 1)
os.environ[key.strip()] = value.strip()
else:
print(f"\n⚠️ No .env file found at {env_file}")
print("Integration tests will be skipped. Create tests/.env from tests/.env.example")
57 changes: 57 additions & 0 deletions tests/integration/test_integration_contract_client_v2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import pytest
import os
from virtuals_acp.contract_clients.contract_client_v2 import ACPContractClientV2


# Skip all integration tests if environment variables are not set
pytestmark = pytest.mark.integration

# Check if we have required environment variables for integration tests
SKIP_INTEGRATION = not all([
os.getenv("WHITELISTED_WALLET_PRIVATE_KEY"),
os.getenv("SELLER_AGENT_WALLET_ADDRESS"),
os.getenv("SELLER_ENTITY_ID"),
])


@pytest.mark.skipif(SKIP_INTEGRATION, reason="Integration test environment variables not set")
class TestIntegrationACPContractClientV2:
@pytest.fixture(scope="class")
def integration_client(self):
wallet_private_key = os.getenv("WHITELISTED_WALLET_PRIVATE_KEY")
agent_wallet_address = os.getenv("SELLER_AGENT_WALLET_ADDRESS")
entity_id = int(os.getenv("SELLER_ENTITY_ID", "0"))

try:
client = ACPContractClientV2(
agent_wallet_address=agent_wallet_address,
wallet_private_key=wallet_private_key,
entity_id=entity_id,
)
yield client
except Exception as e:
pytest.fail(f"Failed to initialize integration client: {e}")

class TestInitialization:
def test_should_connect_to_mainnet(self, integration_client):
assert integration_client is not None
assert integration_client.agent_wallet_address is not None

def test_should_have_valid_web3_connection(self, integration_client):
assert integration_client.w3 is not None
assert integration_client.w3.is_connected()

def test_should_fetch_manager_addresses(self, integration_client):
assert integration_client.job_manager_address is not None
assert integration_client.job_manager_address.startswith("0x")

def test_should_validate_session_key(self, integration_client):
# If client initialized, session key validation already passed
assert integration_client.account is not None
assert integration_client.entity_id is not None

def test_should_have_x402_instance(self, integration_client):
assert integration_client.x402 is not None

def test_should_have_alchemy_kit_instance(self, integration_client):
assert integration_client.alchemy_kit is not None
Loading