ai-rule-engine/tests/test_api.py
root e39829fc4e feat(ai-rule-engine): 完成 MVP 所有批次实现
批次1: 项目结构 + SQLite 存储层 + 数据模型
批次2: REST API (http.server)
批次3: LLM 编译器 (支持 OpenAI/Anthropic)
批次4: RestrictedPython 规则执行器
批次5: 规则匹配器 + LLM Callback 兜底
批次6: 冲突检测器

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-11 22:19:42 +08:00

142 lines
4.0 KiB
Python

"""Tests for REST API."""
import pytest
import json
import os
import tempfile
from http.client import HTTPConnection
from threading import Thread
from time import sleep
from rule_engine.api import create_app
from rule_engine.store import RuleStore
@pytest.fixture
def temp_db():
fd, path = tempfile.mkstemp(suffix=".db")
os.close(fd)
yield path
os.unlink(path)
@pytest.fixture
def store(temp_db):
return RuleStore(temp_db)
@pytest.fixture
def server(store):
srv = create_app(store, host="127.0.0.1", port=18000)
thread = Thread(target=srv.serve_forever, daemon=True)
thread.start()
sleep(0.1) # 等待服务器启动
yield srv
srv.shutdown()
@pytest.fixture
def client(server):
return HTTPConnection("127.0.0.1", 18000)
def test_health(client):
"""验证健康检查。"""
client.request("GET", "/health")
resp = client.getresponse()
assert resp.status == 200
data = json.loads(resp.read())
assert data["status"] == "ok"
def test_create_rule(client):
"""验证创建规则。"""
body = json.dumps({
"name": "test_rule",
"description": "测试规则",
"condition_template": "如果用户是会员则打折"
})
client.request("POST", "/api/rules", body=body, headers={"Content-Type": "application/json"})
resp = client.getresponse()
assert resp.status == 201
data = json.loads(resp.read())
assert data["name"] == "test_rule"
assert "id" in data
def test_create_rule_missing_fields(client):
"""验证缺少必填字段返回错误。"""
body = json.dumps({"name": "only_name"})
client.request("POST", "/api/rules", body=body, headers={"Content-Type": "application/json"})
resp = client.getresponse()
assert resp.status == 400
def test_get_rule(client):
"""验证获取规则。"""
# 先创建
body = json.dumps({"name": "get_test", "condition_template": "test"})
client.request("POST", "/api/rules", body=body, headers={"Content-Type": "application/json"})
resp = client.getresponse()
data = json.loads(resp.read())
rule_id = data["id"]
# 再获取
client.request("GET", f"/api/rules/{rule_id}")
resp = client.getresponse()
data = json.loads(resp.read())
assert data["name"] == "get_test"
def test_get_rule_not_found(client):
"""验证获取不存在的规则。"""
client.request("GET", "/api/rules/nonexistent")
resp = client.getresponse()
assert resp.status == 404
def test_list_rules(client):
"""验证列出规则。"""
# 创建两条规则
for name in ["list_r1", "list_r2"]:
body = json.dumps({"name": name, "condition_template": "test"})
client.request("POST", "/api/rules", body=body, headers={"Content-Type": "application/json"})
client.getresponse()
# 列出
client.request("GET", "/api/rules")
resp = client.getresponse()
assert resp.status == 200
data = json.loads(resp.read())
assert "rules" in data
assert len(data["rules"]) >= 2
def test_delete_rule(client):
"""验证删除规则。"""
# 先创建
body = json.dumps({"name": "delete_test", "condition_template": "test"})
client.request("POST", "/api/rules", body=body, headers={"Content-Type": "application/json"})
resp = client.getresponse()
rule_id = json.loads(resp.read())["id"]
# 删除
client.request("DELETE", f"/api/rules/{rule_id}")
resp = client.getresponse()
assert resp.status == 200
# 确认已删除
client.request("GET", f"/api/rules/{rule_id}")
resp = client.getresponse()
assert resp.status == 404
def test_evaluate_not_implemented(client):
"""验证 evaluate 接口返回 placeholder。"""
body = json.dumps({"facts": {"user_id": "u123"}})
client.request("POST", "/api/rules/evaluate", body=body, headers={"Content-Type": "application/json"})
resp = client.getresponse()
assert resp.status == 200
data = json.loads(resp.read())
assert data["matched"] is False
assert "Executor not implemented" in data["message"]