119 lines
4.2 KiB
Python
119 lines
4.2 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Local mock test for subscription endpoints (subscribe/unsubscribe/tick)."""
|
|
import sys, io, os, json, time, threading, urllib.request, urllib.error
|
|
|
|
if sys.stdout is None:
|
|
sys.stdout = io.StringIO()
|
|
if sys.stderr is None:
|
|
sys.stderr = io.StringIO()
|
|
|
|
RESULT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "sub_test.txt")
|
|
SRC = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "src")
|
|
sys.path.insert(0, SRC)
|
|
|
|
def log(msg):
|
|
with open(RESULT, "a") as f:
|
|
f.write(msg + "\n")
|
|
|
|
import bridge_util, bridge_http_server, bridge_ws_server, bridge_subscription
|
|
|
|
# ---- Fake QMT ContextInfo ----
|
|
class FakeCtx:
|
|
def __init__(self):
|
|
self.subs = {} # handle -> codes
|
|
self._next_handle = 1
|
|
self.pushed = [] # records of (handle, data) pushed
|
|
def subscribe_whole_quote(self, codes, callback=None):
|
|
handle = self._next_handle
|
|
self._next_handle += 1
|
|
self.subs[handle] = list(codes)
|
|
# remember callback so tests can trigger pushes
|
|
self.callback = callback
|
|
return handle
|
|
def unsubscribe_quote(self, handle):
|
|
self.subs.pop(handle, None)
|
|
def get_full_tick(self, codes):
|
|
return {c: {"lastPrice": 10.0, "volume": 100} for c in codes}
|
|
|
|
fake = FakeCtx()
|
|
bridge_util.CTX = fake
|
|
bridge_util.ACCOUNT = "TEST"
|
|
|
|
bridge_http_server.PORT = 18690
|
|
bridge_http_server.TOKEN = ""
|
|
bridge_http_server.start_server()
|
|
time.sleep(0.6)
|
|
|
|
BASE = "http://127.0.0.1:18690"
|
|
|
|
def post(path, obj):
|
|
data = json.dumps(obj).encode("utf-8")
|
|
req = urllib.request.Request(BASE + path, data=data, method="POST",
|
|
headers={"Content-Type": "application/json"})
|
|
try:
|
|
with urllib.request.urlopen(req, timeout=5) as r:
|
|
return r.status, json.loads(r.read().decode())
|
|
except urllib.error.HTTPError as e:
|
|
try:
|
|
return e.code, json.loads(e.read().decode())
|
|
except Exception:
|
|
return e.code, None
|
|
|
|
def get(path):
|
|
try:
|
|
with urllib.request.urlopen(BASE + path, timeout=5) as r:
|
|
return r.status, json.loads(r.read().decode())
|
|
except urllib.error.HTTPError as e:
|
|
try:
|
|
return e.code, json.loads(e.read().decode())
|
|
except Exception:
|
|
return e.code, None
|
|
|
|
# ---- Tests ----
|
|
# 1. subscribe whole
|
|
st, body = post("/data/subscribe", {"type": "whole", "codes": ["SH", "SZ"]})
|
|
log("1. subscribe whole -> HTTP %d body=%s" % (st, json.dumps(body, ensure_ascii=False)))
|
|
sub_id = body.get("sub_id") if body else None
|
|
assert st == 200 and sub_id is not None, "subscribe failed"
|
|
assert fake.subs, "QMT subscribe not created"
|
|
log(" QMT subs: %s" % fake.subs)
|
|
|
|
# 2. simulate QMT push -> should broadcast via ws (no ws client, no crash)
|
|
if fake.callback:
|
|
fake.callback({"600000.SH": {"lastPrice": 10.1}})
|
|
log("2. simulated QMT push OK (no crash)")
|
|
|
|
# 3. subscribe invalid type
|
|
st, body = post("/data/subscribe", {"type": "bogus", "codes": ["SH"]})
|
|
log("3. subscribe bogus type -> HTTP %d body=%s" % (st, json.dumps(body, ensure_ascii=False)))
|
|
assert st == 400, "bogus type should be 400"
|
|
|
|
# 4. subscribe missing codes
|
|
st, body = post("/data/subscribe", {"type": "whole"})
|
|
log("4. subscribe no codes -> HTTP %d body=%s" % (st, json.dumps(body, ensure_ascii=False)))
|
|
assert st == 400, "missing codes should be 400"
|
|
|
|
# 5. unsubscribe
|
|
st, body = post("/data/unsubscribe", {"sub_id": sub_id})
|
|
log("5. unsubscribe -> HTTP %d body=%s" % (st, json.dumps(body, ensure_ascii=False)))
|
|
assert st == 200, "unsubscribe failed"
|
|
assert not fake.subs, "QMT sub should be removed"
|
|
|
|
# 6. unsubscribe unknown
|
|
st, body = post("/data/unsubscribe", {"sub_id": 999999})
|
|
log("6. unsubscribe unknown -> HTTP %d body=%s" % (st, json.dumps(body, ensure_ascii=False)))
|
|
assert st == 404, "unknown sub should be 404"
|
|
|
|
# 7. GET /data/tick
|
|
st, body = get("/data/tick?codes=600000.SH,000001.SZ")
|
|
log("7. tick -> HTTP %d body=%s" % (st, json.dumps(body, ensure_ascii=False)))
|
|
assert st == 200 and "600000.SH" in body.get("data", {}), "tick failed"
|
|
|
|
# 8. tick missing codes
|
|
st, body = get("/data/tick")
|
|
log("8. tick no codes -> HTTP %d body=%s" % (st, json.dumps(body, ensure_ascii=False)))
|
|
assert st == 400, "tick no codes should be 400"
|
|
|
|
bridge_http_server.stop_server()
|
|
log("=== done ===")
|