test_client_id_bulk_tools.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. from __future__ import annotations
  2. import json
  3. from exec_mcp import repo, storage
  4. from exec_mcp.services_orders import cancel_all_orders, get_open_orders
  5. from fastapi import HTTPException
  6. class _FakeTrading:
  7. def cancel_order(self, order_id, version=2):
  8. return True
  9. class _FakeClient:
  10. def __init__(self):
  11. self.trading = _FakeTrading()
  12. def test_bulk_tools_match_open_status_case_and_client_id(tmp_path, monkeypatch):
  13. db_path = tmp_path / "exec.sqlite3"
  14. monkeypatch.setattr(storage, "DB_PATH", db_path)
  15. storage.init_db()
  16. monkeypatch.setattr("exec_mcp.services_orders._get_client", lambda account_id: _FakeClient())
  17. repo.create_account(display_name="strategy", venue="bitstamp", venue_account_ref="ref-1", api_key="k", api_secret="s")
  18. account_id = repo.list_accounts(enabled_only=False)[0]["id"]
  19. with storage.get_connection() as conn:
  20. conn.execute(
  21. """
  22. INSERT INTO order_records
  23. (id, account_id, market, side, order_type, amount, price, expire_time, status, bitstamp_order_id, client_id, client_order_id, raw_json, created_at, updated_at)
  24. VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
  25. """,
  26. (
  27. "rec-1",
  28. account_id,
  29. "xrpusd",
  30. "sell",
  31. "limit",
  32. "10",
  33. "2.00",
  34. None,
  35. "Open",
  36. "1994292738961409",
  37. "test",
  38. None,
  39. json.dumps({"id": "1994292738961409", "status": "Open"}),
  40. "2026-04-09T08:20:50+00:00",
  41. "2026-04-09T08:20:50+00:00",
  42. ),
  43. )
  44. conn.commit()
  45. open_orders = get_open_orders(account_id=account_id, client_id="test")
  46. assert open_orders["ok"] is True
  47. assert len(open_orders["orders"]) == 1
  48. assert open_orders["orders"][0]["bitstamp_order_id"] == "1994292738961409"
  49. cancelled = cancel_all_orders(account_id=account_id, client_id="test")
  50. assert cancelled["ok"] is True
  51. assert cancelled["count"] == 1
  52. assert cancelled["cancelled"][0]["ok"] is True
  53. assert cancelled["cancelled"][0]["order_id"] == "1994292738961409"
  54. def test_cancel_all_orders_skips_missing_orders_and_continues(tmp_path, monkeypatch):
  55. db_path = tmp_path / "exec.sqlite3"
  56. monkeypatch.setattr(storage, "DB_PATH", db_path)
  57. storage.init_db()
  58. repo.create_account(display_name="strategy", venue="bitstamp", venue_account_ref="ref-1", api_key="k", api_secret="s")
  59. account_id = repo.list_accounts(enabled_only=False)[0]["id"]
  60. with storage.get_connection() as conn:
  61. for idx, order_id in enumerate(["missing-order", "ok-order"]):
  62. conn.execute(
  63. """
  64. INSERT INTO order_records
  65. (id, account_id, market, side, order_type, amount, price, expire_time, status, bitstamp_order_id, client_id, client_order_id, raw_json, created_at, updated_at)
  66. VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
  67. """,
  68. (
  69. f"rec-{idx}",
  70. account_id,
  71. "xrpusd",
  72. "sell",
  73. "limit",
  74. "10",
  75. "2.00",
  76. None,
  77. "open",
  78. order_id,
  79. None,
  80. None,
  81. json.dumps({"id": order_id, "status": "Open"}),
  82. "2026-04-09T08:20:50+00:00",
  83. "2026-04-09T08:20:50+00:00",
  84. ),
  85. )
  86. conn.commit()
  87. def fake_cancel_order(*, account_id: str, order_id):
  88. if order_id == "missing-order":
  89. raise HTTPException(status_code=400, detail="Order not found")
  90. with storage.get_connection() as conn:
  91. conn.execute(
  92. "UPDATE order_records SET status = ?, updated_at = ? WHERE bitstamp_order_id = ?",
  93. ("cancelled", "2026-04-09T09:00:00+00:00", order_id),
  94. )
  95. conn.commit()
  96. return {"ok": True, "order_id": order_id, "raw": {"id": order_id}}
  97. monkeypatch.setattr("exec_mcp.services_orders.cancel_order", fake_cancel_order)
  98. result = cancel_all_orders(account_id=account_id)
  99. assert result["ok"] is True
  100. assert result["count"] == 2
  101. assert result["cancelled"][0]["status"] == "missing"
  102. assert result["cancelled"][1]["ok"] is True
  103. open_orders = get_open_orders(account_id=account_id)
  104. assert open_orders["orders"] == []