Files
codex-app-server/cloud/tests/test_gapfill_g2_goal_edges.py

195 lines
7.3 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""gapfill G2:goal_live_update.py 边缘分支补测。
补测基线(055da3c 线定向子集对本模块的覆盖):
80 语句缺 15 行:57、59(写信号校验抛错)、79-80(读信号
applied_version 非整数回落)、88(读信号非 dict)、109-110
(删信号 applied_version 非整数回落)、115-116(删信号
文件缺失/坏 JSON)、118(删信号非 dict)、121(删信号
version 非整数)、126-127(删信号 os.remove 失败)、181
(apply_goal_update old_version 为 0 分支)、187(apply
CAS 未命中回 None)。
只加测试,不改生产代码;信号只写临时目录,不联网。
"""
import json
import os
import sqlite3
import sys
import tempfile
import unittest
from pathlib import Path
from unittest import mock
try:
from cloud.goal_live_update import (
apply_goal_update,
consume_goal_update_signal,
ensure_goal_history_table,
read_goal_update_signal,
signal_path,
write_goal_update_signal,
)
except ImportError:
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
from cloud.goal_live_update import (
apply_goal_update,
consume_goal_update_signal,
ensure_goal_history_table,
read_goal_update_signal,
signal_path,
write_goal_update_signal,
)
class WriteValidationTestCase(unittest.TestCase):
def setUp(self):
self.tmp = tempfile.TemporaryDirectory()
self.state = os.path.join(self.tmp.name, "host-state.json")
def tearDown(self):
self.tmp.cleanup()
def test_bad_version_raises(self):
# 57:version 非正整数(0、负数、bool、字符串)一律
# ValueError,绝不写出信号文件。
for bad in (0, -1, True, "2", 2.5):
with self.assertRaises(ValueError):
write_goal_update_signal(
self.state, "t1", bad, "new goal")
self.assertFalse(os.path.exists(
signal_path(self.state, "t1")))
def test_bad_goal_raises(self):
# 59:goal 非空字符串校验(空串、空白串、非字符串)。
for bad in ("", " ", None, 123):
with self.assertRaises(ValueError):
write_goal_update_signal(self.state, "t1", 1, bad)
class ReadEdgeTestCase(unittest.TestCase):
def setUp(self):
self.tmp = tempfile.TemporaryDirectory()
self.state = os.path.join(self.tmp.name, "host-state.json")
def tearDown(self):
self.tmp.cleanup()
def test_bad_applied_version_falls_back_to_zero(self):
# 79-80:applied_version 非整数(int() 抛 ValueError /
# TypeError)时按 0 计,version=2 的信号仍可应用。
write_goal_update_signal(self.state, "t1", 2, "goal v2")
self.assertEqual(
read_goal_update_signal(self.state, "t1", "not-a-number"),
(2, "goal v2"))
def test_non_dict_signal_returns_none(self):
# 88:信号文件是合法 JSON 但不是 dict(列表)时回 None。
path = signal_path(self.state, "t1")
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path, "w", encoding="utf-8") as fh:
json.dump([1, 2], fh)
self.assertIsNone(read_goal_update_signal(self.state, "t1", 0))
class ConsumeEdgeTestCase(unittest.TestCase):
def setUp(self):
self.tmp = tempfile.TemporaryDirectory()
self.state = os.path.join(self.tmp.name, "host-state.json")
def tearDown(self):
self.tmp.cleanup()
def _write_raw(self, payload):
path = signal_path(self.state, "t1")
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path, "w", encoding="utf-8") as fh:
json.dump(payload, fh)
return path
def test_missing_file_returns_false(self):
# 115-116:信号文件不存在时回 False,不抛。
self.assertFalse(
consume_goal_update_signal(self.state, "t1", 5))
def test_bad_applied_version_falls_back_to_zero(self):
# 109-110:applied_version 非整数时按 0 计;version=1
# 的信号大于 0,故不删、回 False(下一条才是删的路)。
write_goal_update_signal(self.state, "t1", 1, "goal v1")
self.assertFalse(consume_goal_update_signal(
self.state, "t1", "not-a-number"))
self.assertTrue(os.path.exists(signal_path(self.state, "t1")))
def test_non_dict_signal_returns_false(self):
# 118:信号文件非 dict 时回 False,文件原样保留。
path = self._write_raw([1, 2])
self.assertFalse(
consume_goal_update_signal(self.state, "t1", 9))
self.assertTrue(os.path.exists(path))
def test_non_int_version_returns_false(self):
# 121:version 非整数(字符串)时回 False,文件保留。
path = self._write_raw({"version": "3", "goal": "g"})
self.assertFalse(
consume_goal_update_signal(self.state, "t1", 9))
self.assertTrue(os.path.exists(path))
def test_remove_failure_returns_false(self):
# 126-127:os.remove 失败时回 False,不抛。
write_goal_update_signal(self.state, "t1", 1, "goal v1")
with mock.patch("cloud.goal_live_update.os.remove",
side_effect=OSError("disk gone")):
self.assertFalse(
consume_goal_update_signal(self.state, "t1", 1))
self.assertTrue(os.path.exists(signal_path(self.state, "t1")))
class ApplyGoalUpdateTestCase(unittest.TestCase):
def setUp(self):
self.conn = sqlite3.connect(":memory:")
self.conn.execute(
"CREATE TABLE tasks(id TEXT PRIMARY KEY, goal TEXT, "
"goal_version INTEGER, updated_at REAL)")
ensure_goal_history_table(self.conn)
self.conn.execute(
"INSERT INTO tasks VALUES('t1', 'old', NULL, 0)")
self.conn.execute(
"INSERT INTO tasks VALUES('t2', 'old', 5, 0)")
self.conn.commit()
def tearDown(self):
self.conn.close()
def test_null_version_branch(self):
# 181:old_version 为 NULL(按 0 计)时走 NULL/0 分支,
# 新 version 为 1,history 写一行。
self.assertEqual(
apply_goal_update(self.conn, "t1", "old", None,
"new", "u1", 123.0), 1)
row = self.conn.execute(
"SELECT goal, goal_version FROM tasks WHERE id='t1'"
).fetchone()
self.assertEqual(row, ("new", 1))
hist = self.conn.execute(
"SELECT old_goal, new_goal, version FROM task_goal_history "
"WHERE task_id='t1'").fetchall()
self.assertEqual(hist, [("old", "new", 1)])
def test_cas_miss_returns_none_without_history(self):
# 187:CAS 未命中(库里 version=5,调用方按 4 来)时
# 回 None,任务行与 history 一律不动。
self.assertIsNone(
apply_goal_update(self.conn, "t2", "old", 4,
"new", "u1", 123.0))
row = self.conn.execute(
"SELECT goal, goal_version FROM tasks WHERE id='t2'"
).fetchone()
self.assertEqual(row, ("old", 5))
self.assertEqual(self.conn.execute(
"SELECT COUNT(*) FROM task_goal_history "
"WHERE task_id='t2'").fetchone()[0], 0)
if __name__ == "__main__":
unittest.main()