144 lines
4.6 KiB
Python
144 lines
4.6 KiB
Python
"""US-010 integration tests: typed meshnet SDK over local gateway/tracker/nodes."""
|
|
|
|
import json
|
|
import urllib.request
|
|
|
|
from meshnet import Client
|
|
from meshnet_contracts import LocalSolanaContracts
|
|
from meshnet_gateway.server import GatewayServer, _payment_address_for_api_key
|
|
from meshnet_node.server import StubNodeServer
|
|
from meshnet_tracker.server import TrackerServer, _NodeEntry, _coverage_percentage
|
|
|
|
|
|
def test_sdk_support_helpers_are_deterministic_without_network():
|
|
"""Non-socket coverage for SDK-facing gateway/tracker helper behavior."""
|
|
address = _payment_address_for_api_key("sdk-key")
|
|
nodes = [
|
|
_NodeEntry("a", "http://node-a", 0, 15, "stub-model", None, {}, None, 1.0),
|
|
_NodeEntry("b", "http://node-b", 16, 31, "stub-model", None, {}, None, 1.0),
|
|
]
|
|
|
|
assert 32 <= len(address) <= 44
|
|
assert _coverage_percentage(nodes, 0, 31) == 100.0
|
|
|
|
|
|
def _post_json(url: str, payload: dict) -> dict:
|
|
data = json.dumps(payload).encode()
|
|
req = urllib.request.Request(
|
|
url,
|
|
data=data,
|
|
headers={"Content-Type": "application/json"},
|
|
method="POST",
|
|
)
|
|
with urllib.request.urlopen(req) as r:
|
|
return json.loads(r.read())
|
|
|
|
|
|
def _register_node(
|
|
tracker_url: str,
|
|
endpoint: str,
|
|
shard_start: int,
|
|
shard_end: int,
|
|
*,
|
|
wallet_address: str,
|
|
) -> None:
|
|
_post_json(
|
|
f"{tracker_url}/v1/nodes/register",
|
|
{
|
|
"endpoint": endpoint,
|
|
"shard_start": shard_start,
|
|
"shard_end": shard_end,
|
|
"hardware_profile": {},
|
|
"wallet_address": wallet_address,
|
|
"score": 1.0,
|
|
},
|
|
)
|
|
|
|
|
|
def test_meshnet_sdk_methods_against_local_network():
|
|
"""SDK covers OpenAI chat passthrough plus meshnet wallet/model/cost/request APIs."""
|
|
contracts = LocalSolanaContracts(starting_credit_lamports=0)
|
|
contracts.payment.fund_api_key("sdk-key", lamports=2_000_000_000, usdc_micro=123_000_000)
|
|
|
|
tracker = TrackerServer(contracts=contracts)
|
|
tracker_port = tracker.start()
|
|
tracker_url = f"http://127.0.0.1:{tracker_port}"
|
|
|
|
nodes = [
|
|
StubNodeServer(shard_start=0, shard_end=15, is_last_shard=False),
|
|
StubNodeServer(shard_start=16, shard_end=31, is_last_shard=True),
|
|
StubNodeServer(shard_start=0, shard_end=15, is_last_shard=False),
|
|
StubNodeServer(shard_start=16, shard_end=31, is_last_shard=True),
|
|
]
|
|
node_ports = [node.start() for node in nodes]
|
|
|
|
for index, (port, shard_start, shard_end) in enumerate(
|
|
[
|
|
(node_ports[0], 0, 15),
|
|
(node_ports[1], 16, 31),
|
|
(node_ports[2], 0, 15),
|
|
(node_ports[3], 16, 31),
|
|
],
|
|
start=1,
|
|
):
|
|
_register_node(
|
|
tracker_url,
|
|
f"http://127.0.0.1:{port}",
|
|
shard_start,
|
|
shard_end,
|
|
wallet_address=f"wallet-{index}",
|
|
)
|
|
|
|
gateway = GatewayServer(tracker_url=tracker_url, contracts=contracts)
|
|
gateway_port = gateway.start()
|
|
gateway_url = f"http://127.0.0.1:{gateway_port}"
|
|
|
|
try:
|
|
client = Client(api_key="sdk-key", base_url=gateway_url)
|
|
|
|
chat_response = client.chat.completions.create(
|
|
model="stub-model",
|
|
messages=[{"role": "user", "content": "hello sdk"}],
|
|
)
|
|
assert chat_response.choices[0].message.content == "stub response to: hello sdk"
|
|
|
|
balance = client.wallet.balance()
|
|
assert balance.sol == 2.0
|
|
assert balance.usdc == 123.0
|
|
|
|
top_up = client.wallet.top_up(amount_sol=1.0)
|
|
assert top_up.amount_sol == 1.0
|
|
assert 32 <= len(top_up.payment_address) <= 44
|
|
assert top_up.qr.startswith("solana:")
|
|
|
|
available_models = client.models.available()
|
|
assert available_models == [
|
|
{
|
|
"id": "stub-model",
|
|
"shard_coverage_percentage": 100.0,
|
|
}
|
|
]
|
|
|
|
estimate = client.estimate_cost(model="stub-model", tokens=1_000)
|
|
assert estimate.model == "stub-model"
|
|
assert estimate.tokens == 1_000
|
|
assert estimate.sol == 0.000032
|
|
|
|
redundant = client.request(
|
|
model="stub-model",
|
|
messages=[{"role": "user", "content": "redundant"}],
|
|
redundancy=2,
|
|
)
|
|
assert redundant.redundancy == 2
|
|
assert redundant.majority_response.choices[0].message.content == (
|
|
"stub response to: redundant"
|
|
)
|
|
assert len(redundant.responses) == 2
|
|
assert nodes[1].received_activations
|
|
assert nodes[3].received_activations
|
|
finally:
|
|
gateway.stop()
|
|
for node in nodes:
|
|
node.stop()
|
|
tracker.stop()
|