forked from Manuel/meeting-assistant
89 lines
4.3 KiB
C#
89 lines
4.3 KiB
C#
#:property PublishAot=false
|
|
// Local diagnostic only. See TranscriptFileShareProbe.md for the contract and limits.
|
|
using System.Diagnostics;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
using System.Text.Json;
|
|
|
|
const string original = "---\ntitle: transcript probe\n---\n\n# Meeting Transcript\n";
|
|
const string written = original + "[00:00:04] Guest-1: Azure returned ***** here.\n";
|
|
var root = Path.Combine(Path.GetTempPath(), "meeting-assistant-file-share-probe", Guid.NewGuid().ToString("N"));
|
|
if (Directory.Exists(root))
|
|
throw new IOException("Probe directory already exists; refusing to reuse it.");
|
|
Directory.CreateDirectory(root);
|
|
var cases = new List<WriteObservation>();
|
|
var cleanupCompleted = false;
|
|
try
|
|
{
|
|
var path = Path.Combine(root, "original-reader.md");
|
|
await File.WriteAllTextAsync(path, original);
|
|
using (var reader = new StreamReader(path, Encoding.UTF8, detectEncodingFromByteOrderMarks: true))
|
|
{
|
|
if (reader.ReadToEnd() != original)
|
|
throw new InvalidDataException("Original reader did not read the initial fixture.");
|
|
cases.Add(await ObserveWriteAsync("held-original-reader", path, written));
|
|
}
|
|
cases[^1] = cases[^1] with { ContentAfterReaderClosed = await File.ReadAllTextAsync(path) };
|
|
cases.Add(await ObserveWriteAsync("original-reader-released", path, written));
|
|
cases[^1] = cases[^1] with { ContentAfterReaderClosed = await File.ReadAllTextAsync(path) };
|
|
|
|
path = Path.Combine(root, "compatible-reader.md");
|
|
await File.WriteAllTextAsync(path, original);
|
|
using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete))
|
|
using (var reader = new StreamReader(stream, Encoding.UTF8, detectEncodingFromByteOrderMarks: true))
|
|
{
|
|
if (reader.ReadToEnd() != original)
|
|
throw new InvalidDataException("Compatible reader did not read the initial fixture.");
|
|
cases.Add(await ObserveWriteAsync("held-compatible-reader", path, written));
|
|
}
|
|
cases[^1] = cases[^1] with { ContentAfterReaderClosed = await File.ReadAllTextAsync(path) };
|
|
}
|
|
finally
|
|
{
|
|
Directory.Delete(root, recursive: true);
|
|
cleanupCompleted = !Directory.Exists(root);
|
|
}
|
|
|
|
var windowsContractMatched = OperatingSystem.IsWindows()
|
|
? !cases[0].Completed && cases[0].Error is { Type: "System.IO.IOException", NativeCode: 32 }
|
|
&& cases[0].ContentAfterReaderClosed == original
|
|
: (bool?)null;
|
|
var compatibleAndReleasedWritesCompleted = cases.Skip(1).All(result =>
|
|
result.Completed && result.Error is null && result.ContentAfterReaderClosed == written);
|
|
Console.WriteLine(JsonSerializer.Serialize(new
|
|
{
|
|
Schema = "meeting-assistant-file-share-probe/v1",
|
|
Runtime = RuntimeInformation.FrameworkDescription,
|
|
OS = RuntimeInformation.OSDescription,
|
|
Architecture = RuntimeInformation.ProcessArchitecture.ToString(),
|
|
ProbeDirectory = root,
|
|
CleanupCompleted = cleanupCompleted,
|
|
WindowsContractMatched = windowsContractMatched,
|
|
CompatibleAndReleasedWritesCompleted = compatibleAndReleasedWritesCompleted,
|
|
Cases = cases,
|
|
EvidenceLimit = "Held-reader access-mode probe; it does not reproduce the timing or establish the cause of Run4174."
|
|
}, new JsonSerializerOptions { WriteIndented = true }));
|
|
return cleanupCompleted && compatibleAndReleasedWritesCompleted && windowsContractMatched != false ? 0 : 1;
|
|
|
|
static async Task<WriteObservation> ObserveWriteAsync(string name, string path, string content)
|
|
{
|
|
var elapsed = Stopwatch.StartNew();
|
|
Task? write = null;
|
|
using var deadline = new CancellationTokenSource(TimeSpan.FromSeconds(5));
|
|
try
|
|
{
|
|
write = File.WriteAllTextAsync(path, content, deadline.Token);
|
|
await write;
|
|
return new(name, true, write.Status.ToString(), elapsed.ElapsedMilliseconds, null, null);
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
return new(name, false, write?.Status.ToString() ?? "not-returned", elapsed.ElapsedMilliseconds,
|
|
new(exception.GetType().FullName!, $"0x{exception.HResult:X8}", exception.HResult & 0xffff, exception.Message), null);
|
|
}
|
|
}
|
|
|
|
sealed record WriteObservation(string Name, bool Completed, string TaskStatus, long ElapsedMilliseconds,
|
|
WriteError? Error, string? ContentAfterReaderClosed);
|
|
sealed record WriteError(string Type, string HResult, int NativeCode, string Message);
|