feat: requirements analysis, submission checks (stability stress test), AI inspection pipeline
This commit is contained in:
+117
-2
@@ -1,3 +1,118 @@
|
||||
from django.test import TestCase
|
||||
"""端到端测试: 创建作业要求 → 上传项目包 → 检测 → 报告"""
|
||||
import io
|
||||
import tarfile
|
||||
import textwrap
|
||||
import unittest
|
||||
from unittest import mock
|
||||
|
||||
# Create your tests here.
|
||||
from django.contrib.auth.models import User
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from requirements.models import Requirement, Submission
|
||||
|
||||
FLASK_PROJECT = textwrap.dedent("""\
|
||||
from flask import Flask
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route("/")
|
||||
def index():
|
||||
return "ok"
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=8321)
|
||||
""")
|
||||
|
||||
|
||||
def make_tar_bytes(name: str, files: dict) -> bytes:
|
||||
buf = io.BytesIO()
|
||||
with tarfile.open(fileobj=buf, mode="w") as tf:
|
||||
for fname, content in files.items():
|
||||
data = content.encode()
|
||||
info = tarfile.TarInfo(name=f"{name}/{fname}")
|
||||
info.size = len(data)
|
||||
tf.addfile(info, io.BytesIO(data))
|
||||
return buf.getvalue()
|
||||
|
||||
|
||||
class EndToEndTests(APITestCase):
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
cls.user = User.objects.create_user("tester", password="pass12345")
|
||||
|
||||
def setUp(self):
|
||||
self._login()
|
||||
|
||||
def _login(self):
|
||||
from rest_framework.authtoken.models import Token
|
||||
token, _ = Token.objects.get_or_create(user=self.user)
|
||||
self.client.credentials(HTTP_AUTHORIZATION=f"Token {token.key}")
|
||||
|
||||
def test_create_requirement_analyzes_spec(self):
|
||||
self._login()
|
||||
with mock.patch("requirements.llm.requests.post") as post:
|
||||
post.return_value = mock.Mock(
|
||||
json=lambda: {"choices": [{"message": {"content": (
|
||||
'{"ai_inspection": true, '
|
||||
'"stability": {"enabled": true, "requirements": "基准并发20错误率≤1%"}, '
|
||||
'"functional": {"enabled": true, "points": ["首页可访问", "返回 ok"]}, '
|
||||
'"performance": {"enabled": false, "requirements": ""}, '
|
||||
'"security": {"enabled": false, "requirements": ""}}'
|
||||
)}}]},
|
||||
raise_for_status=lambda: None,
|
||||
)
|
||||
resp = self.client.post("/api/requirements/create/", {
|
||||
"title": "作业1-分析",
|
||||
"content": "实现一个 web 服务, 首页返回 ok, 要求稳定度达到 99%",
|
||||
}, format="json")
|
||||
self.assertEqual(resp.status_code, 201, resp.content)
|
||||
requirement = Requirement.objects.get(title="作业1-分析")
|
||||
self.assertTrue(requirement.spec["stability"]["enabled"])
|
||||
self.assertIn("首页可访问", requirement.spec["functional"]["points"])
|
||||
|
||||
def test_submission_full_pipeline(self):
|
||||
self._login()
|
||||
requirement = Requirement.objects.create(
|
||||
title="作业1",
|
||||
content="实现 web 服务",
|
||||
spec={
|
||||
"ai_inspection": True,
|
||||
"stability": {"enabled": True, "requirements": "基准错误率≤1%"},
|
||||
"functional": {"enabled": True, "points": ["首页可访问"]},
|
||||
"performance": {"enabled": False, "requirements": ""},
|
||||
"security": {"enabled": False, "requirements": ""},
|
||||
},
|
||||
)
|
||||
tar_bytes = make_tar_bytes("proj", {"app.py": FLASK_PROJECT})
|
||||
with mock.patch("requirements.llm.ai_summarize", return_value={
|
||||
"summary": "代码结构清晰, 功能点完备",
|
||||
"issues": [{"point": "首页可访问", "status": "pass", "detail": "/ 路由存在"}],
|
||||
}), mock.patch.dict("django.conf.settings.__dict__", {
|
||||
"STABILITY_BASE_DURATION": 2, "STABILITY_RAMPUP_DURATION": 2, "STABILITY_CONCURRENCY": 4,
|
||||
}):
|
||||
resp = self.client.post(
|
||||
f"/api/requirements/{requirement.pk}/submissions/",
|
||||
{"name": "tester-sub", "file": io.BytesIO(tar_bytes)},
|
||||
format="multipart",
|
||||
)
|
||||
self.assertEqual(resp.status_code, 201, resp.content)
|
||||
submission = Submission.objects.get()
|
||||
if submission.status != "completed":
|
||||
submission.report["error"] = submission.report.get("error", "?")
|
||||
raise AssertionError(f"status={submission.status} report={submission.report}")
|
||||
self.assertIn("ai_inspection", submission.report)
|
||||
self.assertIn("stability", submission.report)
|
||||
report = self.client.get(f"/api/submissions/{submission.pk}/report/")
|
||||
self.assertEqual(report.status_code, 200)
|
||||
self.assertIn("stability", report.json())
|
||||
|
||||
|
||||
class AuthTests(APITestCase):
|
||||
def test_requires_login(self):
|
||||
resp = self.client.get("/api/requirements/")
|
||||
self.assertIn(resp.status_code, (401, 403))
|
||||
|
||||
def test_token_login(self):
|
||||
User.objects.create_user("alice", password="pass12345")
|
||||
resp = self.client.post("/api/auth/token/", {"username": "alice", "password": "pass12345"})
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
self.assertIn("token", resp.json())
|
||||
|
||||
Reference in New Issue
Block a user