96 lines
3.9 KiB
Python
96 lines
3.9 KiB
Python
"""n8n 連携 (作業区間の計算・重なり・送信) のテスト。標準ライブラリの unittest だけを使う。
|
|
|
|
python -m unittest discover -s tests -v
|
|
"""
|
|
|
|
import json
|
|
import sys
|
|
import tempfile
|
|
import threading
|
|
import time
|
|
import unittest
|
|
from datetime import date, datetime
|
|
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
|
import chktime # noqa: E402
|
|
|
|
MIN = 60.0
|
|
BASE = datetime(2026, 1, 5, 9, 0).timestamp() # ローカル時刻 2026-01-05 09:00
|
|
|
|
|
|
def turn(start_min, end_min, kind="prompt", reply=True, interrupted=False):
|
|
"""BASE からの分で 1 ターンを作る。reply=False なら応答なし。"""
|
|
ts = BASE + start_min * MIN
|
|
end = BASE + end_min * MIN
|
|
return {"ts": ts, "endTs": end if reply else ts, "firstReplyTs": ts + 1 if reply else None,
|
|
"kind": kind, "interrupted": interrupted}
|
|
|
|
|
|
def session(*turns, sid="s1", mtime=None):
|
|
last_end = max(t["endTs"] for t in turns) if turns else BASE
|
|
return {"id": sid, "turns": list(turns), "mtime": mtime if mtime is not None else last_end}
|
|
|
|
|
|
LATER = BASE + 24 * 3600 # 「今」: 最後のログから十分経っている
|
|
|
|
|
|
class MakeBlocksTest(unittest.TestCase):
|
|
def test_gap_29_minutes_keeps_block(self):
|
|
blocks = chktime.make_blocks(session(turn(0, 10), turn(39, 50)), now=LATER)
|
|
self.assertEqual(len(blocks), 1)
|
|
self.assertEqual(blocks[0]["minutes"], 50)
|
|
self.assertEqual(blocks[0]["turns"], 2)
|
|
|
|
def test_gap_30_minutes_splits_block(self):
|
|
blocks = chktime.make_blocks(session(turn(0, 10), turn(40, 50)), now=LATER)
|
|
self.assertEqual([b["minutes"] for b in blocks], [10, 10])
|
|
|
|
def test_parallel_prompt_keeps_block(self):
|
|
# 前の応答 (0〜20 分) の途中の 5 分に次の発言
|
|
blocks = chktime.make_blocks(session(turn(0, 20), turn(5, 30)), now=LATER)
|
|
self.assertEqual(len(blocks), 1)
|
|
self.assertEqual(blocks[0]["minutes"], 30)
|
|
|
|
def test_short_block_dropped_but_exactly_min_kept(self):
|
|
short = chktime.make_blocks(session(turn(0, 4.9)), now=LATER)
|
|
exact = chktime.make_blocks(session(turn(0, 5)), now=LATER)
|
|
self.assertEqual(short, [])
|
|
self.assertEqual(len(exact), 1)
|
|
|
|
def test_last_block_without_reply_is_in_progress(self):
|
|
blocks = chktime.make_blocks(session(turn(0, 10), turn(60, 60, reply=False)), now=LATER)
|
|
self.assertEqual([b["inProgress"] for b in blocks], [False, True])
|
|
|
|
def test_recent_log_marks_last_block_in_progress(self):
|
|
s = session(turn(0, 10))
|
|
blocks = chktime.make_blocks(s, now=s["mtime"] + 29 * MIN)
|
|
self.assertTrue(blocks[0]["inProgress"])
|
|
blocks = chktime.make_blocks(s, now=s["mtime"] + 30 * MIN)
|
|
self.assertFalse(blocks[0]["inProgress"])
|
|
|
|
def test_interrupted_last_turn_is_not_in_progress(self):
|
|
blocks = chktime.make_blocks(session(turn(0, 10, reply=False, interrupted=True), turn(1, 10)), now=LATER)
|
|
self.assertFalse(blocks[0]["inProgress"])
|
|
only = chktime.make_blocks(session(turn(0, 10), turn(11, 11, reply=False, interrupted=True)), now=LATER)
|
|
self.assertFalse(only[-1]["inProgress"])
|
|
|
|
def test_source_is_stable(self):
|
|
a = chktime.make_blocks(session(turn(0, 10)), now=LATER)
|
|
b = chktime.make_blocks(session(turn(0, 10)), now=LATER + 999)
|
|
self.assertEqual(a[0]["source"], b[0]["source"])
|
|
self.assertEqual(a[0]["source"], f"chktime:s1:{int(round(BASE * 1000))}")
|
|
|
|
def test_custom_gap_and_min(self):
|
|
blocks = chktime.make_blocks(session(turn(0, 3), turn(14, 17)), gap_min=10, min_min=3, now=LATER)
|
|
self.assertEqual([b["minutes"] for b in blocks], [3, 3])
|
|
|
|
def test_date_is_local_start_date(self):
|
|
blocks = chktime.make_blocks(session(turn(0, 10)), now=LATER)
|
|
self.assertEqual(blocks[0]["date"], "2026-01-05")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|