Public Access
204 lines
7.4 KiB
C#
204 lines
7.4 KiB
C#
using MeetingAssistant.Transcription;
|
|
using Microsoft.Extensions.Logging.Abstractions;
|
|
using Microsoft.Extensions.Options;
|
|
|
|
namespace MeetingAssistant.Tests;
|
|
|
|
public sealed class FunAsrBackendLifecycleTests
|
|
{
|
|
[Fact]
|
|
public async Task LifecycleInstallsStartsAndStopsManagedDockerContainer()
|
|
{
|
|
var runner = new CapturingCommandRunner();
|
|
var readinessProbe = new CapturingReadinessProbe();
|
|
var modelsFolder = Path.Combine(Path.GetTempPath(), "meeting-assistant-tests", Guid.NewGuid().ToString("N"));
|
|
var lifecycle = new FunAsrDockerBackendLifecycle(
|
|
runner,
|
|
readinessProbe,
|
|
Options.Create(new MeetingAssistantOptions
|
|
{
|
|
FunAsr = new FunAsrOptions
|
|
{
|
|
Endpoint = "ws://127.0.0.1:10095",
|
|
Backend = new FunAsrBackendOptions
|
|
{
|
|
Enabled = true,
|
|
Image = "funasr:test",
|
|
ContainerName = "meeting-assistant-funasr-test",
|
|
ModelsFolder = modelsFolder,
|
|
StartupTimeout = TimeSpan.Zero
|
|
}
|
|
}
|
|
}),
|
|
NullLogger<FunAsrDockerBackendLifecycle>.Instance);
|
|
|
|
await lifecycle.EnsureStartedAsync(CancellationToken.None);
|
|
await lifecycle.EnsureStartedAsync(CancellationToken.None);
|
|
await lifecycle.DisposeAsync();
|
|
|
|
Assert.Equal(new Uri("ws://127.0.0.1:10095"), readinessProbe.Endpoint);
|
|
Assert.Equal(TimeSpan.Zero, readinessProbe.Timeout);
|
|
Assert.Collection(
|
|
runner.Commands,
|
|
command =>
|
|
{
|
|
Assert.Equal("docker", command.FileName);
|
|
Assert.Equal(["pull", "funasr:test"], command.Arguments);
|
|
},
|
|
command =>
|
|
{
|
|
Assert.Equal(["rm", "-f", "meeting-assistant-funasr-test"], command.Arguments);
|
|
},
|
|
command =>
|
|
{
|
|
Assert.Equal("docker", command.FileName);
|
|
Assert.Contains("run", command.Arguments);
|
|
Assert.Contains("-d", command.Arguments);
|
|
Assert.Contains("--privileged=true", command.Arguments);
|
|
Assert.Contains("--name", command.Arguments);
|
|
Assert.Contains("meeting-assistant-funasr-test", command.Arguments);
|
|
Assert.Contains("-p", command.Arguments);
|
|
Assert.Contains("10095:10095", command.Arguments);
|
|
Assert.Contains($"{modelsFolder}:/workspace/models", command.Arguments);
|
|
Assert.Contains("funasr:test", command.Arguments);
|
|
},
|
|
command =>
|
|
{
|
|
Assert.Equal(["stop", "meeting-assistant-funasr-test"], command.Arguments);
|
|
});
|
|
Assert.True(File.Exists(Path.Combine(modelsFolder, "hotwords.txt")));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task DisabledLifecycleDoesNotRunDockerCommands()
|
|
{
|
|
var runner = new CapturingCommandRunner();
|
|
var lifecycle = new FunAsrDockerBackendLifecycle(
|
|
runner,
|
|
new CapturingReadinessProbe(),
|
|
Options.Create(new MeetingAssistantOptions
|
|
{
|
|
FunAsr = new FunAsrOptions
|
|
{
|
|
Backend = new FunAsrBackendOptions { Enabled = false }
|
|
}
|
|
}),
|
|
NullLogger<FunAsrDockerBackendLifecycle>.Instance);
|
|
|
|
await lifecycle.EnsureStartedAsync(CancellationToken.None);
|
|
await lifecycle.DisposeAsync();
|
|
|
|
Assert.Empty(runner.Commands);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task LifecycleFailsWhenDockerCommandTimesOut()
|
|
{
|
|
var runner = new HangingCommandRunner();
|
|
var lifecycle = new FunAsrDockerBackendLifecycle(
|
|
runner,
|
|
new CapturingReadinessProbe(),
|
|
Options.Create(new MeetingAssistantOptions
|
|
{
|
|
FunAsr = new FunAsrOptions
|
|
{
|
|
Backend = new FunAsrBackendOptions
|
|
{
|
|
Enabled = true,
|
|
CommandTimeout = TimeSpan.FromMilliseconds(1)
|
|
}
|
|
}
|
|
}),
|
|
NullLogger<FunAsrDockerBackendLifecycle>.Instance);
|
|
|
|
var exception = await Assert.ThrowsAsync<TimeoutException>(
|
|
() => lifecycle.EnsureStartedAsync(CancellationToken.None));
|
|
|
|
Assert.Contains("timed out", exception.Message);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task LifecycleWaitsForWebSocketReadinessBeforeMarkingStarted()
|
|
{
|
|
var runner = new CapturingCommandRunner();
|
|
var readinessProbe = new CapturingReadinessProbe();
|
|
var lifecycle = new FunAsrDockerBackendLifecycle(
|
|
runner,
|
|
readinessProbe,
|
|
Options.Create(new MeetingAssistantOptions
|
|
{
|
|
FunAsr = new FunAsrOptions
|
|
{
|
|
Endpoint = "ws://127.0.0.1:10095",
|
|
Backend = new FunAsrBackendOptions
|
|
{
|
|
Enabled = true,
|
|
Image = "funasr:test",
|
|
ContainerName = "meeting-assistant-funasr-test",
|
|
ModelsFolder = Path.Combine(Path.GetTempPath(), "meeting-assistant-tests", Guid.NewGuid().ToString("N")),
|
|
StartupTimeout = TimeSpan.FromMinutes(3)
|
|
}
|
|
}
|
|
}),
|
|
NullLogger<FunAsrDockerBackendLifecycle>.Instance);
|
|
|
|
await lifecycle.EnsureStartedAsync(CancellationToken.None);
|
|
|
|
Assert.Equal(1, readinessProbe.CallCount);
|
|
Assert.Equal(new Uri("ws://127.0.0.1:10095"), readinessProbe.Endpoint);
|
|
Assert.Equal(TimeSpan.FromMinutes(3), readinessProbe.Timeout);
|
|
Assert.Equal(3, runner.Commands.Count);
|
|
await lifecycle.DisposeAsync();
|
|
}
|
|
|
|
private sealed class CapturingCommandRunner : ICommandRunner
|
|
{
|
|
public List<CapturedCommand> Commands { get; } = [];
|
|
|
|
public Task<CommandResult> RunAsync(
|
|
string fileName,
|
|
IReadOnlyList<string> arguments,
|
|
CancellationToken cancellationToken,
|
|
IReadOnlyDictionary<string, string>? environment = null)
|
|
{
|
|
Commands.Add(new CapturedCommand(fileName, arguments.ToArray()));
|
|
return Task.FromResult(new CommandResult(0, "", ""));
|
|
}
|
|
}
|
|
|
|
private sealed record CapturedCommand(string FileName, IReadOnlyList<string> Arguments);
|
|
|
|
private sealed class HangingCommandRunner : ICommandRunner
|
|
{
|
|
public async Task<CommandResult> RunAsync(
|
|
string fileName,
|
|
IReadOnlyList<string> arguments,
|
|
CancellationToken cancellationToken,
|
|
IReadOnlyDictionary<string, string>? environment = null)
|
|
{
|
|
await Task.Delay(Timeout.InfiniteTimeSpan, cancellationToken);
|
|
return new CommandResult(0, "", "");
|
|
}
|
|
}
|
|
|
|
private sealed class CapturingReadinessProbe : IFunAsrBackendReadinessProbe
|
|
{
|
|
public int CallCount { get; private set; }
|
|
|
|
public Uri? Endpoint { get; private set; }
|
|
|
|
public TimeSpan Timeout { get; private set; }
|
|
|
|
public Task WaitUntilReadyAsync(
|
|
Uri endpoint,
|
|
TimeSpan timeout,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
CallCount++;
|
|
Endpoint = endpoint;
|
|
Timeout = timeout;
|
|
return Task.CompletedTask;
|
|
}
|
|
}
|
|
}
|