using Shouldly; using Xunit; namespace ZB.MOM.WW.OtOpcUa.Driver.S7.Cli.Tests; /// /// Driver.S7.Cli-010: the long-running subscribe command must call /// FlushLogging() in its finally block so buffered Serilog log lines /// emitted just before Ctrl+C are not discarded on process exit. /// /// DriverCommandBase.ConfigureLogging() instructs every command to call /// FlushLogging() in a finally. The short-lived read, /// write, and probe commands are less exposed (their log volume is /// small and the process exits immediately after), but subscribe can run for /// minutes and then Ctrl+C — making the flush critical. /// /// [Trait("Category", "Unit")] public sealed class FlushLoggingConventionTests { private static readonly string CommandsDir = LocateCommandsDir(); /// /// Verifies that SubscribeCommand calls FlushLogging() to prevent buffered /// Serilog output from being lost on Ctrl+C. /// [Fact] public void SubscribeCommand_calls_FlushLogging() { // Driver.S7.Cli-010: FlushLogging() must appear in the command so that // DriverCommandBase.ConfigureLogging()'s documented contract is honoured. var source = File.ReadAllText(Path.Combine(CommandsDir, "SubscribeCommand.cs")); source.ShouldContain("FlushLogging()"); } private static string LocateCommandsDir() { var dir = new DirectoryInfo(AppContext.BaseDirectory); while (dir is not null && !File.Exists(Path.Combine(dir.FullName, "ZB.MOM.WW.OtOpcUa.slnx"))) dir = dir.Parent; dir.ShouldNotBeNull("Could not find solution root (ZB.MOM.WW.OtOpcUa.slnx)."); return Path.Combine( dir!.FullName, "src", "Drivers", "Cli", "ZB.MOM.WW.OtOpcUa.Driver.S7.Cli", "Commands"); } }