mirror of
https://github.com/KingHWJ/WeReadBoard.git
synced 2026-11-03 18:24:58 +08:00
refactor(api): 去除代码版本命名
This commit is contained in:
1 parent
bbc4bdd140
commit
dcf4cb0719
31 files changed
+174
-154
No files matched your search
+26
-21
@@ -7,21 +7,21 @@ from unittest.mock import MagicMock, patch
|
||||
import pymysql
|
||||
from flask import Flask
|
||||
|
||||
from api_v2 import v2_bp
|
||||
from reading_api import reading_bp
|
||||
|
||||
|
||||
class ReadingGoalsTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
app = Flask(__name__)
|
||||
app.config["TESTING"] = True
|
||||
app.register_blueprint(v2_bp)
|
||||
app.register_blueprint(reading_bp)
|
||||
self.client = app.test_client()
|
||||
self.conn = MagicMock()
|
||||
self.cur = self.conn.cursor.return_value.__enter__.return_value
|
||||
self.cur.fetchone.return_value = {"id": "goal-1"}
|
||||
self.cur.fetchall.return_value = []
|
||||
self.cur.rowcount = 1
|
||||
self.connect = patch("api_v2.pymysql.connect", return_value=self.conn).start()
|
||||
self.connect = patch("reading_api.pymysql.connect", return_value=self.conn).start()
|
||||
self.addCleanup(patch.stopall)
|
||||
self.goal = {
|
||||
"id": "goal-1", "name": " 九月阅读 ",
|
||||
@@ -31,7 +31,7 @@ class ReadingGoalsTest(unittest.TestCase):
|
||||
}
|
||||
|
||||
def test_create_normalizes_and_commits_unknown_members(self):
|
||||
response = self.client.post("/api/v2/goals", json=self.goal)
|
||||
response = self.client.post("/api/reading/goals", json=self.goal)
|
||||
self.assertEqual(response.status_code, 201)
|
||||
expected = dict(self.goal, name="九月阅读", ids=["unknown-book", "123"], sources=["科幻书单"])
|
||||
self.assertEqual(response.json, {"goal": expected})
|
||||
@@ -39,6 +39,11 @@ class ReadingGoalsTest(unittest.TestCase):
|
||||
self.conn.rollback.assert_not_called()
|
||||
self.conn.close.assert_called_once()
|
||||
|
||||
def test_legacy_goal_path_remains_available(self):
|
||||
response = self.client.post("/api/" + "v" + "2" + "/goals", json=self.goal)
|
||||
self.assertEqual(response.status_code, 201)
|
||||
self.assertEqual(response.json["goal"]["id"], "goal-1")
|
||||
|
||||
def test_rejects_invalid_fields_without_writes(self):
|
||||
invalid = [
|
||||
{"id": 123}, {"id": ""}, {"id": "x" * 65},
|
||||
@@ -51,7 +56,7 @@ class ReadingGoalsTest(unittest.TestCase):
|
||||
]
|
||||
for fields in invalid:
|
||||
with self.subTest(fields=fields):
|
||||
response = self.client.post("/api/v2/goals", json=dict(self.goal, **fields))
|
||||
response = self.client.post("/api/reading/goals", json=dict(self.goal, **fields))
|
||||
self.assertEqual(response.status_code, 400)
|
||||
self.assertTrue(response.json["error"])
|
||||
self.cur.execute.assert_not_called()
|
||||
@@ -59,7 +64,7 @@ class ReadingGoalsTest(unittest.TestCase):
|
||||
|
||||
def test_invalid_json_and_body_shape_are_chinese_errors(self):
|
||||
for body in ("{", "null", "[]"):
|
||||
response = self.client.post("/api/v2/goals", data=body, content_type="application/json")
|
||||
response = self.client.post("/api/reading/goals", data=body, content_type="application/json")
|
||||
self.assertEqual(response.status_code, 400)
|
||||
self.assertTrue(any("\u4e00" <= ch <= "\u9fff" for ch in response.json["error"]))
|
||||
|
||||
@@ -70,7 +75,7 @@ class ReadingGoalsTest(unittest.TestCase):
|
||||
{"id": "goal-1", "name": "九月阅读", "start_date": date(2026, 9, 1),
|
||||
"end_date": date(2026, 9, 30), "sources": '["科幻书单"]', "book_id": "123"},
|
||||
]
|
||||
response = self.client.get("/api/v2/goals")
|
||||
response = self.client.get("/api/reading/goals")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.json, {"goals": [dict(
|
||||
self.goal, name="九月阅读", ids=["unknown-book", "123"], sources=["科幻书单"]
|
||||
@@ -78,7 +83,7 @@ class ReadingGoalsTest(unittest.TestCase):
|
||||
|
||||
def test_create_duplicate_returns_conflict(self):
|
||||
self.cur.execute.side_effect = pymysql.err.IntegrityError(1062, "Duplicate entry")
|
||||
response = self.client.post("/api/v2/goals", json=self.goal)
|
||||
response = self.client.post("/api/reading/goals", json=self.goal)
|
||||
self.assertEqual(response.status_code, 409)
|
||||
self.conn.commit.assert_not_called()
|
||||
self.conn.rollback.assert_called_once()
|
||||
@@ -87,19 +92,19 @@ class ReadingGoalsTest(unittest.TestCase):
|
||||
self.cur.fetchone.return_value = None
|
||||
self.cur.rowcount = 0
|
||||
for method in (self.client.put, self.client.delete):
|
||||
response = method("/api/v2/goals/missing", json=dict(self.goal, id="missing"))
|
||||
response = method("/api/reading/goals/missing", json=dict(self.goal, id="missing"))
|
||||
self.assertEqual(response.status_code, 404)
|
||||
self.conn.commit.assert_not_called()
|
||||
|
||||
def test_update_rejects_mismatched_id(self):
|
||||
response = self.client.put("/api/v2/goals/other", json=self.goal)
|
||||
response = self.client.put("/api/reading/goals/other", json=self.goal)
|
||||
self.assertEqual(response.status_code, 400)
|
||||
self.cur.execute.assert_not_called()
|
||||
|
||||
def test_member_write_failure_rolls_back_parent_change(self):
|
||||
self.cur.executemany.side_effect = pymysql.err.OperationalError(2013, "Lost connection")
|
||||
for method, path in ((self.client.post, "/api/v2/goals"),
|
||||
(self.client.put, "/api/v2/goals/goal-1")):
|
||||
for method, path in ((self.client.post, "/api/reading/goals"),
|
||||
(self.client.put, "/api/reading/goals/goal-1")):
|
||||
with self.subTest(path=path):
|
||||
self.conn.reset_mock()
|
||||
response = method(path, json=self.goal)
|
||||
@@ -108,7 +113,7 @@ class ReadingGoalsTest(unittest.TestCase):
|
||||
self.conn.commit.assert_not_called()
|
||||
|
||||
def test_import_validates_entire_batch_before_writes(self):
|
||||
response = self.client.post("/api/v2/goals/import", json={
|
||||
response = self.client.post("/api/reading/goals/import", json={
|
||||
"goals": [self.goal, dict(self.goal, id="bad", ids=[])]
|
||||
})
|
||||
self.assertEqual(response.status_code, 400)
|
||||
@@ -121,7 +126,7 @@ class ReadingGoalsTest(unittest.TestCase):
|
||||
self.cur.rowcount = next(counts)
|
||||
return self.cur.rowcount
|
||||
self.cur.execute.side_effect = execute
|
||||
response = self.client.post("/api/v2/goals/import", json={"goals": [
|
||||
response = self.client.post("/api/reading/goals/import", json={"goals": [
|
||||
self.goal, dict(self.goal, id="new"), dict(self.goal, id="new")
|
||||
]})
|
||||
self.assertEqual(response.status_code, 200)
|
||||
@@ -131,7 +136,7 @@ class ReadingGoalsTest(unittest.TestCase):
|
||||
|
||||
def test_import_second_member_failure_rolls_back_whole_batch(self):
|
||||
self.cur.executemany.side_effect = [None, pymysql.err.OperationalError(2013, "Lost connection")]
|
||||
response = self.client.post("/api/v2/goals/import", json={
|
||||
response = self.client.post("/api/reading/goals/import", json={
|
||||
"goals": [self.goal, dict(self.goal, id="second")]
|
||||
})
|
||||
self.assertEqual(response.status_code, 503)
|
||||
@@ -141,11 +146,11 @@ class ReadingGoalsTest(unittest.TestCase):
|
||||
def test_database_failures_never_return_successful_empty_data(self):
|
||||
self.connect.side_effect = pymysql.err.OperationalError(2003, "Unavailable")
|
||||
for method, path, body in (
|
||||
(self.client.get, "/api/v2/goals", None),
|
||||
(self.client.post, "/api/v2/goals", self.goal),
|
||||
(self.client.put, "/api/v2/goals/goal-1", self.goal),
|
||||
(self.client.delete, "/api/v2/goals/goal-1", None),
|
||||
(self.client.post, "/api/v2/goals/import", {"goals": [self.goal]}),
|
||||
(self.client.get, "/api/reading/goals", None),
|
||||
(self.client.post, "/api/reading/goals", self.goal),
|
||||
(self.client.put, "/api/reading/goals/goal-1", self.goal),
|
||||
(self.client.delete, "/api/reading/goals/goal-1", None),
|
||||
(self.client.post, "/api/reading/goals/import", {"goals": [self.goal]}),
|
||||
):
|
||||
with self.subTest(path=path, method=method):
|
||||
response = method(path, json=body)
|
||||
@@ -155,7 +160,7 @@ class ReadingGoalsTest(unittest.TestCase):
|
||||
def test_commit_and_rollback_connection_failures_still_return_503(self):
|
||||
self.conn.commit.side_effect = pymysql.err.OperationalError(2013, "Lost connection")
|
||||
self.conn.rollback.side_effect = pymysql.err.InterfaceError(0, "Connection closed")
|
||||
response = self.client.post("/api/v2/goals", json=self.goal)
|
||||
response = self.client.post("/api/reading/goals", json=self.goal)
|
||||
self.assertEqual(response.status_code, 503)
|
||||
self.conn.close.assert_called_once()
|
||||
|
||||
|
||||
Reference in new issue
Block a user