Implemented atomic session replacement.
This commit is contained in:
@@ -20,11 +20,13 @@ const (
|
||||
CommandRemoveAudio
|
||||
CommandEnableSync
|
||||
CommandDisableSync
|
||||
CommandSetSession
|
||||
)
|
||||
|
||||
type SessionCommand struct {
|
||||
Kind SessionCommandKind
|
||||
Config FeedConfig // Used only by SetVideo and SetAudio.
|
||||
Kind SessionCommandKind
|
||||
Config FeedConfig // Used only by SetVideo and SetAudio.
|
||||
Session SessionConfig // Used only by SetSession.
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -99,6 +101,12 @@ func ApplySessionCommand(
|
||||
case CommandDisableSync:
|
||||
next.SyncRequested = false
|
||||
|
||||
case CommandSetSession:
|
||||
next = command.Session
|
||||
// Retry policy belongs to the running controller configuration, not to
|
||||
// GUI or playlist session selections.
|
||||
next.Retry = current.Retry
|
||||
|
||||
default:
|
||||
return current, ErrUnknownSessionCommand
|
||||
}
|
||||
|
||||
@@ -114,6 +114,27 @@ func TestApplySessionCommand(t *testing.T) {
|
||||
command: SessionCommand{Kind: CommandDisableSync},
|
||||
want: func() SessionConfig { c := base; c.SyncRequested = false; return c }(),
|
||||
},
|
||||
{
|
||||
name: "set complete session atomically and preserve retry",
|
||||
current: base,
|
||||
command: SessionCommand{
|
||||
Kind: CommandSetSession,
|
||||
Session: SessionConfig{
|
||||
Video: newVideo,
|
||||
Audio: newAudio,
|
||||
SyncRequested: false,
|
||||
Retry: RetryPolicy{
|
||||
MaxAttempts: 99,
|
||||
},
|
||||
},
|
||||
},
|
||||
want: SessionConfig{
|
||||
Video: newVideo,
|
||||
Audio: newAudio,
|
||||
SyncRequested: false,
|
||||
Retry: base.Retry,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
@@ -157,6 +178,17 @@ func TestApplySessionCommandFailurePreservesState(t *testing.T) {
|
||||
ErrAudioNotConfigured,
|
||||
},
|
||||
{"unknown command", base, SessionCommand{Kind: 255}, ErrUnknownSessionCommand},
|
||||
{
|
||||
"invalid complete session",
|
||||
base,
|
||||
SessionCommand{
|
||||
Kind: CommandSetSession,
|
||||
Session: SessionConfig{
|
||||
Video: FeedConfig{UUID: "video", Active: true},
|
||||
},
|
||||
},
|
||||
ErrFeedDomainRequired,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
||||
@@ -240,6 +240,39 @@ func TestSessionControllerUpdatesOnlyChangedIndependentSlot(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSessionControllerReplacesSynchronizedPairWithOneCommand(t *testing.T) {
|
||||
events := make(chan controllerEvent, 32)
|
||||
controller := newRecordingController(t, events)
|
||||
initial := validCommandSession()
|
||||
commands := make(chan SessionCommand)
|
||||
done := make(chan error, 1)
|
||||
go func() { done <- controller.Run(context.Background(), initial, commands) }()
|
||||
start := receiveControllerEvent(t, events)
|
||||
if start.unit != UnitSync || start.action != "start" {
|
||||
t.Fatalf("initial event = %+v, want sync start", start)
|
||||
}
|
||||
|
||||
next := initial
|
||||
next.Video = FeedConfig{Domain: "/next", UUID: "next-video", Active: true}
|
||||
next.Audio = FeedConfig{Domain: "/next", UUID: "next-audio", Active: true}
|
||||
commands <- SessionCommand{Kind: CommandSetSession, Session: next}
|
||||
event := receiveControllerEvent(t, events)
|
||||
wantPair := SyncPairConfig{Video: next.Video, Audio: next.Audio}
|
||||
if event.unit != UnitSync || event.action != "command" || event.pair != wantPair {
|
||||
t.Fatalf("replacement event = %+v, want one sync command for %#v", event, wantPair)
|
||||
}
|
||||
select {
|
||||
case event := <-events:
|
||||
t.Fatalf("atomic replacement emitted an extra event: %+v", event)
|
||||
case <-time.After(20 * time.Millisecond):
|
||||
}
|
||||
|
||||
close(commands)
|
||||
if err := <-done; err != nil {
|
||||
t.Fatalf("Run() error = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSessionControllerStopsIndependentSlotsBeforeStartingSync(t *testing.T) {
|
||||
events := make(chan controllerEvent, 32)
|
||||
controller := newRecordingController(t, events)
|
||||
|
||||
Reference in New Issue
Block a user