151 lines
4.9 KiB
Python
151 lines
4.9 KiB
Python
"""Coverage batch v2 (E2): cloud/marker_tools.py pure helpers --
|
|
timezone fallback, first-run parsing, int coercion, spawn-default
|
|
parsing, heartbeat/progress formatting, todo/task lines.
|
|
Safety buffer on top of E1; all direct calls.
|
|
"""
|
|
|
|
import sys
|
|
import time
|
|
import unittest
|
|
from pathlib import Path
|
|
from unittest import mock
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parents[2]
|
|
sys.path.insert(0, str(REPO_ROOT))
|
|
|
|
from cloud.marker_tools import (
|
|
_as_int,
|
|
_heartbeat_age_text,
|
|
_model_from_match,
|
|
_progress_lines,
|
|
_shanghai_tz,
|
|
format_snapshot,
|
|
format_task,
|
|
format_todo,
|
|
parse_first_run_at,
|
|
parse_spawn_defaults,
|
|
row_get,
|
|
)
|
|
|
|
|
|
class FakeMatch:
|
|
def __init__(self, token):
|
|
self._token = token
|
|
|
|
def group(self, n):
|
|
return self._token
|
|
|
|
def end(self, n):
|
|
return len(self._token)
|
|
|
|
|
|
class MarkerPureTestCase(unittest.TestCase):
|
|
def test_shanghai_tz_zoneinfo_raises(self):
|
|
with mock.patch("cloud.marker_tools.ZoneInfo",
|
|
side_effect=Exception("no tz")):
|
|
tz = _shanghai_tz()
|
|
self.assertEqual(tz.utcoffset(None).total_seconds(), 8 * 3600)
|
|
|
|
def test_shanghai_tz_no_zoneinfo(self):
|
|
with mock.patch("cloud.marker_tools.ZoneInfo", None):
|
|
tz = _shanghai_tz()
|
|
self.assertEqual(tz.utcoffset(None).total_seconds(), 8 * 3600)
|
|
|
|
def test_first_run_blank(self):
|
|
self.assertIsNone(parse_first_run_at(" "))
|
|
|
|
def test_first_run_negative(self):
|
|
self.assertIsNone(parse_first_run_at(-5))
|
|
|
|
def test_first_run_zero(self):
|
|
self.assertIsNone(parse_first_run_at(0))
|
|
|
|
def test_first_run_valid(self):
|
|
self.assertEqual(parse_first_run_at(1700000000), 1700000000.0)
|
|
self.assertIsNotNone(parse_first_run_at("2026-01-01T00:00:00Z"))
|
|
|
|
def test_row_get_fallback(self):
|
|
self.assertIsNone(row_get(None, "x"))
|
|
self.assertIsNone(row_get({}, "missing"))
|
|
|
|
def test_as_int_bool_and_float(self):
|
|
self.assertEqual(_as_int(True, 7), 7)
|
|
self.assertEqual(_as_int(3.5, 7), 7)
|
|
self.assertEqual(_as_int(3.0, 7), 3)
|
|
self.assertEqual(_as_int(4, 7), 4)
|
|
|
|
def test_model_from_match_empty_token(self):
|
|
self.assertEqual(_model_from_match("x", FakeMatch("."), 1),
|
|
(None, None))
|
|
|
|
def test_model_from_match_effort_word(self):
|
|
self.assertEqual(_model_from_match("x", FakeMatch("max"), 1),
|
|
(None, "max"))
|
|
|
|
def test_spawn_defaults_empty(self):
|
|
self.assertEqual(parse_spawn_defaults(""), {})
|
|
self.assertEqual(parse_spawn_defaults(None), {})
|
|
|
|
def test_spawn_defaults_zh(self):
|
|
out = parse_spawn_defaults("子任务用 gpt-6-luna max")
|
|
self.assertEqual(out.get("model"), "gpt-6-luna")
|
|
|
|
def test_heartbeat_none(self):
|
|
self.assertEqual(_heartbeat_age_text({}), "")
|
|
|
|
def test_heartbeat_bad(self):
|
|
self.assertEqual(
|
|
_heartbeat_age_text({"last_heartbeat": "bad"}), "")
|
|
|
|
def test_heartbeat_future(self):
|
|
now = time.time()
|
|
self.assertEqual(
|
|
_heartbeat_age_text({"last_heartbeat": now + 100}, now=now),
|
|
"0 秒前")
|
|
|
|
def test_heartbeat_seconds(self):
|
|
now = time.time()
|
|
self.assertEqual(
|
|
_heartbeat_age_text({"last_heartbeat": now - 30}, now=now),
|
|
"30 秒前")
|
|
|
|
def test_progress_lines_full(self):
|
|
now = time.time()
|
|
lines = _progress_lines(
|
|
{"executor": "docker", "actual_model": "m1",
|
|
"worktree_host": "h1", "last_heartbeat": now - 5,
|
|
"turn_id": "t9"}, now=now)
|
|
self.assertEqual(len(lines), 5)
|
|
|
|
def test_snapshot_terminal_empty(self):
|
|
text = format_snapshot(
|
|
{"id": "t1", "status": "completed", "result_text": "",
|
|
"error_text": ""}, 100)
|
|
self.assertIn("结果:(空)", text)
|
|
|
|
def test_snapshot_timed_out(self):
|
|
text = format_snapshot(
|
|
{"id": "t1", "status": "running", "result_text": "",
|
|
"error_text": ""}, 100, timed_out=True)
|
|
self.assertIn("等待超时", text)
|
|
|
|
def test_snapshot_cancelled(self):
|
|
text = format_snapshot(
|
|
{"id": "t1", "status": "running", "result_text": "",
|
|
"error_text": ""}, 100, cancelled=True)
|
|
self.assertIn("被取消", text)
|
|
|
|
def test_todo_bad_due_and_task(self):
|
|
line = format_todo({"status": "open", "title": "t", "id": "d1",
|
|
"priority": "high", "due_at": "bad",
|
|
"task_id": "t1"})
|
|
self.assertIn("task_id=t1", line)
|
|
self.assertNotIn("due=", line)
|
|
|
|
def test_task_bad_created(self):
|
|
line = format_task({"status": "completed", "id": "t1",
|
|
"created_by": "u1", "prompt": "do it",
|
|
"created_at": "bad"})
|
|
self.assertIn("do it", line)
|
|
self.assertNotIn("created=", line)
|