package transcoding import ( "bytes" "context" "os/exec" "path/filepath" "testing" "time" ) func genTestFile(t *testing.T, dir string) string { t.Helper() if _, err := exec.LookPath("ffmpeg"); err != nil { t.Skip("ffmpeg not installed") } out := filepath.Join(dir, "src.mp3") ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() cmd := exec.CommandContext(ctx, "ffmpeg", "-f", "lavfi", "-i", "sine=frequency=440:duration=2", "-codec:a", "libmp3lame", out) if combined, err := cmd.CombinedOutput(); err != nil { t.Fatalf("ffmpeg: %v\n%s", err, combined) } return out } func TestStreamProducesOutput(t *testing.T) { dir := t.TempDir() src := genTestFile(t, dir) m := NewManager("") var buf bytes.Buffer ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() if err := m.Stream(ctx, &buf, src, Options{Format: FormatMP3, MaxBitRateKbps: 64}); err != nil { t.Fatalf("Stream: %v", err) } if buf.Len() == 0 { t.Fatal("transcoded output is empty") } } func TestStreamRespectsContextCancellation(t *testing.T) { dir := t.TempDir() src := genTestFile(t, dir) m := NewManager("") ctx, cancel := context.WithCancel(context.Background()) cancel() // already cancelled before starting var buf bytes.Buffer err := m.Stream(ctx, &buf, src, Options{Format: FormatMP3}) if err == nil { t.Fatal("expected an error when the context is already cancelled") } } func TestParseFormat(t *testing.T) { cases := map[string]Format{ "mp3": FormatMP3, "opus": FormatOpus, "aac": FormatAAC, "unknown": FormatMP3, "": FormatMP3, } for in, want := range cases { if got := ParseFormat(in); got != want { t.Errorf("ParseFormat(%q) = %q, want %q", in, got, want) } } } func TestBuildHLS(t *testing.T) { dir := t.TempDir() src := genTestFile(t, dir) m := NewManager("") ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) defer cancel() session, err := m.BuildHLS(ctx, src, filepath.Join(dir, "cache"), Options{Format: FormatAAC, MaxBitRateKbps: 96}) if err != nil { t.Fatalf("BuildHLS: %v", err) } if session.SegmentCount == 0 { t.Fatal("expected at least one HLS segment") } playlist := session.Playlist(func(i int) string { return "seg" + string(rune('0'+i)) }) if playlist == "" { t.Fatal("empty playlist") } if session.SegmentPath(0) == "" { t.Fatal("SegmentPath(0) should resolve") } if session.SegmentPath(9999) != "" { t.Fatal("SegmentPath out of range should return empty") } }