1package stream23import (4 "context"5 "net/http"6 "net/http/httptest"7 "os"8 "path/filepath"9 "testing"10 "time"11)1213// fakeSession adds a session without ffmpeg, last used at used.14func fakeSession(t *testing.T, s *Server, client string, used time.Time) *session {15 t.Helper()16 dir := filepath.Join(t.TempDir(), client)17 if err := os.MkdirAll(dir, 0o755); err != nil {18 t.Fatal(err)19 }20 if err := os.WriteFile(filepath.Join(dir, "stream_0.m3u8"), []byte("#EXTM3U\n"), 0o644); err != nil {21 t.Fatal(err)22 }23 _, cancel := context.WithCancel(context.Background())24 sess := &session{id: client + "-id", client: client, dir: dir, started: used, cancel: cancel, done: make(chan struct{}), stderr: &tail{max: 64}}25 close(sess.done)26 sess.touch(used)27 s.mu.Lock()28 s.sessions[client] = sess29 s.mu.Unlock()30 return sess31}3233// TestIdleStreams: a stream nobody fetches from or touches is stopped once34// idle too long; one fetched from or touched is kept.35func TestIdleStreams(t *testing.T) {36 s := &Server{sessions: map[string]*session{}, idle: time.Minute, quit: make(chan struct{})}37 start := time.Now().Add(-2 * time.Minute)38 gone := fakeSession(t, s, "gone", start)39 fakeSession(t, s, "paused", start)40 fetched := fakeSession(t, s, "watching", start)4142 if !s.Touch("paused") {43 t.Fatal("Touch: no stream for paused")44 }45 rec := httptest.NewRecorder()46 s.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/live/"+fetched.id+"/stream_0.m3u8", nil))47 if rec.Code != http.StatusOK {48 t.Fatalf("playlist: HTTP %d", rec.Code)49 }5051 s.reapIdle(time.Now())52 if s.Touch("gone") {53 t.Error("an idle stream wasn't stopped")54 }55 if _, err := os.Stat(gone.dir); err == nil {56 t.Error("an idle stream's files are left")57 }58 for _, client := range []string{"paused", "watching"} {59 if !s.Touch(client) {60 t.Errorf("%s: stopped though in use", client)61 }62 }6364 // Later, with nothing since, they go too.65 s.reapIdle(time.Now().Add(2 * time.Minute))66 for _, client := range []string{"paused", "watching"} {67 if s.Touch(client) {68 t.Errorf("%s: still there after idling", client)69 }70 }71}