forked from Manuel/meeting-assistant
ci: consolidate platform pipelines and test prerequisites on macOS support
This commit is contained in:
1 parent
1b19b08f2e
commit
728e66dd72
76 files changed
+7477
-239
No files matched your search
@@ -0,0 +1,166 @@
|
||||
using System.Net;
|
||||
using System.Net.Http.Json;
|
||||
using MeetingAssistant.Notifications;
|
||||
using MeetingAssistant.MacOs;
|
||||
using MeetingAssistant.Workflow;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Mvc.Testing;
|
||||
using Microsoft.AspNetCore.TestHost;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
namespace MeetingAssistant.Tests;
|
||||
|
||||
#if !WINDOWS
|
||||
public sealed class DesktopCommunicationEndpointTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task PendingRequestCanBeReadThroughDesktopEndpoint()
|
||||
{
|
||||
await using var factory = CreateFactory();
|
||||
using var client = factory.CreateClient();
|
||||
var requests = factory.Services.GetRequiredService<DesktopUserRequestStore>();
|
||||
var registration = requests.Add(new DesktopUserRequestSpec(
|
||||
"agent-approval", "Project association", "Allow access to project Apollo?",
|
||||
TimeSpan.FromMinutes(10), [new("yes", "Yes"), new("no", "No")]), CancellationToken.None);
|
||||
|
||||
using var response = await client.GetAsync("/desktop/requests");
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var request = Assert.Single((await response.Content.ReadFromJsonAsync<DesktopUserRequest[]>())!);
|
||||
Assert.Equal(registration.Id, request.Id);
|
||||
Assert.Equal("Allow access to project Apollo?", request.Message);
|
||||
Assert.Equal(new[] { "yes", "no" }, request.Actions.Select(action => action.Id));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task OfferedHttpResponseDeliversOneDecisionAndRejectsDuplicate()
|
||||
{
|
||||
await using var factory = CreateFactory();
|
||||
using var client = factory.CreateClient();
|
||||
var requests = factory.Services.GetRequiredService<DesktopUserRequestStore>();
|
||||
var calls = 0;
|
||||
var registration = requests.Add(new DesktopUserRequestSpec(
|
||||
"agent-approval", "Approval", "Apply proposed change?", TimeSpan.FromMinutes(10),
|
||||
[new("yes", "Yes"), new("no", "No")]), CancellationToken.None,
|
||||
(_, _) => { Interlocked.Increment(ref calls); return Task.CompletedTask; });
|
||||
var path = $"/desktop/requests/{registration.Id}/respond";
|
||||
|
||||
using var accepted = await client.PostAsJsonAsync(path, new { action = "yes" });
|
||||
using var duplicate = await client.PostAsJsonAsync(path, new { action = "yes" });
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, accepted.StatusCode);
|
||||
Assert.Equal(HttpStatusCode.Gone, duplicate.StatusCode);
|
||||
Assert.Equal("yes", await registration.Decision);
|
||||
Assert.Equal(1, calls);
|
||||
Assert.Empty((await client.GetFromJsonAsync<DesktopUserRequest[]>("/desktop/requests"))!);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ApprovedWindowAndRepeatedSnapshotsKeepOneIndependentPrompt()
|
||||
{
|
||||
await using var factory = CreateFactory();
|
||||
using var client = factory.CreateClient();
|
||||
var sessions = factory.Services.GetRequiredService<MacOsWorkflowRulesEditorSessions>();
|
||||
sessions.OpenWithPrompt("Add the requested workflow scenario in full.");
|
||||
|
||||
using var response = await client.GetAsync("/desktop/agent-windows");
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var window = Assert.Single((await response.Content.ReadFromJsonAsync<MacOsAgentWindowRequest[]>())!);
|
||||
Assert.EndsWith($"?session={window.Id}", window.Url);
|
||||
var path = $"/diagnostics/settings-and-logs/chat?session={window.Id}";
|
||||
MacOsWorkflowRulesEditorChatResponse? first = null;
|
||||
for (var attempt = 0; attempt < 100; attempt++)
|
||||
{
|
||||
first = await client.GetFromJsonAsync<MacOsWorkflowRulesEditorChatResponse>(path);
|
||||
if (!first!.IsThinking && first.Messages.Count > 0) break;
|
||||
await Task.Delay(10);
|
||||
}
|
||||
Assert.False(first!.IsThinking);
|
||||
var second = await client.GetFromJsonAsync<MacOsWorkflowRulesEditorChatResponse>(path);
|
||||
Assert.Equal("Add the requested workflow scenario in full.", first.Messages[0].Content);
|
||||
Assert.Equal(first.Messages, second!.Messages);
|
||||
Assert.Single(factory.Services.GetRequiredService<EndpointVerificationPipeline>().Calls);
|
||||
Assert.Empty((await client.GetFromJsonAsync<MacOsWorkflowRulesEditorChatResponse>(
|
||||
"/diagnostics/settings-and-logs/chat"))!.Messages);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UnknownChatSessionCannotSendIntoTheDefaultConversation()
|
||||
{
|
||||
await using var factory = CreateFactory();
|
||||
using var client = factory.CreateClient();
|
||||
|
||||
using var response = await client.PostAsJsonAsync(
|
||||
"/diagnostics/settings-and-logs/chat?session=unknown-session", new { message = "Do not route this elsewhere" });
|
||||
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
Assert.Empty(factory.Services.GetRequiredService<EndpointVerificationPipeline>().Calls);
|
||||
Assert.Empty((await client.GetFromJsonAsync<MacOsWorkflowRulesEditorChatResponse>(
|
||||
"/diagnostics/settings-and-logs/chat"))!.Messages);
|
||||
}
|
||||
|
||||
[MacOsFact]
|
||||
public async Task MacOsCompositionWaitsForApprovalAndUsesTheDesktopDecision()
|
||||
{
|
||||
await using var factory = CreateFactory();
|
||||
using var client = factory.CreateClient();
|
||||
using var origin = new CancellationTokenSource();
|
||||
var approval = factory.Services.GetRequiredService<AgentApprovalService>();
|
||||
var requests = factory.Services.GetRequiredService<DesktopUserRequestStore>();
|
||||
var decision = approval.ConfirmAsync("Test approval", "Isolated composition check", origin.Token);
|
||||
try
|
||||
{
|
||||
var pending = Assert.Single(requests.List());
|
||||
Assert.False(decision.IsCompleted);
|
||||
using var response = await client.PostAsJsonAsync(
|
||||
$"/desktop/requests/{pending.Id}/respond", new { action = "no" });
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.False(await decision.WaitAsync(TimeSpan.FromSeconds(5)));
|
||||
Assert.IsType<MacOsMeetingInactivityPromptService>(
|
||||
factory.Services.GetRequiredService<MeetingAssistant.Recording.IMeetingInactivityPromptService>());
|
||||
}
|
||||
finally
|
||||
{
|
||||
origin.Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
internal static WebApplicationFactory<Program> CreateFactory()
|
||||
{
|
||||
return new IsolatedApplicationFactory().WithWebHostBuilder(builder =>
|
||||
{
|
||||
builder.ConfigureAppConfiguration((_, configuration) =>
|
||||
configuration.AddInMemoryCollection(new Dictionary<string, string?>
|
||||
{
|
||||
["MeetingAssistant:FunAsr:Backend:Enabled"] = "false",
|
||||
["MeetingAssistant:CalendarRecordingPrompts:Enabled"] = "false"
|
||||
}));
|
||||
builder.ConfigureTestServices(services =>
|
||||
{
|
||||
services.RemoveAll<IWorkflowRulesEditorChatPipeline>();
|
||||
services.AddSingleton<EndpointVerificationPipeline>();
|
||||
services.AddSingleton<IWorkflowRulesEditorChatPipeline>(provider =>
|
||||
provider.GetRequiredService<EndpointVerificationPipeline>());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private sealed class EndpointVerificationPipeline : IWorkflowRulesEditorChatPipeline
|
||||
{
|
||||
public List<string> Calls { get; } = [];
|
||||
|
||||
public Task<WorkflowRulesEditorChatResult> SendAsync(
|
||||
IReadOnlyList<WorkflowRulesEditorChatMessage> conversation,
|
||||
string userMessage, CancellationToken cancellationToken,
|
||||
Action<WorkflowRulesEditorActivityUpdate>? activityChanged = null)
|
||||
{
|
||||
Calls.Add(userMessage);
|
||||
return Task.FromResult(new WorkflowRulesEditorChatResult("Verification reply"));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Reference in new issue
Block a user