|
| 1 | +package transport |
| 2 | + |
| 3 | +import "testing" |
| 4 | + |
| 5 | +// AI 는 contentType 으로 STT 세션의 디코더를 고른다. RealTime 이 넘기지 않으면 |
| 6 | +// 무엇을 보내든 audio/webm 으로 가정되어 webm 이 아닌 브라우저(Safari=mp4)에서 틀어진다. |
| 7 | +func TestResolveAudioContentType(t *testing.T) { |
| 8 | + cases := []struct { |
| 9 | + name string |
| 10 | + in string |
| 11 | + want string |
| 12 | + }{ |
| 13 | + {"코덱 파라미터를 떼고 base MIME 만", "audio/webm;codecs=opus", "audio/webm"}, |
| 14 | + {"대문자도 정규화", "AUDIO/MP4", "audio/mp4"}, |
| 15 | + {"앞뒤 공백 허용", " audio/ogg ", "audio/ogg"}, |
| 16 | + {"허용 목록의 다른 타입", "audio/mpeg", "audio/mpeg"}, |
| 17 | + {"빈 값이면 기존 동작과 같은 기본값", "", "audio/webm"}, |
| 18 | + {"허용 목록 밖은 기본값", "audio/flac", "audio/webm"}, |
| 19 | + // 사용자 제어 값이므로 임의 문자열이 업스트림 URL 로 새어 나가면 안 된다. |
| 20 | + {"주입 시도도 기본값", "audio/webm&apiKey=leak", "audio/webm"}, |
| 21 | + {"완전히 다른 값", "text/html", "audio/webm"}, |
| 22 | + } |
| 23 | + for _, c := range cases { |
| 24 | + t.Run(c.name, func(t *testing.T) { |
| 25 | + if got := resolveAudioContentType(c.in); got != c.want { |
| 26 | + t.Fatalf("resolveAudioContentType(%q) = %q, want %q", c.in, got, c.want) |
| 27 | + } |
| 28 | + }) |
| 29 | + } |
| 30 | +} |
| 31 | + |
| 32 | +func TestBuildAIStreamURL(t *testing.T) { |
| 33 | + got := buildAIStreamURL("ws://ai:8000/internal/voice/stream", 7, 42, "audio/mp4") |
| 34 | + want := "ws://ai:8000/internal/voice/stream?sessionId=7&messageId=42&contentType=audio%2Fmp4" |
| 35 | + if got != want { |
| 36 | + t.Fatalf("buildAIStreamURL = %q, want %q", got, want) |
| 37 | + } |
| 38 | +} |
| 39 | + |
| 40 | +// 슬래시가 이스케이프되지 않으면 AI 쪽 쿼리 파싱이 어긋난다. |
| 41 | +func TestBuildAIStreamURLEscapesContentType(t *testing.T) { |
| 42 | + got := buildAIStreamURL("ws://ai:8000/s", 1, 2, "audio/webm") |
| 43 | + if want := "contentType=audio%2Fwebm"; !contains(got, want) { |
| 44 | + t.Fatalf("expected %q in %q", want, got) |
| 45 | + } |
| 46 | +} |
| 47 | + |
| 48 | +func contains(s, sub string) bool { |
| 49 | + return len(s) >= len(sub) && (func() bool { |
| 50 | + for i := 0; i+len(sub) <= len(s); i++ { |
| 51 | + if s[i:i+len(sub)] == sub { |
| 52 | + return true |
| 53 | + } |
| 54 | + } |
| 55 | + return false |
| 56 | + })() |
| 57 | +} |
0 commit comments