package main import ( "testing" "time" "mxl-player/internal/playback" ) func TestAppArgsPlaybackConfig(t *testing.T) { tests := []struct { name string args appArgs wantVideoDomain string wantAudioDomain string wantVideoActive bool wantAudioActive bool wantSyncRequested bool wantMaxAttempts int }{ { name: "shared domain applies to both feeds", args: appArgs{ Domain: "/dev/shm/mxl", VideoFlowId: "video-uuid", AudioFlowId: "audio-uuid", }, wantVideoDomain: "/dev/shm/mxl", wantAudioDomain: "/dev/shm/mxl", wantVideoActive: true, wantAudioActive: true, }, { name: "video domain overrides shared domain", args: appArgs{ Domain: "/dev/shm/default", VideoDomain: "/dev/shm/video", VideoFlowId: "video-uuid", AudioFlowId: "audio-uuid", }, wantVideoDomain: "/dev/shm/video", wantAudioDomain: "/dev/shm/default", wantVideoActive: true, wantAudioActive: true, }, { name: "audio domain overrides shared domain", args: appArgs{ Domain: "/dev/shm/default", AudioDomain: "/dev/shm/audio", VideoFlowId: "video-uuid", AudioFlowId: "audio-uuid", }, wantVideoDomain: "/dev/shm/default", wantAudioDomain: "/dev/shm/audio", wantVideoActive: true, wantAudioActive: true, }, { name: "audio and video use different domain overrides", args: appArgs{ Domain: "/dev/shm/default", VideoDomain: "/dev/shm/video", AudioDomain: "/dev/shm/audio", VideoFlowId: "video-uuid", AudioFlowId: "audio-uuid", SyncRequested: true, MaxAttempts: 5, }, wantVideoDomain: "/dev/shm/video", wantAudioDomain: "/dev/shm/audio", wantVideoActive: true, wantAudioActive: true, wantSyncRequested: true, wantMaxAttempts: 5, }, { name: "no UUIDs produce inactive slots", args: appArgs{ Domain: "/dev/shm/mxl", }, wantVideoDomain: "/dev/shm/mxl", wantAudioDomain: "/dev/shm/mxl", }, { name: "video UUID activates only video", args: appArgs{ Domain: "/dev/shm/mxl", VideoFlowId: "video-uuid", }, wantVideoDomain: "/dev/shm/mxl", wantAudioDomain: "/dev/shm/mxl", wantVideoActive: true, }, { name: "audio UUID activates only audio", args: appArgs{ Domain: "/dev/shm/mxl", AudioFlowId: "audio-uuid", }, wantVideoDomain: "/dev/shm/mxl", wantAudioDomain: "/dev/shm/mxl", wantAudioActive: true, }, { name: "unlimited attempts and disabled sync are preserved", args: appArgs{ Domain: "/dev/shm/mxl", VideoFlowId: "video-uuid", SyncRequested: false, MaxAttempts: 0, }, wantVideoDomain: "/dev/shm/mxl", wantAudioDomain: "/dev/shm/mxl", wantVideoActive: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := tt.args.playbackConfig() if got.Video.Domain != tt.wantVideoDomain { t.Errorf("video domain = %q, want %q", got.Video.Domain, tt.wantVideoDomain) } if got.Audio.Domain != tt.wantAudioDomain { t.Errorf("audio domain = %q, want %q", got.Audio.Domain, tt.wantAudioDomain) } if got.Video.Active != tt.wantVideoActive { t.Errorf("video active = %t, want %t", got.Video.Active, tt.wantVideoActive) } if got.Audio.Active != tt.wantAudioActive { t.Errorf("audio active = %t, want %t", got.Audio.Active, tt.wantAudioActive) } if got.SyncRequested != tt.wantSyncRequested { t.Errorf("sync requested = %t, want %t", got.SyncRequested, tt.wantSyncRequested) } if got.Retry.MaxAttempts != tt.wantMaxAttempts { t.Errorf("max attempts = %d, want %d", got.Retry.MaxAttempts, tt.wantMaxAttempts) } if err := got.Validate(); err != nil { t.Fatalf("playbackConfig().Validate() returned error: %v", err) } }) } } func TestResolveRetryPolicy(t *testing.T) { cli := playback.RetryPolicy{ MaxAttempts: 0, InitialDelay: time.Second, MaxDelay: 5 * time.Second, } fileRetry := playback.RetryPolicy{ MaxAttempts: 4, InitialDelay: 250 * time.Millisecond, MaxDelay: 2 * time.Second, } tests := []struct { name string playlist playback.Playlist cliMaxAttemptsSet bool want playback.RetryPolicy }{ {name: "no playlist retry uses CLI", want: cli}, { name: "playlist retry is used by default", playlist: playback.Playlist{Retry: &fileRetry}, want: fileRetry, }, { name: "explicit CLI infinite overrides playlist attempts", playlist: playback.Playlist{Retry: &fileRetry}, cliMaxAttemptsSet: true, want: playback.RetryPolicy{ MaxAttempts: 0, InitialDelay: fileRetry.InitialDelay, MaxDelay: fileRetry.MaxDelay, }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { if got := resolveRetryPolicy(cli, test.cliMaxAttemptsSet, test.playlist); got != test.want { t.Fatalf("resolveRetryPolicy() = %#v, want %#v", got, test.want) } }) } } func TestNormalizeFeedInput(t *testing.T) { domain, uuid := normalizeFeedInput( " \t/dev/shm/mxl\n", "\r 5fbec3b1-1b0f-417d-9059-8b94a47197ef \t", ) if domain != "/dev/shm/mxl" { t.Fatalf("domain = %q", domain) } if uuid != "5fbec3b1-1b0f-417d-9059-8b94a47197ef" { t.Fatalf("UUID = %q", uuid) } }