Skip to content

fix: TestLatencyTrackerPercentiles의 벽시계 의존 단언 수정 #92

Description

@hjbin-25

증상

race-test job에서 internal/mediaTestLatencyTrackerPercentiles가 간헐적으로 실패해요.

--- FAIL: TestLatencyTrackerPercentiles (0.01s)
    egress_latency_test.go:38: expected "p95_ms=9" in log line:
    ... window=0 frames=100 p50_ms=59.947 p95_ms=101.966 min_ms=1.006 max_ms=106.968

최초 관측: run 31464478073 (#90 브랜치). 코드 변경 없이 같은 커밋을 재실행하니 통과해서 비결정성이 확인됐어요. build-and-test(race 미적용)는 통과하고 race-test만 깨져요.

원인

측정값이 주입값이 아니라 벽시계 경과 시간을 포함해요.

egress_latency.go:43

l.samples = append(l.samples, now.Sub(ingestAt))

테스트는 base - 95ms를 주입하지만 실제 기록되는 값은 95ms + (base 캡처 이후 흐른 시간)이에요. 여기에 단언이 부동소수 문자열의 접두어 부분일치라 허용 오차가 비대칭적이고 좁아요.

egress_latency_test.go:34

for _, want := range []string{"p50_ms=5", "p95_ms=9", "min_ms=1", "max_ms=10"}

p95_ms=9는 측정값이 [90, 100)일 때만 통과해요. 주입값이 95이므로 드리프트 5ms에서 100.x가 되며 접두어가 10으로 바뀌어 실패해요.

테스트를 복제해 인위적 지연을 넣고 측정한 임계값:

주입 지연 p50 p95 min max 깨지는 단언
0ms 51.0 96.0 1.0 100.0
2ms 53.2 98.2 3.1 102.1 min_ms=1
4ms 55.6 100.6 5.6 104.6 p95_ms=9, min_ms=1
8ms 61.0 106.0 11.0 110.0 p50_ms=5, p95_ms=9

드리프트 4ms면 깨져요. CI 실측치는 약 7~10ms 드리프트에 해당하고, 이는 공유 러너에서 -race 계측을 켠 채 observe()를 100회 도는 동안의 평범한 스케줄링 지터예요. 유휴 로컬(Apple Silicon)에서는 부하·GOMAXPROCS=1 조건에서도 35회 연속 재현되지 않았어요 — 느린 러너에서만 드러나요.

제안

접두어 문자열 비교를 걷어내고 둘 중 하나로 가요.

  1. 숫자 범위 단언 — 로그 값을 파싱해 95 <= p95 < 95+tolerance 형태로 검사하고 tolerance를 넉넉히(예: 25ms) 잡아요. 테스트 의도(퍼센타일 인덱싱이 맞는지)는 그대로 지키면서 벽시계 지터에 둔감해져요.
  2. 시계 주입latencyTrackernow 함수를 주입받게 해서 테스트에서 결정적으로 만들어요. 더 견고하지만 프로덕션 코드 변경이 필요해요.

1번을 권해요. 프로덕션 코드를 안 건드리고, 이 테스트가 실제로 검증하려는 건 퍼센타일 선택 로직이지 지연 측정 정밀도가 아니에요.

참고

race-test job 이름이 Race test (excluding known flaky)이고 이미 TestBypassWebRTCEndToEnd-skip으로 제외하고 있어요. 이 테스트를 같은 목록에 넣는 건 권하지 않아요 — 커버리지를 잃는 대신 근본 원인이 남아요.

Metadata

Metadata

Assignees

Labels

fix버그 수정

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions