/ agentdiff_x402 / test_local.py
test_local.py
 1  """Smoke test the x402 service locally (without actual payment)."""
 2  
 3  from __future__ import annotations
 4  
 5  import json
 6  import subprocess
 7  import sys
 8  import time
 9  
10  import requests
11  
12  SAMPLE = r"""
13  // SPDX-License-Identifier: MIT
14  pragma solidity ^0.8.20;
15  
16  contract VulnerableVault {
17      mapping(address => uint256) public balances;
18      address public owner;
19  
20      constructor() {
21          owner = msg.sender;
22      }
23  
24      function deposit() external payable {
25          balances[msg.sender] += msg.value;
26      }
27  
28      // Classic reentrancy: external call before state update
29      function withdraw(uint256 amount) external {
30          require(balances[msg.sender] >= amount, "insufficient");
31          (bool ok,) = msg.sender.call{value: amount}("");
32          require(ok, "send failed");
33          balances[msg.sender] -= amount;
34      }
35  
36      // Access control via tx.origin (known bad practice)
37      function setOwner(address newOwner) external {
38          require(tx.origin == owner, "not owner");
39          owner = newOwner;
40      }
41  }
42  """
43  
44  
45  def start_server():
46      from pathlib import Path
47      proc = subprocess.Popen(
48          [sys.executable, "-m", "uvicorn", "app:app", "--port", "8401", "--log-level", "warning"],
49          cwd=str(Path(__file__).parent),
50          stdout=subprocess.PIPE, stderr=subprocess.PIPE,
51      )
52      # Wait for ready
53      for _ in range(60):
54          try:
55              r = requests.get("http://127.0.0.1:8401/health", timeout=1)
56              if r.ok:
57                  return proc
58          except Exception:
59              pass
60          time.sleep(0.5)
61      out, err = proc.communicate(timeout=5)
62      raise RuntimeError(f"server didn't start. stdout: {out[:500]}\nstderr: {err[:1500]}")
63  
64  
65  def main():
66      proc = start_server()
67      try:
68          # 1. /health
69          r = requests.get("http://127.0.0.1:8401/health", timeout=5)
70          print(f"GET /health -> {r.status_code}: {r.text}")
71  
72          # 2. /info
73          r = requests.get("http://127.0.0.1:8401/info", timeout=10)
74          print(f"GET /info -> {r.status_code}:")
75          print(json.dumps(r.json(), indent=2))
76  
77          # 3. POST /analyze (without payment — should return 402 or similar if x402 wired)
78          r = requests.post(
79              "http://127.0.0.1:8401/analyze",
80              json={"source": SAMPLE, "name": "VulnerableVault"},
81              timeout=240,
82          )
83          print(f"POST /analyze (no payment) -> {r.status_code}:")
84          print(r.text[:6000])
85      finally:
86          proc.terminate()
87          try:
88              proc.wait(timeout=10)
89          except subprocess.TimeoutExpired:
90              proc.kill()
91  
92  
93  if __name__ == "__main__":
94      main()