199 lines
6.3 KiB
Text
199 lines
6.3 KiB
Text
<!-- task=ts_kotlin_wss_crosstest plan=0 tag=TEST -->
|
||
|
||
# TypeScript→Kotlin 크로스테스트 WSS 페이즈 추가
|
||
|
||
## 이 파일을 읽는 구현 에이전트에게
|
||
|
||
각 체크리스트 항목을 완료 후 `[x]`로 체크하고, 중간 검증과 최종 검증 명령을 실제로 실행한 뒤 출력을 `CODE_REVIEW.md`의 `검증 결과` 섹션에 붙여넣으세요. 계획과 다르게 구현한 부분이 있으면 `계획 대비 변경 사항`에 이유와 함께 기록하세요.
|
||
|
||
## 배경
|
||
|
||
크로스테스트 매트릭스 점검 결과, `typescript/crosstest/typescript_kotlin.ts`(TypeScript 서버 × Kotlin 클라이언트)에 WSS 페이즈가 누락된 것이 확인됐다. 동일 파일의 TLS/TCP 페이즈는 구현돼 있고, Kotlin 클라이언트 측(`kotlin/crosstest/typescript_kotlin_client.kt` 100-103줄)은 `wss` 모드를 이미 완전히 지원한다. 같은 매트릭스의 `typescript_dart.ts`·`typescript_go.ts`·`typescript_python.ts`는 모두 WSS 페이즈를 포함한다. TypeScript 오케스트레이터 파일 한 곳에만 추가하면 갭이 해소된다.
|
||
|
||
---
|
||
|
||
## [TEST-1] typescript_kotlin.ts에 WSS 페이즈 추가
|
||
|
||
### 문제
|
||
|
||
`typescript/crosstest/typescript_kotlin.ts`
|
||
- 29줄: `TLS_TCP_PORT = 29814` 다음에 `WSS_PORT` 상수가 없다.
|
||
- 37-48줄: `main()`이 `runTcp()`, `runWs()`, `runTls()`만 호출하고 `runWss()`를 호출하지 않는다.
|
||
- `runWss()`, `runWssSendPush()`, `runWssRequests()` 함수가 존재하지 않는다.
|
||
|
||
### 해결 방법
|
||
|
||
`typescript_dart.ts`와 `typescript_go.ts`의 WSS 패턴을 그대로 적용한다. 변경은 `typescript_kotlin.ts` 한 파일만이다.
|
||
|
||
**1) WSS_PORT 상수 추가 — 29~30줄 사이**
|
||
|
||
Before (29-30줄):
|
||
```ts
|
||
const TLS_TCP_PORT = 29814;
|
||
const WS_PATH = "/";
|
||
```
|
||
|
||
After:
|
||
```ts
|
||
const TLS_TCP_PORT = 29814;
|
||
const WSS_PORT = 29816;
|
||
const WS_PATH = "/";
|
||
```
|
||
|
||
포트 29816은 `typescript_python.ts`의 `WS_PORT`와 번호가 같지만, 두 스위트는 동시에 실행되지 않으므로 기존 크로스테스트 관행과 동일하다.
|
||
|
||
**2) main()에 runWss() 호출 추가 — 42줄 다음**
|
||
|
||
Before (37-48줄):
|
||
```ts
|
||
async function main(): Promise<void> {
|
||
console.log(`INFO typeName ts=${TestDataSchema.typeName}`);
|
||
try {
|
||
await runTcp();
|
||
await runWs();
|
||
await runTls();
|
||
console.log("PASS all typescript-server/kotlin-client crosstests passed");
|
||
} catch (err) {
|
||
console.error(`FAIL crosstest error=${errorMessage(err)}`);
|
||
process.exitCode = 1;
|
||
}
|
||
}
|
||
```
|
||
|
||
After:
|
||
```ts
|
||
async function main(): Promise<void> {
|
||
console.log(`INFO typeName ts=${TestDataSchema.typeName}`);
|
||
try {
|
||
await runTcp();
|
||
await runWs();
|
||
await runTls();
|
||
await sleep(150);
|
||
await runWss();
|
||
console.log("PASS all typescript-server/kotlin-client crosstests passed");
|
||
} catch (err) {
|
||
console.error(`FAIL crosstest error=${errorMessage(err)}`);
|
||
process.exitCode = 1;
|
||
}
|
||
}
|
||
```
|
||
|
||
**3) runWss(), runWssSendPush(), runWssRequests() 추가 — 214줄(runTlsTcpRequests 끝) 바로 뒤에 삽입**
|
||
|
||
```ts
|
||
async function runWss(): Promise<void> {
|
||
await runWssSendPush();
|
||
await sleep(150);
|
||
await runWssRequests();
|
||
}
|
||
|
||
async function runWssSendPush(): Promise<void> {
|
||
let resolveReceived: ((value: boolean) => void) | null = null;
|
||
const received = new Promise<boolean>((resolve) => {
|
||
resolveReceived = resolve;
|
||
});
|
||
const server = new WsServer(
|
||
HOST,
|
||
WSS_PORT,
|
||
WS_PATH,
|
||
(ws) => new WsClient(ws, 0, 0, parserMap()),
|
||
serverTlsOptions(),
|
||
);
|
||
server.onClientConnected = (client) => {
|
||
addListenerTyped(client.communicator, TestDataSchema, (data) => {
|
||
console.log(`SERVER_RECEIVED index=${data.index} message=${data.message}`);
|
||
const valid = data.index === 101 && data.message === "fire from kotlin client";
|
||
if (resolveReceived !== null) {
|
||
resolveReceived(valid);
|
||
resolveReceived = null;
|
||
}
|
||
if (valid) {
|
||
void client.communicator.send(
|
||
create(TestDataSchema, {
|
||
index: 200,
|
||
message: "push from typescript server",
|
||
}),
|
||
);
|
||
}
|
||
});
|
||
};
|
||
await withServer(server, async () => {
|
||
await runKotlinClient("wss", WSS_PORT, "send-push", new Set(["1", "2"]), CERT_PATH);
|
||
const ok = await withTimeout(received, SERVER_OBSERVATION_MS, "WSS send-push server did not receive expected data");
|
||
if (!ok) {
|
||
throw new Error("WSS send-push server received unexpected data");
|
||
}
|
||
});
|
||
}
|
||
|
||
async function runWssRequests(): Promise<void> {
|
||
const server = new WsServer(
|
||
HOST,
|
||
WSS_PORT,
|
||
WS_PATH,
|
||
(ws) => new WsClient(ws, 0, 0, parserMap()),
|
||
serverTlsOptions(),
|
||
);
|
||
server.onClientConnected = (client) => {
|
||
addRequestListenerTyped(client.communicator, TestDataSchema, (req) =>
|
||
create(TestDataSchema, {
|
||
index: req.index * 2,
|
||
message: `echo: ${req.message}`,
|
||
}),
|
||
);
|
||
};
|
||
await withServer(server, () =>
|
||
runKotlinClient("wss", WSS_PORT, "requests", new Set(["3", "4"]), CERT_PATH),
|
||
);
|
||
}
|
||
```
|
||
|
||
### 수정 파일 및 체크리스트
|
||
|
||
- [x] `typescript/crosstest/typescript_kotlin.ts`
|
||
- [x] 29줄 다음에 `const WSS_PORT = 29816;` 추가
|
||
- [x] `main()` 안 `await runTls();` 다음에 `await sleep(150); await runWss();` 추가
|
||
- [x] `runTlsTcpRequests()` 끝(214줄) 다음에 `runWss()`, `runWssSendPush()`, `runWssRequests()` 삽입
|
||
|
||
### 테스트 작성
|
||
|
||
별도 테스트 파일을 작성하지 않는다. 이번 변경 자체가 크로스테스트 케이스 추가이며, `runWssSendPush()`와 `runWssRequests()`가 시나리오 1-4를 WSS 전송으로 검증한다.
|
||
|
||
### 중간 검증
|
||
|
||
TypeScript 타입 검사만으로 컴파일 오류 없음을 확인한다:
|
||
|
||
```bash
|
||
cd typescript && npx tsc --noEmit
|
||
```
|
||
|
||
기대 결과: 출력 없이 종료 코드 0.
|
||
|
||
---
|
||
|
||
## 수정 파일 요약
|
||
|
||
| 파일 | 항목 |
|
||
|------|------|
|
||
| `typescript/crosstest/typescript_kotlin.ts` | TEST-1 |
|
||
|
||
---
|
||
|
||
## 최종 검증
|
||
|
||
Kotlin 빌드 환경(JDK + Gradle)이 필요하다. 환경이 없으면 타입 검사(`tsc --noEmit`)만 실행하고 검증 결과에 환경 미비 사유를 명시한다.
|
||
|
||
```bash
|
||
cd typescript && npx tsx crosstest/typescript_kotlin.ts
|
||
```
|
||
|
||
기대 결과:
|
||
```
|
||
INFO typeName ts=TestData
|
||
PASS scenario=1 ...
|
||
PASS scenario=2 ...
|
||
PASS scenario=3 ...
|
||
PASS scenario=4 ...
|
||
... (TCP / WS / TLS / WSS 각 페이즈 반복)
|
||
PASS all typescript-server/kotlin-client crosstests passed
|
||
```
|