forked from Manuel/meeting-assistant
fix: prevent profile-switch transcription deadlock
This commit is contained in:
@@ -2386,12 +2386,17 @@ public sealed class RecordingCoordinatorTests
|
||||
await coordinator.StopAsync(CancellationToken.None);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ToggleToDifferentLaunchProfileBuffersAudioCapturedWhilePreviousPipelineDrains()
|
||||
[Theory]
|
||||
[InlineData("default", "english")]
|
||||
[InlineData("english", "default")]
|
||||
public async Task ProfileSwitchDrainsFinalTranscriptAndResumesBufferedAudioWithoutBlockingNotifications(
|
||||
string initialProfile,
|
||||
string targetProfile)
|
||||
{
|
||||
var audioSource = new ControlledAudioSource();
|
||||
var pipelineFactory = new BlockingProfileSwitchSpeechRecognitionPipelineFactory();
|
||||
var transcriptStore = new InMemoryTranscriptStore();
|
||||
var promptService = new IgnoringMeetingInactivityPromptService();
|
||||
var launchProfiles = CreateLaunchProfiles(
|
||||
Path.Combine(Path.GetTempPath(), "meeting-assistant-tests", Guid.NewGuid().ToString("N"), "default"),
|
||||
Path.Combine(Path.GetTempPath(), "meeting-assistant-tests", Guid.NewGuid().ToString("N"), "english"));
|
||||
@@ -2406,13 +2411,16 @@ public sealed class RecordingCoordinatorTests
|
||||
new CapturingMeetingSummaryPipeline(),
|
||||
Options.Create(launchProfiles.GetRequiredProfile(null).Options),
|
||||
NullLogger<MeetingRecordingCoordinator>.Instance,
|
||||
inactivityPromptService: promptService,
|
||||
launchProfiles: launchProfiles);
|
||||
|
||||
await coordinator.StartAsync(CancellationToken.None);
|
||||
await coordinator.StartAsync(initialProfile, CancellationToken.None);
|
||||
await audioSource.WriteAsync(new AudioChunk([1, 0], 16000, 1), CancellationToken.None);
|
||||
await transcriptStore.WaitForTextAsync("default chunk:2");
|
||||
await transcriptStore.WaitForTextAsync($"{initialProfile} chunk:2");
|
||||
await WaitUntilAsync(() => promptService.DismissAllCount == 1);
|
||||
|
||||
var switchTask = coordinator.ToggleAsync("english", CancellationToken.None);
|
||||
using var switchCancellation = new CancellationTokenSource(TimeSpan.FromSeconds(10));
|
||||
var switchTask = coordinator.ToggleAsync(targetProfile, switchCancellation.Token);
|
||||
await pipelineFactory.WaitUntilFirstPipelineDrainIsBlockedAsync();
|
||||
await audioSource.WriteAsync(new AudioChunk([1, 0, 2, 0, 3, 0], 16000, 1), CancellationToken.None);
|
||||
|
||||
@@ -2420,10 +2428,21 @@ public sealed class RecordingCoordinatorTests
|
||||
|
||||
pipelineFactory.ReleaseFirstPipelineDrain();
|
||||
await switchTask.WaitAsync(TimeSpan.FromSeconds(5));
|
||||
await transcriptStore.WaitForTextAsync("english chunk:6");
|
||||
await transcriptStore.WaitForTextAsync($"{targetProfile} chunk:6");
|
||||
await WaitUntilAsync(() => promptService.DismissAllCount == 3);
|
||||
|
||||
Assert.Equal([null, "english"], pipelineFactory.ProfileNames);
|
||||
await coordinator.StopAsync(CancellationToken.None);
|
||||
Assert.Equal(targetProfile, coordinator.CurrentStatus.LaunchProfile);
|
||||
Assert.Equal([initialProfile, targetProfile], pipelineFactory.ProfileNames);
|
||||
var segments = transcriptStore.Segments.ToList();
|
||||
var finalResultIndex = segments.FindIndex(segment => segment.Text == "Final result emitted while switching profiles.");
|
||||
var markerIndex = segments.FindIndex(segment => segment.Text.Contains($"Transcription profile changed to {targetProfile}", StringComparison.Ordinal));
|
||||
Assert.True(finalResultIndex >= 0 && finalResultIndex < markerIndex);
|
||||
|
||||
await coordinator.ToggleAsync(initialProfile, CancellationToken.None).WaitAsync(TimeSpan.FromSeconds(5));
|
||||
await audioSource.WriteAsync(new AudioChunk([1, 0, 2, 0], 16000, 1), CancellationToken.None);
|
||||
await transcriptStore.WaitForTextAsync($"{initialProfile} chunk:4");
|
||||
await coordinator.StopAsync(CancellationToken.None).WaitAsync(TimeSpan.FromSeconds(5));
|
||||
Assert.False(coordinator.CurrentStatus.IsRecording);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -5140,6 +5159,11 @@ public sealed class RecordingCoordinatorTests
|
||||
|
||||
drainBlocked.TrySetResult();
|
||||
await releaseDrain.Task.WaitAsync(cancellationToken);
|
||||
yield return new TranscriptionSegment(
|
||||
TimeSpan.Zero,
|
||||
TimeSpan.FromSeconds(3),
|
||||
"Unknown",
|
||||
"Final result emitted while switching profiles.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user