from __future__ import annotations import os from pathlib import Path import subprocess import sys import tempfile import unittest from cmbuyer_client.core.errors import SingleInstanceError from cmbuyer_client.localstate.single_instance import NamedMutex @unittest.skipUnless(os.name == "nt", "named mutex 仅在 Windows 验证") class NamedMutexTests(unittest.TestCase): def test_second_process_for_same_database_is_rejected(self) -> None: with tempfile.TemporaryDirectory() as directory: database = Path(directory) / "state.sqlite3" first = NamedMutex(database) try: with self.assertRaises(SingleInstanceError): NamedMutex(database) code = ( "from pathlib import Path; " "from cmbuyer_client.localstate.single_instance import NamedMutex; " "from cmbuyer_client.core.errors import SingleInstanceError; " f"p=Path({str(database)!r}); " "\ntry:\n NamedMutex(p)\nexcept SingleInstanceError:\n raise SystemExit(17)\nraise SystemExit(0)" ) environment = dict(os.environ) environment["PYTHONPATH"] = str(Path(__file__).resolve().parents[2] / "src") result = subprocess.run([sys.executable, "-c", code], env=environment, check=False) self.assertEqual(result.returncode, 17) finally: first.close() with NamedMutex(database): pass