공개 런타임 롤백 경계 강화
This commit is contained in:
parent
ff3c79dfc2
commit
aaebe4450e
7 changed files with 1271 additions and 30 deletions
|
|
@ -15,6 +15,7 @@ BOOT = SCRIPTS / "boot-public-runtime.ps1"
|
|||
BOOT_REGISTER = SCRIPTS / "register-boot-task.ps1"
|
||||
HIDDEN_TRIGGER = SCRIPTS / "watch-public-runtime-hidden.vbs"
|
||||
START = SCRIPTS / "start-public-runtime.ps1"
|
||||
VOICE_PROBE = SCRIPTS / "probe-public-voice-sidecars.py"
|
||||
REPO_ROOT = SCRIPTS.parent
|
||||
RUNBOOK = REPO_ROOT / "docs" / "ops" / "public-runtime-watchdog.md"
|
||||
LOCAL_DEVELOPMENT = REPO_ROOT / "docs" / "guides" / "local-development.md"
|
||||
|
|
@ -117,6 +118,97 @@ class PublicRuntimeWatchdogProvenanceTest(unittest.TestCase):
|
|||
task_registration = BOOT_REGISTER_SOURCE.index("Register-ScheduledTask")
|
||||
self.assertLess(dirty_gate, task_registration)
|
||||
|
||||
def test_watchdog_and_boot_probe_exact_local_voice_stack(self) -> None:
|
||||
for source in (WATCHDOG_SOURCE, BOOT_SOURCE):
|
||||
for expected in (
|
||||
'"--component", "all"',
|
||||
'"--stt-provider", "local_whisper"',
|
||||
'"--stt-model", "small"',
|
||||
'"--stt-device", "cpu"',
|
||||
'"--tts-provider", "melotts"',
|
||||
'"--tts-model", "melotts-korean"',
|
||||
'"scripts\\probe-public-voice-sidecars.py"',
|
||||
"Test-VoiceSidecarStack",
|
||||
):
|
||||
with self.subTest(source=source[:32], expected=expected):
|
||||
self.assertIn(expected, source)
|
||||
self.assertIn("(Test-VoiceSidecarStack)", WATCHDOG_SOURCE)
|
||||
self.assertIn("$voiceSidecarsAfter = Test-VoiceSidecarStack", WATCHDOG_SOURCE)
|
||||
self.assertIn('-Name "voice-api"', WATCHDOG_SOURCE)
|
||||
self.assertIn("$voiceApiAfter = Test-JsonHealth", WATCHDOG_SOURCE)
|
||||
self.assertIn(
|
||||
"(Test-ApiControlPlaneHealthy) -and (Test-EngineHealthy) -and (Test-VoiceApiHealthy) -and (Test-VoiceSidecarStack)",
|
||||
BOOT_SOURCE,
|
||||
)
|
||||
self.assertGreaterEqual(BOOT_SOURCE.count("Test-VoiceApiHealthy"), 3)
|
||||
self.assertIn("-WhisperPort $WhisperPort", BOOT_SOURCE)
|
||||
self.assertIn("-MeloTtsPort $MeloTtsPort", BOOT_SOURCE)
|
||||
self.assertIn("scripts/probe-public-voice-sidecars.py", INSTALLER_SOURCE)
|
||||
self.assertIn("scripts/probe-public-voice-sidecars.py", BOOT_REGISTER_SOURCE)
|
||||
|
||||
def test_old_openai_api_is_not_healthy_when_exact_sidecars_are_ready(self) -> None:
|
||||
powershell = shutil.which("powershell.exe")
|
||||
if powershell is None:
|
||||
self.skipTest("Windows PowerShell 5.1 is not available")
|
||||
|
||||
watchdog_contract = WATCHDOG_SOURCE[
|
||||
WATCHDOG_SOURCE.index("function Test-VoiceApiReady") :
|
||||
WATCHDOG_SOURCE.index("function Test-VoiceSidecarStack")
|
||||
].strip()
|
||||
boot_contract = BOOT_SOURCE[
|
||||
BOOT_SOURCE.index("function Test-VoiceApiReady") :
|
||||
BOOT_SOURCE.index("function Test-VoiceApiHealthy")
|
||||
].strip()
|
||||
self.assertEqual(watchdog_contract, boot_contract)
|
||||
|
||||
with tempfile.TemporaryDirectory() as temporary_directory:
|
||||
harness = Path(temporary_directory) / "voice-api-contract.ps1"
|
||||
harness.write_text(
|
||||
watchdog_contract
|
||||
+ r'''
|
||||
$openAi = [pscustomobject]@{
|
||||
status='ok';available=$true;stt_available=$true;tts_available=$true
|
||||
stt_provider='openai';stt_model='gpt-4o-mini-transcribe'
|
||||
tts_provider='openai';tts_model='gpt-4o-mini-tts'
|
||||
limits=[pscustomobject]@{uvicorn_ws_max_queue=4}
|
||||
}
|
||||
if (Test-VoiceApiReady -Health $openAi) { throw 'old OpenAI API was accepted' }
|
||||
$local = [pscustomobject]@{
|
||||
status='ok';available=$true;stt_available=$true;tts_available=$true
|
||||
stt_provider='local_whisper';stt_model='small'
|
||||
tts_provider='melotts';tts_model='melotts-korean'
|
||||
limits=[pscustomobject]@{uvicorn_ws_max_queue=4}
|
||||
}
|
||||
if (-not (Test-VoiceApiReady -Health $local)) { throw 'exact local API was rejected' }
|
||||
$local.limits.uvicorn_ws_max_queue = 5
|
||||
if (Test-VoiceApiReady -Health $local) { throw 'wrong websocket queue was accepted' }
|
||||
''',
|
||||
encoding="utf-8-sig",
|
||||
)
|
||||
completed = subprocess.run(
|
||||
[
|
||||
powershell,
|
||||
"-NoLogo",
|
||||
"-NoProfile",
|
||||
"-NonInteractive",
|
||||
"-ExecutionPolicy",
|
||||
"Bypass",
|
||||
"-File",
|
||||
str(harness),
|
||||
],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
timeout=30,
|
||||
check=False,
|
||||
)
|
||||
self.assertEqual(
|
||||
completed.returncode,
|
||||
0,
|
||||
msg=f"stdout={completed.stdout}\nstderr={completed.stderr}",
|
||||
)
|
||||
|
||||
def test_hidden_trigger_never_executes_a_workspace_script_directly(self) -> None:
|
||||
for expected in (
|
||||
"VignettePublicRuntimeWatchdog",
|
||||
|
|
@ -178,11 +270,13 @@ class PublicRuntimeWatchdogProvenanceTest(unittest.TestCase):
|
|||
copied_boot = scripts / BOOT.name
|
||||
copied_boot_register = scripts / BOOT_REGISTER.name
|
||||
copied_start = scripts / START.name
|
||||
copied_voice_probe = scripts / VOICE_PROBE.name
|
||||
shutil.copy2(WATCHDOG, copied_watchdog)
|
||||
shutil.copy2(INSTALLER, copied_installer)
|
||||
shutil.copy2(BOOT, copied_boot)
|
||||
shutil.copy2(BOOT_REGISTER, copied_boot_register)
|
||||
shutil.copy2(START, copied_start)
|
||||
shutil.copy2(VOICE_PROBE, copied_voice_probe)
|
||||
|
||||
self._git(root, "init")
|
||||
self._git(root, "config", "user.name", "Watchdog Contract Test")
|
||||
|
|
@ -195,6 +289,7 @@ class PublicRuntimeWatchdogProvenanceTest(unittest.TestCase):
|
|||
"scripts/boot-public-runtime.ps1",
|
||||
"scripts/register-boot-task.ps1",
|
||||
"scripts/start-public-runtime.ps1",
|
||||
"scripts/probe-public-voice-sidecars.py",
|
||||
)
|
||||
self._git(root, "commit", "-m", "watchdog fixture")
|
||||
self._git(root, "checkout", "--detach")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue