Metadata-Version: 2.4
Name: ton-devtools-rpc-mock
Version: 0.1.0
Summary: Deterministic Toncenter API v2 emulator for ICP integration testing
Project-URL: Homepage, https://github.com/ismaildalgatov/ton-devtools
Project-URL: Repository, https://github.com/ismaildalgatov/ton-devtools
Project-URL: Documentation, https://ismaildalgatov.github.io/ton-devtools/
Project-URL: Bug Tracker, https://github.com/ismaildalgatov/ton-devtools/issues
Project-URL: Changelog, https://github.com/ismaildalgatov/ton-devtools/blob/main/packages/ton-devtools-rpc-mock/CHANGELOG.md
License: MIT
License-File: LICENSE
Keywords: blockchain,fastapi,icp,mock,testing,ton,toncenter
Classifier: Development Status :: 3 - Alpha
Classifier: Framework :: FastAPI
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
Classifier: Topic :: Software Development :: Testing
Requires-Python: >=3.11
Requires-Dist: fastapi<1,>=0.115.0
Requires-Dist: uvicorn[standard]<1,>=0.30.0
Provides-Extra: dev
Requires-Dist: asgi-lifespan>=2.1; extra == 'dev'
Requires-Dist: httpx>=0.27; extra == 'dev'
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
Requires-Dist: pytest>=8.3; extra == 'dev'
Requires-Dist: ruff>=0.4; extra == 'dev'
Description-Content-Type: text/markdown

# ton-devtools-rpc-mock

> Deterministic Toncenter API v2 emulator for ICP integration testing.

Part of the [ton-devtools](https://github.com/ismaildalgatov/ton-devtools) monorepo.

[![PyPI](https://img.shields.io/pypi/v/ton-devtools-rpc-mock)](https://pypi.org/project/ton-devtools-rpc-mock/)
[![Python](https://img.shields.io/pypi/pyversions/ton-devtools-rpc-mock)](https://pypi.org/project/ton-devtools-rpc-mock/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

## What it does

Replaces the live Toncenter API v2 node in tests with an in-process server that:

- Returns deterministic responses for pre-configured wallet addresses
- Supports `getWalletInformation` and `runGetMethod` (`get_public_key`)
- Provides runtime state mutation and fault injection via `/_mock/*` endpoints
- Eliminates flaky tests caused by mainnet/testnet availability

## Installation

```bash
pip install ton-devtools-rpc-mock
```

## Quick Start

### As a pytest ASGI fixture (recommended)

```python
import os
import pytest_asyncio
import httpx
from asgi_lifespan import LifespanManager
from ton_devtools_rpc_mock import app, DEPLOYED_WALLET

@pytest_asyncio.fixture
async def trms():
    os.environ["MOCK_CONTROL"] = "1"
    async with LifespanManager(app):
        async with httpx.AsyncClient(
            transport=httpx.ASGITransport(app=app),
            base_url="http://test",
        ) as client:
            await client.post("/_mock/reset")
            yield client

async def test_deployed_wallet(trms):
    resp = await trms.post("/jsonRPC", json={
        "method": "runGetMethod",
        "params": {"address": DEPLOYED_WALLET, "method": "get_public_key", "stack": []},
    })
    assert resp.json()["result"]["exit_code"] == 0
```

### As a standalone server

```bash
# Start with control endpoints enabled
ton-devtools-rpc-mock --port 8080 --control

# Point your ICP core service at it
export TON_API_BASE_URL=http://localhost:8080
```

### As a Docker container

```bash
docker run -p 8080:8080 -e MOCK_CONTROL=1 ghcr.io/ismaildalgatov/ton-devtools-rpc-mock:latest
```

## Pre-configured fixtures

| Constant | Address prefix | Behaviour |
|---|---|---|
| `DEPLOYED_WALLET` | `0:aaaa...` | Active v4r2 wallet, `exit_code: 0`, returns real pubkey |
| `UNDEPLOYED_WALLET` | `0:bbbb...` | Uninitialized, `exit_code: -11`, empty stack |
| `FAULT_WALLET` | `0:cccc...` | Always returns HTTP 500 |

## Control endpoints

Enabled when `MOCK_CONTROL=1`:

| Endpoint | Description |
|---|---|
| `POST /_mock/set_wallet_state` | Mutate balance, seqno, pubkey, status |
| `POST /_mock/inject_fault` | Inject `http_error`, `timeout`, or `corrupt_json` |
| `POST /_mock/reset` | Restore all fixtures, clear global fault |

## Fault injection

```python
# Inject HTTP 503 on a specific address
await client.post("/_mock/inject_fault", json={
    "address": DEPLOYED_WALLET,
    "fault": {"type": "http_error", "status_code": 503},
})

# Global outage
await client.post("/_mock/inject_fault", json={
    "address": None,
    "fault": {"type": "http_error", "status_code": 502},
})

# Corrupt JSON response
await client.post("/_mock/inject_fault", json={
    "address": DEPLOYED_WALLET,
    "fault": {"type": "corrupt_json"},
})
```

## License

MIT
