Add resilient Azure offline transcription backlog
PR and Push Build/Test / build-and-test (push) Successful in 18m41s

This commit is contained in:
2026-06-15 17:26:34 +02:00
parent b22754ce5d
commit b774ccc375
35 changed files with 2456 additions and 198 deletions
@@ -1,5 +1,6 @@
using MeetingAssistant.MeetingNotes;
using MeetingAssistant.Workflow;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
@@ -203,6 +204,71 @@ public sealed class MeetingWorkflowEngineTests
Assert.Equal("[00:00:04] Guest-1: Azure returned [redacted] here.", line);
}
[Fact]
public async Task TranscriptLineRulePreservesUtf8CharactersWhenRenderingRazor()
{
var fixture = await WorkflowFixture.CreateAsync(MeetingWorkflowTestRules.MaskedProfanityRedactionYaml);
var line = await fixture.Engine.TransformTranscriptLineAsync(
MeetingWorkflowEvent.TranscriptLine(
fixture.Artifacts,
"[00:00:57] Guest-1: Das heißt, Schimpfwörter wie ***** müssen als nächstes richtig bleiben.",
"Guest-1"),
fixture.Options,
CancellationToken.None);
Assert.Equal(
"[00:00:57] Guest-1: Das heißt, Schimpfwörter wie [redacted] müssen als nächstes richtig bleiben.",
line);
}
[Fact]
public async Task TriggeredWorkflowRuleLogsStartAndCompletion()
{
var logger = new ListLogger<MeetingWorkflowEngine>();
var fixture = await WorkflowFixture.CreateAsync(
"""
rules:
- name: logged-rule
on:
- created: {}
steps:
- uses: add_project
value: Diagnostics
""",
logger: logger);
await RunCreatedAsync(fixture);
Assert.Contains(logger.Messages, message =>
message.Contains("Triggered meeting workflow rule logged-rule for event Created", StringComparison.Ordinal));
Assert.Contains(logger.Messages, message =>
message.Contains("Completed meeting workflow rule logged-rule for event Created", StringComparison.Ordinal));
}
[Fact]
public async Task WorkflowRuleFailureLogsRuleNameAndEventType()
{
var logger = new ListLogger<MeetingWorkflowEngine>();
var fixture = await WorkflowFixture.CreateAsync(
"""
rules:
- name: broken-rule
on:
- created: {}
steps:
- uses: set_property
property: unsupported
value: Diagnostics
""",
logger: logger);
await Assert.ThrowsAsync<InvalidOperationException>(() => RunCreatedAsync(fixture));
Assert.Contains(logger.Messages, message =>
message.Contains("Meeting workflow rule broken-rule failed for event Created", StringComparison.Ordinal));
}
[Fact]
public async Task RuleCanRemoveAttendeeWhenNestedConditionMatches()
{
@@ -775,7 +841,8 @@ public sealed class MeetingWorkflowEngineTests
string title = "Planning Sync",
IReadOnlyList<string>? attendees = null,
IReadOnlyList<string>? projects = null,
string? rulesPath = null)
string? rulesPath = null,
ILogger<MeetingWorkflowEngine>? logger = null)
{
var root = Path.Combine(Path.GetTempPath(), "meeting-assistant-tests", Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(root);
@@ -837,7 +904,7 @@ public sealed class MeetingWorkflowEngineTests
NullLogger<FileMeetingWorkflowRulesProvider>.Instance),
noteStore,
artifactStore,
NullLogger<MeetingWorkflowEngine>.Instance);
logger ?? NullLogger<MeetingWorkflowEngine>.Instance);
return new WorkflowFixture(options, noteStore, artifacts, engine);
}
@@ -851,4 +918,39 @@ public sealed class MeetingWorkflowEngineTests
return File.ReadAllTextAsync(Artifacts.AssistantContextPath);
}
}
private sealed class ListLogger<T> : ILogger<T>
{
public List<string> Messages { get; } = [];
public IDisposable BeginScope<TState>(TState state)
where TState : notnull
{
return NullScope.Instance;
}
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public void Log<TState>(
LogLevel logLevel,
EventId eventId,
TState state,
Exception? exception,
Func<TState, Exception?, string> formatter)
{
Messages.Add(formatter(state, exception));
}
private sealed class NullScope : IDisposable
{
public static NullScope Instance { get; } = new();
public void Dispose()
{
}
}
}
}