feat: harden isolated Tornado test workflow
This commit is contained in:
@@ -115,12 +115,12 @@ MBN_STOCK_PLAYOUT_RECONNECT_ENABLED
|
||||
`Test` 전환 전 다음 조건을 모두 사람이 확인합니다.
|
||||
|
||||
1. Tornado 인스턴스가 현재 PGM과 물리적·논리적으로 분리되어 있고 Test의 `host`가 로컬 loopback IP literal(`127.0.0.1` 또는 `::1`)입니다. `localhost`를 포함한 호스트 이름은 허용하지 않습니다.
|
||||
2. `testProcessWindowTitlePattern`이 전용 테스트 인스턴스 하나만 식별합니다.
|
||||
2. 전용 테스트 창 제목에 독립된 `TEST` 토큰(예: `Tornado2 TEST`)이 있고 `testProcessWindowTitlePattern`이 그 인스턴스 하나만 식별합니다. 빈 제목이나 일반 `Tornado2` 제목은 허용하지 않습니다.
|
||||
3. `outputChannel`이 라우터/엔진에서 테스트 출력임을 확인했습니다.
|
||||
4. `sceneDirectory`가 승인된 테스트 자산 루트이고 사용할 scene name이 `testSceneAllowlist`에 있으며 운영 씬이 아닙니다.
|
||||
5. 같은 플레이리스트로 `DryRun`의 `PREPARE`, `TAKE IN`, `NEXT`, `TAKE OUT` 메시지와 화면 상태를 먼저 확인했습니다.
|
||||
|
||||
프로세스 감시는 이름이 `Tornado2`로 시작하는 모든 프로세스를 대소문자 구분 없이 찾습니다. 이는 가용성 신호일 뿐 송출 권한이 아닙니다. Test에서는 Tornado2 프로세스가 정확히 하나이고 그 창 제목이 테스트 규칙에만 일치해야 하며, `PGM`/`PROGRAM` 창이 하나라도 있거나 여러 인스턴스가 모호하면 COM을 활성화하지 않습니다. 즉 현재 방송 PGM이 실행 중인 장비에서는 Test 연결을 거부합니다.
|
||||
프로세스 감시는 이름이 `Tornado2`로 시작하는 모든 프로세스를 대소문자 구분 없이 찾습니다. 이는 가용성 신호일 뿐 송출 권한이 아닙니다. Test에서는 Tornado2 프로세스가 정확히 하나이고 그 창 제목이 독립된 `TEST` 토큰과 설정 규칙에 모두 일치해야 합니다. `PGM`/`PROGRAM`, 빈 제목, 일반 `Tornado2` 제목, TEST 표식 없는 제목 또는 여러 인스턴스가 모호하면 COM을 활성화하지 않습니다. 즉 현재 방송 PGM이 실행 중인 장비에서는 창 제목이 순간적으로 바뀌더라도 Test 연결을 거부합니다.
|
||||
|
||||
Test에서 로컬 프로세스/창 제목 검사를 원격 KTAP endpoint의 신원 증명으로 사용하지 않습니다. 따라서 Test 모드는 loopback endpoint만 허용하며, 원격 host는 아래의 Live 이중 승인을 모두 통과한 경우에만 사용할 수 있습니다.
|
||||
|
||||
@@ -145,10 +145,63 @@ dotnet run --project .\tools\MBN_STOCK_WEBVIEW.PlayoutSmoke `
|
||||
-c Debug -p:Platform=x64 -- --dry-run
|
||||
dotnet test .\MBN_STOCK_WEBVIEW.sln -c Debug -p:Platform=x64
|
||||
dotnet test .\MBN_STOCK_WEBVIEW.sln -c Release -p:Platform=x64
|
||||
powershell -NoProfile -ExecutionPolicy Bypass `
|
||||
-File .\scripts\Test-WebPlayout.ps1
|
||||
```
|
||||
|
||||
`PlayoutSmoke --probe`의 기본 출력은 등록 준비 여부·issue 이름, Tornado2 프로세스 수와 PROGRAM 감지 여부만 제공합니다. 벤더 DLL 전체 경로, 프로세스 ID/이름 및 창 제목은 출력하거나 로그에 남기지 않습니다. 정확한 로컬 등록 경로가 필요한 관리자는 `Inspect-K3DRegistration.ps1` 결과를 해당 장비에서만 확인하고 지원 첨부파일에 포함하지 않습니다.
|
||||
|
||||
### 격리 Test 단계별 CLI
|
||||
|
||||
실제 Test 검증은 아래 세 단계를 순서대로 사용합니다. 세 명령 모두 절대 경로의 일반 로컬 JSON 파일과 `--acknowledge-isolated-non-program-test-output` 승인이 필요합니다. `MBN_STOCK_PLAYOUT_*` 환경 변수가 하나라도 존재하면 파일과 환경의 합성 결과가 달라지는 것을 막기 위해 엔진 생성 전에 거부합니다. JSON은 반드시 `mode: "Test"`, `trustedLiveOutputEnabled: false`여야 하며 기존 Test 안전 게이트를 그대로 통과해야 합니다.
|
||||
|
||||
먼저 씬 파일과 설정만 검사합니다. 이 단계는 엔진·STA·COM을 생성하지 않으며 실행 중 프로세스의 적격성도 아직 판단하지 않습니다. 승인된 Test 씬 후보인 `5001.t2s`와 `5006.t2s`를 사용할 때 로컬 JSON의 외부 `sceneDirectory` 및 `testSceneAllowlist`에는 각각 basename `5001`, `5006`을 설정합니다. 실제 절대 경로는 로컬 JSON에만 두고 저장소 문서나 예제 설정에 기록하지 않습니다.
|
||||
|
||||
```powershell
|
||||
$config = [IO.Path]::GetFullPath(
|
||||
"$env:LOCALAPPDATA\MBN_STOCK_WEBVIEW\Config\playout.test.local.json")
|
||||
|
||||
dotnet run --project .\tools\MBN_STOCK_WEBVIEW.PlayoutSmoke `
|
||||
-c Debug -p:Platform=x64 -- `
|
||||
--test-plan `
|
||||
--acknowledge-isolated-non-program-test-output `
|
||||
--config $config `
|
||||
--prepare 5001 `
|
||||
--next 5006 `
|
||||
--observe-ms 5000
|
||||
```
|
||||
|
||||
별도 Test Tornado만 정확히 하나 실행되고 PGM/PROGRAM 창이 전혀 없는 것을 사람이 다시 확인한 뒤 연결만 검증합니다. 이 명령은 씬이나 출력 상태를 변경하지 않고 `Connect → Disconnect`만 요청합니다.
|
||||
|
||||
```powershell
|
||||
dotnet run --project .\tools\MBN_STOCK_WEBVIEW.PlayoutSmoke `
|
||||
-c Debug -p:Platform=x64 -- `
|
||||
--test-connect `
|
||||
--acknowledge-isolated-non-program-test-output `
|
||||
--config $config
|
||||
```
|
||||
|
||||
마지막으로 격리된 Test 모니터를 관찰하면서 실제 시퀀스를 실행합니다. `--observe-ms`는 `TAKE IN` 뒤와 `NEXT` 뒤에 각각 적용되는 필수 관찰 시간이며 1,000~30,000ms만 허용합니다.
|
||||
|
||||
```powershell
|
||||
dotnet run --project .\tools\MBN_STOCK_WEBVIEW.PlayoutSmoke `
|
||||
-c Debug -p:Platform=x64 -- `
|
||||
--test-sequence `
|
||||
--acknowledge-isolated-non-program-test-output `
|
||||
--config $config `
|
||||
--prepare 5001 `
|
||||
--next 5006 `
|
||||
--observe-ms 5000
|
||||
```
|
||||
|
||||
시퀀스는 `Connect → Prepare(5001) → TakeIn → 관찰 → Next(5006) → 관찰 → TakeOut(All) → Disconnect` 순서입니다. 자동 재연결은 CLI가 강제로 비활성화합니다. 성공한 `TakeIn` 뒤 관찰 취소처럼 결과가 확정된 중단이면 `TakeOut(All)`을 한 번만 정리 단계로 요청한 뒤, 정리가 성공한 경우에만 `Disconnect`합니다. 이미 실행 결과가 불명확하거나 `TakeOut`이 어떤 비성공 결과라도 반환하면 출력이 남아 있을 수 있으므로 추가 출력 명령과 SDK `Disconnect`를 보내지 않습니다. 이때 `QuarantineAsync`가 같은 STA에서 제어 메서드 호출 없이 로컬 COM 참조만 해제한 다음 bounded 어댑터 폐기를 수행합니다. quarantine 자체를 완료하지 못하면 의도하지 않은 Disconnect보다 로컬 누수를 택해 일반 Dispose도 생략합니다. 어느 경우든 격리 모니터에서 최종 Test 출력 상태를 사람이 확인해야 합니다.
|
||||
|
||||
JSON 결과는 단계별 operation/result code와 `connectRequestIssued`, nullable `comActivationAttempted`, `outputMayBeActive`, quarantine 시도·완료 여부를 제공합니다. `comActivationAttempted`의 `false`는 시도하지 않았음, `true`는 시도했음, `null`은 COM 활성화 시도 여부를 확정할 수 없음을 뜻합니다. `outputMayBeActive: true`이면 자동 정리를 성공으로 확인하지 못했으므로 사람이 격리 출력을 확인해야 합니다. 특히 `Unavailable`, 취소, timeout은 연결 전 거부와 연결 도중 안전 게이트 변화가 같은 결과 code가 될 수 있으므로 추측하지 않고 `null`로 보고합니다. 로컬 경로, 씬 code, PID, 창 제목, HRESULT 및 엔진 원문 오류는 출력하지 않습니다. `--test-plan`의 `runtimeProcessGateChecked: false`는 자산 계획만 검증했다는 뜻이며 실제 연결 가능성을 증명하지 않습니다.
|
||||
|
||||
현재 장비처럼 PGM Tornado가 실행 중이거나 loopback 포트를 PGM이 소유한 상태에서는 `--test-connect`와 `--test-sequence`를 실행하지 않습니다. 기존 Test 엔진도 exactly-one Tornado2, non-PGM 제목 정규식, loopback literal, Test outputChannel, 외부 non-reparse scene root와 allowlist를 연결 전 및 각 명령 전에 재검사합니다.
|
||||
|
||||
CLI용 Test JSON은 위처럼 앱 기본 경로인 `playout.local.json`과 다른 파일명을 사용합니다. 기본 경로에 Test 설정을 두면 일반 앱 시작 시 자동 연결을 요청할 수 있으므로, 운영자가 의도적으로 앱 UI Test 모드를 검증하는 회차 외에는 사용하지 않습니다.
|
||||
|
||||
앱을 실행한 뒤 다음을 확인합니다.
|
||||
|
||||
1. 시작 상태가 `DRY RUN`으로 보이고 앱이 COM 또는 Tornado 없이 종료되지 않습니다.
|
||||
@@ -156,6 +209,12 @@ dotnet test .\MBN_STOCK_WEBVIEW.sln -c Release -p:Platform=x64
|
||||
3. 잘못된 설정 또는 엔진 부재가 앱 종료가 아니라 연결 상태와 안전한 오류 메시지로 표시됩니다.
|
||||
4. x64 MSIX를 설치해도 같은 dry-run 흐름이 동작합니다.
|
||||
|
||||
WebView 상태 wire는 `Disconnected`, `Connecting`, `Connected`, `Reconnecting`, `Faulted`, `OutcomeUnknown` 등 native connection state를 별도로 전달합니다. `OutcomeUnknown`과 timeout은 `retryable: false`이며 오류 창을 닫아도 native 잠금은 앱 재시작 전까지 유지됩니다. 브라우저 응답 제한 시간은 고정 15초가 아니라 검증된 native operation timeout에 5초 전달 여유를 더해 사용하고, native 명령이 끝나면 상관 응답을 놓친 경우에도 authoritative status를 다시 게시합니다. NEXT는 원본의 `m_TakeIn` 조건처럼 on-air 장면이 있을 때만 native와 Web 양쪽에서 허용됩니다. Test on-air 배지는 실제 PROGRAM과 구분해 `TEST ON AIR`로 표시합니다.
|
||||
|
||||
On-air 표식이 남은 상태에서는 프로세스 감시, 연결 해제, 앱 종료 및 세션 재활용 경로도 SDK `Disconnect`를 호출하지 않습니다. 중앙 `ReleaseSessionAsync` 방어가 세션을 quarantine/abandon하고 결과를 불명확 상태로 승격하므로, 운영자는 먼저 성공한 `TAKE OUT`을 확인한 다음 정상 종료해야 합니다.
|
||||
|
||||
승인 컷의 load/play 경로와 원본 Scene/PageN 데이터 표현력은 서로 다른 검증 범위입니다. 현재 지원 범위와 아직 포팅되지 않은 복합 mutation·페이지 갱신은 [원본 Tornado 송출 흐름 분석](LEGACY_PLAYOUT_ANALYSIS.md)을 기준으로 판단합니다.
|
||||
|
||||
실제 COM 스모크는 별도 테스트 인스턴스와 테스트 씬이 준비된 때에만 진행합니다. 위 안전 게이트를 독립적으로 재확인하고 `mode`를 `Test`로 바꾼 뒤 테스트 모니터에서 `PREPARE → TAKE IN → NEXT → TAKE OUT` 결과를 관찰합니다. PGM/운영 출력에 변화가 보이면 즉시 앱을 종료하고 롤백합니다. 명령 timeout 뒤 결과가 불명확하면 명령을 자동 또는 수동으로 반복하지 말고 테스트 출력 상태를 먼저 확인합니다.
|
||||
|
||||
패키지 스모크에서는 벤더 x64 COM이 장비에 정식 등록되어 있어야 합니다. MSIX에 벤더 DLL을 복사해 활성화 오류를 우회하지 않습니다. 패키지 컨텍스트에서 COM 활성화가 막히면 `DryRun` 또는 `Disabled`를 유지하고 HRESULT와 등록 검사 결과만 보고합니다.
|
||||
|
||||
Reference in New Issue
Block a user