From da6b68ee97f397f2df72e8f8ca96634d674dd57e Mon Sep 17 00:00:00 2001 From: Pantazis Deligiannis Date: Fri, 25 Mar 2022 18:07:13 -0700 Subject: [PATCH] updates to the CLI experience (#321) --- Coyote.sln | 4 +- Samples/CloudMessaging/CloudMessaging.sln | 4 +- Samples/CloudMessaging/Raft.Azure/Program.cs | 33 +- Scripts/NuGet/Coyote.Test.nuspec | 22 +- Scripts/NuGet/Coyote.nuspec | 21 +- Scripts/test-cli-package.ps1 | 2 +- Source/Core/Actors/ActorExecutionContext.cs | 21 +- Source/Core/Actors/ActorId.cs | 2 + .../Coverage/ActorRuntimeLogGraphBuilder.cs | 124 +- Source/Core/Configuration.cs | 155 +-- Source/Core/IO/Debugging/Error.cs | 23 - .../ConfiguredValueTaskAwaitable.cs | 1 - .../Testing/Interleaving/ReplayStrategy.cs | 18 +- .../Passes/Rewriting/MSTestRewritingPass.cs | 4 +- .../Passes/Rewriting/RewritingPass.cs | 1 - .../Types/MethodBodyTypeRewritingPass.cs | 1 - Source/Test/SmartSockets/SmartSocketClient.cs | 596 --------- Source/Test/SmartSockets/SmartSocketServer.cs | 366 ------ .../SmartSockets/SmartSocketTypeResolver.cs | 71 - Source/Test/SmartSockets/SocketMessage.cs | 39 - .../SystematicTesting/Reports/TestReport.cs | 6 +- .../Test/SystematicTesting/TestingEngine.cs | 395 +++--- .../Test/Telemetry/CoyoteTelemetryClient.cs | 358 ----- .../Test/Telemetry/CoyoteTelemetryServer.cs | 246 ---- Source/Test/Telemetry/TelemetryClient.cs | 209 +++ Source/Test/Test.csproj | 13 +- .../EventGroups/LargeEventGroupTests.cs | 2 +- .../Logging/CustomActorRuntimeLogTests.cs | 149 +-- .../Tasks/Logging/CustomTaskLogTests.cs | 4 +- Tests/compare-rewriting-diff-logs.ps1 | 2 +- Tools/Coyote/Cli/CommandLineParser.cs | 993 ++++++++++++++ Tools/Coyote/Cli/ExitCode.cs | 34 + Tools/Coyote/Cli/OutputFileManager.cs | 77 ++ Tools/Coyote/Coyote.csproj | 12 +- .../CodeCoverageInstrumentation.cs | 260 ---- Tools/Coyote/Interfaces/BugFoundMessage.cs | 21 - .../Coyote/Interfaces/TestProgressMessage.cs | 25 - Tools/Coyote/Interfaces/TestReportMessage.cs | 25 - Tools/Coyote/Interfaces/TestServerMessage.cs | 20 - Tools/Coyote/Interfaces/TestTraceMessage.cs | 29 - .../Coyote/Monitoring/CodeCoverageMonitor.cs | 154 --- Tools/Coyote/Program.cs | 239 +--- .../Scheduling/TestingProcessScheduler.cs | 663 ---------- Tools/Coyote/Testing/TestingPortfolio.cs | 37 - Tools/Coyote/Testing/TestingProcess.cs | 404 ------ Tools/Coyote/Testing/TestingProcessFactory.cs | 179 --- .../Utilities/CommandLineArgumentParser.cs | 972 -------------- Tools/Coyote/Utilities/CommandLineOptions.cs | 513 -------- Tools/Coyote/Utilities/DependencyGraph.cs | 74 -- Tools/Coyote/Utilities/ExitCode.cs | 26 - Tools/Coyote/Utilities/Reporter.cs | 100 -- docs/concepts/actors/state-machine-demo.md | 2 +- docs/get-started/install.md | 4 +- docs/get-started/telemetry.md | 6 +- docs/get-started/using-coyote.md | 46 +- docs/how-to/coverage.md | 110 +- docs/how-to/liveness-checking.md | 25 +- docs/how-to/unit-testing.md | 2 +- ...crosoft.Coyote.Actors.CoverageNamespace.md | 1 - .../RewritingEngine.md | 24 + .../RewritingEngine/IsAssemblyRewritten.md | 23 + .../RewritingSignatureAttribute.md | 27 + .../RewritingSignatureAttribute.md | 15 + .../RewritingSignatureAttribute/Signature.md | 15 + .../RewritingSignatureAttribute/Version.md | 15 + .../Microsoft.Coyote.RewritingNamespace.md | 8 + .../TestAttribute.md | 21 + .../TestAttribute/TestAttribute.md | 15 + .../TestDisposeAttribute.md | 21 + .../TestDisposeAttribute.md | 15 + .../TestInitAttribute.md | 21 + .../TestInitAttribute/TestInitAttribute.md | 15 + .../TestIterationDisposeAttribute.md | 21 + .../TestIterationDisposeAttribute.md | 15 + .../TestReport.md | 43 + .../TestReport/BugReports.md | 15 + .../TestReport/Clone.md | 15 + .../TestReport/Configuration.md | 15 + .../TestReport/CoverageInfo.md | 15 + .../TestReport/GetText.md | 15 + .../TestReport/InternalErrors.md | 15 + .../TestReport/MaxConcurrencyDegree.md | 15 + .../TestReport/MaxControlledOperations.md | 15 + .../TestReport/MaxExploredFairSteps.md | 15 + .../TestReport/MaxFairStepsHitInFairTests.md | 15 + .../MaxUnfairStepsHitInFairTests.md | 15 + .../MaxUnfairStepsHitInUnfairTests.md | 15 + .../TestReport/Merge.md | 19 + .../TestReport/MinConcurrencyDegree.md | 15 + .../TestReport/MinControlledOperations.md | 15 + .../TestReport/MinExploredFairSteps.md | 15 + .../TestReport/NumOfExploredFairSchedules.md | 15 + .../NumOfExploredUnfairSchedules.md | 15 + .../TestReport/NumOfFoundBugs.md | 15 + .../TestReport/TestReport.md | 15 + .../TestReport/TotalConcurrencyDegree.md | 15 + .../TestReport/TotalControlledOperations.md | 15 + .../TestReport/TotalExploredFairSteps.md | 15 + .../TestReport/UncontrolledInvocations.md | 15 + .../TestingEngine.md | 32 + .../TestingEngine/Create.md | 111 ++ .../TestingEngine/GetReport.md | 15 + .../TestingEngine/IsTestRewritten.md | 19 + .../TestingEngine/Logger.md | 19 + .../TestingEngine/ReadableTrace.md | 15 + .../RegisterPerIterationCallBack.md | 15 + .../TestingEngine/ReproducibleTrace.md | 15 + .../TestingEngine/Run.md | 15 + .../TestingEngine/Stop.md | 15 + .../TestingEngine/TestReport.md | 16 + .../TestingEngine/ThrowIfBugFound.md | 15 + .../TestingEngine/TryEmitCoverageReports.md | 16 + .../TestingEngine/TryEmitReports.md | 15 + ...osoft.Coyote.SystematicTestingNamespace.md | 12 + docs/ref/Microsoft.Coyote.Test.md | 27 + .../RequestControllerMiddlewareExtensions.md | 20 + .../UseRequestController.md | 19 + docs/ref/Microsoft.Coyote.WebNamespace.md | 7 + docs/ref/Microsoft.Coyote.md | 3 +- docs/ref/Microsoft.Coyote/Configuration.md | 4 +- .../Configuration/WithDgmlGraphEnabled.md | 19 - .../WithTraceVisualizationEnabled.md | 19 + docs/ref/Microsoft.CoyoteNamespace.md | 2 +- docs/ref/toc.yml | 1146 ++--------------- .../actors/failover-robot-navigator.md | 20 +- docs/samples/actors/failure-detector.md | 16 +- docs/tutorials/actors/raft-mocking.md | 14 +- docs/tutorials/actors/test-failover.md | 39 +- docs/tutorials/test-failover.md | 34 +- mkdocs.yml | 623 ++------- 130 files changed, 3161 insertions(+), 7819 deletions(-) delete mode 100644 Source/Test/SmartSockets/SmartSocketClient.cs delete mode 100644 Source/Test/SmartSockets/SmartSocketServer.cs delete mode 100644 Source/Test/SmartSockets/SmartSocketTypeResolver.cs delete mode 100644 Source/Test/SmartSockets/SocketMessage.cs delete mode 100644 Source/Test/Telemetry/CoyoteTelemetryClient.cs delete mode 100644 Source/Test/Telemetry/CoyoteTelemetryServer.cs create mode 100644 Source/Test/Telemetry/TelemetryClient.cs create mode 100644 Tools/Coyote/Cli/CommandLineParser.cs create mode 100644 Tools/Coyote/Cli/ExitCode.cs create mode 100644 Tools/Coyote/Cli/OutputFileManager.cs delete mode 100644 Tools/Coyote/Instrumentation/CodeCoverageInstrumentation.cs delete mode 100644 Tools/Coyote/Interfaces/BugFoundMessage.cs delete mode 100644 Tools/Coyote/Interfaces/TestProgressMessage.cs delete mode 100644 Tools/Coyote/Interfaces/TestReportMessage.cs delete mode 100644 Tools/Coyote/Interfaces/TestServerMessage.cs delete mode 100644 Tools/Coyote/Interfaces/TestTraceMessage.cs delete mode 100644 Tools/Coyote/Monitoring/CodeCoverageMonitor.cs delete mode 100644 Tools/Coyote/Scheduling/TestingProcessScheduler.cs delete mode 100644 Tools/Coyote/Testing/TestingPortfolio.cs delete mode 100644 Tools/Coyote/Testing/TestingProcess.cs delete mode 100644 Tools/Coyote/Testing/TestingProcessFactory.cs delete mode 100644 Tools/Coyote/Utilities/CommandLineArgumentParser.cs delete mode 100644 Tools/Coyote/Utilities/CommandLineOptions.cs delete mode 100644 Tools/Coyote/Utilities/DependencyGraph.cs delete mode 100644 Tools/Coyote/Utilities/ExitCode.cs delete mode 100644 Tools/Coyote/Utilities/Reporter.cs create mode 100644 docs/ref/Microsoft.Coyote.Rewriting/RewritingEngine.md create mode 100644 docs/ref/Microsoft.Coyote.Rewriting/RewritingEngine/IsAssemblyRewritten.md create mode 100644 docs/ref/Microsoft.Coyote.Rewriting/RewritingSignatureAttribute.md create mode 100644 docs/ref/Microsoft.Coyote.Rewriting/RewritingSignatureAttribute/RewritingSignatureAttribute.md create mode 100644 docs/ref/Microsoft.Coyote.Rewriting/RewritingSignatureAttribute/Signature.md create mode 100644 docs/ref/Microsoft.Coyote.Rewriting/RewritingSignatureAttribute/Version.md create mode 100644 docs/ref/Microsoft.Coyote.RewritingNamespace.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestAttribute.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestAttribute/TestAttribute.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestDisposeAttribute.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestDisposeAttribute/TestDisposeAttribute.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestInitAttribute.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestInitAttribute/TestInitAttribute.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestIterationDisposeAttribute.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestIterationDisposeAttribute/TestIterationDisposeAttribute.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestReport.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/BugReports.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/Clone.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/Configuration.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/CoverageInfo.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/GetText.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/InternalErrors.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxConcurrencyDegree.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxControlledOperations.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxExploredFairSteps.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxFairStepsHitInFairTests.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxUnfairStepsHitInFairTests.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxUnfairStepsHitInUnfairTests.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/Merge.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MinConcurrencyDegree.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MinControlledOperations.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MinExploredFairSteps.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/NumOfExploredFairSchedules.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/NumOfExploredUnfairSchedules.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/NumOfFoundBugs.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/TestReport.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/TotalConcurrencyDegree.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/TotalControlledOperations.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/TotalExploredFairSteps.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/UncontrolledInvocations.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/Create.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/GetReport.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/IsTestRewritten.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/Logger.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/ReadableTrace.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/RegisterPerIterationCallBack.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/ReproducibleTrace.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/Run.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/Stop.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/TestReport.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/ThrowIfBugFound.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/TryEmitCoverageReports.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/TryEmitReports.md create mode 100644 docs/ref/Microsoft.Coyote.SystematicTestingNamespace.md create mode 100644 docs/ref/Microsoft.Coyote.Test.md create mode 100644 docs/ref/Microsoft.Coyote.Web/RequestControllerMiddlewareExtensions.md create mode 100644 docs/ref/Microsoft.Coyote.Web/RequestControllerMiddlewareExtensions/UseRequestController.md create mode 100644 docs/ref/Microsoft.Coyote.WebNamespace.md delete mode 100644 docs/ref/Microsoft.Coyote/Configuration/WithDgmlGraphEnabled.md create mode 100644 docs/ref/Microsoft.Coyote/Configuration/WithTraceVisualizationEnabled.md diff --git a/Coyote.sln b/Coyote.sln index 07494a50f..3aebffac4 100644 --- a/Coyote.sln +++ b/Coyote.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.28803.156 +# Visual Studio Version 17 +VisualStudioVersion = 17.1.32228.430 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{458F6344-4ADE-475F-8A31-4DF3D01CF364}" ProjectSection(SolutionItems) = preProject diff --git a/Samples/CloudMessaging/CloudMessaging.sln b/Samples/CloudMessaging/CloudMessaging.sln index b84b7c56d..068fc9408 100644 --- a/Samples/CloudMessaging/CloudMessaging.sln +++ b/Samples/CloudMessaging/CloudMessaging.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.28803.156 +# Visual Studio Version 17 +VisualStudioVersion = 17.1.32228.430 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Raft", "Raft\Raft.csproj", "{64EA33E6-A1C1-4E8B-9CE0-E581E344EE49}" EndProject diff --git a/Samples/CloudMessaging/Raft.Azure/Program.cs b/Samples/CloudMessaging/Raft.Azure/Program.cs index a1ef335b5..d30fed3b3 100644 --- a/Samples/CloudMessaging/Raft.Azure/Program.cs +++ b/Samples/CloudMessaging/Raft.Azure/Program.cs @@ -4,15 +4,12 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.IO; using System.Reflection; -using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.Azure.ServiceBus; using Microsoft.Azure.ServiceBus.Management; using Microsoft.Coyote.Actors; -using Microsoft.Coyote.Actors.Coverage; namespace Microsoft.Coyote.Samples.CloudMessaging { @@ -22,7 +19,7 @@ namespace Microsoft.Coyote.Samples.CloudMessaging /// in separate processes. /// The presence of the --server-id and --client-process-id arguments makes /// a server instance. The Client instance starts the number of servers specified - /// in the --num-servers argumenet. + /// in the --num-servers argument. /// public class Program { @@ -36,7 +33,6 @@ public class Program private int ServerId = -1; private int ClientProcessId = -1; private readonly bool Debug = false; - private bool GraphIt = false; private TaskCompletionSource completed; internal static void PrintUsage() @@ -50,7 +46,6 @@ internal static void PrintUsage() Console.WriteLine(" --connection-string your Azure Service Bus connection string"); Console.WriteLine(" --topic-name optional string for Service Bus Topic (default 'rafttopic')"); Console.WriteLine(" --num-servers number of servers to spawn"); - Console.WriteLine(" --graph produce DGML graphs of the activity"); } private bool ParseCommandLine(string[] args) @@ -104,10 +99,6 @@ private bool ParseCommandLine(string[] args) Task.Delay(10000).Wait(); break; - case "--graph": - this.GraphIt = true; - break; - case "--?": case "--help": case "-?": @@ -183,13 +174,6 @@ await managementClient.CreateSubscriptionAsync( IActorRuntime runtime = RuntimeFactory.Create(Configuration.Create().WithVerbosityEnabled()); - if (this.GraphIt) - { - var graphBuilder = new ActorRuntimeLogGraphBuilder(false); - runtime.RegisterLog(graphBuilder); - _ = Task.Run(() => { PeriodicSaves(graphBuilder, subscriptionName); }); - } - // We create a new Coyote actor runtime instance, and pass an optional configuration // that increases the verbosity level to see the Coyote runtime log. runtime.OnFailure += RuntimeOnFailure; @@ -213,21 +197,6 @@ await managementClient.CreateSubscriptionAsync( } } - private static async void PeriodicSaves(ActorRuntimeLogGraphBuilder log, string baseName) - { - while (true) - { - await Task.Delay(10000); - Graph graph = log.SnapshotGraph(false); - string filename = baseName + ".dgml"; - using (var stream = new StreamWriter(filename, false, Encoding.UTF8)) - { - Console.WriteLine("############ saved " + filename + " ##########################################"); - graph.WriteDgml(stream, true); - } - } - } - private async Task RunClient(IActorRuntime runtime, ActorId clusterManager, string subscriptionName) { CancellationTokenSource cancelSource = new CancellationTokenSource(); diff --git a/Scripts/NuGet/Coyote.Test.nuspec b/Scripts/NuGet/Coyote.Test.nuspec index fa10121f0..7f74f27ef 100644 --- a/Scripts/NuGet/Coyote.Test.nuspec +++ b/Scripts/NuGet/Coyote.Test.nuspec @@ -16,23 +16,29 @@ - - + + + - - + + + - - + + + + - - + + + + diff --git a/Scripts/NuGet/Coyote.nuspec b/Scripts/NuGet/Coyote.nuspec index f21d1eeef..bed7678e2 100644 --- a/Scripts/NuGet/Coyote.nuspec +++ b/Scripts/NuGet/Coyote.nuspec @@ -14,11 +14,22 @@ docs\readme.md asynchrony reliability tasks actors state-machines specifications testing - - - - - + + + + + + + + + + + + + + + + diff --git a/Scripts/test-cli-package.ps1 b/Scripts/test-cli-package.ps1 index 42a596efd..42824d5b9 100644 --- a/Scripts/test-cli-package.ps1 +++ b/Scripts/test-cli-package.ps1 @@ -33,7 +33,7 @@ else { $help = (& "$PSScriptRoot/../temp/coyote" -?) -join '\n' -if (!$help.Contains("usage: Coyote command path")) { +if (!$help.Contains("coyote [command] [options]")) { Write-Error "### Unexpected output from coyote command" Write-Error $help Exit 1 diff --git a/Source/Core/Actors/ActorExecutionContext.cs b/Source/Core/Actors/ActorExecutionContext.cs index bee71c9d1..e25287c73 100644 --- a/Source/Core/Actors/ActorExecutionContext.cs +++ b/Source/Core/Actors/ActorExecutionContext.cs @@ -740,10 +740,11 @@ internal CoverageInfo BuildCoverageInfo() var result = this.CoverageInfo; if (result != null) { - var builder = this.LogWriter.GetLogsOfType().FirstOrDefault(); + var builder = this.LogWriter.GetLogsOfType() + .FirstOrDefault(builder => builder.CollapseInstances); if (builder != null) { - result.CoverageGraph = builder.SnapshotGraph(this.Configuration.IsDgmlBugGraph); + result.CoverageGraph = builder.SnapshotGraph(false); } var eventCoverage = this.LogWriter.GetLogsOfType().FirstOrDefault(); @@ -756,6 +757,22 @@ internal CoverageInfo BuildCoverageInfo() return result; } + /// + /// Returns the DGML graph of the current execution, if there is any. + /// + internal Graph GetExecutionGraph() + { + Graph result = null; + var builder = this.LogWriter.GetLogsOfType() + .FirstOrDefault(builder => !builder.CollapseInstances); + if (builder != null) + { + result = builder.SnapshotGraph(true); + } + + return result; + } + /// /// Returns the program counter of the specified actor. /// diff --git a/Source/Core/Actors/ActorId.cs b/Source/Core/Actors/ActorId.cs index fc5d7cc6e..340034f76 100644 --- a/Source/Core/Actors/ActorId.cs +++ b/Source/Core/Actors/ActorId.cs @@ -2,7 +2,9 @@ // Licensed under the MIT License. using System; +#if !DEBUG using System.Diagnostics; +#endif using System.Globalization; using System.Runtime.Serialization; diff --git a/Source/Core/Actors/Coverage/ActorRuntimeLogGraphBuilder.cs b/Source/Core/Actors/Coverage/ActorRuntimeLogGraphBuilder.cs index 9ef299fb3..275b49192 100644 --- a/Source/Core/Actors/Coverage/ActorRuntimeLogGraphBuilder.cs +++ b/Source/Core/Actors/Coverage/ActorRuntimeLogGraphBuilder.cs @@ -16,25 +16,46 @@ namespace Microsoft.Coyote.Actors.Coverage /// Implements the and builds a directed graph /// from the recorded events and state transitions. /// - public class ActorRuntimeLogGraphBuilder : IActorRuntimeLog + internal class ActorRuntimeLogGraphBuilder : IActorRuntimeLog { - private Graph CurrentGraph; - private readonly Dictionary Dequeued = new Dictionary(); // current dequeued event. - private readonly Dictionary HaltedStates = new Dictionary(); // halted state for given actor. - private readonly bool MergeEventLinks; // merge events from node A to node B instead of making them separate links. private const string ExternalCodeName = "ExternalCode"; private const string ExternalStateName = "ExternalState"; private const string StateMachineCategory = "StateMachine"; private const string ActorCategory = "Actor"; private const string MonitorCategory = "Monitor"; + /// + /// The currently manipulated graph. + /// + private Graph CurrentGraph; + + /// + /// Current dequeued event. + /// + private readonly Dictionary Dequeued = new Dictionary(); + + /// + /// Halted state for given actor. + /// + private readonly Dictionary HaltedStates = new Dictionary(); + + /// + /// Merge events from node A to node B instead of making them separate links. + /// + internal bool MergeEventLinks { get; private set; } + + /// + /// Set this boolean to true to get a collapsed graph showing only machine types, states and events. + /// + internal bool CollapseInstances { get; private set; } + private class EventInfo { - public string Name; - public string Type; - public string State; - public string Event; - public string HandlingState; + internal string Name; + internal string Type; + internal string State; + internal string Event; + internal string HandlingState; } private readonly Dictionary> Inbox = new Dictionary>(); @@ -42,6 +63,30 @@ private class EventInfo private readonly HashSet Namespaces = new HashSet(); private static readonly char[] TypeSeparators = new char[] { '.', '+' }; + /// + /// Get or set the underlying logging object. + /// + /// + /// See Logging for more information. + /// + internal TextWriter Logger { get; set; } + + /// + /// Get the Graph object built by this logger. + /// + internal Graph Graph + { + get + { + if (this.CurrentGraph is null) + { + this.CurrentGraph = new Graph(); + } + + return this.CurrentGraph; + } + } + private class DoActionEvent : Event { } @@ -67,42 +112,13 @@ static ActorRuntimeLogGraphBuilder() /// /// Initializes a new instance of the class. /// - public ActorRuntimeLogGraphBuilder(bool mergeEventLinks) + internal ActorRuntimeLogGraphBuilder(bool mergeEventLinks, bool collapseInstances) { this.MergeEventLinks = mergeEventLinks; + this.CollapseInstances = collapseInstances; this.CurrentGraph = new Graph(); } - /// - /// Set this boolean to true to get a collapsed graph showing only - /// machine types, states and events. This will not show machine "instances". - /// - public bool CollapseMachineInstances { get; set; } - - /// - /// Get or set the underlying logging object. - /// - /// - /// See Logging for more information. - /// - public TextWriter Logger { get; set; } - - /// - /// Get the Graph object built by this logger. - /// - public Graph Graph - { - get - { - if (this.CurrentGraph is null) - { - this.CurrentGraph = new Graph(); - } - - return this.CurrentGraph; - } - } - /// public void OnCreateActor(ActorId id, string creatorName, string creatorType) { @@ -448,10 +464,9 @@ public void OnMonitorStateTransition(string monitorType, string stateName, bool var source = this.GetOrCreateChild(monitorType, monitorType, info.State); var shortStateName = this.GetLabel(monitorType, monitorType, stateName); - string suffix = string.Empty; if (isInHotState.HasValue) { - suffix = (isInHotState is true) ? "[hot]" : "[cold]"; + string suffix = (isInHotState is true) ? "[hot]" : "[cold]"; shortStateName += suffix; } @@ -495,12 +510,12 @@ public void OnCompleted() /// /// Set to true will reset the graph for the next iteration. /// The graph. - public Graph SnapshotGraph(bool reset) + internal Graph SnapshotGraph(bool reset) { Graph result = this.CurrentGraph; if (reset) { - // start fresh. + // Reset the graph to start fresh. this.CurrentGraph = null; } @@ -515,7 +530,7 @@ private string GetResolveActorId(string name, string type) return ExternalCodeName; } - if (this.CollapseMachineInstances) + if (this.CollapseInstances) { return type; } @@ -681,10 +696,9 @@ private string GetLabel(string name, string type, string fullyQualifiedName) { // then this is probably an Actor, not a StateMachine. For Actors we can invent a state // name equal to the short name of the class, this then looks like a Constructor which is fine. - fullyQualifiedName = this.CollapseMachineInstances ? type : name; + fullyQualifiedName = this.CollapseInstances ? type : name; } - var len = fullyQualifiedName.Length; var index = fullyQualifiedName.LastIndexOfAny(TypeSeparators); if (index > 0) { @@ -872,19 +886,15 @@ internal int GetUniqueLinkIndex(GraphNode source, GraphNode target, string id) /// public override string ToString() { - using (var writer = new StringWriter()) - { - this.WriteDgml(writer, false); - return writer.ToString(); - } + using var writer = new StringWriter(); + this.WriteDgml(writer, false); + return writer.ToString(); } internal void SaveDgml(string graphFilePath, bool includeDefaultStyles) { - using (StreamWriter writer = new StreamWriter(graphFilePath, false, Encoding.UTF8)) - { - this.WriteDgml(writer, includeDefaultStyles); - } + using StreamWriter writer = new StreamWriter(graphFilePath, false, Encoding.UTF8); + this.WriteDgml(writer, includeDefaultStyles); } /// diff --git a/Source/Core/Configuration.cs b/Source/Core/Configuration.cs index ef929b7bf..75ff1ad30 100644 --- a/Source/Core/Configuration.cs +++ b/Source/Core/Configuration.cs @@ -11,23 +11,12 @@ namespace Microsoft.Coyote { #pragma warning disable CA1724 // Type names should not match namespaces /// - /// The Coyote project configurations. + /// The Coyote runtime and testing configuration. /// [DataContract] [Serializable] public class Configuration { - /// - /// The user-specified command to perform by the Coyote tool. - /// - [DataMember] - internal string ToolCommand; - - /// - /// Something to add to the PATH environment at test time. - /// - internal string AdditionalPaths { get; set; } - /// /// The output path. /// @@ -52,6 +41,12 @@ public class Configuration [DataMember] public string SchedulingStrategy { get; internal set; } + /// + /// A strategy-specific bound. + /// + [DataMember] + internal int StrategyBound; + /// /// Number of testing iterations. /// @@ -146,12 +141,6 @@ public class Configuration [DataMember] internal bool ConsiderDepthBoundHitAsBug; - /// - /// A strategy-specific bound. - /// - [DataMember] - internal int StrategyBound; - /// /// Value that controls the probability of triggering a timeout each time an operation gets delayed /// or a built-in timer gets scheduled during systematic testing. Decrease the value to increase the @@ -248,36 +237,18 @@ public class Configuration [DataMember] public LogSeverity LogLevel { get; internal set; } - /// - /// Enables code coverage reporting of a Coyote program. - /// - [DataMember] - internal bool ReportCodeCoverage; - /// /// Enables activity coverage reporting of a Coyote program. /// [DataMember] internal bool IsActivityCoverageReported; - /// - /// Enables activity coverage debugging. - /// - internal bool DebugActivityCoverage; - - /// - /// Is DGML graph showing all test iterations or just one "bug" iteration. - /// False means all, and True means only the iteration containing a bug. - /// - [DataMember] - internal bool IsDgmlBugGraph; - /// /// If specified, requests a DGML graph of the iteration that contains a bug, if a bug is found. /// This is different from a coverage activity graph, as it will also show actor instances. /// [DataMember] - internal bool IsDgmlGraphEnabled; + internal bool IsTraceVisualizationEnabled; /// /// Produce an XML formatted runtime log file. @@ -286,82 +257,9 @@ public class Configuration internal bool IsXmlLogEnabled; /// - /// If specified, requests a custom runtime log to be used instead of the default. - /// This is the AssemblyQualifiedName of the type to load. - /// - [DataMember] - internal string CustomActorRuntimeLogType; - - /// - /// Number of parallel systematic testing tasks. - /// By default it is 1 task. - /// - [DataMember] - internal uint ParallelBugFindingTasks; - - /// - /// Put a debug prompt at the beginning of each child TestProcess. - /// - [DataMember] - internal bool ParallelDebug; - - /// - /// Specify ip address if you want to use something other than localhost. - /// - [DataMember] - internal string TestingSchedulerIpAddress; - - /// - /// Do not automatically launch the TestingProcesses in parallel mode, instead wait for them - /// to be launched independently. - /// - [DataMember] - internal bool WaitForTestingProcesses; - - /// - /// Runs this process as a parallel systematic testing task. - /// - [DataMember] - internal bool RunAsParallelBugFindingTask; - - /// - /// The testing scheduler unique endpoint. + /// If true, then anonymized telemetry is enabled, else false. /// - [DataMember] - internal string TestingSchedulerEndPoint; - - /// - /// The unique testing process id. - /// - [DataMember] - internal uint TestingProcessId; - - /// - /// Additional assembly specifications to instrument for code coverage, besides those in the - /// dependency graph between and the Microsoft.Coyote DLLs. - /// Key is filename, value is whether it is a list file (true) or a single file (false). - /// - internal Dictionary AdditionalCodeCoverageAssemblies; - - /// - /// Enables colored console output. - /// - internal bool EnableColoredConsoleOutput; - - /// - /// If true, then environment exit will be disabled. - /// - internal bool DisableEnvironmentExit; - - /// - /// Enable Coyote sending Telemetry to Azure which is used to help improve the tool (default true). - /// - internal bool EnableTelemetry; - - /// - /// Optional location of app that can run as a telemetry server. - /// - internal string TelemetryServerPath; + internal bool IsTelemetryEnabled; /// /// Initializes a new instance of the class. @@ -387,12 +285,6 @@ protected Configuration() this.MaxUnfairSchedulingSteps = 10000; this.MaxFairSchedulingSteps = 100000; // 10 times the unfair steps. this.UserExplicitlySetMaxFairSchedulingSteps = false; - this.ParallelBugFindingTasks = 0; - this.ParallelDebug = false; - this.RunAsParallelBugFindingTask = false; - this.TestingSchedulerEndPoint = "CoyoteTestScheduler.4723bb92-c413-4ecb-8e8a-22eb2ba22234"; - this.TestingSchedulerIpAddress = null; - this.TestingProcessId = 0; this.ConsiderDepthBoundHitAsBug = false; this.StrategyBound = 0; this.TimeoutDelay = 10; @@ -409,25 +301,16 @@ protected Configuration() this.ScheduleFile = string.Empty; this.ScheduleTrace = string.Empty; - this.ReportCodeCoverage = false; this.IsActivityCoverageReported = false; - this.DebugActivityCoverage = false; + this.IsTraceVisualizationEnabled = false; + this.IsXmlLogEnabled = false; this.IsVerbose = false; this.IsDebugVerbosityEnabled = false; this.LogLevel = LogSeverity.Informational; - this.AdditionalCodeCoverageAssemblies = new Dictionary(); - - this.EnableColoredConsoleOutput = false; - this.DisableEnvironmentExit = true; - this.EnableTelemetry = true; - string optout = Environment.GetEnvironmentVariable("COYOTE_CLI_TELEMETRY_OPTOUT"); - if (optout is "1" || optout is "true") - { - this.EnableTelemetry = false; - } + this.IsTelemetryEnabled = optout != "1" && optout != "true"; } /// @@ -760,12 +643,14 @@ public Configuration WithActivityCoverageReported(bool isEnabled = true) } /// - /// Updates the configuration with DGML graph generation enabled or disabled. + /// Updates the configuration with trace visualization enabled or disabled. + /// If enabled, the testing engine can produce a DGML graph representing + /// an execution leading up to a bug. /// - /// If true, then enables DGML graph generation. - public Configuration WithDgmlGraphEnabled(bool isEnabled = true) + /// If true, then enables trace visualization. + public Configuration WithTraceVisualizationEnabled(bool isEnabled = true) { - this.IsDgmlGraphEnabled = isEnabled; + this.IsTraceVisualizationEnabled = isEnabled; return this; } @@ -784,7 +669,7 @@ public Configuration WithXmlLogEnabled(bool isEnabled = true) /// public Configuration WithTelemetryEnabled(bool isEnabled = true) { - this.EnableTelemetry = isEnabled; + this.IsTelemetryEnabled = isEnabled; return this; } diff --git a/Source/Core/IO/Debugging/Error.cs b/Source/Core/IO/Debugging/Error.cs index a22287c27..826489cad 100644 --- a/Source/Core/IO/Debugging/Error.cs +++ b/Source/Core/IO/Debugging/Error.cs @@ -29,29 +29,6 @@ public static void Report(string format, params object[] args) Console.Error.WriteLine(string.Empty); } - /// - /// Reports a generic error to the user and exits. - /// - public static void ReportAndExit(string value) - { - Write(ConsoleColor.Red, "Error: "); - Write(ConsoleColor.Yellow, value); - Console.Error.WriteLine(string.Empty); - Environment.Exit(1); - } - - /// - /// Reports a generic error to the user and exits. - /// - public static void ReportAndExit(string format, params object[] args) - { - string message = string.Format(CultureInfo.InvariantCulture, format, args); - Write(ConsoleColor.Red, "Error: "); - Write(ConsoleColor.Yellow, message); - Console.Error.WriteLine(string.Empty); - Environment.Exit(1); - } - /// /// Writes the specified string value to the output stream. /// diff --git a/Source/Core/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs b/Source/Core/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs index 645cf1691..9156e3072 100644 --- a/Source/Core/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs +++ b/Source/Core/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs @@ -3,7 +3,6 @@ using System; using System.Runtime.CompilerServices; -using System.Threading; using System.Threading.Tasks; using SystemCompiler = System.Runtime.CompilerServices; diff --git a/Source/Core/Testing/Interleaving/ReplayStrategy.cs b/Source/Core/Testing/Interleaving/ReplayStrategy.cs index 4074c5d6d..fd007842f 100644 --- a/Source/Core/Testing/Interleaving/ReplayStrategy.cs +++ b/Source/Core/Testing/Interleaving/ReplayStrategy.cs @@ -70,11 +70,7 @@ internal override bool GetNextOperation(IEnumerable ops, Co } catch (InvalidOperationException ex) { - if (!this.Configuration.DisableEnvironmentExit) - { - Error.ReportAndExit(ex.Message); - } - + Error.Report(ex.Message); next = null; return false; } @@ -111,11 +107,7 @@ internal override bool GetNextBooleanChoice(ControlledOperation current, int max } catch (InvalidOperationException ex) { - if (!this.Configuration.DisableEnvironmentExit) - { - Error.ReportAndExit(ex.Message); - } - + Error.Report(ex.Message); next = false; return false; } @@ -153,11 +145,7 @@ internal override bool GetNextIntegerChoice(ControlledOperation current, int max } catch (InvalidOperationException ex) { - if (!this.Configuration.DisableEnvironmentExit) - { - Error.ReportAndExit(ex.Message); - } - + Error.Report(ex.Message); next = 0; return false; } diff --git a/Source/Test/Rewriting/Passes/Rewriting/MSTestRewritingPass.cs b/Source/Test/Rewriting/Passes/Rewriting/MSTestRewritingPass.cs index c395b25fb..31fa843d1 100644 --- a/Source/Test/Rewriting/Passes/Rewriting/MSTestRewritingPass.cs +++ b/Source/Test/Rewriting/Passes/Rewriting/MSTestRewritingPass.cs @@ -252,10 +252,10 @@ internal void RewriteTestMethod(MethodDefinition method, MethodDefinition testMe this.Configuration.IsVerbose, this.Configuration.LogLevel); } - if (!this.Configuration.EnableTelemetry) + if (!this.Configuration.IsTelemetryEnabled) { this.EmitMethodCall(processor, resolvedConfigurationType, "WithTelemetryEnabled", - this.Configuration.EnableTelemetry); + this.Configuration.IsTelemetryEnabled); } processor.Emit(OpCodes.Ldarg_0); diff --git a/Source/Test/Rewriting/Passes/Rewriting/RewritingPass.cs b/Source/Test/Rewriting/Passes/Rewriting/RewritingPass.cs index c2173dfe6..5afe0500d 100644 --- a/Source/Test/Rewriting/Passes/Rewriting/RewritingPass.cs +++ b/Source/Test/Rewriting/Passes/Rewriting/RewritingPass.cs @@ -7,7 +7,6 @@ using Mono.Cecil; using Mono.Cecil.Cil; using Mono.Cecil.Rocks; -using Mono.Collections.Generic; namespace Microsoft.Coyote.Rewriting { diff --git a/Source/Test/Rewriting/Passes/Rewriting/Types/MethodBodyTypeRewritingPass.cs b/Source/Test/Rewriting/Passes/Rewriting/Types/MethodBodyTypeRewritingPass.cs index 3d14391c3..40b60ae06 100644 --- a/Source/Test/Rewriting/Passes/Rewriting/Types/MethodBodyTypeRewritingPass.cs +++ b/Source/Test/Rewriting/Passes/Rewriting/Types/MethodBodyTypeRewritingPass.cs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using System; using System.Collections.Generic; using Microsoft.Coyote.IO; using Mono.Cecil; diff --git a/Source/Test/SmartSockets/SmartSocketClient.cs b/Source/Test/SmartSockets/SmartSocketClient.cs deleted file mode 100644 index 9fdd3520f..000000000 --- a/Source/Test/SmartSockets/SmartSocketClient.cs +++ /dev/null @@ -1,596 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Net; -using System.Net.NetworkInformation; -using System.Net.Sockets; -using System.Runtime.Serialization; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.Coyote.SmartSockets -{ - /// - /// This class wraps the Socket class providing some useful semantics like FindServerAsync - /// which looks for the UDP message broadcast by the SmartSocketServer. It also provides a - /// useful SendReceiveAsync message that synchronously waits for a response from the server. - /// It also supports serializing custom message objects via the DataContractSerializer using - /// known types provided in your SmartSocketTypeResolver. - /// - internal class SmartSocketClient : IDisposable - { - private readonly Socket Client; - private readonly NetworkStream Stream; - private readonly SmartSocketServer Server; - private bool Closed; - private readonly SmartSocketTypeResolver Resolver; - private readonly DataContractSerializer Serializer; - - // Some standard message ids used for socket bookkeeping. - public const string DisconnectMessageId = "DisconnectMessageId.3d9cd318-fcae-4a4f-ae63-34907be2700a"; - public const string ConnectedMessageId = "ConnectedMessageId.822280ed-26f5-4cdd-b45c-412e05d1005a"; - public const string MessageAck = "MessageAck.822280ed-26f5-4cdd-b45c-412e05d1005a"; - public const string ErrorMessageId = "ErrorMessageId.385ff3c1-84d8-491a-a8b3-e2a9e8f0e256"; - public const string OpenBackChannelMessageId = "OpenBackChannel.bd89da83-95c8-42e7-bf4e-6e7d0168754a"; - - internal SmartSocketClient(SmartSocketServer server, Socket client, SmartSocketTypeResolver resolver) - { - this.Client = client; - this.Stream = new NetworkStream(client); - this.Server = server; - this.Resolver = resolver; - client.NoDelay = true; - - DataContractSerializerSettings settings = new DataContractSerializerSettings(); - settings.DataContractResolver = this.Resolver; - settings.PreserveObjectReferences = true; - this.Serializer = new DataContractSerializer(typeof(MessageWrapper), settings); - } - - internal Socket Socket => this.Client; - - public string Name { get; set; } - - /// - /// Find a SmartSocketServer on the local network using UDP broadcast. This will block - /// waiting for a server to respond or until you cancel using the CancellationToken. - /// - /// The connected client or null if task is cancelled. - public static async Task FindServerAsync(string serviceName, string clientName, SmartSocketTypeResolver resolver, - CancellationToken token, string udpGroupAddress = "226.10.10.2", int udpGroupPort = 37992) - { - return await Task.Run(async () => - { - string localHost = FindLocalHostName(); - if (localHost is null) - { - return null; - } - - while (!token.IsCancellationRequested) - { - try - { - var groupAddr = IPAddress.Parse(udpGroupAddress); - IPEndPoint remoteEP = new IPEndPoint(groupAddr, udpGroupPort); - UdpClient udpClient = new UdpClient(0); - MemoryStream ms = new MemoryStream(); - BinaryWriter writer = new BinaryWriter(ms); - writer.Write(serviceName.Length); - writer.Write(serviceName); - byte[] bytes = ms.ToArray(); - udpClient.Send(bytes, bytes.Length, remoteEP); - - CancellationTokenSource receiveTaskSource = new CancellationTokenSource(); - Task receiveTask = udpClient.ReceiveAsync(); - if (receiveTask.Wait(5000, receiveTaskSource.Token)) - { - UdpReceiveResult result = receiveTask.Result; - IPEndPoint serverEP = result.RemoteEndPoint; - byte[] buffer = result.Buffer; - BinaryReader reader = new BinaryReader(new MemoryStream(buffer)); - int len = reader.ReadInt32(); - string addr = reader.ReadString(); - string[] parts = addr.Split(':'); - if (parts.Length is 2) - { - var a = IPAddress.Parse(parts[0]); - SmartSocketClient client = await ConnectAsync(new IPEndPoint(a, int.Parse(parts[1])), clientName, resolver); - if (client != null) - { - client.ServerName = serviceName; - client.Name = localHost; - return client; - } - } - } - else - { - receiveTaskSource.Cancel(); - } - } - catch (Exception ex) - { - Debug.WriteLine("Something went wrong with Udp connection: " + ex.Message); - } - } - - return null; - }); - } - - /// - /// Create another socket that will allow the server to send messages to the client any time. - /// It is expected you will start a ReceiveAsync loop on this server object to process - /// those messages. - /// - /// An event handler to invoke when the server opens the back channel. - /// New server object that will get one ClientConnected event when the remote server connects. - public async Task OpenBackChannel(EventHandler connectedHandler) - { - IPEndPoint ipe = (IPEndPoint)this.Socket.LocalEndPoint; - // start a new server that does not use UDP. - var server = SmartSocketServer.StartServer(this.Name, this.Resolver, ipe.Address.ToString(), null, 0); - server.ClientConnected += connectedHandler; - int port = server.EndPoint.Port; - // tell the server we've opened another channel and pass the "port" number - var response = await this.SendReceiveAsync(new SocketMessage(OpenBackChannelMessageId, this.Name + ":" + port)); - if (response.Id == ErrorMessageId) - { - throw new InvalidOperationException(response.Message); - } - - return server; - } - - internal static async Task ConnectAsync(IPEndPoint serverEP, string clientName, SmartSocketTypeResolver resolver) - { - Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - bool connected = false; - CancellationTokenSource src = new CancellationTokenSource(); - try - { - Task task = Task.Run(() => - { - try - { - client.Connect(serverEP); - connected = true; - } - catch (Exception e) - { - Debug.WriteLine("Connect exception: " + e.Message); - } - }, src.Token); - - // give it 30 seconds to connect... - if (!task.Wait(60000)) - { - src.Cancel(); - } - } - catch (TaskCanceledException) - { - // move on... - } - - if (connected) - { - var result = new SmartSocketClient(null, client, resolver) - { - Name = clientName, - ServerName = GetHostName(serverEP.Address) - }; - SocketMessage response = await result.SendReceiveAsync(new SocketMessage(ConnectedMessageId, clientName)); - return result; - } - - return null; - } - - private static string GetHostName(IPAddress addr) - { - try - { - var entry = Dns.GetHostEntry(addr); - if (!string.IsNullOrEmpty(entry.HostName)) - { - return entry.HostName; - } - } - catch (Exception) - { - // this can fail if machines are in different domains. - } - - return addr.ToString(); - } - - internal static string FindLocalHostName() - { - try - { - IPHostEntry e = Dns.GetHostEntry(IPAddress.Loopback); - return e.HostName; - } - catch (Exception) - { - // ignore failures to do with DNS lookups - } - - return null; - } - - internal static List FindLocalIpAddresses() - { - List ipAddresses = new List(); - foreach (NetworkInterface ni in NetworkInterface.GetAllNetworkInterfaces()) - { - if (ni.OperationalStatus == OperationalStatus.Up && - ni.SupportsMulticast && ni.NetworkInterfaceType != NetworkInterfaceType.Loopback - && ni.NetworkInterfaceType != NetworkInterfaceType.Tunnel) - { - var props = ni.GetIPProperties(); - if (props.IsDnsEnabled || props.IsDynamicDnsEnabled) - { - IPHostEntry e = Dns.GetHostEntry(IPAddress.Loopback); - foreach (var addr in e.AddressList) - { - ipAddresses.Add(addr.ToString()); - } - - return ipAddresses; - } - } - } - - ipAddresses.Add("127.0.0.1"); - return ipAddresses; - } - - public string ServerName { get; set; } - - public bool IsConnected => !this.Closed; - - /// - /// If OpenBackChannel is called, and the server supports it then this property will - /// be defined when that channel is connected. - /// - public SmartSocketClient BackChannel { get; internal set; } - - /// - /// This event is raised if a socket error is detected. - /// - public event EventHandler Error; - - /// - /// This even is raised if the socket is disconnected. - /// - public event EventHandler Disconnected; - - internal async void Close() - { - if (this.Closed) - { - return; - } - - try - { - await this.SendAsync(new SocketMessage(DisconnectMessageId, this.Name)); - - this.Closed = true; - - using (this.Client) - { - this.Client.Close(); - } - } - catch (Exception) - { - // ignore failures on close. - } - } - - private void OnError(Exception ex) - { - Exception inner = ex; - while (inner != null) - { - if (inner is SocketException se && se.SocketErrorCode == SocketError.ConnectionReset) - { - // we're toast! - if (this.Server != null) - { - this.Server.RemoveClient(this); - } - - this.Closed = true; - } - - if (ex is ObjectDisposedException) - { - this.Closed = true; - } - - inner = inner.InnerException; - } - - if (this.Error != null) - { - this.Error(this, ex); - } - } - - [DataContract] - internal class MessageWrapper - { - [DataMember] - public object Message { get; set; } - } - - /// - /// Send a message back to the client. - /// - /// The response message. - public async Task SendReceiveAsync(SocketMessage msg) - { - if (this.Closed) - { - throw new SocketException((int)SocketError.NotConnected); - } - - // must serialize this send/response sequence, cannot interleave them! - using (await this.GetSendLock()) - { - return await Task.Run(async () => - { - try - { - await this.InternalSendAsync(msg); - - SocketMessage response = await this.InternalReceiveAsync(); - return response; - } - catch (Exception ex) - { - // is the socket dead? - this.OnError(ex); - } - - return null; - }); - } - } - - /// - /// Send a message and do not wait for a response. - /// - /// The response message. - public async Task SendAsync(SocketMessage msg) - { - // must serialize this send/response sequence, cannot interleave them! - using (await this.GetSendLock()) - { - await this.InternalSendAsync(msg); - } - } - - public async Task InternalSendAsync(SocketMessage msg) - { - if (this.Closed) - { - throw new SocketException((int)SocketError.NotConnected); - } - - // get the buffer containing the serialized message. - await Task.Run(() => - { - try - { - // Wrap the message in a MessageWrapper and send it - MemoryStream ms = new MemoryStream(); - this.Serializer.WriteObject(ms, new MessageWrapper() { Message = msg }); - - byte[] buffer = ms.ToArray(); - - BinaryWriter streamWriter = new BinaryWriter(this.Stream, Encoding.UTF8, true); - streamWriter.Write(buffer.Length); - streamWriter.Write(buffer, 0, buffer.Length); - } - catch (Exception ex) - { - // is the socket dead? - this.OnError(ex); - } - }); - } - - private void OnClosed() - { - this.Closed = true; - if (this.Disconnected != null) - { - this.Disconnected(this, EventArgs.Empty); - } - } - - /// - /// Receive one message from the socket. This call blocks until a message has arrived. - /// - public async Task ReceiveAsync() - { - using (await this.GetSendLock()) - { - return await this.InternalReceiveAsync(); - } - } - - private async Task InternalReceiveAsync() - { - if (this.Closed) - { - throw new SocketException((int)SocketError.NotConnected); - } - - SocketMessage msg = null; - try - { - using (BinaryReader streamReader = new BinaryReader(this.Stream, Encoding.UTF8, true)) - { - int len = streamReader.ReadInt32(); - byte[] block = streamReader.ReadBytes(len); - - object result = null; - if (len != block.Length) - { - // Can happen if the process at the other side of this socket was terminated. - // If we don't have the exact requested bytes then we cannot deserialize it. - } - else - { - try - { - result = this.Serializer.ReadObject(new MemoryStream(block)); - } - catch (Exception) - { - // This can also happen when process on other side is terminated, the last network - // packet can be scrambled. This is usually just the DisconnectMessageId which is - // ignorable. - } - } - - if (result is MessageWrapper wrapper && wrapper.Message is SocketMessage) - { - msg = (SocketMessage)wrapper.Message; - if (msg.Id == DisconnectMessageId) - { - // client is politely saying good bye... - this.OnClosed(); - } - else if (msg.Id == ConnectedMessageId) - { - // must send an acknowledgement of the connect message - this.Name = msg.Sender; - await this.SendAsync(new SocketMessage(MessageAck, this.Name)); - } - else if (msg.Id == OpenBackChannelMessageId && this.Server != null) - { - // client is requesting a back channel. - await this.HandleBackchannelRequest(msg); - } - } - } - } - catch (EndOfStreamException) - { - this.OnClosed(); - } - catch (IOException ioe) - { - SocketException se = ioe.InnerException as SocketException; - if (se.SocketErrorCode == SocketError.ConnectionReset) - { - this.OnClosed(); - } - } - catch (Exception ex) - { - this.OnError(ex); - } - - return msg; - } - - private async Task HandleBackchannelRequest(SocketMessage msg) - { - string[] parts = msg.Sender.Split(':'); - if (parts.Length is 2) - { - if (int.TryParse(parts[1], out int port)) - { - bool rc = await this.Server.OpenBackChannel(this, port); - if (rc) - { - await this.SendAsync(new SocketMessage(MessageAck, this.Name)); - return; - } - else - { - await this.SendAsync(new SocketMessage(ErrorMessageId, this.Name) - { - Message = "Server is not expecting a back channel" - }); - return; - } - } - } - - await this.SendAsync(new SocketMessage(ErrorMessageId, this.Name) - { - Message = "Valid port number was not found in backchannel message" - }); - } - - public void Dispose() - { - this.Close(); - - GC.SuppressFinalize(this); - } - - ~SmartSocketClient() - { - this.Close(); - } - - private readonly SendLock Lock = new SendLock(); - - private async Task GetSendLock() - { - while (this.Lock.Locked) - { - await Task.Delay(100); - lock (this.Lock) - { - if (!this.Lock.Locked) - { - this.Lock.Locked = true; - return new ReleaseLock(this.Lock); - } - } - } - - return null; - } - - internal class SendLock - { - public bool Locked { get; set; } - } - - internal class ReleaseLock : IDisposable - { - private readonly SendLock Lock; - - public ReleaseLock(SendLock sendLock) - { - this.Lock = sendLock; - } - - public void Dispose() - { - lock (this.Lock) - { - this.Lock.Locked = false; - } - } - } - } -} diff --git a/Source/Test/SmartSockets/SmartSocketServer.cs b/Source/Test/SmartSockets/SmartSocketServer.cs deleted file mode 100644 index bc748a82e..000000000 --- a/Source/Test/SmartSockets/SmartSocketServer.cs +++ /dev/null @@ -1,366 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Net; -using System.Net.Sockets; -using System.Threading.Tasks; - -namespace Microsoft.Coyote.SmartSockets -{ - /// - /// This class sets up a UDP broadcaster so clients on the same network can find the server by - /// a given string name, no fussing about with ip addresses and ports.It then listens for - /// new clients to connect and spins off ClientConnected messages so your app can process the - /// server side of each conversation.Your application server then can handle any number of - /// clients at the same time, each client will have their own SmartSocketClient on different ports. - /// If the client goes away, the ClientDisconnected event is raised so the server can cleanup. - /// - internal class SmartSocketServer - { - private bool Stopped; - private Socket Listener; - private readonly string ServiceName; - private readonly IPEndPoint IpAddress; - private readonly List Clients = new List(); - private readonly SmartSocketTypeResolver Resolver; - private UdpClient UdpListener; - private SocketAsyncEventArgs acceptArgs; - - /// - /// Address for UDP group. - /// - public IPAddress GroupAddress { get; internal set; } - - /// - /// Port used for UDP broadcasts. - /// - public int GroupPort { get; internal set; } - - /// - /// The end point we are listening on (valid after calling StartServer). - /// - public IPEndPoint EndPoint { get; set; } - - /// - /// Raised when a new client is connected - /// - public event EventHandler ClientConnected; - - /// - /// Raised when the given client disconnects - /// - public event EventHandler ClientDisconnected; - - /// - /// Raised when client requests a back channel for server to communicate independently with the client - /// The given SmartSocketClient will have a BackChannel property set to a new SmartSocketClient that - /// the server can use to send messages to the client. - /// - public event EventHandler BackChannelOpened; - - /// - /// Initializes a new instance of the class. - /// Construct a new SmartSocketServer. - /// - /// The name the client will check in UDP broadcasts to make sure it is connecting to the right server. - /// A way of providing custom Message types for serialization. - /// An optional ipAddress so you can decide which network interface to use. - /// An optional UDP group address. - /// An optional UDP group port. - private SmartSocketServer(string name, SmartSocketTypeResolver resolver, string ipAddress = "127.0.0.1:0", - string udpGroupAddress = "226.10.10.2", int udpGroupPort = 37992) - { - this.ServiceName = name; - this.Resolver = resolver; - if (ipAddress.Contains(':')) - { - string[] parts = ipAddress.Split(':'); - if (parts.Length is 2 && int.TryParse(parts[1], out int port)) - { - this.IpAddress = new IPEndPoint(IPAddress.Parse(parts[0]), port); - } - else - { - throw new ArgumentException("ipAddress is not a valid format"); - } - } - else - { - this.IpAddress = new IPEndPoint(IPAddress.Parse(ipAddress), 0); - } - - if (!string.IsNullOrEmpty(udpGroupAddress)) - { - this.GroupAddress = IPAddress.Parse(udpGroupAddress); - this.GroupPort = udpGroupPort; - } - } - - /// - /// Start a new server that listens for connections from anyone. - /// - /// The unique name of the server. - /// For resolving custom message types received from the client. - /// Determines which local network interface to use. - /// Optional request to setup UDP listener, pass null if you don't want that. - /// Optional port required if you provide udpGroupAddress. - /// Returns the new server object. - public static SmartSocketServer StartServer(string name, SmartSocketTypeResolver resolver, string ipAddress, - string udpGroupAddress = "226.10.10.2", int udpGroupPort = 37992) - { - if (string.IsNullOrEmpty(ipAddress)) - { - ipAddress = "127.0.0.1:0"; - } - - SmartSocketServer server = new SmartSocketServer(name, resolver, ipAddress, udpGroupAddress, udpGroupPort); - server.StartListening(); - return server; - } - - /// - /// Start listening for connections from anyone. - /// - private void StartListening() - { - this.Listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - IPEndPoint ep = this.IpAddress; - this.Listener.Bind(ep); - - IPEndPoint ip = this.Listener.LocalEndPoint as IPEndPoint; - this.EndPoint = ip; - this.Listener.Listen(10); - - // now start a background thread to process incoming requests. - Task.Run(this.Run); - - if (this.GroupAddress != null) - { - // Start the UDP listener thread - Task.Run(this.UdpListenerThread); - } - } - - private void UdpListenerThread() - { - try - { - var localHost = SmartSocketClient.FindLocalHostName(); - List addresses = SmartSocketClient.FindLocalIpAddresses(); - if (localHost is null || addresses.Count is 0) - { - return; // no network. - } - - IPEndPoint remoteEP = new IPEndPoint(this.GroupAddress, this.GroupPort); - this.UdpListener = new UdpClient(this.GroupPort); - this.UdpListener.JoinMulticastGroup(this.GroupAddress); - while (true) - { - byte[] data = this.UdpListener.Receive(ref remoteEP); - if (data != null) - { - BinaryReader reader = new BinaryReader(new MemoryStream(data)); - int len = reader.ReadInt32(); - string msg = reader.ReadString(); - if (msg == this.ServiceName) - { - // send response back with info on how to connect to this server. - IPEndPoint localEp = (IPEndPoint)this.Listener.LocalEndPoint; - string addr = localEp.ToString(); - MemoryStream ms = new MemoryStream(); - BinaryWriter writer = new BinaryWriter(ms); - writer.Write(addr.Length); - writer.Write(addr); - writer.Flush(); - byte[] buffer = ms.ToArray(); - this.UdpListener.Send(buffer, buffer.Length, remoteEP); - } - } - } - } - catch (Exception) - { - // UdpListenerThread failed - } - } - - /// - /// Send a message to all connected clients. - /// - /// The message to send. - public async Task BroadcastAsync(SocketMessage message) - { - SmartSocketClient[] snapshot = null; - lock (this.Clients) - { - snapshot = this.Clients.ToArray(); - } - - foreach (var client in snapshot) - { - await client.SendAsync(message); - } - } - - /// - /// Call this method on a background thread to listen to our port. - /// - internal void Run() - { - if (this.acceptArgs is null) - { - this.acceptArgs = new SocketAsyncEventArgs(); - this.acceptArgs.Completed += this.OnAcceptComplete; - } - - if (!this.Stopped) - { - try - { - this.Listener.AcceptAsync(this.acceptArgs); - } - catch (Exception) - { - // listener was probably closed then, which means we've probably been stopped. - Debug.WriteLine("Listener is gone"); - } - } - } - - private void OnAcceptComplete(object sender, SocketAsyncEventArgs e) - { - if (this.acceptArgs == e) - { - this.acceptArgs = null; - Socket client = e.AcceptSocket; - this.OnAccept(client); - this.Run(); - } - } - - private void OnAccept(Socket client) - { - IPEndPoint ep1 = client.RemoteEndPoint as IPEndPoint; - SmartSocketClient proxy = new SmartSocketClient(this, client, this.Resolver) - { - Name = ep1.ToString(), - ServerName = SmartSocketClient.FindLocalHostName() - }; - - proxy.Disconnected += this.OnClientDisconnected; - - SmartSocketClient[] snapshot = null; - - lock (this.Clients) - { - snapshot = this.Clients.ToArray(); - } - - foreach (SmartSocketClient s in snapshot) - { - IPEndPoint ep2 = s.Socket.RemoteEndPoint as IPEndPoint; - if (ep1 == ep2) - { - // can only have one client using this end point. - this.RemoveClient(s); - } - } - - lock (this.Clients) - { - this.Clients.Add(proxy); - } - - if (this.ClientConnected != null) - { - this.ClientConnected(this, proxy); - } - } - - private void OnClientDisconnected(object sender, EventArgs e) - { - SmartSocketClient client = (SmartSocketClient)sender; - this.RemoveClient(client); - } - - internal void RemoveClient(SmartSocketClient client) - { - bool found = false; - lock (this.Clients) - { - found = this.Clients.Contains(client); - this.Clients.Remove(client); - } - - if (found && this.ClientDisconnected != null) - { - this.ClientDisconnected(this, client); - } - } - - /// - /// Call this method to stop the background thread, it is good to do this before your app shuts down. - /// This will also send a Disconnect message to all the clients so they know the server is gone. - /// - public void Stop() - { - this.Stopped = true; - using (this.Listener) - { - try - { - if (this.acceptArgs != null) - { - this.acceptArgs.Dispose(); - this.acceptArgs = null; - } - } - catch (Exception) - { - } - } - - this.Listener = null; - - SmartSocketClient[] snapshot = null; - lock (this.Clients) - { - snapshot = this.Clients.ToArray(); - } - - foreach (SmartSocketClient client in snapshot) - { - client.Close(); - } - - lock (this.Clients) - { - this.Clients.Clear(); - } - } - - internal async Task OpenBackChannel(SmartSocketClient client, int port) - { - if (this.BackChannelOpened != null) - { - IPEndPoint ipe = (IPEndPoint)client.Socket.RemoteEndPoint; - IPEndPoint endPoint = new IPEndPoint(ipe.Address, port); - SmartSocketClient channel = await SmartSocketClient.ConnectAsync(endPoint, this.ServiceName, this.Resolver); - client.BackChannel = channel; - this.BackChannelOpened(this, client); - return true; - } - else - { - // server is not expecting a backchannel! - return false; - } - } - } -} diff --git a/Source/Test/SmartSockets/SmartSocketTypeResolver.cs b/Source/Test/SmartSockets/SmartSocketTypeResolver.cs deleted file mode 100644 index 89f6baab5..000000000 --- a/Source/Test/SmartSockets/SmartSocketTypeResolver.cs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.Serialization; -using System.Xml; - -namespace Microsoft.Coyote.SmartSockets -{ - internal class SmartSocketTypeResolver : DataContractResolver - { - private readonly Dictionary TypeMap = new Dictionary(); - - public SmartSocketTypeResolver() - { - this.AddBaseTypes(); - } - - public SmartSocketTypeResolver(params Type[] knownTypes) - { - this.AddTypes(knownTypes); - } - - public SmartSocketTypeResolver(IEnumerable knownTypes) - { - this.AddTypes(knownTypes); - } - - private void AddTypes(IEnumerable knownTypes) - { - this.AddBaseTypes(); - foreach (var t in knownTypes) - { - this.TypeMap[t.FullName] = t; - } - } - - private void AddBaseTypes() - { - foreach (var t in new Type[] { typeof(SocketMessage) }) - { - this.TypeMap[t.FullName] = t; - } - } - - public override Type ResolveName(string typeName, string typeNamespace, Type declaredType, DataContractResolver knownTypeResolver) - { - string fullName = typeName; - if (!string.IsNullOrEmpty(typeNamespace)) - { - Uri uri = new Uri(typeNamespace); - string clrNamespace = uri.Segments.Last(); - fullName = clrNamespace + "." + typeName; - } - - if (!this.TypeMap.TryGetValue(fullName, out Type t)) - { - t = knownTypeResolver.ResolveName(typeName, typeNamespace, declaredType, knownTypeResolver); - } - - return t; - } - - public override bool TryResolveType(Type type, Type declaredType, DataContractResolver knownTypeResolver, out XmlDictionaryString typeName, out XmlDictionaryString typeNamespace) - { - return knownTypeResolver.TryResolveType(type, declaredType, knownTypeResolver, out typeName, out typeNamespace); - } - } -} diff --git a/Source/Test/SmartSockets/SocketMessage.cs b/Source/Test/SmartSockets/SocketMessage.cs deleted file mode 100644 index 343dffbaa..000000000 --- a/Source/Test/SmartSockets/SocketMessage.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System.Runtime.Serialization; - -namespace Microsoft.Coyote.SmartSockets -{ - /// - /// This is the base class for messages send over SmartSockets. - /// - [DataContract] - internal class SocketMessage - { - public SocketMessage(string id, string sender) - { - this.Id = id; - this.Sender = sender; - } - - /// - /// This is like a message type, class of message or are completely unique id. - /// It's up to you how you want to use it. - /// - [DataMember] - public string Id { get; set; } - - /// - /// This will be filled automatically by the SmartSocket class so you. - /// - [DataMember] - public string Sender { get; set; } - - /// - /// An optional string message. - /// - [DataMember] - public string Message { get; set; } - } -} diff --git a/Source/Test/SystematicTesting/Reports/TestReport.cs b/Source/Test/SystematicTesting/Reports/TestReport.cs index cdedbdc71..c330426af 100644 --- a/Source/Test/SystematicTesting/Reports/TestReport.cs +++ b/Source/Test/SystematicTesting/Reports/TestReport.cs @@ -374,7 +374,7 @@ public string GetText(Configuration configuration, string prefix = "") this.TotalControlledOperations, this.TotalControlledOperations is 1 ? string.Empty : "s", this.MinControlledOperations, - (int)(this.TotalControlledOperations / totalExploredSchedules), + this.TotalControlledOperations / totalExploredSchedules, this.MaxControlledOperations); } @@ -385,7 +385,7 @@ public string GetText(Configuration configuration, string prefix = "") "{0} Degree of concurrency: {1} (min), {2} (avg), {3} (max).", prefix.Equals("...") ? "....." : prefix, this.MinConcurrencyDegree, - (int)(this.TotalConcurrencyDegree / totalExploredSchedules), + this.TotalConcurrencyDegree / totalExploredSchedules, this.MaxConcurrencyDegree); } @@ -396,7 +396,7 @@ public string GetText(Configuration configuration, string prefix = "") "{0} Number of scheduling decisions in fair terminating schedules: {1} (min), {2} (avg), {3} (max).", prefix.Equals("...") ? "....." : prefix, this.MinExploredFairSteps < 0 ? 0 : this.MinExploredFairSteps, - (int)(this.TotalExploredFairSteps / this.NumOfExploredFairSchedules), + this.TotalExploredFairSteps / this.NumOfExploredFairSchedules, this.MaxExploredFairSteps < 0 ? 0 : this.MaxExploredFairSteps); if (configuration.MaxUnfairSchedulingSteps > 0 && diff --git a/Source/Test/SystematicTesting/TestingEngine.cs b/Source/Test/SystematicTesting/TestingEngine.cs index edb725984..6fd8b1197 100644 --- a/Source/Test/SystematicTesting/TestingEngine.cs +++ b/Source/Test/SystematicTesting/TestingEngine.cs @@ -9,7 +9,6 @@ using System.Reflection; using System.Runtime.ExceptionServices; using System.Text; -using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using System.Xml; @@ -41,6 +40,11 @@ public sealed class TestingEngine /// private const string LearnAboutTelemetryUrl = "https://aka.ms/coyote-telemetry"; + /// + /// The client used to optionally send anonymized telemetry data. + /// + private static TelemetryClient TelemetryClient; + /// /// The project configuration. /// @@ -65,12 +69,7 @@ public sealed class TestingEngine /// /// The profiler. /// - private readonly Profiler Profiler; - - /// - /// The client used to optionally send anonymized telemetry data. - /// - private static CoyoteTelemetryClient TelemetryClient; + internal Profiler Profiler { get; private set; } /// /// The testing task cancellation token source. @@ -126,9 +125,9 @@ public ILogger Logger } /// - /// A graph of the actors, state machines and events of a single test iteration. + /// The DGML graph of the execution path explored in the last iteration. /// - private Graph Graph; + private Graph LastExecutionGraph; /// /// Contains a single iteration of XML log output in the case where the IsXmlLogEnabled @@ -156,25 +155,16 @@ public ILogger Logger /// public static TestingEngine Create(Configuration configuration) { - TestMethodInfo testMethodInfo = null; - try { - testMethodInfo = TestMethodInfo.Create(configuration); + TestMethodInfo testMethodInfo = TestMethodInfo.Create(configuration); + return new TestingEngine(configuration, testMethodInfo); } catch (Exception ex) { - if (configuration.DisableEnvironmentExit) - { - throw; - } - else - { - Error.ReportAndExit(ex.Message); - } + Error.Report(ex.Message); + throw; } - - return new TestingEngine(configuration, testMethodInfo); } /// @@ -255,29 +245,15 @@ private TestingEngine(Configuration configuration, TestMethodInfo testMethodInfo error = "Replaying a bug trace is not currently supported in systematic fuzzing."; } - if (configuration.SchedulingStrategy is "portfolio") - { - error = "Portfolio testing strategy is only available in parallel testing."; - } - if (!string.IsNullOrEmpty(error)) { - if (configuration.DisableEnvironmentExit) - { - throw new Exception(error); - } - else - { - Error.ReportAndExit(error); - } + Error.Report(error); + throw new InvalidOperationException(error); } this.Scheduler = OperationScheduler.Setup(configuration); - if (TelemetryClient is null) - { - TelemetryClient = new CoyoteTelemetryClient(this.Configuration); - } + TelemetryClient = TelemetryClient.GetOrCreate(this.Configuration); } /// @@ -285,18 +261,21 @@ private TestingEngine(Configuration configuration, TestMethodInfo testMethodInfo /// public void Run() { - bool isReplaying = this.Scheduler.IsReplayingSchedule; - try { - TelemetryClient.TrackEventAsync(isReplaying ? "replay" : "test").Wait(); + if (this.Configuration.IsTelemetryEnabled) + { + this.Logger.WriteLine(LogSeverity.Important, $"..... Anonymized telemetry is enabled, see {LearnAboutTelemetryUrl}."); + } - if (Debugger.IsAttached) + if (!this.IsTestRewritten()) { - TelemetryClient.TrackEventAsync(isReplaying ? "replay-debug" : "test-debug").Wait(); + // TODO: eventually will throw an exception; we allow this for now. + this.Logger.WriteLine(LogSeverity.Error, + $"... Assembly is not rewritten for testing, see {LearnAboutRewritingUrl}."); } - Task task = this.CreateTestingTask(); + Task task = this.CreateTestingTask(this.TestMethodInfo); if (this.Configuration.TestingTimeout > 0) { this.CancellationTokenSource.CancelAfter( @@ -314,7 +293,7 @@ public void Run() { if (this.CancellationTokenSource.IsCancellationRequested) { - this.Logger.WriteLine(LogSeverity.Warning, $"... Task {this.Configuration.TestingProcessId} timed out."); + this.Logger.WriteLine(LogSeverity.Warning, $"... Test timed out."); } } catch (AggregateException aex) @@ -328,29 +307,16 @@ public void Run() if (aex.InnerException is FileNotFoundException) { - if (this.Configuration.DisableEnvironmentExit) - { - throw aex.InnerException; - } - else - { - Error.ReportAndExit($"{aex.InnerException.Message}"); - } + Error.Report($"{aex.InnerException.Message}"); + throw; } - if (this.Configuration.DisableEnvironmentExit) - { - throw aex.InnerException; - } - else - { - Error.ReportAndExit("Exception thrown during testing outside the context of an actor, " + - "possibly in a test method. Please enable debug verbosity to print more information."); - } + Error.Report("Unhandled or internal exception was thrown. Please enable debug verbosity to print more information."); + throw; } catch (Exception ex) { - this.Logger.WriteLine(LogSeverity.Error, $"... Task {this.Configuration.TestingProcessId} failed due to an internal error: {ex}"); + this.Logger.WriteLine(LogSeverity.Error, $"... Test failed due to an internal error: {ex}"); this.TestReport.InternalErrors.Add(ex.ToString()); } finally @@ -358,47 +324,44 @@ public void Run() this.Profiler.StopMeasuringExecutionTime(); } - if (this.TestReport != null && this.TestReport.NumOfFoundBugs > 0) - { - TelemetryClient.TrackMetricAsync(isReplaying ? "replay-bugs" : "test-bugs", this.TestReport.NumOfFoundBugs).Wait(); - } - - if (!Debugger.IsAttached) + if (this.Configuration.IsTelemetryEnabled) { - TelemetryClient.TrackMetricAsync(isReplaying ? "replay-time" : "test-time", this.Profiler.Results()).Wait(); + this.TrackTelemetry(); } } /// - /// Creates a new testing task. + /// Creates a new testing task for the specified test method. /// - private Task CreateTestingTask() + private Task CreateTestingTask(TestMethodInfo methodInfo) { - this.Logger.WriteLine(LogSeverity.Important, $"... Task {this.Configuration.TestingProcessId} is " + - $"using the {this.Scheduler.GetDescription()} strategy."); - if (!this.IsTestRewritten()) - { - // TODO: eventually will throw an exception; we allow this for now for pure actor programs. - this.Logger.WriteLine(LogSeverity.Error, - $"... Assembly is not rewritten for testing, see {LearnAboutRewritingUrl}."); - } - - if (this.Configuration.EnableTelemetry) - { - this.Logger.WriteLine(LogSeverity.Important, $"... Telemetry is enabled, see {LearnAboutTelemetryUrl}."); - } - return new Task(() => { + this.Logger.WriteLine(LogSeverity.Important, "... Setting up the{0} test:", + string.IsNullOrEmpty(methodInfo.Name) ? string.Empty : $" '{methodInfo.Name}'"); + this.Logger.WriteLine(LogSeverity.Important, + $"..... Using the {this.Scheduler.GetDescription()} exploration strategy."); if (this.Configuration.AttachDebugger) { + this.Logger.WriteLine(LogSeverity.Important, + $"..... Launching and attaching the debugger."); Debugger.Launch(); } try { // Invokes the user-specified initialization method. - this.TestMethodInfo.InitializeAllIterations(); + methodInfo.InitializeAllIterations(); + + if (this.Scheduler.IsReplayingSchedule) + { + this.Logger.WriteLine(LogSeverity.Important, "... Replaying the trace{0}.", + this.Configuration.ScheduleFile.Length > 0 ? $" from {this.Configuration.ScheduleFile}" : string.Empty); + } + else + { + this.Logger.WriteLine(LogSeverity.Important, "... Running test iterations:"); + } uint iteration = 0; while (iteration < this.Configuration.TestingIterations || this.Configuration.TestingTimeout > 0) @@ -409,7 +372,7 @@ private Task CreateTestingTask() } // Runs the next iteration. - bool runNext = this.RunNextIteration(iteration); + bool runNext = this.RunNextIteration(methodInfo, iteration); if ((!this.Configuration.RunTestIterationsToCompletion && this.TestReport.NumOfFoundBugs > 0) || this.Scheduler.IsReplayingSchedule || !runNext) { @@ -427,7 +390,7 @@ private Task CreateTestingTask() } // Invokes the user-specified test disposal method. - this.TestMethodInfo.DisposeAllIterations(); + methodInfo.DisposeAllIterations(); } catch (Exception ex) { @@ -451,9 +414,9 @@ private Task CreateTestingTask() } /// - /// Runs the next testing iteration. + /// Runs the next testing iteration for the specified test method. /// - private bool RunNextIteration(uint iteration) + private bool RunNextIteration(TestMethodInfo methodInfo, uint iteration) { if (!this.Scheduler.InitializeNextIteration(iteration)) { @@ -511,11 +474,11 @@ private bool RunNextIteration(uint iteration) this.InitializeCustomActorLogging(runtime.DefaultActorExecutionContext); // Runs the test and waits for it to terminate. - Task task = runtime.RunTestAsync(this.TestMethodInfo.Method, this.TestMethodInfo.Name); + Task task = runtime.RunTestAsync(methodInfo.Method, methodInfo.Name); task.Wait(); // Invokes the user-specified iteration disposal method. - this.TestMethodInfo.DisposeCurrentIteration(); + methodInfo.DisposeCurrentIteration(); // Invoke the per iteration callbacks, if any. foreach (var callback in this.PerIterationCallbacks) @@ -532,9 +495,9 @@ private bool RunNextIteration(uint iteration) if (runtimeLogger != null) { this.ReadableTrace = string.Empty; - if (this.Configuration.EnableTelemetry) + if (this.Configuration.IsTelemetryEnabled) { - this.ReadableTrace += $" Telemetry is enabled, see {LearnAboutTelemetryUrl}.\n"; + this.ReadableTrace += $" Anonymized telemetry is enabled, see {LearnAboutTelemetryUrl}.\n"; } this.ReadableTrace += runtimeLogger.ToString(); @@ -566,21 +529,22 @@ runtime.SchedulingPolicy is SchedulingPolicy.Interleaving && this.Scheduler = OperationScheduler.Setup(this.Configuration, SchedulingPolicy.Fuzzing, this.Scheduler.ValueGenerator); this.Logger.WriteLine(LogSeverity.Important, $"..... Iteration #{iteration + 1} " + - $"switching to fuzzing due to uncontrolled concurrency " + - $"[task-{this.Configuration.TestingProcessId}]"); + $"switching to fuzzing due to uncontrolled concurrency"); } else if (runtime.IsBugFound) { - if (!this.Scheduler.IsReplayingSchedule && - this.Configuration.RunTestIterationsToCompletion) + if (!this.Scheduler.IsReplayingSchedule) { this.Logger.WriteLine(LogSeverity.Important, $"..... Iteration #{iteration + 1} " + - $"triggered bug #{this.TestReport.NumOfFoundBugs} " + - $"[task-{this.Configuration.TestingProcessId}]"); + $"found bug #{this.TestReport.NumOfFoundBugs}"); } this.Logger.WriteLine(LogSeverity.Error, runtime.BugReport); } + else if (this.Scheduler.IsReplayingSchedule) + { + this.Logger.WriteLine(LogSeverity.Error, "Failed to reproduce the bug."); + } // Cleans up the runtime before the next iteration starts. runtimeLogger?.Close(); @@ -611,7 +575,6 @@ public string GetReport() this.TestReport.NumOfFoundBugs is 1 ? string.Empty : "s", this.Configuration.AttachDebugger ? string.Empty : " (use --break to attach the debugger)"); report.AppendLine(); - report.Append($"... Elapsed {this.Profiler.Results()} sec."); return report.ToString(); } @@ -636,92 +599,126 @@ public void ThrowIfBugFound() } /// - /// Tries to emit the testing reports, if any. + /// Tries to emit the available reports to the specified directory with the given file name, + /// and returns the paths of all emitted reports. /// - public IEnumerable TryEmitReports(string directory, string file) + public bool TryEmitReports(string directory, string fileName, out IEnumerable reportPaths) { - bool reportsEmitted = false; - - // Find the next available file index. - int index = 0; - Regex match = new Regex("^(.*)_([0-9]+)_([0-9]+)"); - foreach (var path in Directory.GetFiles(directory)) - { - string name = Path.GetFileName(path); - if (name.StartsWith(file)) - { - var result = match.Match(name); - if (result.Success) - { - string value = result.Groups[3].Value; - if (int.TryParse(value, out int i)) - { - index = Math.Max(index, i + 1); - } - } - } - } - + var paths = new List(); if (!this.Configuration.RunTestIterationsToCompletion) { // Emits the human readable trace, if it exists. if (!string.IsNullOrEmpty(this.ReadableTrace)) { - string readableTracePath = Path.Combine(directory, file + "_" + index + ".txt"); - this.Logger.WriteLine(LogSeverity.Important, $"..... Writing {readableTracePath}"); + string readableTracePath = Path.Combine(directory, fileName + ".txt"); File.WriteAllText(readableTracePath, this.ReadableTrace); - reportsEmitted = true; - yield return readableTracePath; + paths.Add(readableTracePath); } } - if (this.Configuration.IsXmlLogEnabled) + if (!this.Configuration.RunTestIterationsToCompletion) { - string xmlPath = Path.Combine(directory, file + "_" + index + ".trace.xml"); - this.Logger.WriteLine(LogSeverity.Important, $"..... Writing {xmlPath}"); - File.WriteAllText(xmlPath, this.XmlLog.ToString()); - reportsEmitted = true; - yield return xmlPath; - } + if (this.Configuration.IsXmlLogEnabled) + { + string xmlPath = Path.Combine(directory, fileName + ".trace.xml"); + File.WriteAllText(xmlPath, this.XmlLog.ToString()); + paths.Add(xmlPath); + } - if (this.Graph != null) - { - string graphPath = Path.Combine(directory, file + "_" + index + ".dgml"); - this.Logger.WriteLine(LogSeverity.Important, $"..... Writing {graphPath}"); - this.Graph.SaveDgml(graphPath, true); - reportsEmitted = true; - yield return graphPath; - } + if (this.LastExecutionGraph != null && this.TestReport.NumOfFoundBugs > 0) + { + string graphPath = Path.Combine(directory, fileName + ".trace.dgml"); + this.LastExecutionGraph.SaveDgml(graphPath, true); + paths.Add(graphPath); + } - if (!this.Configuration.RunTestIterationsToCompletion) - { // Emits the reproducible trace, if it exists. if (!string.IsNullOrEmpty(this.ReproducibleTrace)) { - string reproTracePath = Path.Combine(directory, file + "_" + index + ".schedule"); - this.Logger.WriteLine(LogSeverity.Important, $"..... Writing {reproTracePath}"); + string reproTracePath = Path.Combine(directory, fileName + ".schedule"); File.WriteAllText(reproTracePath, this.ReproducibleTrace); - reportsEmitted = true; - yield return reproTracePath; + paths.Add(reproTracePath); } } // Emits the uncontrolled invocations report, if it exists. if (this.TestReport.UncontrolledInvocations.Count > 0) { - string reportPath = Path.Combine(directory, file + "_" + index + ".uncontrolled.json"); - this.Logger.WriteLine(LogSeverity.Important, $"..... Writing {reportPath}"); + string reportPath = Path.Combine(directory, fileName + ".uncontrolled.json"); File.WriteAllText(reportPath, UncontrolledInvocationsReport.ToJSON(this.TestReport.UncontrolledInvocations)); - reportsEmitted = true; - yield return reportPath; + paths.Add(reportPath); + } + + reportPaths = paths; + return paths.Count > 0; + } + + /// + /// Tries to emit the available coverage reports to the specified directory with the given file name, + /// and returns the paths of all emitted coverage reports. + /// + public bool TryEmitCoverageReports(string directory, string fileName, out IEnumerable reportPaths) + { + var paths = new List(); + if (this.Configuration.IsActivityCoverageReported) + { + var codeCoverageReporter = new ActivityCoverageReporter(this.TestReport.CoverageInfo); + + string graphFilePath = Path.Combine(directory, fileName + ".coverage.dgml"); + codeCoverageReporter.EmitVisualizationGraph(graphFilePath); + paths.Add(graphFilePath); + + string coverageFilePath = Path.Combine(directory, fileName + ".coverage.txt"); + codeCoverageReporter.EmitCoverageReport(coverageFilePath); + paths.Add(coverageFilePath); + + string serFilePath = Path.Combine(directory, fileName + ".sci"); + this.TestReport.CoverageInfo.Save(serFilePath); + paths.Add(serFilePath); } - if (!reportsEmitted) + reportPaths = paths; + return paths.Count > 0; + } + + /// + /// Gathers the exploration strategy statistics from the specified runtimne. + /// + private void GatherTestingStatistics(CoyoteRuntime runtime) + { + TestReport report = new TestReport(this.Configuration); + runtime.PopulateTestReport(report); + + var coverageInfo = runtime.DefaultActorExecutionContext.BuildCoverageInfo(); + report.CoverageInfo.Merge(coverageInfo); + this.TestReport.Merge(report); + + // Save the DGML graph of the execution path explored in the last iteration. + this.LastExecutionGraph = runtime.DefaultActorExecutionContext.GetExecutionGraph(); + } + + /// + /// Tracks anonymized telemetry data. + /// + private void TrackTelemetry() + { + bool isReplaying = this.Scheduler.IsReplayingSchedule; + TelemetryClient.TrackEvent(isReplaying ? "replay" : "test"); + if (Debugger.IsAttached) + { + TelemetryClient.TrackEvent(isReplaying ? "replay-debug" : "test-debug"); + } + else + { + TelemetryClient.TrackMetric(isReplaying ? "replay-time" : "test-time", this.Profiler.Results()); + } + + if (this.TestReport != null && this.TestReport.NumOfFoundBugs > 0) { - Console.WriteLine($"..... No reports available."); + TelemetryClient.TrackMetric(isReplaying ? "replay-bugs" : "test-bugs", this.TestReport.NumOfFoundBugs); } - this.Logger.WriteLine(LogSeverity.Important, $"... Elapsed {this.Profiler.Results()} sec."); + TelemetryClient.Flush(); } /// @@ -734,32 +731,21 @@ public void RegisterPerIterationCallBack(Action callback) } /// - /// Take care of handling the settings for , - /// , and by setting up the - /// LogWriters on the given object. + /// Initializes any custom actor logs. /// private void InitializeCustomActorLogging(IActorRuntime runtime) { - if (!string.IsNullOrEmpty(this.Configuration.CustomActorRuntimeLogType)) - { - var log = this.Activate(this.Configuration.CustomActorRuntimeLogType); - if (log != null) - { - runtime.RegisterLog(log); - } - } - - if (this.Configuration.IsDgmlGraphEnabled || this.Configuration.IsActivityCoverageReported) + if (this.Configuration.IsTraceVisualizationEnabled) { // Registers an activity coverage graph builder. - runtime.RegisterLog(new ActorRuntimeLogGraphBuilder(false) - { - CollapseMachineInstances = this.Configuration.IsActivityCoverageReported - }); + runtime.RegisterLog(new ActorRuntimeLogGraphBuilder(false, false)); } if (this.Configuration.IsActivityCoverageReported) { + // Registers an activity coverage graph builder that collapses instances. + runtime.RegisterLog(new ActorRuntimeLogGraphBuilder(false, true)); + // Need this additional logger to get the event coverage report correct runtime.RegisterLog(new ActorRuntimeLogEventCoverage()); } @@ -772,63 +758,6 @@ private void InitializeCustomActorLogging(IActorRuntime runtime) } } - private T Activate(string assemblyQualifiedName) - where T : class - { - // Parses the result of Type.AssemblyQualifiedName. - // e.g.: ConsoleApp1.Program, ConsoleApp1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null - try - { - string[] parts = assemblyQualifiedName.Split(','); - if (parts.Length > 1) - { - string typeName = parts[0]; - string assemblyName = parts[1]; - Assembly a = null; - if (File.Exists(assemblyName)) - { - a = Assembly.LoadFrom(assemblyName); - } - else - { - a = Assembly.Load(assemblyName); - } - - if (a != null) - { - object o = a.CreateInstance(typeName); - return o as T; - } - } - } - catch (Exception ex) - { - this.Logger.WriteLine(LogSeverity.Error, ex.Message); - } - - return null; - } - - /// - /// Gathers the exploration strategy statistics from the specified runtimne. - /// - private void GatherTestingStatistics(CoyoteRuntime runtime) - { - TestReport report = new TestReport(this.Configuration); - runtime.PopulateTestReport(report); - if (this.Configuration.IsActivityCoverageReported) - { - report.CoverageInfo.CoverageGraph = this.Graph; - } - - var coverageInfo = runtime.DefaultActorExecutionContext.BuildCoverageInfo(); - report.CoverageInfo.Merge(coverageInfo); - this.TestReport.Merge(report); - - // Also save the graph snapshot of the last iteration, if there is one. - this.Graph = coverageInfo.CoverageGraph; - } - /// /// Returns true if the engine should print the current iteration. /// diff --git a/Source/Test/Telemetry/CoyoteTelemetryClient.cs b/Source/Test/Telemetry/CoyoteTelemetryClient.cs deleted file mode 100644 index 8c994048e..000000000 --- a/Source/Test/Telemetry/CoyoteTelemetryClient.cs +++ /dev/null @@ -1,358 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Runtime.InteropServices; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Coyote.SmartSockets; - -namespace Microsoft.Coyote.Telemetry -{ - internal class CoyoteTelemetryClient : IDisposable - { - private SmartSocketClient Server; - private CancellationTokenSource FindServerTokenSource = new CancellationTokenSource(); - private bool Enabled; - private List Pending = new List(); - private readonly ManualResetEvent PendingCleared = new ManualResetEvent(false); - private readonly string Name; - private const string CoyoteMachineIdFileName = "CoyoteMachineId.txt"; - private readonly string Framework = "unknown"; - private static string MachineId; - private static CoyoteTelemetryServer InProcServer; - - public CoyoteTelemetryClient(Configuration configuration) - { - this.Enabled = configuration.EnableTelemetry && !configuration.RunAsParallelBugFindingTask; -#if NETFRAMEWORK - this.Framework = ".NET Framework"; -#else - this.Framework = RuntimeInformation.FrameworkDescription; -#endif - - if (this.Enabled) - { - if (string.IsNullOrEmpty(configuration.TelemetryServerPath)) - { - // then server is running in-proc (as we do for unit testing) - if (InProcServer is null) - { - InProcServer = new CoyoteTelemetryServer(false); - } - - return; - } - else - { - // run the server out of proc. - this.Name = $"coyote{Process.GetCurrentProcess().Id}"; - _ = this.ConnectToServer(configuration.TelemetryServerPath); - } - } - } - - ~CoyoteTelemetryClient() - { - this.Dispose(false); - } - - public static void PrintTelemetryMessage(TextWriter writer) - { - writer.WriteLine(); - writer.WriteLine("Telemetry is enabled"); - writer.WriteLine("--------------------"); - writer.WriteLine("Microsoft Coyote tools collect usage data in order to help us improve your experience. " + - "The data is anonymous. It is collected by Microsoft and shared with the community. " + - "You can opt-out of telemetry by setting the COYOTE_CLI_TELEMETRY_OPTOUT environment variable to '1' or 'true'."); - writer.WriteLine(); - writer.WriteLine("Read more about Microsoft Coyote Telemetry at http://aka.ms/coyote-telemetry"); - writer.WriteLine("--------------------------------------------------------------------------------------------"); - } - - public async Task TrackEventAsync(string name) - { - if (!this.Enabled) - { - return; - } - - var e = new TelemetryEvent(this.Framework, name, this.Name); - - if (InProcServer != null) - { - InProcServer.HandleEvent(e); - } - else if (this.Server != null) - { - await this.Server.SendReceiveAsync(e); - } - else - { - // queue the event until the telemetry server is ready. - lock (this.Pending) - { - this.Pending.Add(e); - } - } - } - - public async Task TrackMetricAsync(string name, double value) - { - if (!this.Enabled) - { - return; - } - - var e = new TelemetryMetric(this.Framework, name, this.Name, value); - - if (InProcServer != null) - { - InProcServer.HandleMetric(e); - } - else if (this.Server != null) - { - await this.Server.SendReceiveAsync(e); - } - else - { - // queue the event until the telemetry server is ready. - lock (this.Pending) - { - this.Pending.Add(e); - } - } - } - - /// - /// Starts a telemetry server in a separate coyote process. - /// - private async Task ConnectToServer(string serverPath) - { - this.FindServerTokenSource = new CancellationTokenSource(); - var token = this.FindServerTokenSource.Token; - - string serviceName = CoyoteTelemetryServer.TelemetryServerEndPoint; - var resolver = new SmartSocketTypeResolver(typeof(TelemetryEvent), typeof(TelemetryMetric)); - - SmartSocketClient client = null; - var findTask = SmartSocketClient.FindServerAsync(serviceName, this.Name, resolver, token, - CoyoteTelemetryServer.UdpGroupAddress, CoyoteTelemetryServer.UdpGroupPort); - try - { - if (findTask.Wait(1000, token)) - { - client = findTask.Result; - } - } - catch - { - // timeout or cancelled. - if (token.IsCancellationRequested) - { - return; - } - } - - if (client is null) - { - try - { - StartServer(serverPath); - client = await SmartSocketClient.FindServerAsync(serviceName, this.Name, resolver, token, - CoyoteTelemetryServer.UdpGroupAddress, CoyoteTelemetryServer.UdpGroupPort); - } - catch - { - // failed to connect to new telemetry server - this.Enabled = false; - return; - } - } - - client.Error += this.OnClientError; - client.ServerName = serviceName; - this.Server = client; - - // send any pending queue of stuff. - List pending = null; - lock (this.Pending) - { - pending = this.Pending; - this.Pending = null; - } - - foreach (var e in pending) - { - await this.Server.SendReceiveAsync(e); - } - - this.PendingCleared.Set(); - - _ = Task.Run(this.SendHeartbeats); - } - - private void OnClientError(object sender, Exception e) - { - // todo: error handling? - } - - private static void StartServer(string assembly) - { - string ext = Path.GetExtension(assembly); - string program = assembly; - string args = "telemetry server"; - if (string.Compare(ext, ".dll", StringComparison.OrdinalIgnoreCase) is 0) - { - args = "\"" + assembly + "\" telemetry server"; - program = "dotnet"; - } - - ProcessStartInfo startInfo = new ProcessStartInfo(program, args) - { - UseShellExecute = false, - CreateNoWindow = true - }; - - Process process = new Process - { - StartInfo = startInfo - }; - if (!process.Start()) - { - Console.WriteLine("Error starting coyote telemetry"); - } - } - - private void Close() - { - if (InProcServer != null) - { - InProcServer.Flush(); - } - else if (this.Enabled) - { - this.PendingCleared.WaitOne(5000); - } - - this.FindServerTokenSource.Cancel(); - } - - public void Dispose() - { - this.Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - this.Close(); - } - - private async void SendHeartbeats() - { - // This keeps the server alive until this test finishes (in case the test - // takes longer than 60 seconds!). - var token = this.FindServerTokenSource.Token; - while (!token.IsCancellationRequested) - { - try - { - await Task.Delay(30000, token); - if (this.Server != null) - { - await this.Server.SendReceiveAsync(new SocketMessage("ping", this.Name)); - } - } - catch - { - break; - } - } - } - - internal static async Task> GetOrCreateMachineId() - { - bool firstTime = false; - if (MachineId != null) - { - return new Tuple(MachineId, firstTime); - } - - string path = CoyoteHomePath; - int retries = 3; - while (retries-- > 0) - { - try - { - if (!Directory.Exists(path)) - { - Directory.CreateDirectory(path); - } - - string fullpath = Path.Combine(path, CoyoteMachineIdFileName); - if (!File.Exists(fullpath)) - { - try - { - firstTime = true; - Guid id = Guid.NewGuid(); - using (StreamWriter writer = new StreamWriter(fullpath)) - { - writer.Write(id.ToString()); - } - - MachineId = id.ToString(); - } - catch - { - // race condition, another process beat us to it? - MachineId = File.ReadAllText(fullpath); - } - } - else - { - MachineId = File.ReadAllText(fullpath); - } - } - catch - { - // ignore race conditions on this first time file. - await Task.Delay(50); - } - } - - if (MachineId is null) - { - // hmmm, something is horribly wrong with the file system, so just invent a new guid for now. - MachineId = Guid.NewGuid().ToString(); - } - - return new Tuple(MachineId, firstTime); - } - - internal static string CoyoteHomePath - { - get - { - return IsWindowsLike ? Path.Combine(Environment.GetEnvironmentVariable("LocalAppData"), "Microsoft", "coyote") : - Path.Combine(Environment.GetEnvironmentVariable("HOME"), ".microsoft", "coyote"); - } - } - - internal static bool IsWindowsLike - { - get - { - return Environment.OSVersion.Platform == PlatformID.Win32NT || - Environment.OSVersion.Platform == PlatformID.Win32S || - Environment.OSVersion.Platform == PlatformID.Win32Windows || - Environment.OSVersion.Platform == PlatformID.WinCE || - Environment.OSVersion.Platform == PlatformID.Xbox; - } - } - } -} diff --git a/Source/Test/Telemetry/CoyoteTelemetryServer.cs b/Source/Test/Telemetry/CoyoteTelemetryServer.cs deleted file mode 100644 index 7db99bb6b..000000000 --- a/Source/Test/Telemetry/CoyoteTelemetryServer.cs +++ /dev/null @@ -1,246 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; -using System.Runtime.Serialization; -using System.Threading.Tasks; -using Microsoft.ApplicationInsights; -using Microsoft.ApplicationInsights.DataContracts; -using Microsoft.ApplicationInsights.Extensibility; -using Microsoft.Coyote.SmartSockets; - -namespace Microsoft.Coyote.Telemetry -{ - /// - /// A custom SocketMessage used to convey a telemetry event. - /// - [DataContract] - internal class TelemetryEvent : SocketMessage - { - [DataMember] - public string Framework { get; set; } - - public TelemetryEvent(string framework, string id, string sender) - : base(id, sender) - { - this.Framework = framework; - } - } - - /// - /// A custom SocketMessage used to convey a telemetry metric. - /// - [DataContract] - internal class TelemetryMetric : SocketMessage - { - [DataMember] - public string Framework { get; set; } - - [DataMember] - public double Value { get; set; } - - public TelemetryMetric(string framework, string id, string sender, double value) - : base(id, sender) - { - this.Value = value; - this.Framework = framework; - } - } - - /// - /// This is a SmartSocketServer designed for sending the coyote custom telemetry messages - /// to Azure. The server runs in a separate process communicating for smart sockets. - /// It sticks around for 60 seconds then terminates, unless a heartbeat or telemetry - /// message is received from another coyote process. You can debug this server easily - /// by running "coyote telemetry server" from the command line. - /// See . - /// - internal class CoyoteTelemetryServer - { - /// - /// The server socket that all the coyote apps will connect to. - /// - private SmartSocketServer Server; - - /// - /// The App Insights client. - /// - private TelemetryClient Telemetry; - - public const string TelemetryServerEndPoint = "CoyoteTelemetryServer.132d4357-1b32-473f-994b-e35eccaacd46"; - - private string MachineId; - private DateTime LastEvent; - private bool PendingEvents; - private readonly bool Verbose; - - private readonly TimeSpan ServerTerminateDelay = TimeSpan.FromSeconds(30); - - internal const string UdpGroupAddress = "226.10.10.3"; - internal const int UdpGroupPort = 37993; - - public CoyoteTelemetryServer(bool verbose) - { - this.Verbose = verbose; - - // you may use different options to create configuration as shown later in this article - TelemetryConfiguration configuration = TelemetryConfiguration.CreateDefault(); - configuration.InstrumentationKey = "17a6badb-bf2d-4f5d-959b-6843b8bb1f7f"; - this.Telemetry = new TelemetryClient(configuration); - string version = typeof(Runtime.CoyoteRuntime).Assembly.GetName().Version.ToString(); - this.Telemetry.Context.GlobalProperties["coyote"] = version; - this.Telemetry.Context.Device.OperatingSystem = Environment.OSVersion.Platform.ToString(); - this.Telemetry.Context.Session.Id = Guid.NewGuid().ToString(); - this.LastEvent = DateTime.Now; - } - - /// - /// Opens the local server for local coyote test processes to connect to. - /// - internal async Task RunServerAsync() - { - this.WriteLine("Starting telemetry server..."); - - var result = await CoyoteTelemetryClient.GetOrCreateMachineId(); - this.MachineId = result.Item1; - this.Telemetry.Context.Device.Id = this.MachineId; - - var resolver = new SmartSocketTypeResolver(typeof(TelemetryEvent), typeof(TelemetryMetric)); - var server = SmartSocketServer.StartServer(TelemetryServerEndPoint, resolver, null /* localhost only */, UdpGroupAddress, UdpGroupPort); - server.ClientConnected += this.OnClientConnected; - server.ClientDisconnected += this.OnClientDisconnected; - this.Server = server; - - // Here we see the reason for this entire class. In order to allow coyote.exe to terminate quickly - // and not lose telemetry messages, we have to wait a bit to allow the App Insights cloud messages - // to get through, then we can safely terminate this server process. - while (this.Telemetry != null && this.LastEvent + this.ServerTerminateDelay > DateTime.Now) - { - await Task.Delay((int)this.ServerTerminateDelay.TotalMilliseconds); - if (this.PendingEvents) - { - this.WriteLine("Flushing telemetry..."); - this.Flush(); - this.LastEvent = DateTime.Now; // go around again to give flush time to finish. - } - } - - this.Telemetry = null; - } - - /// - /// Flush events to Azure. - /// - internal void Flush() - { - if (this.Telemetry != null) - { - this.PendingEvents = false; - this.Telemetry.Flush(); - } - } - - /// - /// Called when a separate coyote test/replay process termiantes. - /// - private void OnClientDisconnected(object sender, SmartSocketClient e) - { - this.WriteLine("Client disconnected: " + e.Name); - } - - /// - /// Called when a separate coyote test/replay process starts up and connects to - /// this server. - /// - private void OnClientConnected(object sender, SmartSocketClient e) - { - // A coyote process has started up, so this socket will be used to receive telemetry requests. - Task.Run(() => this.HandleClient(e)); - } - - private async void HandleClient(SmartSocketClient e) - { - this.WriteLine("Client connected: " + e.Name); - this.LastEvent = DateTime.Now; - - while (e.IsConnected && this.Telemetry != null) - { - try - { - var msg = await e.ReceiveAsync(); - if (msg != null) - { - this.LastEvent = DateTime.Now; - if (msg is TelemetryEvent tm) - { - this.HandleEvent(tm); - } - else if (msg is TelemetryMetric metric) - { - this.HandleMetric(metric); - } - else - { - this.WriteLine("Received heartbeat"); - } - - await e.SendAsync(new SocketMessage("ok", TelemetryServerEndPoint)); - } - } - catch (Exception) - { - } - } - } - - /// - /// Calls the App Insights TrackEvent method. - /// - internal void HandleEvent(TelemetryEvent e) - { - try - { - this.WriteLine("Tracking event ({1}): {0}", e.Id, e.Framework); - if (this.Telemetry != null) - { - this.PendingEvents = true; - this.Telemetry.Context.GlobalProperties["dotnet"] = e.Framework; - this.Telemetry.TrackEvent(new EventTelemetry(e.Id)); - } - } - catch (Exception ex) - { - this.WriteLine("Error sending TrackEvent: {0}", ex.Message); - } - } - - /// - /// Calls the App Insights TrackMetric method. - /// - internal void HandleMetric(TelemetryMetric e) - { - try - { - this.WriteLine("Tracking metric ({2}): {0}={1}", e.Id, e.Value, e.Framework); - if (this.Telemetry != null) - { - this.PendingEvents = true; - this.Telemetry.Context.GlobalProperties["dotnet"] = e.Framework; - this.Telemetry.TrackMetric(new MetricTelemetry(e.Id, e.Value)); - } - } - catch (Exception ex) - { - this.WriteLine("Error sending TrackMetric: {0}", ex.Message); - } - } - - private void WriteLine(string msg, params object[] args) - { - if (this.Verbose) - { - Console.WriteLine(msg, args); - } - } - } -} diff --git a/Source/Test/Telemetry/TelemetryClient.cs b/Source/Test/Telemetry/TelemetryClient.cs new file mode 100644 index 000000000..c74f6dbbe --- /dev/null +++ b/Source/Test/Telemetry/TelemetryClient.cs @@ -0,0 +1,209 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.IO; +using System.Runtime.InteropServices; +using System.Threading; +using Microsoft.ApplicationInsights.DataContracts; +using Microsoft.ApplicationInsights.Extensibility; +using AppInsightsClient = Microsoft.ApplicationInsights.TelemetryClient; + +namespace Microsoft.Coyote.Telemetry +{ + /// + /// Thread-safe client for sending telemetry messages to Azure. + /// + /// + /// See . + /// + internal class TelemetryClient + { + /// + /// Path to the Coyote home directory where the UUID is stored. + /// + private static string CoyoteHomePath => IsWindowsLike ? + Path.Combine(Environment.GetEnvironmentVariable("LocalAppData"), "Microsoft", "coyote") : + Path.Combine(Environment.GetEnvironmentVariable("HOME"), ".microsoft", "coyote"); + + /// + /// File name where the UUID is stored. + /// + private const string IdFileName = "device_id.txt"; + + /// + /// Used to synchronize access to the telemetry client. + /// + private static readonly object SyncObject = new object(); + + /// + /// The current instance of the telemetry client. + /// + private static TelemetryClient Current; + + /// + /// The App Insights client. + /// + private readonly AppInsightsClient Client; + + /// + /// True if telemetry is enabled, else false. + /// + private readonly bool IsEnabled; + + /// + /// Initializes a new instance of the class. + /// + private TelemetryClient(bool isEnabled) + { + if (isEnabled) + { + TelemetryConfiguration configuration = TelemetryConfiguration.CreateDefault(); + configuration.InstrumentationKey = "17a6badb-bf2d-4f5d-959b-6843b8bb1f7f"; + this.Client = new AppInsightsClient(configuration); + + string version = typeof(Runtime.CoyoteRuntime).Assembly.GetName().Version.ToString(); + this.Client.Context.GlobalProperties["coyote"] = version; +#if NETFRAMEWORK + this.Client.Context.GlobalProperties["dotnet"] = ".NET Framework"; +#else + this.Client.Context.GlobalProperties["dotnet"] = RuntimeInformation.FrameworkDescription; +#endif + this.Client.Context.Device.Id = GetOrCreateDeviceId(out bool isFirstTime); + this.Client.Context.Device.OperatingSystem = Environment.OSVersion.Platform.ToString(); + this.Client.Context.Session.Id = Guid.NewGuid().ToString(); + + if (isFirstTime) + { + this.TrackEvent("welcome"); + } + } + + this.IsEnabled = isEnabled; + } + + /// + /// Returns the existing telemetry client if one has already been created for this process, + /// or creates and returns a new one with the specified configuration. + /// + internal static TelemetryClient GetOrCreate(Configuration configuration) + { + lock (SyncObject) + { + Current ??= new TelemetryClient(configuration.IsTelemetryEnabled); + return Current; + } + } + + /// + /// Tracks the specified telemetry event. + /// + internal void TrackEvent(string name) + { + if (this.IsEnabled) + { + lock (SyncObject) + { + try + { + IO.Debug.WriteLine(" Tracking event: {0}.", name); + this.Client.TrackEvent(new EventTelemetry(name)); + } + catch (Exception ex) + { + IO.Debug.WriteLine(" Error sending event: {0}", ex.Message); + } + } + } + } + + /// + /// Tracks the specified telemetry metric. + /// + internal void TrackMetric(string name, double value) + { + if (this.IsEnabled) + { + lock (SyncObject) + { + try + { + IO.Debug.WriteLine(" Tracking metric: {0}={1}.", name, value); + this.Client.TrackMetric(new MetricTelemetry(name, value)); + } + catch (Exception ex) + { + IO.Debug.WriteLine(" Error sending metric: {0}", ex.Message); + } + } + } + } + + /// + /// Flushes any buffered in-memory telemetry data. + /// + internal void Flush() + { + if (this.IsEnabled) + { + lock (SyncObject) + { + try + { + this.Client.Flush(); + } + catch (Exception ex) + { + IO.Debug.WriteLine(" Error flushing: {0}", ex.Message); + } + } + } + } + + /// + /// Returns the unique device id or creates a new one. + /// + private static string GetOrCreateDeviceId(out bool isFirstTime) + { + string deviceId = Guid.NewGuid().ToString(); + isFirstTime = true; + + int attempts = 5; + while (attempts-- > 0) + { + try + { + string fullpath = Path.Combine(CoyoteHomePath, IdFileName); + if (!File.Exists(fullpath)) + { + Directory.CreateDirectory(CoyoteHomePath); + using StreamWriter writer = new StreamWriter(fullpath); + writer.Write(deviceId); + } + else + { + deviceId = File.ReadAllText(fullpath); + isFirstTime = false; + } + + break; + } + catch + { + Thread.Sleep(1); + } + } + + return deviceId; + } + + /// + /// Returns true if this is a Windows platform, else false. + /// + private static bool IsWindowsLike => Environment.OSVersion.Platform == PlatformID.Win32NT || + Environment.OSVersion.Platform == PlatformID.Win32S || + Environment.OSVersion.Platform == PlatformID.Win32Windows || + Environment.OSVersion.Platform == PlatformID.WinCE || + Environment.OSVersion.Platform == PlatformID.Xbox; + } +} diff --git a/Source/Test/Test.csproj b/Source/Test/Test.csproj index a68e613da..ca882a2da 100644 --- a/Source/Test/Test.csproj +++ b/Source/Test/Test.csproj @@ -10,20 +10,11 @@ - - - - - - - - - + + - - diff --git a/Tests/Tests.Actors/EventGroups/LargeEventGroupTests.cs b/Tests/Tests.Actors/EventGroups/LargeEventGroupTests.cs index e7d568ebb..1ecc6a9b8 100644 --- a/Tests/Tests.Actors/EventGroups/LargeEventGroupTests.cs +++ b/Tests/Tests.Actors/EventGroups/LargeEventGroupTests.cs @@ -95,7 +95,7 @@ public void TestQuiescentNetwork() { this.Test(async r => { - var graphBuilder = new ActorRuntimeLogGraphBuilder(false); + var graphBuilder = new ActorRuntimeLogGraphBuilder(false, false); r.RegisterLog(graphBuilder); var op = new ActorHaltedEventGroup(); diff --git a/Tests/Tests.Actors/Logging/CustomActorRuntimeLogTests.cs b/Tests/Tests.Actors/Logging/CustomActorRuntimeLogTests.cs index 456e1c6f8..53c78a2a0 100644 --- a/Tests/Tests.Actors/Logging/CustomActorRuntimeLogTests.cs +++ b/Tests/Tests.Actors/Logging/CustomActorRuntimeLogTests.cs @@ -131,18 +131,17 @@ public void TestCustomLogger() { this.Test(async runtime => { - using (CustomLogger logger = new CustomLogger()) - { - runtime.Logger = logger; - var tcs = new TaskCompletionSource(); - runtime.RegisterMonitor(); - runtime.Monitor(new SetupEvent(tcs)); - runtime.CreateActor(typeof(M)); - await this.WaitAsync(tcs.Task); - await Task.Delay(200); - Assert.True(tcs.Task.IsCompleted, "The task await returned but the task is not completed???"); - - string expected = @" TestMonitor was created. + using CustomLogger logger = new CustomLogger(); + runtime.Logger = logger; + var tcs = new TaskCompletionSource(); + runtime.RegisterMonitor(); + runtime.Monitor(new SetupEvent(tcs)); + runtime.CreateActor(typeof(M)); + await this.WaitAsync(tcs.Task); + await Task.Delay(200); + Assert.True(tcs.Task.IsCompleted, "The task await returned but the task is not completed???"); + + string expected = @" TestMonitor was created. TestMonitor enters state 'Init'. TestMonitor is processing event 'SetupEvent' in state 'Init'. TestMonitor executed action 'OnSetup' in state 'Init'. @@ -164,12 +163,11 @@ public void TestCustomLogger() TestMonitor is processing event 'CompletedEvent' in state 'Init'. TestMonitor executed action 'OnCompleted' in state 'Init'."; - string actual = logger.ToString().RemoveNonDeterministicValues(); - expected = expected.NormalizeNewLines(); - actual = actual.SortLines(); // threading makes this non-deterministic otherwise. - expected = expected.SortLines(); - Assert.Equal(expected, actual); - } + string actual = logger.ToString().RemoveNonDeterministicValues(); + expected = expected.NormalizeNewLines(); + actual = actual.SortLines(); // threading makes this non-deterministic otherwise. + expected = expected.SortLines(); + Assert.Equal(expected, actual); }, this.GetConfiguration()); } @@ -178,20 +176,19 @@ public void TestGraphLogger() { this.Test(async runtime => { - using (CustomLogger logger = new CustomLogger()) - { - runtime.Logger = logger; - var tcs = new TaskCompletionSource(); - runtime.RegisterMonitor(); - runtime.Monitor(new SetupEvent(tcs)); - var graphBuilder = new ActorRuntimeLogGraphBuilder(false); - runtime.RegisterLog(graphBuilder); - runtime.CreateActor(typeof(M)); - await this.WaitAsync(tcs.Task); - await Task.Delay(200); - Assert.True(tcs.Task.IsCompleted, "The task await returned but the task is not completed???"); - - string expected = @" + using CustomLogger logger = new CustomLogger(); + runtime.Logger = logger; + var tcs = new TaskCompletionSource(); + runtime.RegisterMonitor(); + runtime.Monitor(new SetupEvent(tcs)); + var graphBuilder = new ActorRuntimeLogGraphBuilder(false, false); + runtime.RegisterLog(graphBuilder); + runtime.CreateActor(typeof(M)); + await this.WaitAsync(tcs.Task); + await Task.Delay(200); + Assert.True(tcs.Task.IsCompleted, "The task await returned but the task is not completed???"); + + string expected = @" @@ -216,11 +213,10 @@ public void TestGraphLogger() "; - string dgml = graphBuilder.Graph.ToString(); - string actual = dgml.RemoveNonDeterministicValues(); - expected = expected.RemoveNonDeterministicValues(); - Assert.Equal(expected, actual); - } + string dgml = graphBuilder.Graph.ToString(); + string actual = dgml.RemoveNonDeterministicValues(); + expected = expected.RemoveNonDeterministicValues(); + Assert.Equal(expected, actual); }, this.GetConfiguration()); } @@ -377,33 +373,31 @@ public void TestGraphLoggerInstances() { this.Test(async runtime => { - using (CustomLogger logger = new CustomLogger()) - { - runtime.Logger = logger; + using CustomLogger logger = new CustomLogger(); + runtime.Logger = logger; - var graphBuilder = new ActorRuntimeLogGraphBuilder(false); + var graphBuilder = new ActorRuntimeLogGraphBuilder(false, false); - var tcs = new TaskCompletionSource(); - runtime.RegisterMonitor(); - runtime.Monitor(new SetupEvent(tcs)); - runtime.RegisterLog(graphBuilder); + var tcs = new TaskCompletionSource(); + runtime.RegisterMonitor(); + runtime.Monitor(new SetupEvent(tcs)); + runtime.RegisterLog(graphBuilder); - ActorId serverId = runtime.CreateActor(typeof(Server)); - runtime.CreateActor(typeof(Client), new ClientSetupEvent(serverId)); - runtime.CreateActor(typeof(Client), new ClientSetupEvent(serverId)); - runtime.CreateActor(typeof(Client), new ClientSetupEvent(serverId)); + ActorId serverId = runtime.CreateActor(typeof(Server)); + runtime.CreateActor(typeof(Client), new ClientSetupEvent(serverId)); + runtime.CreateActor(typeof(Client), new ClientSetupEvent(serverId)); + runtime.CreateActor(typeof(Client), new ClientSetupEvent(serverId)); - await this.WaitAsync(tcs.Task); - await Task.Delay(1000); - Assert.True(tcs.Task.IsCompleted, "The task await returned but the task is not completed???"); + await this.WaitAsync(tcs.Task); + await Task.Delay(1000); + Assert.True(tcs.Task.IsCompleted, "The task await returned but the task is not completed???"); - string actual = graphBuilder.Graph.ToString(); - actual = actual.RemoveInstanceIds(); + string actual = graphBuilder.Graph.ToString(); + actual = actual.RemoveInstanceIds(); - Assert.Contains("", actual); - Assert.Contains("", actual); - Assert.Contains("", actual); - } + Assert.Contains("", actual); + Assert.Contains("", actual); + Assert.Contains("", actual); }, this.GetConfiguration()); } @@ -412,34 +406,29 @@ public void TestGraphLoggerCollapsed() { this.Test(async runtime => { - using (CustomLogger logger = new CustomLogger()) - { - runtime.Logger = logger; + using CustomLogger logger = new CustomLogger(); + runtime.Logger = logger; - var graphBuilder = new ActorRuntimeLogGraphBuilder(false) - { - CollapseMachineInstances = true - }; + var graphBuilder = new ActorRuntimeLogGraphBuilder(false, true); - var tcs = new TaskCompletionSource(); - runtime.RegisterMonitor(); - runtime.Monitor(new SetupEvent(tcs)); - runtime.RegisterLog(graphBuilder); + var tcs = new TaskCompletionSource(); + runtime.RegisterMonitor(); + runtime.Monitor(new SetupEvent(tcs)); + runtime.RegisterLog(graphBuilder); - ActorId serverId = runtime.CreateActor(typeof(Server)); - runtime.CreateActor(typeof(Client), new ClientSetupEvent(serverId)); - runtime.CreateActor(typeof(Client), new ClientSetupEvent(serverId)); - runtime.CreateActor(typeof(Client), new ClientSetupEvent(serverId)); + ActorId serverId = runtime.CreateActor(typeof(Server)); + runtime.CreateActor(typeof(Client), new ClientSetupEvent(serverId)); + runtime.CreateActor(typeof(Client), new ClientSetupEvent(serverId)); + runtime.CreateActor(typeof(Client), new ClientSetupEvent(serverId)); - await this.WaitAsync(tcs.Task, 5000); - await Task.Delay(1000); - Assert.True(tcs.Task.IsCompleted, "The task await returned but the task is not completed???"); + await this.WaitAsync(tcs.Task, 5000); + await Task.Delay(1000); + Assert.True(tcs.Task.IsCompleted, "The task await returned but the task is not completed???"); - string actual = graphBuilder.Graph.ToString(); + string actual = graphBuilder.Graph.ToString(); - Assert.Contains("", actual); - Assert.Contains("", actual); - } + Assert.Contains("", actual); + Assert.Contains("", actual); }, this.GetConfiguration()); } } diff --git a/Tests/Tests.BugFinding/Tasks/Logging/CustomTaskLogTests.cs b/Tests/Tests.BugFinding/Tasks/Logging/CustomTaskLogTests.cs index 2c9c9f71a..694b71d60 100644 --- a/Tests/Tests.BugFinding/Tasks/Logging/CustomTaskLogTests.cs +++ b/Tests/Tests.BugFinding/Tasks/Logging/CustomTaskLogTests.cs @@ -36,7 +36,9 @@ public void TestCustomLogger() var result = log.ToString(); result = result.RemoveNonDeterministicValues(); - var expected = @"... Task 0 is using the random[seed:0] strategy. + var expected = @"... Setting up the test: +..... Using the random[seed:0] exploration strategy. +... Running test iterations: ..... Iteration #1 Runtime '' started test on thread ''. Hello world! diff --git a/Tests/compare-rewriting-diff-logs.ps1 b/Tests/compare-rewriting-diff-logs.ps1 index 3fe1a1d84..8c985cb3e 100644 --- a/Tests/compare-rewriting-diff-logs.ps1 +++ b/Tests/compare-rewriting-diff-logs.ps1 @@ -16,7 +16,7 @@ $expected_hashes = [ordered]@{ "rewriting" = "D8A88CC026C77128ED5F4C31604AD8602A2F2C073CD234CBF5C43606911585BD" "rewriting-helpers" = "55C8CBC027DE1044EBA50FB20C5E8A8922CE7E841C8FBDC81447F15B9DD7F6CD" "testing" = "002CDC36FAE9D646378CC6579AF51A31C6637EB0E4D3B504C510CCAE115CC9ED" - "actors" = "B96A5838E3F794190BD9191C6E6F70626620777084996C39839A28C736FBFD11" + "actors" = "7CD5CC5B1FDE6ABAA4323E9729000E3BD83F7A5E3DAFF6D673E7E3AAADF1D6FD" "actors-testing" = "0D18E697B6FAA838109D3BE66DD8E79464152E15FC573BE42D9D2DDAF1F92EC0" } diff --git a/Tools/Coyote/Cli/CommandLineParser.cs b/Tools/Coyote/Cli/CommandLineParser.cs new file mode 100644 index 000000000..a64e72d36 --- /dev/null +++ b/Tools/Coyote/Cli/CommandLineParser.cs @@ -0,0 +1,993 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.CommandLine; +using System.CommandLine.Builder; +using System.CommandLine.Invocation; +using System.CommandLine.Parsing; +using System.IO; +using System.Linq; +using Microsoft.Coyote.IO; +using Microsoft.Coyote.Rewriting; + +namespace Microsoft.Coyote.Cli +{ + internal sealed class CommandLineParser + { + /// + /// Url with information on learning about coyote. + /// + private const string LearnAboutCoyoteUrl = "https://aka.ms/learn-coyote"; + + /// + /// Url with information about what is new with coyote. + /// + private const string LearnWhatIsNewUrl = "https://aka.ms/coyote-what-is-new"; + + /// + /// Url with information about the testing process. + /// + private const string LearnAboutTestUrl = "https://aka.ms/coyote-test"; + + /// + /// Url with information about the replaying process. + /// + private const string LearnAboutReplayUrl = "https://aka.ms/coyote-replay"; + + /// + /// Url with information about the rewriting process. + /// + private const string LearnAboutRewritingUrl = "https://aka.ms/coyote-rewrite"; + + /// + /// The Coyote runtime and testing configuration. + /// + private readonly Configuration Configuration; + + /// + /// The Coyote rewriting options. + /// + private readonly RewritingOptions RewritingOptions; + + /// + /// The test command. + /// + private readonly Command TestCommand; + + /// + /// The replay command. + /// + private readonly Command ReplayCommand; + + /// + /// The rewrite command. + /// + private readonly Command RewriteCommand; + + /// + /// Mao from argument names to arguments. + /// + private readonly Dictionary Arguments; + + /// + /// Mao from option names to options. + /// + private readonly Dictionary Options; + + /// + /// The parse results. + /// + private readonly ParseResult Results; + + /// + /// True if parsing was successful, else false. + /// + internal bool IsSuccessful { get; private set; } + + /// + /// Initializes a new instance of the class. + /// + internal CommandLineParser(string[] args) + { + this.Configuration = Configuration.Create(); + this.RewritingOptions = RewritingOptions.Create(); + this.Arguments = new Dictionary(); + this.Options = new Dictionary(); + + var allowedVerbosityLevels = new HashSet + { + "quiet", + "minimal", + "normal", + "detailed" + }; + + var verbosityOption = new Option( + aliases: new[] { "-v", "--verbosity" }, + getDefaultValue: () => "quiet", + description: "Enable verbosity with an optional verbosity level. " + + $"Allowed values are {string.Join(", ", allowedVerbosityLevels)}. " + + "Skipping the argument sets the verbosity level to 'detailed'.") + { + ArgumentHelpName = "LEVEL", + Arity = ArgumentArity.ZeroOrOne + }; + + var debugOption = new Option(aliases: new[] { "-d", "--debug" }) + { + Arity = ArgumentArity.Zero + }; + + // Add validators. + verbosityOption.AddValidator(result => ValidateOptionValueIsAllowed(result, allowedVerbosityLevels)); + + // Create the commands. + this.TestCommand = this.CreateTestCommand(this.Configuration); + this.ReplayCommand = this.CreateReplayCommand(); + this.RewriteCommand = this.CreateRewriteCommand(); + + // Create the root command. + var rootCommand = new RootCommand("The Coyote systematic testing tool.\n\n" + + $"Learn how to use Coyote at {LearnAboutCoyoteUrl}.\nLearn what is new at {LearnWhatIsNewUrl}."); + this.AddGlobalOption(rootCommand, verbosityOption); + this.AddGlobalOption(rootCommand, debugOption); + rootCommand.AddCommand(this.TestCommand); + rootCommand.AddCommand(this.ReplayCommand); + rootCommand.AddCommand(this.RewriteCommand); + rootCommand.TreatUnmatchedTokensAsErrors = true; + + var commandLineBuilder = new CommandLineBuilder(rootCommand); + commandLineBuilder.UseDefaults(); + + var parser = commandLineBuilder.Build(); + this.Results = parser.Parse(args); + if (this.Results.Errors.Any() || IsHelpRequested(this.Results)) + { + // There are parsing errors, so invoke the result to print the errors and help message. + this.Results.Invoke(); + this.IsSuccessful = false; + } + else + { + // There were no errors, so use the parsed results to update the default configurations. + this.UpdateConfigurations(this.Results); + this.IsSuccessful = true; + } + } + + /// + /// Invoke the handler of the command that was selected by the user. + /// + internal ExitCode InvokeSelectedCommand( + Func testHandler, + Func replayHandler, + Func rewriteHandler) + { + PrintDetailedCoyoteVersion(); + + this.TestCommand.SetHandler((InvocationContext context) => context.ExitCode = (int)testHandler(this.Configuration)); + this.ReplayCommand.SetHandler((InvocationContext context) => context.ExitCode = (int)replayHandler(this.Configuration)); + this.RewriteCommand.SetHandler((InvocationContext context) => context.ExitCode = (int)rewriteHandler( + this.Configuration, this.RewritingOptions)); + return (ExitCode)this.Results.Invoke(); + } + + /// + /// Creates the test command. + /// + private Command CreateTestCommand(Configuration configuration) + { + var pathArg = new Argument("path", $"Path to the assembly (*.dll, *.exe) to test.") + { + HelpName = "PATH" + }; + + var methodOption = new Option( + aliases: new[] { "-m", "--method" }, + description: "Suffix of the test method to execute.") + { + ArgumentHelpName = "METHOD" + }; + + var iterationsOption = new Option( + aliases: new[] { "-i", "--iterations" }, + getDefaultValue: () => (int)configuration.TestingIterations, + description: "Number of testing iterations to run.") + { + ArgumentHelpName = "ITERATIONS" + }; + + var timeoutOption = new Option( + aliases: new[] { "-t", "--timeout" }, + getDefaultValue: () => configuration.TestingTimeout, + description: "Timeout in seconds after which no more testing iterations will run (disabled by default).") + { + ArgumentHelpName = "TIMEOUT" + }; + + var allowedStrategies = new HashSet + { + "random", + "prioritization", + "fair-prioritization", + "probabilistic", + "rl", + "portfolio" + }; + + var strategyOption = new Option( + aliases: new[] { "-s", "--strategy" }, + getDefaultValue: () => configuration.SchedulingStrategy, + description: "Set exploration strategy to use during testing. The exploration strategy " + + "controls all scheduling decisions and nondeterministic choices. " + + $"Allowed values are {string.Join(", ", allowedStrategies)}.") + { + ArgumentHelpName = "STRATEGY" + }; + + var strategyValueOption = new Option( + aliases: new[] { "-sv", "--strategy-value" }, + description: "Set exploration strategy specific value. Supported strategies (and values): " + + "(fair-)prioritization (maximum number of priority change points per iteration), " + + "probabilistic (probability of deviating from a scheduled operation).") + { + ArgumentHelpName = "VALUE" + }; + + var maxStepsOption = new Option( + aliases: new[] { "-ms", "--max-steps" }, + description: "Max scheduling steps (i.e. decisions) to be explored during testing. " + + "Choosing value 'STEPS' sets 'STEPS' unfair max-steps and 'STEPS*10' fair steps.") + { + ArgumentHelpName = "STEPS" + }; + + var maxFairStepsOption = new Option( + name: "--max-fair-steps", + getDefaultValue: () => configuration.MaxFairSchedulingSteps, + description: "Max fair scheduling steps (i.e. decisions) to be explored during testing. " + + "Used by exploration strategies that perform fair scheduling.") + { + ArgumentHelpName = "STEPS" + }; + + var maxUnfairStepsOption = new Option( + name: "--max-unfair-steps", + getDefaultValue: () => configuration.MaxUnfairSchedulingSteps, + description: "Max unfair scheduling steps (i.e. decisions) to be explored during testing. " + + "Used by exploration strategies that perform unfair scheduling.") + { + ArgumentHelpName = "STEPS" + }; + + var fuzzOption = new Option( + name: "--fuzz", + description: "Use systematic fuzzing instead of controlled testing.") + { + Arity = ArgumentArity.Zero + }; + + var coverageOption = new Option( + aliases: new[] { "-c", "--coverage" }, + description: "Generate coverage reports if supported for the programming model used by the test.") + { + Arity = ArgumentArity.Zero + }; + + var graphOption = new Option( + name: "--graph", + description: "Output a DGML graph that visualizes the failing execution path if a bug is found.") + { + Arity = ArgumentArity.Zero + }; + + var xmlLogOption = new Option( + name: "--xml-trace", + description: "Output an XML formatted runtime log file.") + { + Arity = ArgumentArity.Zero + }; + + var reduceSharedStateOption = new Option( + name: "--reduce-shared-state", + description: "Enables shared state reduction based on 'READ' and 'WRITE' scheduling points.") + { + Arity = ArgumentArity.Zero + }; + + var seedOption = new Option( + name: "--seed", + description: "Specify the random value generator seed.") + { + ArgumentHelpName = "VALUE" + }; + + var livenessTemperatureThresholdOption = new Option( + name: "--liveness-temperature-threshold", + getDefaultValue: () => configuration.LivenessTemperatureThreshold, + description: "Specify the threshold (in number of steps) that triggers a liveness bug.") + { + ArgumentHelpName = "THRESHOLD" + }; + + var timeoutDelayOption = new Option( + name: "--timeout-delay", + getDefaultValue: () => (int)configuration.TimeoutDelay, + description: "Controls the frequency of timeouts by built-in timers (not a unit of time).") + { + ArgumentHelpName = "DELAY" + }; + + var deadlockTimeoutOption = new Option( + name: "--deadlock-timeout", + getDefaultValue: () => (int)configuration.DeadlockTimeout, + description: "Controls how much time (in ms) to wait before reporting a potential deadlock.") + { + ArgumentHelpName = "TIMEOUT" + }; + + var uncontrolledConcurrencyTimeoutOption = new Option( + name: "--uncontrolled-concurrency-timeout", + getDefaultValue: () => (int)configuration.UncontrolledConcurrencyResolutionTimeout, + description: "Controls how much time (in ms) to try resolve uncontrolled concurrency.") + { + ArgumentHelpName = "TIMEOUT" + }; + + var uncontrolledConcurrencyIntervalOption = new Option( + name: "--uncontrolled-concurrency-interval", + getDefaultValue: () => (int)configuration.UncontrolledConcurrencyResolutionInterval, + description: "Controls the interval (in ms) between attempts to resolve uncontrolled concurrency.") + { + ArgumentHelpName = "INTERVAL" + }; + + var skipPotentialDeadlocksOption = new Option( + name: "--skip-potential-deadlocks", + description: "Only report a deadlock when the runtime can fully determine that it is genuine " + + "and not due to partially-controlled concurrency.") + { + Arity = ArgumentArity.Zero + }; + + var failOnMaxStepsOption = new Option( + name: "--fail-on-maxsteps", + description: "Reaching the specified max-steps is considered a bug.") + { + Arity = ArgumentArity.Zero + }; + + var noFuzzingFallbackOption = new Option( + name: "--no-fuzzing-fallback", + description: "Disable automatic fallback to systematic fuzzing upon detecting uncontrolled concurrency.") + { + Arity = ArgumentArity.Zero + }; + + var noPartialControlOption = new Option( + name: "--no-partial-control", + description: "Disallow partially controlled concurrency during controlled testing.") + { + Arity = ArgumentArity.Zero + }; + + var noReproOption = new Option( + name: "--no-repro", + description: "Disable bug trace repro to ignore uncontrolled concurrency errors.") + { + Arity = ArgumentArity.Zero + }; + + var exploreOption = new Option( + name: "explore", + description: "Keep testing until the bound (e.g. iteration or time) is reached.") + { + Arity = ArgumentArity.Zero, + IsHidden = true + }; + + var breakOption = new Option( + aliases: new[] { "-b", "--break" }, + description: "Attaches the debugger and adds a breakpoint when an assertion fails.") + { + Arity = ArgumentArity.Zero + }; + + var outputDirectoryOption = new Option( + aliases: new[] { "-o", "--outdir" }, + description: "Output directory for emitting reports. This can be an absolute path or relative to current directory.") + { + ArgumentHelpName = "PATH" + }; + + // Add validators. + pathArg.AddValidator(result => ValidateArgumentValueIsExpectedFile(result, ".dll", ".exe")); + iterationsOption.AddValidator(result => ValidateOptionValueIsUnsignedInteger(result)); + timeoutOption.AddValidator(result => ValidateOptionValueIsUnsignedInteger(result)); + strategyOption.AddValidator(result => ValidateOptionValueIsAllowed(result, allowedStrategies)); + strategyValueOption.AddValidator(result => ValidatePrerequisiteOptionValueIsAvailable(result, strategyOption)); + maxStepsOption.AddValidator(result => ValidateOptionValueIsUnsignedInteger(result)); + maxStepsOption.AddValidator(result => ValidateExclusiveOptionValueIsAvailable(result, maxFairStepsOption)); + maxStepsOption.AddValidator(result => ValidateExclusiveOptionValueIsAvailable(result, maxUnfairStepsOption)); + maxFairStepsOption.AddValidator(result => ValidateOptionValueIsUnsignedInteger(result)); + maxFairStepsOption.AddValidator(result => ValidateExclusiveOptionValueIsAvailable(result, maxStepsOption)); + maxUnfairStepsOption.AddValidator(result => ValidateOptionValueIsUnsignedInteger(result)); + maxUnfairStepsOption.AddValidator(result => ValidateExclusiveOptionValueIsAvailable(result, maxStepsOption)); + seedOption.AddValidator(result => ValidateOptionValueIsUnsignedInteger(result)); + livenessTemperatureThresholdOption.AddValidator(result => ValidateOptionValueIsUnsignedInteger(result)); + timeoutDelayOption.AddValidator(result => ValidateOptionValueIsUnsignedInteger(result)); + deadlockTimeoutOption.AddValidator(result => ValidateOptionValueIsUnsignedInteger(result)); + uncontrolledConcurrencyTimeoutOption.AddValidator(result => ValidateOptionValueIsUnsignedInteger(result)); + uncontrolledConcurrencyIntervalOption.AddValidator(result => ValidateOptionValueIsUnsignedInteger(result)); + + // Build command. + var command = new Command("test", "Run tests using the Coyote systematic testing engine.\n" + + $"Learn more at {LearnAboutTestUrl}."); + this.AddArgument(command, pathArg); + this.AddOption(command, methodOption); + this.AddOption(command, iterationsOption); + this.AddOption(command, timeoutOption); + this.AddOption(command, strategyOption); + this.AddOption(command, strategyValueOption); + this.AddOption(command, maxStepsOption); + this.AddOption(command, maxFairStepsOption); + this.AddOption(command, maxUnfairStepsOption); + this.AddOption(command, fuzzOption); + this.AddOption(command, coverageOption); + this.AddOption(command, graphOption); + this.AddOption(command, xmlLogOption); + this.AddOption(command, reduceSharedStateOption); + this.AddOption(command, seedOption); + this.AddOption(command, livenessTemperatureThresholdOption); + this.AddOption(command, timeoutDelayOption); + this.AddOption(command, deadlockTimeoutOption); + this.AddOption(command, uncontrolledConcurrencyTimeoutOption); + this.AddOption(command, uncontrolledConcurrencyIntervalOption); + this.AddOption(command, skipPotentialDeadlocksOption); + this.AddOption(command, failOnMaxStepsOption); + this.AddOption(command, noFuzzingFallbackOption); + this.AddOption(command, noPartialControlOption); + this.AddOption(command, noReproOption); + this.AddOption(command, exploreOption); + this.AddOption(command, breakOption); + this.AddOption(command, outputDirectoryOption); + command.TreatUnmatchedTokensAsErrors = true; + return command; + } + + /// + /// Creates the replay command. + /// + private Command CreateReplayCommand() + { + var pathArg = new Argument("path", $"Path to the assembly (*.dll, *.exe) to replay.") + { + HelpName = "PATH" + }; + + var scheduleFileArg = new Argument("schedule", $"*.schedule file containing the execution to replay.") + { + HelpName = "SCHEDULE_FILE" + }; + + var methodOption = new Option( + aliases: new[] { "-m", "--method" }, + description: "Suffix of the test method to execute.") + { + ArgumentHelpName = "METHOD" + }; + + var breakOption = new Option( + aliases: new[] { "-b", "--break" }, + description: "Attaches the debugger and adds a breakpoint when an assertion fails.") + { + Arity = ArgumentArity.Zero + }; + + var outputDirectoryOption = new Option( + aliases: new[] { "-o", "--outdir" }, + description: "Output directory for emitting reports. This can be an absolute path or relative to current directory.") + { + ArgumentHelpName = "PATH" + }; + + // Add validators. + pathArg.AddValidator(result => ValidateArgumentValueIsExpectedFile(result, ".dll", ".exe")); + scheduleFileArg.AddValidator(result => ValidateArgumentValueIsExpectedFile(result, ".schedule")); + + // Build command. + var command = new Command("replay", "Replay bugs that Coyote discovered during systematic testing.\n" + + $"Learn more at {LearnAboutReplayUrl}."); + this.AddArgument(command, pathArg); + this.AddArgument(command, scheduleFileArg); + this.AddOption(command, methodOption); + this.AddOption(command, breakOption); + this.AddOption(command, outputDirectoryOption); + command.TreatUnmatchedTokensAsErrors = true; + return command; + } + + /// + /// Creates the rewrite command. + /// + private Command CreateRewriteCommand() + { + var pathArg = new Argument("path", "Path to the assembly (*.dll, *.exe) to rewrite or to a JSON rewriting configuration file.") + { + HelpName = "PATH" + }; + + var assertDataRacesOption = new Option( + name: "--assert-data-races", + getDefaultValue: () => false, + description: "Add assertions for read/write data races.") + { + Arity = ArgumentArity.Zero, + IsHidden = true + }; + + var rewriteDependenciesOption = new Option( + name: "--rewrite-dependencies", + getDefaultValue: () => false, + description: "Rewrite all dependent assemblies that are found in the same location as the given path.") + { + Arity = ArgumentArity.Zero, + IsHidden = true + }; + + var rewriteUnitTestsOption = new Option( + name: "--rewrite-unit-tests", + getDefaultValue: () => false, + description: "Rewrite unit tests to automatically inject the Coyote testing engine.") + { + Arity = ArgumentArity.Zero, + IsHidden = true + }; + + var rewriteThreadsOption = new Option( + name: "--rewrite-threads", + getDefaultValue: () => false, + description: "Rewrite low-level threading APIs.") + { + Arity = ArgumentArity.Zero, + IsHidden = true + }; + + var dumpILOption = new Option( + name: "--dump-il", + getDefaultValue: () => false, + description: "Dumps the original and rewritten IL in JSON for debugging purposes.") + { + Arity = ArgumentArity.Zero + }; + + var dumpILDiffOption = new Option( + name: "--dump-il-diff", + getDefaultValue: () => false, + description: "Dumps the IL diff in JSON for debugging purposes.") + { + Arity = ArgumentArity.Zero + }; + + // Add validators. + pathArg.AddValidator(result => ValidateArgumentValueIsExpectedFile(result, ".dll", ".exe", ".json")); + + // Build command. + var command = new Command("rewrite", "Rewrite your assemblies to inject logic that allows " + + "Coyote to take control of the schedule during systematic testing.\n" + + $"Learn more at {LearnAboutRewritingUrl}."); + this.AddArgument(command, pathArg); + this.AddOption(command, assertDataRacesOption); + this.AddOption(command, rewriteDependenciesOption); + this.AddOption(command, rewriteUnitTestsOption); + this.AddOption(command, rewriteThreadsOption); + this.AddOption(command, dumpILOption); + this.AddOption(command, dumpILDiffOption); + command.TreatUnmatchedTokensAsErrors = true; + return command; + } + + /// + /// Adds an argument to the specified command. + /// + private void AddArgument(Command command, Argument argument) + { + command.AddArgument(argument); + if (!this.Arguments.ContainsKey(argument.Name)) + { + this.Arguments.Add(argument.Name, argument); + } + } + + /// + /// Adds a global option to the specified command. + /// + private void AddGlobalOption(Command command, Option option) + { + command.AddGlobalOption(option); + if (!this.Options.ContainsKey(option.Name)) + { + this.Options.Add(option.Name, option); + } + } + + /// + /// Adds an option to the specified command. + /// + private void AddOption(Command command, Option option) + { + command.AddOption(option); + if (!this.Options.ContainsKey(option.Name)) + { + this.Options.Add(option.Name, option); + } + } + + /// + /// Validates that the specified argument result is found and has an expected file extension. + /// + private static void ValidateArgumentValueIsExpectedFile(ArgumentResult result, params string[] extensions) + { + string fileName = result.GetValueOrDefault(); + string foundExtension = Path.GetExtension(fileName); + if (!extensions.Any(extension => extension == foundExtension)) + { + if (extensions.Length is 1) + { + result.ErrorMessage = $"File '{fileName}' does not have the expected '{extensions[0]}' extension."; + } + else + { + result.ErrorMessage = $"File '{fileName}' does not have one of the expected extensions: " + + $"{string.Join(", ", extensions)}."; + } + } + else if (!File.Exists(fileName)) + { + result.ErrorMessage = $"File '{fileName}' does not exist."; + } + } + + /// + /// Validates that the specified option result is an unsigned integer. + /// + private static void ValidateOptionValueIsUnsignedInteger(OptionResult result) + { + if (result.Tokens.Select(token => token.Value).Where(v => !uint.TryParse(v, out _)).Any()) + { + result.ErrorMessage = $"Please give a positive integer to option '{result.Option.Name}'."; + } + } + + /// + /// Validates that the specified option result has an allowed value. + /// + private static void ValidateOptionValueIsAllowed(OptionResult result, IEnumerable allowedValues) + { + if (result.Tokens.Select(token => token.Value).Where(v => !allowedValues.Contains(v)).Any()) + { + result.ErrorMessage = $"Please give an allowed value to option '{result.Option.Name}': " + + $"{string.Join(", ", allowedValues)}."; + } + } + + /// + /// Validates that the specified prerequisite option is available. + /// + private static void ValidatePrerequisiteOptionValueIsAvailable(OptionResult result, Option prerequisite) + { + OptionResult prerequisiteResult = result.FindResultFor(prerequisite); + if (!result.IsImplicit && (prerequisiteResult is null || prerequisiteResult.IsImplicit)) + { + result.ErrorMessage = $"Setting option '{result.Option.Name}' requires option '{prerequisite.Name}'."; + } + } + + /// + /// Validates that the specified exclusive option is available. + /// + private static void ValidateExclusiveOptionValueIsAvailable(OptionResult result, Option exclusive) + { + OptionResult exclusiveResult = result.FindResultFor(exclusive); + if (!result.IsImplicit && exclusiveResult != null && !exclusiveResult.IsImplicit) + { + result.ErrorMessage = $"Setting options '{result.Option.Name}' and '{exclusive.Name}' at the same time is not allowed."; + } + } + + /// + /// Populates the configurations from the specified parse result. + /// + private void UpdateConfigurations(ParseResult result) + { + CommandResult commandResult = result.CommandResult; + Command command = commandResult.Command; + foreach (var symbolResult in commandResult.Children) + { + if (symbolResult is ArgumentResult argument) + { + this.UpdateConfigurationsWithParsedArgument(command, argument); + } + else if (symbolResult is OptionResult option) + { + this.UpdateConfigurationsWithParsedOption(option); + } + } + } + + /// + /// Updates the configuration with the specified parsed argument. + /// + private void UpdateConfigurationsWithParsedArgument(Command command, ArgumentResult result) + { + switch (result.Argument.Name) + { + case "path": + if (command.Name is "test" || command.Name is "replay") + { + // In the case of 'coyote test' or 'replay', the path is the assembly to be tested. + this.Configuration.AssemblyToBeAnalyzed = result.GetValueOrDefault(); + } + else if (command.Name is "rewrite") + { + // In the case of 'coyote rewrite', the path is the JSON this.Configuration file + // with the binary rewriting options. + string filename = result.GetValueOrDefault(); + if (Directory.Exists(filename)) + { + // Then we want to rewrite a whole folder full of assemblies. + var assembliesDir = Path.GetFullPath(filename); + this.RewritingOptions.AssembliesDirectory = assembliesDir; + this.RewritingOptions.OutputDirectory = assembliesDir; + } + else + { + string extension = Path.GetExtension(filename); + if (string.Compare(extension, ".json", StringComparison.OrdinalIgnoreCase) is 0) + { + // Parse the rewriting options from the JSON file. + RewritingOptions.ParseFromJSON(this.RewritingOptions, filename); + } + else if (string.Compare(extension, ".dll", StringComparison.OrdinalIgnoreCase) is 0 || + string.Compare(extension, ".exe", StringComparison.OrdinalIgnoreCase) is 0) + { + this.Configuration.AssemblyToBeAnalyzed = filename; + var fullPath = Path.GetFullPath(filename); + var assembliesDir = Path.GetDirectoryName(fullPath); + this.RewritingOptions.AssembliesDirectory = assembliesDir; + this.RewritingOptions.OutputDirectory = assembliesDir; + this.RewritingOptions.AssemblyPaths.Add(fullPath); + } + } + } + + break; + case "schedule": + if (command.Name is "replay") + { + this.Configuration.ScheduleFile = result.GetValueOrDefault(); + } + + break; + default: + throw new Exception(string.Format("Unhandled parsed argument '{0}'.", result.Argument.Name)); + } + } + + /// + /// Updates the configuration with the specified parsed option. + /// + private void UpdateConfigurationsWithParsedOption(OptionResult result) + { + if (!result.IsImplicit) + { + switch (result.Option.Name) + { + case "method": + this.Configuration.TestMethodName = result.GetValueOrDefault(); + break; + case "iterations": + this.Configuration.TestingIterations = (uint)result.GetValueOrDefault(); + break; + case "timeout": + this.Configuration.TestingTimeout = result.GetValueOrDefault(); + break; + case "strategy": + var strategyBound = result.FindResultFor(this.Options["strategy-value"]); + string strategy = result.GetValueOrDefault(); + switch (strategy) + { + case "prioritization": + case "fair-prioritization": + if (strategyBound is null) + { + this.Configuration.StrategyBound = 10; + } + + break; + case "probabilistic": + if (strategyBound is null) + { + this.Configuration.StrategyBound = 3; + } + + break; + case "rl": + this.Configuration.IsProgramStateHashingEnabled = true; + break; + case "portfolio": + strategy = "random"; + break; + default: + break; + } + + this.Configuration.SchedulingStrategy = strategy; + break; + case "strategy-value": + this.Configuration.StrategyBound = result.GetValueOrDefault(); + break; + case "max-steps": + this.Configuration.WithMaxSchedulingSteps((uint)result.GetValueOrDefault()); + break; + case "max-fair-steps": + var maxUnfairSteps = result.FindResultFor(this.Options["max-unfair-steps"]); + this.Configuration.WithMaxSchedulingSteps( + (uint)(maxUnfairSteps?.GetValueOrDefault() ?? this.Configuration.MaxUnfairSchedulingSteps), + (uint)result.GetValueOrDefault()); + break; + case "max-unfair-steps": + var maxFairSteps = result.FindResultFor(this.Options["max-fair-steps"]); + this.Configuration.WithMaxSchedulingSteps( + (uint)result.GetValueOrDefault(), + (uint)(maxFairSteps?.GetValueOrDefault() ?? this.Configuration.MaxFairSchedulingSteps)); + break; + case "fuzz": + case "no-repro": + this.Configuration.IsSystematicFuzzingEnabled = true; + break; + case "coverage": + this.Configuration.IsActivityCoverageReported = true; + break; + case "graph": + this.Configuration.IsTraceVisualizationEnabled = true; + break; + case "xml-trace": + this.Configuration.IsXmlLogEnabled = true; + break; + case "reduce-shared-state": + this.Configuration.IsSharedStateReductionEnabled = true; + break; + case "seed": + this.Configuration.RandomGeneratorSeed = (uint)result.GetValueOrDefault(); + break; + case "liveness-temperature-threshold": + this.Configuration.LivenessTemperatureThreshold = result.GetValueOrDefault(); + this.Configuration.UserExplicitlySetLivenessTemperatureThreshold = true; + break; + case "timeout-delay": + this.Configuration.TimeoutDelay = (uint)result.GetValueOrDefault(); + break; + case "deadlock-timeout": + this.Configuration.DeadlockTimeout = (uint)result.GetValueOrDefault(); + break; + case "uncontrolled-concurrency-timeout": + this.Configuration.UncontrolledConcurrencyResolutionTimeout = (uint)result.GetValueOrDefault(); + break; + case "uncontrolled-concurrency-interval": + this.Configuration.UncontrolledConcurrencyResolutionInterval = (uint)result.GetValueOrDefault(); + break; + case "skip-potential-deadlocks": + this.Configuration.ReportPotentialDeadlocksAsBugs = false; + break; + case "fail-on-maxsteps": + this.Configuration.ConsiderDepthBoundHitAsBug = true; + break; + case "no-fuzzing-fallback": + this.Configuration.IsSystematicFuzzingFallbackEnabled = false; + break; + case "no-partial-control": + this.Configuration.IsPartiallyControlledConcurrencyAllowed = false; + break; + case "explore": + this.Configuration.RunTestIterationsToCompletion = true; + break; + case "break": + this.Configuration.AttachDebugger = true; + break; + case "outdir": + this.Configuration.OutputFilePath = result.GetValueOrDefault(); + break; + case "debug": + this.Configuration.IsDebugVerbosityEnabled = true; + Debug.IsEnabled = true; + break; + case "assert-data-races": + this.RewritingOptions.IsDataRaceCheckingEnabled = true; + break; + case "rewrite-dependencies": + this.RewritingOptions.IsRewritingDependencies = true; + break; + case "rewrite-unit-tests": + this.RewritingOptions.IsRewritingUnitTests = true; + break; + case "rewrite-threads": + this.RewritingOptions.IsRewritingThreads = true; + break; + case "dump-il": + this.RewritingOptions.IsLoggingAssemblyContents = true; + break; + case "dump-il-diff": + this.RewritingOptions.IsDiffingAssemblyContents = true; + break; + case "verbosity": + switch (result.GetValueOrDefault()) + { + case "quiet": + this.Configuration.IsVerbose = false; + break; + case "minimal": + this.Configuration.LogLevel = LogSeverity.Error; + this.Configuration.IsVerbose = true; + break; + case "normal": + this.Configuration.LogLevel = LogSeverity.Warning; + this.Configuration.IsVerbose = true; + break; + case "detailed": + default: + this.Configuration.LogLevel = LogSeverity.Informational; + this.Configuration.IsVerbose = true; + break; + } + + break; + case "help": + break; + default: + throw new Exception(string.Format("Unhandled parsed option '{0}.", result.Option.Name)); + } + } + } + + /// + /// Returns true if the user is asking for help. + /// + private static bool IsHelpRequested(ParseResult result) => result.CommandResult.Children + .OfType() + .Any(result => result.Option.Name is "help" && !result.IsImplicit); + + /// + /// Prints the detailed Coyote version. + /// + private static void PrintDetailedCoyoteVersion() + { + Console.WriteLine("Microsoft (R) Coyote version {0} for .NET{1}", + typeof(CommandLineParser).Assembly.GetName().Version, GetDotNetVersion()); + Console.WriteLine("Copyright (C) Microsoft Corporation. All rights reserved.\n"); + } + + /// + /// Returns the current .NET version. + /// + private static string GetDotNetVersion() + { + var path = typeof(string).Assembly.Location; + string result = string.Empty; + + string[] parts = path.Replace("\\", "/").Split('/'); + if (parts.Length > 2) + { + var version = parts[parts.Length - 2]; + if (char.IsDigit(version[0])) + { + result += " " + version; + } + } + + return result; + } + } +} diff --git a/Tools/Coyote/Cli/ExitCode.cs b/Tools/Coyote/Cli/ExitCode.cs new file mode 100644 index 000000000..00817dc76 --- /dev/null +++ b/Tools/Coyote/Cli/ExitCode.cs @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.Coyote.Cli +{ + /// + /// The exit code returned by the tool. + /// + internal enum ExitCode + { + /// + /// Indicates that the tool terminated successfully. + /// + /// + /// If the tool run in test mode, it also indicates that no bugs were found. + /// + Success = 0, + + /// + /// Indicates that the tool terminated with an error. + /// + Error = 1, + + /// + /// Indicates that a bug was found during testing. + /// + BugFound = 2, + + /// + /// Indicates that the tool terminated with an internal error. + /// + InternalError = 3 + } +} diff --git a/Tools/Coyote/Cli/OutputFileManager.cs b/Tools/Coyote/Cli/OutputFileManager.cs new file mode 100644 index 000000000..0954c3a47 --- /dev/null +++ b/Tools/Coyote/Cli/OutputFileManager.cs @@ -0,0 +1,77 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.IO; +using System.Text.RegularExpressions; + +namespace Microsoft.Coyote.Cli +{ + /// + /// The manager for output files. + /// + internal static class OutputFileManager + { + /// + /// Creates the output directory at either the user-specified + /// or at the same directory as the . + /// + internal static string CreateOutputDirectory(Configuration configuration) + { + string directory; + if (!string.IsNullOrEmpty(configuration.OutputFilePath)) + { + directory = configuration.OutputFilePath + Path.DirectorySeparatorChar; + } + else + { + var subpath = Path.GetDirectoryName(configuration.AssemblyToBeAnalyzed); + if (subpath.Length is 0) + { + subpath = "."; + } + + directory = subpath + + Path.DirectorySeparatorChar + "Output" + Path.DirectorySeparatorChar + + Path.GetFileName(configuration.AssemblyToBeAnalyzed) + Path.DirectorySeparatorChar; + } + + string suffix = "CoyoteOutput"; + if (suffix.Length > 0) + { + directory += suffix + Path.DirectorySeparatorChar; + } + + Directory.CreateDirectory(directory); + return directory; + } + + /// + /// Returns the filename with the next available index appended to it. + /// + internal static string GetResolvedFileName(string fileName, string directory) + { + int index = 0; + Regex match = new Regex("^(.*)_([0-9]+)"); + fileName = Path.GetFileNameWithoutExtension(fileName); + foreach (var path in Directory.GetFiles(directory)) + { + string name = Path.GetFileName(path); + if (name.StartsWith(fileName)) + { + var result = match.Match(name); + if (result.Success) + { + string value = result.Groups[2].Value; + if (int.TryParse(value, out int i)) + { + index = Math.Max(index, i + 1); + } + } + } + } + + return fileName + "_" + index; + } + } +} diff --git a/Tools/Coyote/Coyote.csproj b/Tools/Coyote/Coyote.csproj index 2eb866d8c..66717ea19 100644 --- a/Tools/Coyote/Coyote.csproj +++ b/Tools/Coyote/Coyote.csproj @@ -14,15 +14,23 @@ - + + + + + + + + + + - diff --git a/Tools/Coyote/Instrumentation/CodeCoverageInstrumentation.cs b/Tools/Coyote/Instrumentation/CodeCoverageInstrumentation.cs deleted file mode 100644 index 1ed57b264..000000000 --- a/Tools/Coyote/Instrumentation/CodeCoverageInstrumentation.cs +++ /dev/null @@ -1,260 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; -using System.Collections.Generic; -#if NETFRAMEWORK -using System.Configuration; -#endif -using System.Diagnostics; -using System.IO; -using Microsoft.Coyote.IO; -using Microsoft.Coyote.SystematicTesting.Utilities; - -namespace Microsoft.Coyote.SystematicTesting -{ - /// - /// Instruments a binary for code coverage. - /// - internal static class CodeCoverageInstrumentation - { - internal static string OutputDirectory = string.Empty; - - internal static void Instrument(Configuration configuration) - { - if (string.IsNullOrEmpty(OutputDirectory)) - { - throw new Exception("Please set the OutputDirectory before calling Instrument"); - } - - // HashSet in case of duplicate file specifications. - var assembliesToInstrument = new HashSet(GetInstrumentAssemblies(configuration)); - assembliesToInstrument.UnionWith(GetDependencies(configuration.AssemblyToBeAnalyzed, assembliesToInstrument)); - - foreach (var assemblyPath in assembliesToInstrument) - { - string newAssembly = Instrument(assemblyPath); - if (string.IsNullOrEmpty(newAssembly)) - { - Error.ReportAndExit($"Terminating due to VSInstr error."); - } - - if (assemblyPath == configuration.AssemblyToBeAnalyzed) - { - // Remember the location of the original assembly so we can add this to the PATH - // when we run the test out of proc. - configuration.AdditionalPaths = Path.GetDirectoryName(configuration.AssemblyToBeAnalyzed); - configuration.AssemblyToBeAnalyzed = newAssembly; - } - } - } - - private static IEnumerable GetDependencies(string assemblyToBeAnalyzed, HashSet additionalAssemblies) - { - var fullPath = Path.GetFullPath(assemblyToBeAnalyzed); - DependencyGraph graph = new DependencyGraph(Path.GetDirectoryName(fullPath), additionalAssemblies); - return graph.GetDependencies(fullPath); - } - - private static IEnumerable GetInstrumentAssemblies(Configuration configuration) - { - var fullPath = Path.GetFullPath(configuration.AssemblyToBeAnalyzed); - var testAssemblyPath = Path.GetDirectoryName(fullPath); - yield return fullPath; - - Uri baseUri = new Uri(fullPath); - - IEnumerable ResolveFileSpec(string spec) - { - var localPath = Path.GetFullPath(spec); - if (!File.Exists(localPath)) - { - // If not rooted, the file path might be relative to testAssemblyPath. - var resolved = new Uri(baseUri, spec); - localPath = resolved.LocalPath; - - if (!File.Exists(localPath)) - { - Error.ReportAndExit($"Cannot find specified file for code-coverage instrumentation: '{spec}'."); - } - } - - yield return localPath; - } - - IEnumerable ResolveAdditionalFiles(KeyValuePair kvp) - { - if (!kvp.Value) - { - foreach (var file in ResolveFileSpec(kvp.Key)) - { - yield return file; - } - - yield break; - } - - var dir = Path.GetDirectoryName(kvp.Key); - var fullDir = Path.GetFullPath(dir.Length > 0 ? dir : testAssemblyPath); - var listFile = Path.Combine(fullDir, Path.GetFileName(kvp.Key)); - if (!File.Exists(listFile)) - { - Error.ReportAndExit($"Cannot find specified list file for code-coverage instrumentation: '{kvp.Key}'."); - } - - foreach (var spec in File.ReadAllLines(listFile)) - { - var trimmed = spec.Trim(); - if (!string.IsNullOrEmpty(trimmed) && !trimmed.StartsWith("//")) - { - foreach (var file in ResolveFileSpec(trimmed)) - { - yield return file; - } - } - } - } - - // Note: Resolution has been deferred to here so that all empty path qualifiations, including to the list - // file, will resolve to testAssemblyPath (as config coverage parameters may be specified before /test). - // Return .ToList() to force iteration and return errors before we start instrumenting. - foreach (var kvp in configuration.AdditionalCodeCoverageAssemblies) - { - foreach (var file in ResolveAdditionalFiles(kvp)) - { - yield return file; - } - } - } - - private static string Instrument(string assemblyName) - { - int exitCode; - string error; - Console.WriteLine($"Instrumenting {assemblyName}"); - - using (var instrProc = new Process()) - { - instrProc.StartInfo.FileName = GetToolPath("VSInstrToolPath", "VSInstr"); - instrProc.StartInfo.Arguments = $"\"{assemblyName}\" /COVERAGE \"/OUTPUTPATH:{OutputDirectory}\""; - instrProc.StartInfo.UseShellExecute = false; - instrProc.StartInfo.RedirectStandardOutput = true; - instrProc.StartInfo.RedirectStandardError = true; - instrProc.Start(); - - error = instrProc.StandardError.ReadToEnd(); - - instrProc.WaitForExit(); - exitCode = instrProc.ExitCode; - } - - if (error.StartsWith("Error")) - { - // sometimes VSInstr fails, provides error message and returns 0 ?! - if (error.Contains("VSP1014")) - { - Error.Report($"[Coyote] 'VSInstr' requires you build with 'full' and 'true'"); - } - - exitCode = 1; - } - - // Exit code 0 means that the file was instrumented successfully. - // Exit code 4 means that the file was already instrumented. - if (exitCode != 0 && exitCode != 4) - { - Error.Report($"[Coyote] 'VSInstr' failed to instrument '{assemblyName}'. " + error); - return null; - } - - string fileName = Path.GetFileName(assemblyName); - string newFileName = Path.Combine(OutputDirectory, fileName); - if (!File.Exists(newFileName)) - { - Error.Report($"[Coyote] 'VSInstr' did not produce output assembly '{newFileName}'. " + error); - return null; - } - - return newFileName; - } - - /// - /// Returns the tool path to the code coverage instrumentor. - /// - /// The name of the setting; also used to query the environment variables. - /// The name of the tool; used in messages only. - internal static string GetToolPath(string settingName, string toolName) - { - string toolPath = string.Empty; - try - { - toolPath = Environment.GetEnvironmentVariable(settingName); - if (string.IsNullOrEmpty(toolPath)) - { -#if NETFRAMEWORK - toolPath = ConfigurationManager.AppSettings[settingName]; -#else - if (settingName == "VSInstrToolPath") - { - toolPath = @"$(DevEnvDir)..\..\Team Tools\Performance Tools\x64\vsinstr.exe"; - } - else - { - toolPath = @"$(DevEnvDir)..\..\..\..\Shared\Common\VSPerfCollectionTools\vs2019\x64\VSPerfCmd.exe"; - } -#endif - } - else - { - Console.WriteLine($"{toolName} overriding app settings path with environment variable"); - } - } - catch (Exception) - { - Error.ReportAndExit($"[Coyote] required '{settingName}' value is not set in configuration file."); - } - - if (toolPath.Contains("$(DevEnvDir)")) - { - var devenvDir = Environment.GetEnvironmentVariable("DevEnvDir"); - if (string.IsNullOrEmpty(devenvDir)) - { - Error.ReportAndExit($"[Coyote] '{toolName}' tool needs DevEnvDir variable to be set."); - } - - toolPath = toolPath.Replace("$(DevEnvDir)", devenvDir); - } - - if (!File.Exists(toolPath)) - { - Error.ReportAndExit($"[Coyote] '{toolName}' tool '{toolPath}' not found."); - } - - return toolPath; - } - - /// - /// Set the to either the user-specified - /// or to a unique output directory name in the same directory as - /// and starting with its name. - /// - internal static void SetOutputDirectory(Configuration configuration, bool makeHistory) - { - if (OutputDirectory.Length > 0) - { - return; - } - - // Do not create the output directory yet if we have to scroll back the history first. - OutputDirectory = Reporter.GetOutputDirectory(configuration.OutputFilePath, configuration.AssemblyToBeAnalyzed, - "CoyoteOutput", createDir: !makeHistory); - if (!makeHistory) - { - return; - } - - // Now create the new directory. - Directory.CreateDirectory(OutputDirectory); - } - } -} diff --git a/Tools/Coyote/Interfaces/BugFoundMessage.cs b/Tools/Coyote/Interfaces/BugFoundMessage.cs deleted file mode 100644 index 7d0c00195..000000000 --- a/Tools/Coyote/Interfaces/BugFoundMessage.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System.Runtime.Serialization; -using Microsoft.Coyote.SmartSockets; - -namespace Microsoft.Coyote.SystematicTesting.Interfaces -{ - [DataContract] - internal class BugFoundMessage : SocketMessage - { - [DataMember] - public uint ProcessId { get; set; } - - public BugFoundMessage(string id, string name, uint processId) - : base(id, name) - { - this.ProcessId = processId; - } - } -} diff --git a/Tools/Coyote/Interfaces/TestProgressMessage.cs b/Tools/Coyote/Interfaces/TestProgressMessage.cs deleted file mode 100644 index daad4d6b4..000000000 --- a/Tools/Coyote/Interfaces/TestProgressMessage.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System.Runtime.Serialization; -using Microsoft.Coyote.SmartSockets; - -namespace Microsoft.Coyote.SystematicTesting.Interfaces -{ - [DataContract] - internal class TestProgressMessage : SocketMessage - { - [DataMember] - public uint ProcessId { get; set; } - - [DataMember] - public double Progress { get; set; } - - public TestProgressMessage(string id, string name, uint processId, double progress) - : base(id, name) - { - this.ProcessId = processId; - this.Progress = progress; - } - } -} diff --git a/Tools/Coyote/Interfaces/TestReportMessage.cs b/Tools/Coyote/Interfaces/TestReportMessage.cs deleted file mode 100644 index 16d7e5560..000000000 --- a/Tools/Coyote/Interfaces/TestReportMessage.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System.Runtime.Serialization; -using Microsoft.Coyote.SmartSockets; - -namespace Microsoft.Coyote.SystematicTesting.Interfaces -{ - [DataContract] - internal class TestReportMessage : SocketMessage - { - [DataMember] - public uint ProcessId { get; set; } - - [DataMember] - public TestReport TestReport { get; set; } - - public TestReportMessage(string id, string name, uint processId, TestReport testReport) - : base(id, name) - { - this.ProcessId = processId; - this.TestReport = testReport; - } - } -} diff --git a/Tools/Coyote/Interfaces/TestServerMessage.cs b/Tools/Coyote/Interfaces/TestServerMessage.cs deleted file mode 100644 index 28ac4381e..000000000 --- a/Tools/Coyote/Interfaces/TestServerMessage.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System.Runtime.Serialization; -using Microsoft.Coyote.SmartSockets; - -namespace Microsoft.Coyote.SystematicTesting.Interfaces -{ - [DataContract] - internal class TestServerMessage : SocketMessage - { - [DataMember] - public bool Stop { get; set; } - - public TestServerMessage(string id, string name) - : base(id, name) - { - } - } -} diff --git a/Tools/Coyote/Interfaces/TestTraceMessage.cs b/Tools/Coyote/Interfaces/TestTraceMessage.cs deleted file mode 100644 index f42a18f43..000000000 --- a/Tools/Coyote/Interfaces/TestTraceMessage.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System.Runtime.Serialization; -using Microsoft.Coyote.SmartSockets; - -namespace Microsoft.Coyote.SystematicTesting.Interfaces -{ - [DataContract] - internal class TestTraceMessage : SocketMessage - { - [DataMember] - public uint ProcessId { get; set; } - - [DataMember] - public string FileName { get; set; } - - [DataMember] - public string Contents { get; set; } - - public TestTraceMessage(string id, string name, uint processId, string fileName, string textContents) - : base(id, name) - { - this.ProcessId = processId; - this.FileName = fileName; - this.Contents = textContents; - } - } -} diff --git a/Tools/Coyote/Monitoring/CodeCoverageMonitor.cs b/Tools/Coyote/Monitoring/CodeCoverageMonitor.cs deleted file mode 100644 index e42c43526..000000000 --- a/Tools/Coyote/Monitoring/CodeCoverageMonitor.cs +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; -using System.Diagnostics; -using System.IO; - -namespace Microsoft.Coyote.SystematicTesting -{ - /// - /// Monitors the program being tested for code coverage. - /// - internal static class CodeCoverageMonitor - { - /// - /// Configuration. - /// - private static Configuration Configuration; - - /// - /// Monitoring process is running. - /// - internal static bool IsRunning; - - /// - /// Starts the code coverage monitor. - /// - /// Configuration. - internal static void Start(Configuration configuration) - { - if (IsRunning) - { - throw new InvalidOperationException("Process has already started."); - } - - Configuration = configuration; - RunMonitorProcess(true); - IsRunning = true; - } - - /// - /// Stops the code coverage monitor. - /// - internal static void Stop() - { - if (Configuration is null) - { - throw new InvalidOperationException("Process has not been configured."); - } - - if (!IsRunning) - { - throw new InvalidOperationException("Process is not running."); - } - - RunMonitorProcess(false); - IsRunning = false; - } - - private static void RunMonitorProcess(bool isStarting) - { - var error = string.Empty; - var exitCode = 0; - var outputFile = GetOutputName(); - var arguments = isStarting ? $"/start:coverage /output:{outputFile}" : "/shutdown"; - var timedOut = false; - using (var monitorProc = new Process()) - { - monitorProc.StartInfo.FileName = CodeCoverageInstrumentation.GetToolPath("VSPerfCmdToolPath", "VSPerfCmd"); - monitorProc.StartInfo.Arguments = arguments; - monitorProc.StartInfo.UseShellExecute = false; - monitorProc.StartInfo.RedirectStandardOutput = true; - monitorProc.StartInfo.RedirectStandardError = true; - monitorProc.Start(); - - Console.WriteLine($"... {(isStarting ? "Starting" : "Shutting down")} code coverage monitor"); - - int retries = 0; - // timedOut can only become true on shutdown (non-infinite timeout value) - do - { - timedOut = !monitorProc.WaitForExit(5000); - if (!timedOut) - { - exitCode = monitorProc.ExitCode; - if (exitCode != 0) - { - error = monitorProc.StandardError.ReadToEnd(); - } - - break; - } - else - { - // we've been asked to stop, but it is not stopping... - retries++; - if (isStarting) - { - Console.WriteLine($"Waiting for VSPerfCmd to start. Retry {retries} of 5 ..."); - } - else - { - Console.WriteLine($"Waiting for VSPerfCmd /shutdown to complete. Retry {retries} of 5 ..."); - } - } - } - while (retries < 5); - - if (timedOut && retries == 5) - { - monitorProc.Kill(); - } - } - - if (exitCode != 0 || error.Length > 0) - { - if (error.Length is 0) - { - error = ""; - } - - Console.WriteLine($"Warning: 'VSPerfCmd {arguments}' exit code {exitCode}: {error}"); - } - - if (!isStarting) - { - if (timedOut) - { - Console.WriteLine($"Warning: VsPerfCmd timed out on shutdown"); - } - - if (File.Exists(outputFile)) - { - var fileInfo = new FileInfo(outputFile); - Console.WriteLine($"..... Created {outputFile}"); - } - else - { - Console.WriteLine($"Warning: Code coverage output file {outputFile} was not created"); - } - } - } - - /// - /// Returns the output name. - /// - private static string GetOutputName() - { - string file = Path.GetFileNameWithoutExtension(Configuration.AssemblyToBeAnalyzed); - string directory = CodeCoverageInstrumentation.OutputDirectory; - return $"{directory}{file}.coverage"; - } - } -} diff --git a/Tools/Coyote/Program.cs b/Tools/Coyote/Program.cs index cddd0eecc..401028a3c 100644 --- a/Tools/Coyote/Program.cs +++ b/Tools/Coyote/Program.cs @@ -2,202 +2,132 @@ // Licensed under the MIT License. using System; +using System.Collections.Generic; using System.IO; using System.Linq; +using Microsoft.Coyote.Cli; using Microsoft.Coyote.IO; using Microsoft.Coyote.Rewriting; using Microsoft.Coyote.SystematicTesting; -using Microsoft.Coyote.Telemetry; -using Microsoft.Coyote.Utilities; namespace Microsoft.Coyote { /// - /// Entry point to the Coyote tool. + /// The entry point to the Coyote tool. /// internal class Program { - private static CoyoteTelemetryClient TelemetryClient; private static TextWriter StdOut; private static TextWriter StdError; private static readonly object ConsoleLock = new object(); - private static void Main(string[] args) + private static int Main(string[] args) { - // Save these so we can force output to happen even if TestingProcess has re-routed it. + // Save these so we can force output to happen even if they have been re-routed. StdOut = Console.Out; StdError = Console.Error; - AppDomain.CurrentDomain.ProcessExit += OnProcessExit; - AppDomain.CurrentDomain.UnhandledException += OnUnhandledException; - Console.CancelKeyPress += OnProcessCanceled; - - // Parses the command line options to get the configuration and rewriting options. - var configuration = Configuration.Create(); - configuration.TelemetryServerPath = typeof(Program).Assembly.Location; - var rewritingOptions = RewritingOptions.Create(); - - var result = CoyoteTelemetryClient.GetOrCreateMachineId().Result; - bool firstTime = result.Item2; - - var options = new CommandLineOptions(); - if (!options.Parse(args, configuration, rewritingOptions)) - { - options.PrintHelp(Console.Out); - if (!firstTime && configuration.EnableTelemetry) - { - CoyoteTelemetryClient.PrintTelemetryMessage(Console.Out); - } - Environment.Exit(1); - } - - if (!configuration.RunAsParallelBugFindingTask) - { - if (firstTime) - { - string version = typeof(Runtime.CoyoteRuntime).Assembly.GetName().Version.ToString(); - Console.WriteLine("Welcome to Microsoft Coyote {0}", version); - Console.WriteLine("----------------------------{0}", new string('-', version.Length)); - if (configuration.EnableTelemetry) - { - CoyoteTelemetryClient.PrintTelemetryMessage(Console.Out); - } - - TelemetryClient = new CoyoteTelemetryClient(configuration); - TelemetryClient.TrackEventAsync("welcome").Wait(); - } - - Console.WriteLine("Microsoft (R) Coyote version {0} for .NET{1}", - typeof(CommandLineOptions).Assembly.GetName().Version, - GetDotNetVersion()); - Console.WriteLine("Copyright (C) Microsoft Corporation. All rights reserved.\n"); - } - - SetEnvironment(configuration); + AppDomain.CurrentDomain.UnhandledException += OnUnhandledException; - switch (configuration.ToolCommand.ToLower()) + var parser = new CommandLineParser(args); + if (!parser.IsSuccessful) { - case "test": - RunTest(configuration); - break; - case "replay": - ReplayTest(configuration); - break; - case "rewrite": - RewriteAssemblies(configuration, rewritingOptions); - break; - case "telemetry": - RunServer(configuration); - break; + return (int)ExitCode.Error; } - } - public static void RunServer(Configuration configuration) - { - CoyoteTelemetryServer server = new CoyoteTelemetryServer(configuration.IsVerbose); - server.RunServerAsync().Wait(); - } - - private static void SetEnvironment(Configuration config) - { - if (!string.IsNullOrEmpty(config.AdditionalPaths)) - { - string path = Environment.GetEnvironmentVariable("PATH"); - Environment.SetEnvironmentVariable("PATH", path + Path.PathSeparator + config.AdditionalPaths); - } + return (int)parser.InvokeSelectedCommand(RunTest, ReplayTest, RewriteAssemblies); } /// /// Runs the test specified in the configuration. /// - private static void RunTest(Configuration configuration) + private static ExitCode RunTest(Configuration configuration) { - if (configuration.RunAsParallelBugFindingTask) - { - // This is being run as the child test process. - if (configuration.ParallelDebug) - { - Console.WriteLine("Attach the debugger and press ENTER to continue..."); - Console.ReadLine(); - } + Console.WriteLine($". Testing {configuration.AssemblyToBeAnalyzed}."); + TestingEngine engine = TestingEngine.Create(configuration); + engine.Run(); - // Load the configuration of the assembly to be tested. - LoadAssemblyConfiguration(configuration.AssemblyToBeAnalyzed); + string directory = OutputFileManager.CreateOutputDirectory(configuration); + string fileName = OutputFileManager.GetResolvedFileName(configuration.AssemblyToBeAnalyzed, directory); - TestingProcess testingProcess = TestingProcess.Create(configuration); - testingProcess.Run(); - return; - } - - if (configuration.ReportCodeCoverage || configuration.IsActivityCoverageReported) + // Emit the test reports. + Console.WriteLine($"... Emitting trace-related reports:"); + if (engine.TryEmitReports(directory, fileName, out IEnumerable reportPaths)) { - // This has to be here because both forms of coverage require it. - CodeCoverageInstrumentation.SetOutputDirectory(configuration, makeHistory: true); + foreach (var path in reportPaths) + { + Console.WriteLine($"..... Writing {path}."); + } } - - if (configuration.ReportCodeCoverage) + else { - // Instruments the program under test for code coverage. - CodeCoverageInstrumentation.Instrument(configuration); - - // Starts monitoring for code coverage. - CodeCoverageMonitor.Start(configuration); + Console.WriteLine($"..... No test reports available."); } - Console.WriteLine(". Testing " + configuration.AssemblyToBeAnalyzed); - if (!string.IsNullOrEmpty(configuration.TestMethodName)) + // Emit the coverage reports. + Console.WriteLine($"... Emitting coverage reports:"); + if (engine.TryEmitCoverageReports(directory, fileName, out reportPaths)) { - Console.WriteLine("... Method {0}", configuration.TestMethodName); + foreach (var path in reportPaths) + { + Console.WriteLine($"..... Writing {path}."); + } } - - if (configuration.ParallelBugFindingTasks is 0) + else { - configuration.DisableEnvironmentExit = false; + Console.WriteLine($"..... No coverage reports available."); } - // Creates and runs the testing process scheduler. - TestingProcessScheduler.Create(configuration).Run(); + Console.WriteLine(engine.TestReport.GetText(configuration, "...")); + Console.WriteLine($"... Elapsed {engine.Profiler.Results()} sec."); + return GetExitCodeFromTestReport(engine.TestReport); } /// /// Replays an execution that is specified in the configuration. /// - private static void ReplayTest(Configuration configuration) + private static ExitCode ReplayTest(Configuration configuration) { // Set some replay specific options. configuration.SchedulingStrategy = "replay"; - configuration.EnableColoredConsoleOutput = true; - configuration.DisableEnvironmentExit = false; // Load the configuration of the assembly to be replayed. LoadAssemblyConfiguration(configuration.AssemblyToBeAnalyzed); - Console.WriteLine($". Replaying {configuration.ScheduleFile}"); + Console.WriteLine($". Testing {configuration.AssemblyToBeAnalyzed}."); TestingEngine engine = TestingEngine.Create(configuration); engine.Run(); - Console.WriteLine(engine.GetReport()); + + // Emit the report. + if (engine.TestReport.NumOfFoundBugs > 0) + { + Console.WriteLine(engine.GetReport()); + } + + Console.WriteLine($"... Elapsed {engine.Profiler.Results()} sec."); + return GetExitCodeFromTestReport(engine.TestReport); } /// /// Rewrites the assemblies specified in the configuration. /// - private static void RewriteAssemblies(Configuration configuration, RewritingOptions options) + private static ExitCode RewriteAssemblies(Configuration configuration, RewritingOptions options) { try { if (options.AssemblyPaths.Count is 1) { - Console.WriteLine($". Rewriting {options.AssemblyPaths.First()}"); + Console.WriteLine($". Rewriting {options.AssemblyPaths.First()}."); } else { - Console.WriteLine($". Rewriting the assemblies specified in {options.AssembliesDirectory}"); + Console.WriteLine($". Rewriting the assemblies specified in {options.AssembliesDirectory}."); } var profiler = new Profiler(); RewritingEngine.Run(options, configuration, profiler); - Console.WriteLine($". Done rewriting in {profiler.Results()} sec"); + Console.WriteLine($"... Elapsed {profiler.Results()} sec."); } catch (Exception ex) { @@ -206,8 +136,11 @@ private static void RewriteAssemblies(Configuration configuration, RewritingOpti ex = aex.Flatten().InnerException; } - Error.ReportAndExit(configuration.IsDebugVerbosityEnabled ? ex.ToString() : ex.Message); + Error.Report(configuration.IsDebugVerbosityEnabled ? ex.ToString() : ex.Message); + return ExitCode.Error; } + + return ExitCode.Success; } /// @@ -238,30 +171,13 @@ private static void LoadAssemblyConfiguration(string assemblyFile) } } - /// - /// Callback invoked when the current process terminates. - /// - private static void OnProcessExit(object sender, EventArgs e) => Shutdown(); - - /// - /// Callback invoked when the current process is canceled. - /// - private static void OnProcessCanceled(object sender, EventArgs e) - { - if (!TestingProcessScheduler.IsProcessCanceled) - { - TestingProcessScheduler.IsProcessCanceled = true; - Shutdown(); - } - } - /// /// Callback invoked when an unhandled exception occurs. /// private static void OnUnhandledException(object sender, UnhandledExceptionEventArgs args) { ReportUnhandledException((Exception)args.ExceptionObject); - Environment.Exit(1); + Environment.Exit((int)ExitCode.InternalError); } private static void ReportUnhandledException(Exception ex) @@ -276,6 +192,11 @@ private static void ReportUnhandledException(Exception ex) } } + private static ExitCode GetExitCodeFromTestReport(TestReport report) => + report.InternalErrors.Count > 0 ? ExitCode.InternalError : + report.NumOfFoundBugs > 0 ? ExitCode.BugFound : + ExitCode.Success; + private static void PrintException(Exception ex) { lock (ConsoleLock) @@ -284,41 +205,5 @@ private static void PrintException(Exception ex) StdOut.WriteLine(ex.StackTrace); } } - - /// - /// Shutdowns any active monitors. - /// - private static void Shutdown() - { - if (CodeCoverageMonitor.IsRunning) - { - Console.WriteLine(". Shutting down the code coverage monitor, this may take a few seconds..."); - - // Stops monitoring for code coverage. - CodeCoverageMonitor.Stop(); - } - - using (TelemetryClient) - { - } - } - - private static string GetDotNetVersion() - { - var path = typeof(string).Assembly.Location; - string result = string.Empty; - - string[] parts = path.Replace("\\", "/").Split('/'); - if (parts.Length > 2) - { - var version = parts[parts.Length - 2]; - if (char.IsDigit(version[0])) - { - result += " " + version; - } - } - - return result; - } } } diff --git a/Tools/Coyote/Scheduling/TestingProcessScheduler.cs b/Tools/Coyote/Scheduling/TestingProcessScheduler.cs deleted file mode 100644 index 984b7dff4..000000000 --- a/Tools/Coyote/Scheduling/TestingProcessScheduler.cs +++ /dev/null @@ -1,663 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Threading.Tasks; -using Microsoft.Coyote.Actors.Coverage; -using Microsoft.Coyote.SmartSockets; -using Microsoft.Coyote.SystematicTesting.Interfaces; -using Microsoft.Coyote.Telemetry; - -namespace Microsoft.Coyote.SystematicTesting -{ - internal sealed class TestingProcessScheduler - { - /// - /// Configuration. - /// - private readonly Configuration Configuration; - - /// - /// The server that all the TestingProcess clients will connect to. - /// - private SmartSocketServer Server; - - /// - /// Map from testing process ids to testing processes. - /// - private readonly Dictionary TestingProcesses; - - /// - /// Map from testing process name to testing process channels. - /// - private readonly Dictionary TestingProcessChannels; - - /// - /// Total number of remote test processes that have called home. - /// - private int TestProcessesConnected; - - /// - /// Time that last message was received from a parallel test. - /// - private int LastMessageTime; - - /// - /// Records if we want certain child test processes to terminate, this key here is the - /// SmartSocketClient Name. - /// - private readonly HashSet Terminating = new HashSet(); - - /// - /// The test reports per process. - /// - private readonly ConcurrentDictionary TestReports; - - /// - /// Test Trace files. - /// - private readonly ConcurrentDictionary TraceFiles; - - /// - /// The global test report, which contains merged information - /// from the test report of each testing process. - /// - private readonly TestReport GlobalTestReport; - - /// - /// The testing profiler. - /// - private readonly Profiler Profiler; - - /// - /// The scheduler lock. - /// - private readonly object SchedulerLock; - - /// - /// The process id of the process that discovered a bug, else null. - /// - private uint? BugFoundByProcess; - - /// - /// Set if ctrl-c or ctrl-break occurred. - /// - internal static bool IsProcessCanceled; - - /// - /// Set true if we have multiple parallel processes or are running code coverage. - /// - private readonly bool IsRunOutOfProcess; - - /// - /// Whether to write verbose output. - /// - private readonly bool IsVerbose; - - /// - /// Initializes a new instance of the class. - /// - private TestingProcessScheduler(Configuration configuration) - { - this.TestingProcesses = new Dictionary(); - this.TestingProcessChannels = new Dictionary(); - this.TestReports = new ConcurrentDictionary(); - this.TraceFiles = new ConcurrentDictionary(); - this.GlobalTestReport = new TestReport(configuration); - this.Profiler = new Profiler(); - this.SchedulerLock = new object(); - this.BugFoundByProcess = null; - - // Code coverage should be run out-of-process; otherwise VSPerfMon won't shutdown correctly - // because an instrumented process (this one) is still running. - if (configuration.ReportCodeCoverage) - { - configuration.ParallelBugFindingTasks = 1; - } - - this.IsRunOutOfProcess = configuration.ParallelBugFindingTasks > 0; - - this.IsVerbose = configuration.IsVerbose; - - if (configuration.ParallelBugFindingTasks > 1) - { - configuration.IsVerbose = false; - } - - configuration.EnableColoredConsoleOutput = true; - - this.Configuration = configuration; - } - - /// - /// Notifies the testing process scheduler that a bug was found. - /// - private void NotifyBugFound(uint processId) - { - string name = "CoyoteTestingProcess." + processId; - lock (this.Terminating) - { - this.Terminating.Add(name); - } - - lock (this.SchedulerLock) - { - if (!this.Configuration.RunTestIterationsToCompletion && this.BugFoundByProcess is null) - { - Console.WriteLine($"... Task {processId} found a bug."); - this.BugFoundByProcess = processId; - // Must be async relative to this NotifyBugFound handler. - Task.Run(() => this.CleanupTestProcesses(processId)); - } - } - } - - private async void CleanupTestProcesses(uint bugProcessId, int maxWait = 60000) - { - try - { - string serverName = this.Configuration.TestingSchedulerEndPoint; - var stopRequest = new TestServerMessage("TestServerMessage", serverName) - { - Stop = true - }; - - var snapshot = new Dictionary(this.TestingProcesses); - - foreach (var testingProcess in snapshot) - { - if (testingProcess.Key != bugProcessId) - { - string name = "CoyoteTestingProcess." + testingProcess.Key; - - lock (this.Terminating) - { - this.Terminating.Add(name); - } - - if (this.TestingProcessChannels.TryGetValue(name, out SmartSocketClient client) && client.BackChannel != null) - { - // use the back channel to stop the client immediately, which will trigger client - // to also send us their TestReport (on the regular channel). - await client.BackChannel.SendAsync(stopRequest); - } - } - } - - await this.WaitForParallelTestReports(maxWait); - } - catch (Exception ex) - { - Console.WriteLine($"... Exception: {ex.Message}"); - } - } - - private void KillTestingProcesses() - { - lock (this.SchedulerLock) - { - foreach (var testingProcess in this.TestingProcesses) - { - try - { - var process = testingProcess.Value; - if (!process.HasExited) - { - IO.Debug.WriteLine("... Killing child process : " + process.Id); - process.Kill(); - process.Dispose(); - } - } - catch (Exception e) - { - IO.Debug.WriteLine("... Unable to terminate testing task: " + e.Message); - } - } - - this.TestingProcesses.Clear(); - } - } - - /// - /// Sets the test report from the specified process. - /// - private void SetTestReport(TestReport testReport, uint processId) - { - lock (this.SchedulerLock) - { - this.MergeTestReport(testReport, processId); - } - } - - /// - /// Creates a new testing process scheduler. - /// - internal static TestingProcessScheduler Create(Configuration configuration) - { - return new TestingProcessScheduler(configuration); - } - - /// - /// Runs the Coyote testing scheduler. - /// - internal void Run() - { - Console.WriteLine($"... Started the testing task scheduler (process:{Process.GetCurrentProcess().Id})."); - - // Start the local server. - this.StartServer(); - - this.Profiler.StartMeasuringExecutionTime(); - - if (this.IsRunOutOfProcess) - { - using (var telemetryClient = new CoyoteTelemetryClient(this.Configuration)) - { - telemetryClient.TrackEventAsync("test").Wait(); - - Stopwatch watch = new Stopwatch(); - watch.Start(); - - this.CreateParallelTestingProcesses(); - if (this.Configuration.WaitForTestingProcesses) - { - this.WaitForParallelTestingProcesses().Wait(); - } - else - { - this.RunParallelTestingProcesses(); - } - - watch.Stop(); - - if (this.GlobalTestReport.NumOfFoundBugs > 0) - { - telemetryClient.TrackMetricAsync("test-bugs", this.GlobalTestReport.NumOfFoundBugs).Wait(); - } - - if (!Debugger.IsAttached) - { - telemetryClient.TrackMetricAsync("test-time", watch.Elapsed.TotalSeconds).Wait(); - } - } - } - else - { - this.CreateAndRunInMemoryTestingProcess(); - } - - this.Profiler.StopMeasuringExecutionTime(); - - // Stop listening and close the server. - this.StopServer(); - - if (!IsProcessCanceled) - { - // Merges and emits the test report. - this.EmitTestReport(); - } - } - - /// - /// Creates the user specified number of parallel testing processes. - /// - private void CreateParallelTestingProcesses() - { - for (uint testId = 0; testId < this.Configuration.ParallelBugFindingTasks; testId++) - { - var process = TestingProcessFactory.Create(testId, this.Configuration); - this.TestingProcesses.Add(testId, process); - } - - Console.WriteLine($"... Created '{this.Configuration.ParallelBugFindingTasks}' " + - "testing tasks."); - } - - private async Task WaitForParallelTestingProcesses() - { - if (this.TestingProcesses.Count > 0) - { - Console.WriteLine($"... Waiting for testing processes to start. Use the following command line to launch each test"); - Console.WriteLine($"... Make sure to change /testing-process-id:x so that x goes from 0 to {this.TestingProcesses.Count}"); - Process p = this.TestingProcesses[0]; - Console.WriteLine($"{p.StartInfo.FileName} {p.StartInfo.Arguments}"); - } - - await this.WaitForParallelTestReports(); - } - - private async Task WaitForParallelTestReports(int maxWait = 60000) - { - this.LastMessageTime = Environment.TickCount; - - // wait for the parallel tasks to connect to us - while (this.TestProcessesConnected < this.TestingProcesses.Count) - { - await Task.Delay(100); - this.AssertTestProcessActivity(maxWait); - } - - // wait 60 seconds for tasks to call back with all their reports and disconnect. - // and reset the click each time a message is received - while (this.TestingProcessChannels.Count > 0) - { - await Task.Delay(100); - this.AssertTestProcessActivity(maxWait); - } - } - - private void AssertTestProcessActivity(int maxWait) - { - if (this.LastMessageTime + maxWait < Environment.TickCount) - { - // oh dear, haven't heard from anyone in 60 seconds, and they have not - // disconnected, so time to get out the sledge hammer and kill them! - this.KillTestingProcesses(); - throw new Exception("Terminating TestProcesses due to inactivity"); - } - } - - /// - /// Runs the parallel testing processes. - /// - private void RunParallelTestingProcesses() - { - // Starts the testing processes. - for (uint testId = 0; testId < this.Configuration.ParallelBugFindingTasks; testId++) - { - this.TestingProcesses[testId].Start(); - } - - // Waits the testing processes to exit. - for (uint testId = 0; testId < this.Configuration.ParallelBugFindingTasks; testId++) - { - try - { - if (this.TestingProcesses.TryGetValue(testId, out Process p)) - { - p.WaitForExit(); - } - } - catch (InvalidOperationException) - { - IO.Debug.WriteLine($"... Unable to wait for testing task '{testId}' to " + - "terminate. Task has already terminated."); - } - } - } - - /// - /// Creates and runs an in-memory testing process. - /// - /// The number of bugs found. - private int CreateAndRunInMemoryTestingProcess() - { - TestingProcess testingProcess = TestingProcess.Create(this.Configuration); - - Console.WriteLine($"... Created '1' testing task (process:{Process.GetCurrentProcess().Id})."); - - // Runs the testing process. - int bugs = testingProcess.Run(); - - // Get and merge the test report. - TestReport testReport = testingProcess.GetTestReport(); - if (testReport != null) - { - this.MergeTestReport(testReport, 0); - } - - return bugs; - } - - /// - /// Opens the local server for TestingProcesses to connect to. - /// If we are not running anything out of process then this does nothing. - /// - private void StartServer() - { - if (!this.IsRunOutOfProcess) - { - return; - } - - var resolver = new SmartSocketTypeResolver(typeof(BugFoundMessage), - typeof(TestReportMessage), - typeof(TestServerMessage), - typeof(TestProgressMessage), - typeof(TestTraceMessage), - typeof(TestReport), - typeof(CoverageInfo), - typeof(Configuration)); - var server = SmartSocketServer.StartServer(this.Configuration.TestingSchedulerEndPoint, resolver, this.Configuration.TestingSchedulerIpAddress); - server.ClientConnected += this.OnClientConnected; - server.ClientDisconnected += this.OnClientDisconnected; - server.BackChannelOpened += this.OnBackChannelOpened; - - // pass this along to the TestingProcesses. - this.Configuration.TestingSchedulerIpAddress = server.EndPoint.ToString(); - - IO.Debug.WriteLine($"... Server listening on '{server.EndPoint}'"); - - this.Server = server; - } - - private async void OnBackChannelOpened(object sender, SmartSocketClient e) - { - // this is the socket we can use to communicate directly to the client... it will be - // available as the "BackChannel" property on the associated client socket. - // But if we've already asked this client to terminate then tell it to stop. - SocketMessage response = new TestServerMessage("ok", this.Configuration.TestingSchedulerEndPoint); - TestServerMessage message = null; - lock (this.Terminating) - { - if (this.Terminating.Contains(e.Name)) - { - message = new TestServerMessage("ok", this.Configuration.TestingSchedulerEndPoint) - { - Stop = true - }; - } - } - - if (message != null) - { - await e.BackChannel.SendAsync(message); - } - } - - private void OnClientDisconnected(object sender, SmartSocketClient e) - { - lock (this.SchedulerLock) - { - this.TestingProcessChannels.Remove(e.Name); - } - } - - private void OnClientConnected(object sender, SmartSocketClient e) - { - e.Error += this.OnClientError; - - if (this.IsVerbose) - { - Console.WriteLine($"... TestProcess '{e.Name}' is connected"); - } - - Task.Run(() => this.HandleClientAsync(e)); - } - - private async void HandleClientAsync(SmartSocketClient client) - { - while (client.IsConnected) - { - SocketMessage e = await client.ReceiveAsync(); - if (e != null) - { - this.LastMessageTime = Environment.TickCount; - uint processId = 0; - - if (e.Id == SmartSocketClient.ConnectedMessageId) - { - lock (this.SchedulerLock) - { - this.TestProcessesConnected++; - this.TestingProcessChannels.Add(e.Sender, client); - } - } - else if (e is BugFoundMessage) - { - BugFoundMessage bug = (BugFoundMessage)e; - processId = bug.ProcessId; - await client.SendAsync(new SocketMessage("ok", this.Configuration.TestingSchedulerEndPoint)); - if (this.IsVerbose) - { - Console.WriteLine($"... Bug report received from '{bug.Sender}'"); - } - - this.NotifyBugFound(processId); - } - else if (e is TestReportMessage) - { - TestReportMessage report = (TestReportMessage)e; - processId = report.ProcessId; - await client.SendAsync(new SocketMessage("ok", this.Configuration.TestingSchedulerEndPoint)); - if (this.IsVerbose) - { - Console.WriteLine($"... Test report received from '{report.Sender}'"); - } - - this.SetTestReport(report.TestReport, report.ProcessId); - } - else if (e is TestTraceMessage) - { - TestTraceMessage report = (TestTraceMessage)e; - processId = report.ProcessId; - await client.SendAsync(new SocketMessage("ok", this.Configuration.TestingSchedulerEndPoint)); - this.SaveTraceReport(report); - } - else if (e is TestProgressMessage) - { - TestProgressMessage progress = (TestProgressMessage)e; - processId = progress.ProcessId; - await client.SendAsync(new SocketMessage("ok", this.Configuration.TestingSchedulerEndPoint)); - // todo: do something fun with progress info. - } - } - } - } - - private void SaveTraceReport(TestTraceMessage report) - { - if (report.Contents != null) - { - string fileName = this.Configuration.AssemblyToBeAnalyzed; - string targetDir = Path.GetDirectoryName(fileName); - string outputDir = Path.Combine(targetDir, "Output", Path.GetFileName(fileName), "CoyoteOutput"); - string remoteFileName = Path.GetFileName(report.FileName); - string localTraceFile = Path.Combine(outputDir, remoteFileName); - File.WriteAllText(localTraceFile, report.Contents); - Console.WriteLine($"... Saved trace report: {localTraceFile}"); - } - else - { - // tests ran locally so the file name is good! - Console.WriteLine($"... See trace report: {report.FileName}"); - } - } - - private void OnClientError(object sender, Exception e) - { - // todo: handle client failures? The client process died, etc... - SmartSocketClient client = (SmartSocketClient)sender; - if (!this.Terminating.Contains(client.Name)) - { - Console.WriteLine($"### Error from client {client.Name}: {e.Message}"); - } - } - - /// - /// Closes the local server, if we have one. - /// - private void StopServer() - { - if (this.Server != null) - { - this.Server.Stop(); - this.Server = null; - } - } - - /// - /// Merges the test report from the specified process. - /// - private void MergeTestReport(TestReport testReport, uint processId) - { - if (this.TestReports.TryAdd(processId, testReport)) - { - // Merges the test report into the global report. - IO.Debug.WriteLine($"... Merging task {processId} test report."); - this.GlobalTestReport.Merge(testReport); - } - else - { - IO.Debug.WriteLine($"... Unable to merge test report from task '{processId}'. " + - " Report is already merged."); - } - } - - /// - /// Emits the test report. - /// - private void EmitTestReport() - { - var testReports = new List(this.TestReports.Values); - foreach (var process in this.TestingProcesses) - { - if (!this.TestReports.ContainsKey(process.Key)) - { - Console.WriteLine($"... Task {process.Key} failed due to an internal error."); - } - } - - if (this.TestReports.Count is 0) - { - Environment.ExitCode = (int)ExitCode.InternalError; - return; - } - - if (this.Configuration.IsActivityCoverageReported) - { - Console.WriteLine($"... Emitting coverage reports:"); - Reporter.EmitTestingCoverageReport(this.GlobalTestReport); - } - - if (this.Configuration.DebugActivityCoverage) - { - Console.WriteLine($"... Emitting debug coverage reports:"); - foreach (var report in this.TestReports) - { - Reporter.EmitTestingCoverageReport(report.Value, report.Key, isDebug: true); - } - } - - Console.WriteLine(this.GlobalTestReport.GetText(this.Configuration, "...")); - Console.WriteLine($"... Elapsed {this.Profiler.Results()} sec."); - - if (this.GlobalTestReport.InternalErrors.Count > 0) - { - Environment.ExitCode = (int)ExitCode.InternalError; - } - else if (this.GlobalTestReport.NumOfFoundBugs > 0) - { - Environment.ExitCode = (int)ExitCode.BugFound; - } - else - { - Environment.ExitCode = (int)ExitCode.Success; - } - } - } -} diff --git a/Tools/Coyote/Testing/TestingPortfolio.cs b/Tools/Coyote/Testing/TestingPortfolio.cs deleted file mode 100644 index 70184bb2c..000000000 --- a/Tools/Coyote/Testing/TestingPortfolio.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -namespace Microsoft.Coyote.SystematicTesting -{ - /// - /// A portfolio of systematic testing strategies. - /// - internal static class TestingPortfolio - { - /// - /// Configures the systematic testing strategy for the current testing process. - /// - internal static void ConfigureStrategyForCurrentProcess(Configuration configuration) - { - if (configuration.TestingProcessId is 0) - { - configuration.SchedulingStrategy = "random"; - } - else if (configuration.TestingProcessId % 2 is 0) - { - configuration.SchedulingStrategy = "probabilistic"; - configuration.StrategyBound = (int)(configuration.TestingProcessId / 2); - } - else if (configuration.TestingProcessId is 1) - { - configuration.SchedulingStrategy = "fair-prioritization"; - configuration.StrategyBound = 1; - } - else - { - configuration.SchedulingStrategy = "fair-prioritization"; - configuration.StrategyBound = 5 * (int)((configuration.TestingProcessId + 1) / 2); - } - } - } -} diff --git a/Tools/Coyote/Testing/TestingProcess.cs b/Tools/Coyote/Testing/TestingProcess.cs deleted file mode 100644 index a778c238a..000000000 --- a/Tools/Coyote/Testing/TestingProcess.cs +++ /dev/null @@ -1,404 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; -using System.Collections.Generic; -using System.IO; -using System.Net; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Coyote.Actors.Coverage; -using Microsoft.Coyote.SmartSockets; -using Microsoft.Coyote.SystematicTesting.Interfaces; - -namespace Microsoft.Coyote.SystematicTesting -{ - /// - /// A testing process, this can also be the client side of a multi-process test. - /// - internal sealed class TestingProcess - { - /// - /// Whether this process is terminating. - /// - private bool Terminating; - - /// - /// A name for the test client. - /// - private readonly string Name = "CoyoteTestingProcess"; - - /// - /// Configuration. - /// - private readonly Configuration Configuration; - - /// - /// The testing engine associated with - /// this testing process. - /// - private readonly TestingEngine TestingEngine; - - /// - /// The channel to the TestProcessScheduler. - /// - private SmartSocketClient Server; - - /// - /// A way to synchronouse background progress task with the main thread. - /// - private ProgressLock ProgressTask; - - /// - /// Creates a Coyote testing process. - /// - internal static TestingProcess Create(Configuration configuration) - { - return new TestingProcess(configuration); - } - - /// - /// Get the current test report. - /// - public TestReport GetTestReport() - { - return this.TestingEngine.TestReport.Clone(); - } - - // Gets a handle to the standard output and error streams. - private readonly TextWriter StdOut = Console.Out; - - /// - /// Runs the Coyote testing process. - /// - /// The number of bugs found. - internal int Run() - { - return this.RunAsync().Result; - } - - internal async Task RunAsync() - { - if (this.Configuration.RunAsParallelBugFindingTask) - { - // Opens the remote notification listener. - await this.ConnectToServer(); - - this.StartProgressMonitorTask(); - } - - this.TestingEngine.Run(); - - Console.SetOut(this.StdOut); - - this.Terminating = true; - - // Wait for any pending progress. - var task = this.ProgressTask; - task?.Wait(30000); - - if (this.Configuration.RunAsParallelBugFindingTask) - { - if (this.TestingEngine.TestReport.InternalErrors.Count > 0) - { - Environment.ExitCode = (int)ExitCode.InternalError; - } - else if (this.TestingEngine.TestReport.NumOfFoundBugs > 0) - { - Environment.ExitCode = (int)ExitCode.BugFound; - await this.NotifyBugFound(); - } - - await this.SendTestReport(); - } - - if (!this.Configuration.RunTestIterationsToCompletion && - this.TestingEngine.TestReport.NumOfFoundBugs > 0 && - !this.Configuration.RunAsParallelBugFindingTask) - { - Console.WriteLine($"... Task {this.Configuration.TestingProcessId} found a bug."); - } - - // Emit any test reports. - await this.EmitReports(); - - // Closes the remote notification listener. - if (this.Configuration.IsVerbose) - { - Console.WriteLine($"... ### Task {this.Configuration.TestingProcessId} is terminating"); - } - - this.Disconnect(); - return this.TestingEngine.TestReport.NumOfFoundBugs; - } - - /// - /// Initializes a new instance of the class. - /// - private TestingProcess(Configuration configuration) - { - this.Name = this.Name + "." + configuration.TestingProcessId; - - if (configuration.SchedulingStrategy is "portfolio") - { - TestingPortfolio.ConfigureStrategyForCurrentProcess(configuration); - } - - if (configuration.RandomGeneratorSeed.HasValue) - { - configuration.RandomGeneratorSeed = configuration.RandomGeneratorSeed.Value + - (673 * configuration.TestingProcessId); - } - - configuration.EnableColoredConsoleOutput = true; - - this.Configuration = configuration; - this.TestingEngine = TestingEngine.Create(this.Configuration); - } - - ~TestingProcess() - { - this.Terminating = true; - } - - /// - /// Opens the remote notification listener. If this is not a parallel testing - /// process, then this operation does nothing. - /// - private async Task ConnectToServer() - { - string serviceName = this.Configuration.TestingSchedulerEndPoint; - var source = new CancellationTokenSource(); - - var resolver = new SmartSocketTypeResolver(typeof(BugFoundMessage), typeof(TestReportMessage), - typeof(TestServerMessage), typeof(TestProgressMessage), typeof(TestTraceMessage), - typeof(TestReport), typeof(CoverageInfo), typeof(Configuration)); - - SmartSocketClient client = null; - if (!string.IsNullOrEmpty(this.Configuration.TestingSchedulerIpAddress)) - { - string[] parts = this.Configuration.TestingSchedulerIpAddress.Split(':'); - if (parts.Length is 2) - { - var endPoint = new IPEndPoint(IPAddress.Parse(parts[0]), int.Parse(parts[1])); - while (!source.IsCancellationRequested && client is null) - { - client = await SmartSocketClient.ConnectAsync(endPoint, this.Name, resolver); - } - } - } - else - { - client = await SmartSocketClient.FindServerAsync(serviceName, this.Name, resolver, source.Token); - } - - if (client is null) - { - throw new Exception("Failed to connect to server"); - } - - client.Error += this.OnClientError; - client.ServerName = serviceName; - this.Server = client; - - // Open back channel so server can also send messages to us any time. - await client.OpenBackChannel(this.OnBackChannelConnected); - } - - private void OnBackChannelConnected(object sender, SmartSocketClient e) - { - Task.Run(() => this.HandleBackChannel(e)); - } - - private async void HandleBackChannel(SmartSocketClient server) - { - while (!this.Terminating && server.IsConnected) - { - var msg = await server.ReceiveAsync(); - if (msg is TestServerMessage) - { - this.HandleServerMessage((TestServerMessage)msg); - } - } - } - - private void OnClientError(object sender, Exception e) - { - // TODO: error handling, happens if we fail to get a message to the server for some reason. - } - - /// - /// Closes the remote notification listener. If this is not a parallel testing - /// process, then this operation does nothing. - /// - private void Disconnect() - { - using (this.Server) - { - if (this.Server != null) - { - this.Server.Close(); - } - } - } - - /// - /// Notifies the remote testing scheduler about a discovered bug. - /// - private async Task NotifyBugFound() - { - await this.Server.SendReceiveAsync(new BugFoundMessage("BugFoundMessage", - this.Name, this.Configuration.TestingProcessId)); - } - - /// - /// Sends the test report associated with this testing process. - /// - private async Task SendTestReport() - { - var report = this.TestingEngine.TestReport.Clone(); - await this.Server.SendReceiveAsync(new TestReportMessage("TestReportMessage", - this.Name, this.Configuration.TestingProcessId, report)); - } - - /// - /// Emits the testing reports, if any. - /// - private async Task EmitReports() - { - string file = Path.GetFileNameWithoutExtension(this.Configuration.AssemblyToBeAnalyzed); - file += "_" + this.Configuration.TestingProcessId; - - // If this is a separate (sub-)process, CodeCoverageInstrumentation.OutputDirectory may not have been set up. - CodeCoverageInstrumentation.SetOutputDirectory(this.Configuration, makeHistory: false); - - Console.WriteLine($"... Emitting task {this.Configuration.TestingProcessId} reports:"); - var traces = new List(this.TestingEngine.TryEmitReports(CodeCoverageInstrumentation.OutputDirectory, file)); - - if (this.Server != null && this.Server.IsConnected) - { - await this.SendTraces(traces); - } - } - - private async Task SendTraces(List traces) - { - IPEndPoint localEndPoint = (IPEndPoint)this.Server.Socket.LocalEndPoint; - IPEndPoint serverEndPoint = (IPEndPoint)this.Server.Socket.RemoteEndPoint; - bool differentMachine = localEndPoint.Address.ToString() != serverEndPoint.Address.ToString(); - foreach (var filename in traces) - { - string contents = null; - if (differentMachine) - { - Console.WriteLine($"... Sending trace file: {filename}"); - contents = File.ReadAllText(filename); - } - - await this.Server.SendReceiveAsync(new TestTraceMessage("TestTraceMessage", this.Name, this.Configuration.TestingProcessId, filename, contents)); - } - } - - /// - /// Creates a task that pings the server with a heartbeat telling the server our current progress. - /// - private async void StartProgressMonitorTask() - { - while (!this.Terminating) - { - await Task.Delay(100); - using (this.ProgressTask = new ProgressLock()) - { - await this.SendProgressMessage(); - } - } - } - - /// - /// Sends the TestProgressMessage and if server cannot be reached, stop the testing. - /// - private async Task SendProgressMessage() - { - if (this.Server != null && !this.Terminating && this.Server.IsConnected) - { - // TODO: get this from the TestingEngine. - double progress = 0.0; - try - { - await this.Server.SendReceiveAsync(new TestProgressMessage("TestProgressMessage", this.Name, this.Configuration.TestingProcessId, progress)); - } - catch (Exception) - { - // Can't contact the server, so perhaps it died, time to stop. - this.TestingEngine.Stop(); - } - } - } - - private void HandleServerMessage(TestServerMessage tsr) - { - if (tsr.Stop) - { - // Server wants us to stop! - if (this.Configuration.IsVerbose) - { - this.StdOut.WriteLine($"... ### Client {this.Configuration.TestingProcessId} is being told to stop!"); - } - - this.TestingEngine.Stop(); - this.Terminating = true; - } - } - - internal class ProgressLock : IDisposable - { - private bool Disposed; - private bool WaitingOnProgress; - private readonly object SyncObject = new object(); - private readonly ManualResetEvent ProgressEvent = new ManualResetEvent(false); - - public ProgressLock() - { - } - - ~ProgressLock() - { - this.Dispose(); - } - - public void Wait(int timeout = 10000) - { - bool wait = false; - lock (this.SyncObject) - { - if (this.Disposed) - { - return; - } - - this.WaitingOnProgress = true; - wait = true; - } - - if (wait) - { - this.ProgressEvent.WaitOne(timeout); - } - } - - public void Dispose() - { - lock (this.SyncObject) - { - this.Disposed = true; - if (this.WaitingOnProgress) - { - this.ProgressEvent.Set(); - } - } - - GC.SuppressFinalize(this); - } - } - } -} diff --git a/Tools/Coyote/Testing/TestingProcessFactory.cs b/Tools/Coyote/Testing/TestingProcessFactory.cs deleted file mode 100644 index d7b928d8a..000000000 --- a/Tools/Coyote/Testing/TestingProcessFactory.cs +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; -using System.Diagnostics; -using System.Reflection; -using System.Text; - -namespace Microsoft.Coyote.SystematicTesting -{ - /// - /// The Coyote testing process factory. - /// - internal static class TestingProcessFactory - { - /// - /// Creates a new testing process. - /// - public static Process Create(uint id, Configuration configuration) - { - string assembly = Assembly.GetExecutingAssembly().Location; - Console.WriteLine("Launching " + assembly); -#if NETFRAMEWORK - ProcessStartInfo startInfo = new ProcessStartInfo(assembly, - CreateArgumentsFromConfiguration(id, configuration)); -#else - ProcessStartInfo startInfo = new ProcessStartInfo("dotnet", assembly + " " + - CreateArgumentsFromConfiguration(id, configuration)); -#endif - startInfo.UseShellExecute = false; - - Process process = new Process(); - process.StartInfo = startInfo; - - return process; - } - - /// - /// Creates arguments from the specified configuration. - /// - internal static string CreateArgumentsFromConfiguration(uint id, Configuration configuration) - { - StringBuilder arguments = new StringBuilder(); - - arguments.Append($"test {configuration.AssemblyToBeAnalyzed} "); - - if (configuration.IsDebugVerbosityEnabled) - { - arguments.Append("--debug "); - } - - if (!string.IsNullOrEmpty(configuration.TestMethodName)) - { - arguments.Append($"--method {configuration.TestMethodName} "); - } - - arguments.Append($"--iterations {configuration.TestingIterations} "); - arguments.Append($"--timeout {configuration.TestingTimeout} "); - - if (configuration.UserExplicitlySetMaxFairSchedulingSteps) - { - arguments.Append($"--max-steps {configuration.MaxUnfairSchedulingSteps} " + - $"{configuration.MaxFairSchedulingSteps} "); - } - else - { - arguments.Append($"--max-steps {configuration.MaxUnfairSchedulingSteps} "); - } - - if (configuration.UserExplicitlySetLivenessTemperatureThreshold) - { - arguments.Append($"--liveness-temperature-threshold {configuration.LivenessTemperatureThreshold} "); - } - - if (configuration.SchedulingStrategy is "prioritization" || - configuration.SchedulingStrategy is "fair-prioritization" || - configuration.SchedulingStrategy is "probabilistic" || - configuration.SchedulingStrategy is "rl") - { - arguments.Append($"--sch-{configuration.SchedulingStrategy} {configuration.StrategyBound} "); - } - else if (configuration.SchedulingStrategy is "random" || - configuration.SchedulingStrategy is "portfolio") - { - arguments.Append($"--sch-{configuration.SchedulingStrategy} "); - } - - if (!configuration.IsPartiallyControlledConcurrencyAllowed) - { - arguments.Append("--no-partial-control "); - } - - if (configuration.IsSystematicFuzzingEnabled) - { - arguments.Append("--systematic-fuzzing "); - } - - if (!configuration.IsSystematicFuzzingFallbackEnabled) - { - arguments.Append("--no-fuzzing-fallback "); - } - - if (configuration.IsSharedStateReductionEnabled) - { - arguments.Append("--reduce-shared-state "); - } - - if (configuration.RandomGeneratorSeed.HasValue) - { - arguments.Append($"--seed {configuration.RandomGeneratorSeed.Value} "); - } - - if (configuration.RunTestIterationsToCompletion) - { - arguments.Append("--explore "); - } - - arguments.Append($"--timeout-delay {configuration.TimeoutDelay} "); - arguments.Append($"--deadlock-timeout {configuration.DeadlockTimeout} "); - arguments.Append($"--uncontrolled-concurrency-timeout {configuration.UncontrolledConcurrencyResolutionTimeout} "); - arguments.Append($"--uncontrolled-concurrency-interval {configuration.UncontrolledConcurrencyResolutionInterval} "); - - if (!configuration.ReportPotentialDeadlocksAsBugs) - { - arguments.Append("--skip-potential-deadlocks "); - } - - if (configuration.ReportCodeCoverage && configuration.IsActivityCoverageReported) - { - arguments.Append("--coverage "); - } - else if (configuration.ReportCodeCoverage) - { - arguments.Append("--coverage code "); - } - else if (configuration.IsActivityCoverageReported) - { - arguments.Append("--coverage activity "); - } - - if (configuration.IsDgmlGraphEnabled) - { - arguments.Append("--graph "); - } - - if (configuration.IsXmlLogEnabled) - { - arguments.Append("--xml-trace "); - } - - if (!string.IsNullOrEmpty(configuration.CustomActorRuntimeLogType)) - { - arguments.Append($"--actor-runtime-log {configuration.CustomActorRuntimeLogType} "); - } - - if (configuration.OutputFilePath.Length > 0) - { - arguments.Append($"--outdir {configuration.OutputFilePath} "); - } - - arguments.Append("--run-as-parallel-testing-task "); - arguments.Append($"--testing-scheduler-endpoint {configuration.TestingSchedulerEndPoint} "); - arguments.Append($"--testing-scheduler-ipaddress {configuration.TestingSchedulerIpAddress} "); - arguments.Append($"--testing-process-id {id} "); - - if (!string.IsNullOrEmpty(configuration.AdditionalPaths)) - { - arguments.Append($"--additional-paths \"{configuration.AdditionalPaths}\" "); - } - - if (configuration.ParallelDebug) - { - arguments.Append($"--parallel-debug "); - } - - return arguments.ToString(); - } - } -} diff --git a/Tools/Coyote/Utilities/CommandLineArgumentParser.cs b/Tools/Coyote/Utilities/CommandLineArgumentParser.cs deleted file mode 100644 index 252eb7170..000000000 --- a/Tools/Coyote/Utilities/CommandLineArgumentParser.cs +++ /dev/null @@ -1,972 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; -using System.Collections.Generic; -using System.Data; -using System.IO; -using System.Linq; - -namespace Microsoft.Coyote.Utilities -{ - /// - /// Specifies a dependency between arguments. - /// - internal class CommandLineArgumentDependency - { - /// - /// Name of an argument. - /// - public string Name; - - /// - /// Value of that argument. - /// - public string Value; - } - - /// - /// Exception raised from ParseArguments. - /// - internal class CommandLineException : Exception - { - public CommandLineException(string msg, List result) - : base(msg) - { - this.Result = result; - } - - public List Result { get; set; } - } - - /// - /// A single command line argument. - /// - internal class CommandLineArgument - { - /// - /// The long name referenced using two dashes (e.g. "--max-steps"). - /// - public string LongName; - - /// - /// The short name referenced using single dash (e.g. "-ms"). - /// - public string ShortName; - - /// - /// Optional datatype (default string). Supported datatypes are primitive types - /// only (e.g. int, uint, float, string, bool). - /// - public Type DataType; - - /// - /// Help text for the command line option. You can use newlines to format the help content - /// but each line will be auto-indented by the PrintHelp function. - /// - public string Description; - - /// - /// Checks if the arugment is required. - /// - public bool IsRequired; - - /// - /// Checks if the arugment is positional. - /// - public bool IsPositional; - - /// - /// Optional name to a . - /// - public string Group; - - /// - /// Hide this option from the printed help message. - /// - public bool IsHidden; - - /// - /// Checks if the value of the argument is an array (e.g. "--coverage data activity"). - /// - public bool IsMultiValue; - - /// - /// The parsed command line value matching DataType. - /// - public object Value; - - /// - /// The default value to use if no value provided. - /// - public string DefaultValue; - - /// - /// This is the print help option. - /// - public bool PrintFullHelp; - - /// - /// This argument depends on the specific value of another. - /// - public CommandLineArgumentDependency DependsOn; - - /// - /// Defines a list of possible values. - /// - public List AllowedValues = new List(); - - internal string LongSyntax - { - get - { - if (this.IsPositional) - { - return this.LongName; - } - - return "--" + this.LongName; - } - } - - internal string LongSyntaxAndDataType - { - get - { - string text = this.LongSyntax; - if (this.DataType != typeof(bool)) - { - text += " " + this.DataTypeString; - } - - return text; - } - } - - internal string ShortSyntax - { - get - { - return "-" + this.ShortName; - } - } - - internal string DataTypeString - { - get - { - string type = null; - if (this.DataType == typeof(string)) - { - type = "string"; - } - else if (this.DataType == typeof(int)) - { - type = "int"; - } - else if (this.DataType == typeof(uint)) - { - type = "uint"; - } - else if (this.DataType == typeof(double)) - { - type = "double"; - } - else if (this.DataType == typeof(string)) - { - type = "bool"; - } - else if (this.DataType != null) - { - throw new Exception(string.Format("Unsupported data type: {0}", this.DataType.Name)); - } - - return type; - } - } - - internal object ParseValue(string value) - { - Type type = this.DataType; - if (value is null) - { - if (type == typeof(bool)) - { - return true; // Default for boolean options. - } - else - { - if (!this.AllowedValues.Contains(string.Empty)) - { - throw new Exception(string.Format("Argument: '{0}' missing a value", this.LongName)); - } - } - } - - object result; - if (type is null || type == typeof(string)) - { - result = value; - } - else if (type == typeof(bool)) - { - if (!bool.TryParse(value, out bool x)) - { - throw new Exception(string.Format("Argument: '{0}' value is not a valid bool", this.LongName)); - } - - result = x; - } - else if (type == typeof(int)) - { - if (!int.TryParse(value, out int x)) - { - throw new Exception(string.Format("Argument: '{0}' value is not a valid integer", this.LongName)); - } - - result = x; - } - else if (type == typeof(uint)) - { - if (!uint.TryParse(value, out uint x)) - { - throw new Exception(string.Format("Argument: '{0}' value is not a valid unsigned integer", this.LongName)); - } - - result = x; - } - else if (type == typeof(double)) - { - if (!double.TryParse(value, out double x)) - { - throw new Exception(string.Format("Argument: '{0}' value is not a valid double", this.LongName)); - } - - result = x; - } - else - { - throw new Exception(string.Format("Argument: '{0}' type '{1}' is not supported, use bool, int, uint, double, string", this.LongName, type.Name)); - } - - if (this.AllowedValues.Count > 0) - { - if (result is null) - { - result = string.Empty; - } - - string s = result.ToString(); - if (!this.AllowedValues.Contains(s)) - { - throw new Exception(string.Format("Argument: '{0}' value '{1}' must be one of [{2}]", this.LongName, s, string.Join(", ", this.AllowedValues.ToArray()))); - } - } - - return result; - } - - internal CommandLineArgument Clone() - { - return new CommandLineArgument() - { - LongName = this.LongName, - ShortName = this.ShortName, - DataType = this.DataType, - Description = this.Description, - IsRequired = this.IsRequired, - DefaultValue = this.DefaultValue, - Group = this.Group, - IsHidden = this.IsHidden, - AllowedValues = this.AllowedValues, - IsMultiValue = this.IsMultiValue, - IsPositional = this.IsPositional, - DependsOn = this.DependsOn, - PrintFullHelp = this.PrintFullHelp - }; - } - - internal void AddParsedValue(string arg) - { - if (!this.IsMultiValue) - { - if (this.Value != null) - { - throw new Exception(string.Format("Argument: '--{0}' has too many values", this.LongName)); - } - - this.Value = this.ParseValue(arg); - } - else - { - var value = this.ParseValue(arg); - if (this.DataType == typeof(string)) - { - this.Value = Append(this.Value, value); - } - else if (this.DataType == typeof(int)) - { - this.Value = Append(this.Value, value); - } - else if (this.DataType == typeof(uint)) - { - this.Value = Append(this.Value, value); - } - else if (this.DataType == typeof(double)) - { - this.Value = Append(this.Value, value); - } - else if (this.DataType == typeof(string)) - { - this.Value = Append(this.Value, value); - } - else if (this.DataType != null) - { - throw new Exception(string.Format("Unsupported data type: {0}", this.DataType.Name)); - } - else - { - this.Value = value; - } - } - } - - private static T[] Append(object value1, object value2) - { - if (value1 is null) - { - return new T[1] { (T)value2 }; - } - - T[] existing = (T[])value1; - T[] newList = new T[existing.Length + 1]; - int i = 0; - while (i < existing.Length) - { - newList[i] = existing[i]; - i++; - } - - newList[i] = (T)value2; - return newList; - } - - internal void CheckDefaultValue() - { - if (this.Value is null && !string.IsNullOrEmpty(this.DefaultValue)) - { - this.AddParsedValue(this.DefaultValue); - } - } - } - - /// - /// Provides a way of grouping command line arguments in the help text. - /// - internal class CommandLineGroup - { - private readonly CommandLineArgumentParser Parser; - private readonly List LongNames; - - internal CommandLineGroup(CommandLineArgumentParser parser, List longNames) - { - this.Parser = parser; - this.LongNames = longNames; - } - - /// - /// The unique name of the group. - /// - public string Name; - - /// - /// Help text for the command line group. You can use newlines to format the help content - /// but each line will be auto-indented by the PrintHelp function. - /// - public string Description; - - /// - /// The whole group is hidden. - /// - public bool IsHidden; - - /// - /// Specifies that this group is only required if the given dependency is true. - /// - public CommandLineArgumentDependency DependsOn; - - /// - /// Whether this group should be included in all help messages. - /// - internal bool AlwaysPrint { get; set; } - - /// - /// Add a positional argument. Positional arguments have no switch (--foo) and must be specified in the - /// order that they are defined. Note that positional arguments must appear before any named arguments. - /// - /// The logical name of the argument. - /// Help text for the command line option. You can use newlines to format the - /// help content but each line will be auto-indented by the PrintHelp function. - /// Optional datatype (default string). Supported datatypes are primitive types - /// only (e.g. int, uint, float, string, bool). - /// The new option or throws . - public CommandLineArgument AddPositionalArgument(string name, string description = null, Type dataType = null) - { - var argument = this.Parser.AddPositionalArgument(name, description, dataType); - argument.IsHidden = this.IsHidden; - argument.Group = this.Name; - argument.DependsOn = this.DependsOn; - return argument; - } - - /// - /// Add a new command line option to the group. The option names still need to be unique. - /// - /// The long name referenced using two dashes (e.g. "--max-steps"). - /// The short name referenced using single dash (e.g. "-ms"). - /// Help text for the command line option. You can use newlines to format the - /// help content but each line will be auto-indented by the PrintHelp function. - /// Optional datatype (default string). Supported datatypes are primitive types - /// only (e.g. int, float, string, bool). - /// Whether the argument is required or not. - /// The default value to use if no value is provided. - /// The new object. - public CommandLineArgument AddArgument(string longName, string shortName, string description = null, Type dataType = null, bool required = false, string defaultValue = null) - { - if (dataType is null) - { - dataType = typeof(string); - } - - var argument = this.Parser.AddArgument(longName, shortName, description, dataType, required, defaultValue); - argument.IsHidden = this.IsHidden; - argument.Group = this.Name; - return argument; - } - } - - /// - /// A handy command line argument parser. - /// - internal class CommandLineArgumentParser - { - private readonly string AppName; - private readonly string AppDescription; - private readonly List ParsedArguments = new List(); - - /// - /// To remember the oder in which they were added. - /// - private readonly List GroupNames = new List(); - - /// - /// To remember the order in which positional arguments were added. - /// - private readonly List PositionalNames = new List(); - - /// - /// To remember the order in which switch arguments were added. - /// - private readonly List LongNames = new List(); - - /// - /// The currnet list of command line groups. - /// - public Dictionary Groups = new Dictionary(); - - /// - /// The current set of possible command line arguments. - /// - public Dictionary Arguments = new Dictionary(); - - /// - /// Initializes a new instance of the class. - /// - /// The name of the application. - /// The overview help text for the application. - public CommandLineArgumentParser(string appName, string appDescription) - { - this.AppName = appName; - this.AppDescription = appDescription; - this.AddArgument("?", "?", "Show full help text", typeof(bool)).PrintFullHelp = true; - } - - /// - /// Add a new command line group or return the existing group if it already exists. - /// - /// The name of the group. - /// The help text for the group. - /// Whether to include this in all help messages. - /// The new command line group. - public CommandLineGroup GetOrCreateGroup(string name, string description, bool alwaysPrint = false) - { - if (this.Groups.TryGetValue(name, out CommandLineGroup group)) - { - return group; - } - - group = new CommandLineGroup(this, this.LongNames) { Name = name, Description = description, AlwaysPrint = alwaysPrint }; - this.Groups.Add(name, group); - this.GroupNames.Add(name); - return group; - } - - /// - /// Add a positional argument. Positional arguments have no switch (--foo) and must be specified in the - /// order that they are defined. Note that positional arguments must appear before any named arguments. - /// - /// The logical name of the argument. - /// Help text for the command line option. You can use newlines to format the - /// help content but each line will be auto-indented by the PrintHelp function. - /// Optional datatype (default string). Supported datatypes are primitive types - /// only (e.g. int, float, string, bool). - /// The new option or throws . - public CommandLineArgument AddPositionalArgument(string name, string description = null, Type dataType = null) - { - if (this.Arguments.ContainsKey(name)) - { - throw new DuplicateNameException(string.Format("Argument {0} already defined", name)); - } - - CommandLineArgument argument = new CommandLineArgument() - { - LongName = name, - DataType = dataType, - Description = description, - IsRequired = true, - IsPositional = true - }; - - this.Arguments[name] = argument; - this.PositionalNames.Add(name); - return argument; - } - - /// - /// Add a new command line option. - /// - /// The long name referenced using two dashes (e.g. "--max-steps"). - /// The short name referenced using single dash (e.g. "-ms"). - /// Help text for the command line option. You can use newlines to format the - /// help content but each line will be auto-indented by the PrintHelp function. - /// Optional datatype (default string). Supported datatypes are primitive types - /// only (e.g. int, float, string, bool). - /// Whether argument is required. - /// The default value to use if no value is provided. - /// The new option or throws . - public CommandLineArgument AddArgument(string longName, string shortName, string description = null, Type dataType = null, bool required = false, string defaultValue = null) - { - if (this.Arguments.TryGetValue(longName, out CommandLineArgument argument)) - { - throw new DuplicateNameException(string.Format("Argument {0} already defined", longName)); - } - - if (shortName != null) - { - var existing = (from a in this.Arguments.Values where a.ShortName == shortName select a).FirstOrDefault(); - if (existing != null) - { - throw new DuplicateNameException(string.Format("Argument short name '{0}' is already being used by '{1}'", shortName, existing.LongName)); - } - } - - argument = new CommandLineArgument() - { - LongName = longName, - ShortName = shortName, - DataType = dataType, - Description = description, - IsRequired = required, - DefaultValue = defaultValue - }; - this.Arguments[longName] = argument; - this.LongNames.Add(longName); - return argument; - } - - private class WordWrapper - { - private readonly TextWriter Output; - private readonly int Indent; - private readonly int LineLength; - private int CurrentLineLength; - private readonly string IndentText; - - internal WordWrapper(TextWriter output, int indent, int lineLength) - { - this.Output = output; - this.Indent = indent; - this.LineLength = lineLength; - this.CurrentLineLength = indent; - this.IndentText = new string(' ', this.Indent); - } - - internal void Write(string text) - { - bool first = true; - foreach (string line in text.Split('\n')) - { - if (!first) - { - this.NewLine(); - } - - first = false; - foreach (string word in line.Split(' ')) - { - this.WriteWord(word); - } - } - } - - internal void WriteWord(string word) - { - if (this.CurrentLineLength + word.Length > this.LineLength) - { - this.NewLine(); - } - - this.Output.Write(word); - this.Output.Write(" "); - this.CurrentLineLength += word.Length + 1; - } - - private void NewLine() - { - this.Output.WriteLine(); - this.CurrentLineLength = this.Indent; - if (this.Indent > 0) - { - this.Output.Write(this.IndentText); - } - } - } - - /// - /// Parse the command line using the options defined in this argument parser. - /// - /// The command line. - /// The parsed arguments. - public List ParseArguments(string[] args) - { - List result = this.ParsedArguments; - result.Clear(); - - int position = 0; // For positional arguments. - CommandLineArgument current = null; - - for (int idx = 0; idx < args.Length; idx++) - { - string arg = args[idx]; - - if (arg.StartsWith("-")) - { - if (arg.StartsWith("--")) - { - current?.CheckDefaultValue(); - var name = arg.Substring(2); - current = null; - this.Arguments.TryGetValue(name, out current); - } - else if (arg.StartsWith("-")) - { - current?.CheckDefaultValue(); - current = null; - var name = arg.Substring(1); - // Note that "/" is not supported as an argument delimiter because it conflicts with unix file paths. - foreach (var s in this.Arguments.Values) - { - if (s.ShortName == name) - { - current = s; - break; - } - } - - if (current is null) - { - // See if there's a matching long name with no short name defined. - foreach (var s in this.Arguments.Values) - { - if (s.LongName == name) - { - current = s; - break; - } - } - } - } - - if (current is null) - { - throw new CommandLineException(string.Format("Unexpected argument: '{0}'", arg), result); - } - - current = current.Clone(); - result.Add(current); - - if (current.PrintFullHelp) - { - return null; - } - } - else if (current != null) - { - // The value for the current switch argument. - current.AddParsedValue(arg); - } - else - { - // Positional arguments. - do - { - if (position < this.PositionalNames.Count) - { - var name = this.PositionalNames[position++]; - current = this.Arguments[name]; - } - else - { - throw new CommandLineException(string.Format("Unexpected positional argument: '{0}'", arg), result); - } - } - while (!this.IsRequired(current)); - - // Positional arguments have no name so the arg is the value. - var temp = current.Clone(); - temp.Value = current.ParseValue(arg); - result.Add(temp); - current = null; // This argument is done, cannot have any more values. - } - } - - current?.CheckDefaultValue(); - - foreach (var arg in this.Arguments.Values) - { - if (this.IsRequired(arg) && !(from r in result where r.LongName == arg.LongName select r).Any()) - { - if (arg.IsPositional) - { - throw new CommandLineException(string.Format("Missing required argument: '{0}'", arg.LongName), result); - } - else - { - throw new CommandLineException(string.Format("Missing required argument: '--{0}'", arg.LongName), result); - } - } - } - - foreach (var arg in result) - { - if (!arg.IsPositional && arg.Value is null && string.IsNullOrEmpty(arg.DefaultValue) && arg.DataType != typeof(bool) && !arg.AllowedValues.Contains(string.Empty)) - { - throw new CommandLineException(string.Format("Missing value for argument: '--{0}'", arg.LongName), result); - } - } - - return result; - } - - private bool IsRequired(CommandLineArgument argument) - { - if (argument.IsRequired) - { - if (argument.DependsOn != null) - { - var dependent = (from r in this.ParsedArguments where r.LongName == argument.DependsOn.Name select r).FirstOrDefault(); - if (dependent != null && string.Compare(dependent.Value.ToString(), argument.DependsOn.Value, StringComparison.OrdinalIgnoreCase) is 0) - { - return true; - } - } - else - { - return true; - } - } - - return false; - } - - private bool IsGroupSelected(CommandLineGroup g) - { - // return true if the group that this argument belongs to has been selected by the - // parse command line arguments. - if (g.DependsOn != null) - { - var dependent = (from r in this.ParsedArguments where r.LongName == g.DependsOn.Name select r).FirstOrDefault(); - return dependent != null && string.Compare(dependent.Value.ToString(), g.DependsOn.Value, StringComparison.OrdinalIgnoreCase) is 0; - } - - return false; - } - - /// - /// Shows help. - /// - public void PrintHelp(TextWriter output) - { - const int ArgHelpLineLength = 100; - const int ArgHelpIndent = 30; - var fullHelp = (from a in this.ParsedArguments where a.PrintFullHelp select a).Any(); - - string prefix = string.Format("usage: {0} ", this.AppName); - output.Write(prefix); - int indent = prefix.Length; - - var wrapper = new WordWrapper(output, indent, ArgHelpLineLength); - foreach (var name in this.PositionalNames) - { - var arg = this.Arguments[name]; - string text = arg.LongSyntax; - if (arg.DependsOn != null) - { - text = "[" + text + "]"; - } - - wrapper.WriteWord(text); - } - - foreach (var name in this.LongNames) - { - var arg = this.Arguments[name]; - if (arg.IsHidden) - { - continue; - } - - string text = arg.LongSyntaxAndDataType; - - if (!arg.IsRequired) - { - text = "[" + text + "]"; - } - - wrapper.WriteWord(text); - } - - output.WriteLine(); - output.WriteLine(); - wrapper = new WordWrapper(output, 0, ArgHelpLineLength); - wrapper.Write(this.AppDescription); - output.WriteLine(); - output.WriteLine(); - var visitedOptions = new HashSet(); - - foreach (var name in this.GroupNames) - { - CommandLineGroup g = this.Groups[name]; - if (g.IsHidden) - { - continue; - } - - bool suppressed = !fullHelp && !g.AlwaysPrint && !this.IsGroupSelected(g); - - if (!suppressed) - { - output.WriteLine(g.Description + ":"); - output.WriteLine(new string('-', g.Description.Length + 1)); - } - - foreach (var option in this.PositionalNames.Concat(this.LongNames)) - { - var arg = this.Arguments[option]; - if (arg.IsHidden) - { - continue; - } - - if (arg.Group == name) - { - visitedOptions.Add(option); - - if (!suppressed) - { - string syntax = " "; - if (!string.IsNullOrEmpty(arg.ShortName)) - { - syntax += string.Format("{0}, ", arg.ShortSyntax); - } - - syntax += string.Format("{0} ", arg.LongSyntaxAndDataType); - - output.Write(syntax); - if (syntax.Length < ArgHelpIndent) - { - output.Write(new string(' ', ArgHelpIndent - syntax.Length)); - } - else - { - output.WriteLine(); - output.Write(new string(' ', ArgHelpIndent)); - } - - if (!string.IsNullOrEmpty(arg.Description)) - { - output.Write(": "); - wrapper = new WordWrapper(output, ArgHelpIndent + 2, ArgHelpLineLength); - wrapper.Write(arg.Description); - } - - output.WriteLine(); - } - } - } - - if (!suppressed) - { - output.WriteLine(); - } - } - - bool optionalHeader = false; - foreach (var option in this.PositionalNames.Concat(this.LongNames)) - { - var arg = this.Arguments[option]; - if (arg.IsHidden) - { - continue; - } - - if (!visitedOptions.Contains(arg.LongName)) - { - if (!optionalHeader) - { - optionalHeader = true; - const string optionalBanner = "Optional Arguments:"; - output.WriteLine(optionalBanner); - output.WriteLine(new string('-', optionalBanner.Length)); - } - - string syntax = " "; - if (!string.IsNullOrEmpty(arg.ShortName)) - { - syntax += string.Format("{0}, ", arg.ShortSyntax); - } - - syntax += string.Format("{0} ", arg.LongSyntax); - output.Write(syntax); - if (syntax.Length < ArgHelpIndent) - { - output.Write(new string(' ', ArgHelpIndent - syntax.Length)); - } - else - { - output.WriteLine(); - output.Write(new string(' ', ArgHelpIndent)); - } - - if (!string.IsNullOrEmpty(arg.Description)) - { - wrapper = new WordWrapper(output, ArgHelpIndent, ArgHelpLineLength); - wrapper.Write(arg.Description); - } - - output.WriteLine(); - } - } - } - } -} diff --git a/Tools/Coyote/Utilities/CommandLineOptions.cs b/Tools/Coyote/Utilities/CommandLineOptions.cs deleted file mode 100644 index ec264bb18..000000000 --- a/Tools/Coyote/Utilities/CommandLineOptions.cs +++ /dev/null @@ -1,513 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using Microsoft.Coyote.IO; -using Microsoft.Coyote.Rewriting; - -namespace Microsoft.Coyote.Utilities -{ - internal sealed class CommandLineOptions - { - /// - /// The command line parser to use. - /// - private readonly CommandLineArgumentParser Parser; - - /// - /// Initializes a new instance of the class. - /// - internal CommandLineOptions() - { - this.Parser = new CommandLineArgumentParser("Coyote", - "The Coyote tool enables you to systematically test a specified Coyote test, generate " + - "a reproducible bug-trace if a bug is found, and replay a bug-trace using the VS debugger."); - - var basicGroup = this.Parser.GetOrCreateGroup("Basic", "Basic options", true); - var commandArg = basicGroup.AddPositionalArgument("command", "The operation perform (test, replay, rewrite)"); - commandArg.AllowedValues = new List(new string[] { "test", "replay", "rewrite", "telemetry" }); - basicGroup.AddPositionalArgument("path", "Path to the Coyote program to test"); - basicGroup.AddArgument("method", "m", "Suffix of the test method to execute"); - basicGroup.AddArgument("outdir", "o", "Dump output to directory x (absolute path or relative to current directory"); - var verbosityArg = basicGroup.AddArgument("verbosity", "v", "Enable verbose log output during testing providing the level of logging you want to see: quiet, minimal, normal, detailed. Using -v with no argument defaults to 'detailed'", typeof(string), defaultValue: "detailed"); - verbosityArg.AllowedValues = new List(new string[] { "quiet", "minimal", "normal", "detailed" }); - basicGroup.AddArgument("debug", "d", "Enable debugging", typeof(bool)).IsHidden = true; - basicGroup.AddArgument("break", "b", "Attaches the debugger and also adds a breakpoint when an assertion fails (disabled during parallel testing)", typeof(bool)); - basicGroup.AddArgument("version", null, "Show tool version", typeof(bool)); - - var testingGroup = this.Parser.GetOrCreateGroup("testingGroup", "Testing options"); - testingGroup.DependsOn = new CommandLineArgumentDependency() { Name = "command", Value = "test" }; - testingGroup.AddArgument("iterations", "i", "Number of schedules to explore for bugs", typeof(uint)); - testingGroup.AddArgument("timeout", "t", "Timeout in seconds after which no more testing iterations will run (disabled by default)", typeof(uint)); - testingGroup.AddArgument("max-steps", "ms", @"Max scheduling steps to be explored during testing (by default 10,000 unfair and 100,000 fair steps). -You can provide one or two unsigned integer values", typeof(uint)).IsMultiValue = true; - testingGroup.AddArgument("fail-on-maxsteps", null, "Consider it a bug if the test hits the specified max-steps", typeof(bool)); - testingGroup.AddArgument("liveness-temperature-threshold", null, "Specify the liveness temperature threshold is the liveness temperature value that triggers a liveness bug", typeof(uint)); - testingGroup.AddArgument("parallel", "p", "Number of parallel testing processes (the default '0' runs the test in-process)", typeof(uint)); - testingGroup.AddArgument("systematic-fuzzing", null, "Use systematic fuzzing instead of controlled testing", typeof(bool)); - testingGroup.AddArgument("sch-random", null, "Choose the random scheduling strategy (this is the default)", typeof(bool)); - testingGroup.AddArgument("sch-probabilistic", "sp", "Choose the probabilistic scheduling strategy with given probability for each scheduling decision where the probability is " + - "specified as the integer N in the equation 0.5 to the power of N. So for N=1, the probability is 0.5, for N=2 the probability is 0.25, N=3 you get 0.125, etc.", typeof(uint)); - testingGroup.AddArgument("sch-prioritization", null, "Choose the priority-based scheduling strategy with given maximum number of priority change points", typeof(uint)); - testingGroup.AddArgument("sch-fair-prioritization", null, "Choose the fair priority-based scheduling strategy with given maximum number of priority change points", typeof(uint)); - testingGroup.AddArgument("sch-portfolio", null, "Choose the portfolio scheduling strategy", typeof(bool)); - testingGroup.AddArgument("no-repro", null, "Disable bug trace repro to ignore uncontrolled concurrency errors", typeof(bool)); - - var replayOptions = this.Parser.GetOrCreateGroup("replayOptions", "Replay options"); - replayOptions.DependsOn = new CommandLineArgumentDependency() { Name = "command", Value = "replay" }; - replayOptions.AddPositionalArgument("schedule", "Schedule file to replay"); - - var rewritingGroup = this.Parser.GetOrCreateGroup("rewritingGroup", "Binary rewriting options"); - rewritingGroup.DependsOn = new CommandLineArgumentDependency() { Name = "command", Value = "rewrite" }; - rewritingGroup.AddArgument("assert-data-races", null, "Add assertions for read/write data races", typeof(bool)); - rewritingGroup.AddArgument("rewrite-dependencies", null, "Rewrite all dependent assemblies that are found in the same location as the given path", typeof(bool)); - rewritingGroup.AddArgument("rewrite-unit-tests", null, "Rewrite unit tests to run in the scope of the Coyote testing engine", typeof(bool)); - rewritingGroup.AddArgument("rewrite-threads", null, "Rewrite low-level threading APIs (experimental)", typeof(bool)); - rewritingGroup.AddArgument("dump-il", null, "Dumps the original and rewritten IL in JSON", typeof(bool)); - rewritingGroup.AddArgument("dump-il-diff", null, "Dumps the IL diff in JSON", typeof(bool)); - - var coverageGroup = this.Parser.GetOrCreateGroup("coverageGroup", "Code and activity coverage options"); - coverageGroup.DependsOn = new CommandLineArgumentDependency() { Name = "command", Value = "test" }; - var coverageArg = coverageGroup.AddArgument("coverage", "c", @"Generate code coverage statistics (via VS instrumentation) with zero or more values equal to: - code: Generate code coverage statistics (via VS instrumentation) - activity: Generate activity (state machine, event, etc.) coverage statistics - activity-debug: Print activity coverage statistics with debug info", typeof(string)); - coverageArg.AllowedValues = new List(new string[] { string.Empty, "code", "activity", "activity-debug" }); - coverageArg.IsMultiValue = true; - coverageGroup.AddArgument("instrument", "instr", "Additional file spec(s) to instrument for code coverage (wildcards supported)", typeof(string)); - coverageGroup.AddArgument("instrument-list", "instr-list", "File containing the paths to additional file(s) to instrument for code " + - "coverage, one per line, wildcards supported, lines starting with '//' are skipped", typeof(string)); - - var advancedGroup = this.Parser.GetOrCreateGroup("advancedGroup", "Advanced options"); - advancedGroup.DependsOn = new CommandLineArgumentDependency() { Name = "command", Value = "test" }; - advancedGroup.AddArgument("explore", null, "Keep testing until the bound (e.g. iteration or time) is reached", typeof(bool)); - advancedGroup.AddArgument("no-fuzzing-fallback", null, "Disable automatic fallback to systematic fuzzing upon detecting uncontrolled concurrency", typeof(bool)); - advancedGroup.AddArgument("no-partial-control", null, "Disallow partially controlled concurrency during controlled testing", typeof(bool)); - advancedGroup.AddArgument("timeout-delay", null, "Controls the frequency of timeouts by built-in timers (not a unit of time)", typeof(uint)); - advancedGroup.AddArgument("deadlock-timeout", null, "Controls how much time (in ms) to wait before reporting a potential deadlock", typeof(uint)); - advancedGroup.AddArgument("skip-potential-deadlocks", null, "Only report a deadlock when the runtime can fully determine that it is genuine and not due to partially-controlled concurrency", typeof(bool)); - advancedGroup.AddArgument("uncontrolled-concurrency-timeout", null, "Controls how much time (in ms) to try resolve uncontrolled concurrency during testing", typeof(uint)); - advancedGroup.AddArgument("uncontrolled-concurrency-interval", null, "Controls the interval (in ms) between attempts to resolve uncontrolled concurrency during testing", typeof(uint)); - advancedGroup.AddArgument("reduce-shared-state", null, "Enables shared state reduction during testing", typeof(bool)); - advancedGroup.AddArgument("seed", null, "Specify the random value generator seed", typeof(uint)); - advancedGroup.AddArgument("graph-bug", null, "Output a DGML graph of the iteration that found a bug", typeof(bool)); - advancedGroup.AddArgument("graph", null, "Output a DGML graph of all test iterations whether a bug was found or not", typeof(bool)); - advancedGroup.AddArgument("xml-trace", null, "Specify a filename for XML runtime log output to be written to", typeof(bool)); - advancedGroup.AddArgument("actor-runtime-log", null, "Specify an additional custom logger using fully qualified name: 'fullclass,assembly'", typeof(string)); - - var experimentalGroup = this.Parser.GetOrCreateGroup("experimentalGroup", "Experimental options"); - experimentalGroup.DependsOn = new CommandLineArgumentDependency() { Name = "command", Value = "test" }; - experimentalGroup.AddArgument("sch-dfs", null, "Choose the depth-first search (DFS) scheduling strategy", typeof(bool)); - experimentalGroup.AddArgument("sch-rl", null, "Choose the reinforcement learning (RL) scheduling strategy", typeof(bool)); - - // Hidden options (for debugging or experimentation only). - var hiddenGroup = this.Parser.GetOrCreateGroup("hiddenGroup", "Hidden Options"); - hiddenGroup.IsHidden = true; - hiddenGroup.AddArgument("run-as-parallel-testing-task", null, null, typeof(bool)); - hiddenGroup.AddArgument("additional-paths", null, null, typeof(string)); - hiddenGroup.AddArgument("testing-scheduler-ipaddress", null, "Specify server ip address and optional port (default: 127.0.0.1:0))", typeof(string)); - hiddenGroup.AddArgument("testing-scheduler-endpoint", null, "Specify a name for the server (default: CoyoteTestScheduler)", typeof(string)); - hiddenGroup.AddArgument("testing-process-id", null, "The id of the controlling TestingProcessScheduler", typeof(uint)); - hiddenGroup.AddArgument("wait-for-testing-processes", null, "Wait for testing processes to start (default is to launch them)", typeof(bool)); - hiddenGroup.AddArgument("parallel-debug", "pd", "Used with --parallel to put up a debugger prompt on each child process", typeof(bool)); - } - - internal void PrintHelp(TextWriter w) - { - this.Parser.PrintHelp(w); - } - - /// - /// Parses the command line options and returns a configuration. - /// - /// The command line arguments to parse. - /// The configuration object populated with the parsed command line options. - /// The rewriting options. - internal bool Parse(string[] args, Configuration configuration, RewritingOptions rewritingOptions) - { - try - { - var result = this.Parser.ParseArguments(args); - if (result != null) - { - foreach (var arg in result) - { - UpdateConfigurationWithParsedArgument(configuration, rewritingOptions, arg); - } - - SanitizeConfiguration(configuration); - return true; - } - } - catch (CommandLineException ex) - { - if ((from arg in ex.Result where arg.LongName == "version" select arg).Any()) - { - WriteVersion(); - Environment.Exit(1); - } - else - { - this.Parser.PrintHelp(Console.Out); - Error.ReportAndExit(ex.Message); - } - } - catch (Exception ex) - { - this.Parser.PrintHelp(Console.Out); - Error.ReportAndExit(ex.Message); - } - - return false; - } - - /// - /// Updates the configuration with the specified parsed argument. - /// - private static void UpdateConfigurationWithParsedArgument(Configuration configuration, - RewritingOptions rewritingOptions, CommandLineArgument option) - { - switch (option.LongName) - { - case "command": - configuration.ToolCommand = (string)option.Value; - break; - case "outdir": - configuration.OutputFilePath = (string)option.Value; - break; - case "debug": - configuration.IsDebugVerbosityEnabled = true; - Debug.IsEnabled = true; - break; - case "verbosity": - configuration.IsVerbose = true; - string verbosity = (string)option.Value; - switch (verbosity) - { - case "quiet": - configuration.IsVerbose = false; - break; - case "detailed": - configuration.LogLevel = LogSeverity.Informational; - break; - case "normal": - configuration.LogLevel = LogSeverity.Warning; - break; - case "minimal": - configuration.LogLevel = LogSeverity.Error; - break; - default: - Error.ReportAndExit($"Please give a valid value for 'verbosity' must be one of 'errors', 'warnings', or 'info', but found {verbosity}."); - break; - } - - break; - case "path": - if (configuration.ToolCommand is "test" || configuration.ToolCommand is "replay") - { - // In the case of 'coyote test' or 'replay', the path is the assembly to be tested. - configuration.AssemblyToBeAnalyzed = (string)option.Value; - } - else if (configuration.ToolCommand is "rewrite") - { - // In the case of 'coyote rewrite', the path is the JSON configuration file - // with the binary rewriting options. - string filename = (string)option.Value; - if (Directory.Exists(filename)) - { - // Then we want to rewrite a whole folder full of assemblies. - var assembliesDir = Path.GetFullPath(filename); - rewritingOptions.AssembliesDirectory = assembliesDir; - rewritingOptions.OutputDirectory = assembliesDir; - } - else - { - string extension = Path.GetExtension(filename); - if (string.Compare(extension, ".json", StringComparison.OrdinalIgnoreCase) is 0) - { - // Parse the rewriting options from the JSON file. - RewritingOptions.ParseFromJSON(rewritingOptions, filename); - } - else if (string.Compare(extension, ".dll", StringComparison.OrdinalIgnoreCase) is 0 || - string.Compare(extension, ".exe", StringComparison.OrdinalIgnoreCase) is 0) - { - configuration.AssemblyToBeAnalyzed = filename; - var fullPath = Path.GetFullPath(filename); - var assembliesDir = Path.GetDirectoryName(fullPath); - rewritingOptions.AssembliesDirectory = assembliesDir; - rewritingOptions.OutputDirectory = assembliesDir; - rewritingOptions.AssemblyPaths.Add(fullPath); - } - else - { - Error.ReportAndExit("Please give a valid .dll or JSON configuration file for binary rewriting."); - } - } - } - - break; - case "method": - configuration.TestMethodName = (string)option.Value; - break; - case "systematic-fuzzing": - case "no-repro": - configuration.IsSystematicFuzzingEnabled = true; - break; - case "no-partial-control": - configuration.IsPartiallyControlledConcurrencyAllowed = false; - break; - case "no-fuzzing-fallback": - configuration.IsSystematicFuzzingFallbackEnabled = false; - break; - case "reduce-shared-state": - configuration.IsSharedStateReductionEnabled = true; - break; - case "explore": - configuration.RunTestIterationsToCompletion = true; - break; - case "seed": - configuration.RandomGeneratorSeed = (uint)option.Value; - break; - case "sch-random": - case "sch-dfs": - case "sch-portfolio": - configuration.SchedulingStrategy = option.LongName.Substring(4); - break; - case "sch-probabilistic": - case "sch-prioritization": - case "sch-fair-prioritization": - configuration.SchedulingStrategy = option.LongName.Substring(4); - configuration.StrategyBound = (int)(uint)option.Value; - break; - case "sch-rl": - configuration.SchedulingStrategy = option.LongName.Substring(4); - configuration.IsProgramStateHashingEnabled = true; - break; - case "schedule": - { - string filename = (string)option.Value; - string extension = Path.GetExtension(filename); - if (!extension.Equals(".schedule")) - { - Error.ReportAndExit("Please give a valid schedule file " + - "with extension '.schedule'."); - } - - configuration.ScheduleFile = filename; - } - - break; - case "version": - WriteVersion(); - Environment.Exit(1); - break; - case "break": - configuration.AttachDebugger = true; - break; - case "iterations": - configuration.TestingIterations = (uint)option.Value; - break; - case "timeout": - configuration.TestingTimeout = (int)(uint)option.Value; - break; - case "parallel": - configuration.ParallelBugFindingTasks = (uint)option.Value; - break; - case "parallel-debug": - configuration.ParallelDebug = true; - break; - case "wait-for-testing-processes": - configuration.WaitForTestingProcesses = true; - break; - case "testing-scheduler-ipaddress": - { - var ipAddress = (string)option.Value; - int port = 0; - if (ipAddress.Contains(":")) - { - string[] parts = ipAddress.Split(':'); - if (parts.Length != 2 || !int.TryParse(parts[1], out port)) - { - Error.ReportAndExit("Please give a valid port number for --testing-scheduler-ipaddress option"); - } - - ipAddress = parts[0]; - } - - if (!IPAddress.TryParse(ipAddress, out _)) - { - Error.ReportAndExit("Please give a valid ip address for --testing-scheduler-ipaddress option"); - } - - configuration.TestingSchedulerIpAddress = ipAddress + ":" + port; - } - - break; - case "run-as-parallel-testing-task": - configuration.RunAsParallelBugFindingTask = true; - break; - case "additional-paths": - configuration.AdditionalPaths = (string)option.Value; - break; - case "testing-scheduler-endpoint": - configuration.TestingSchedulerEndPoint = (string)option.Value; - break; - case "testing-process-id": - configuration.TestingProcessId = (uint)option.Value; - break; - case "graph": - configuration.IsDgmlGraphEnabled = true; - configuration.IsDgmlBugGraph = false; - break; - case "graph-bug": - configuration.IsDgmlGraphEnabled = true; - configuration.IsDgmlBugGraph = true; - break; - case "xml-trace": - configuration.IsXmlLogEnabled = true; - break; - case "actor-runtime-log": - configuration.CustomActorRuntimeLogType = (string)option.Value; - break; - case "coverage": - if (option.Value is null) - { - configuration.ReportCodeCoverage = true; - configuration.IsActivityCoverageReported = true; - } - else - { - foreach (var item in (string[])option.Value) - { - switch (item) - { - case "code": - configuration.ReportCodeCoverage = true; - break; - case "activity": - configuration.IsActivityCoverageReported = true; - break; - case "activity-debug": - configuration.IsActivityCoverageReported = true; - configuration.DebugActivityCoverage = true; - break; - default: - break; - } - } - } - - break; - case "instrument": - configuration.AdditionalCodeCoverageAssemblies[(string)option.Value] = false; - break; - case "instrument-list": - configuration.AdditionalCodeCoverageAssemblies[(string)option.Value] = true; - break; - case "assert-data-races": - rewritingOptions.IsDataRaceCheckingEnabled = true; - break; - case "rewrite-dependencies": - rewritingOptions.IsRewritingDependencies = true; - break; - case "rewrite-unit-tests": - rewritingOptions.IsRewritingUnitTests = true; - break; - case "rewrite-threads": - rewritingOptions.IsRewritingThreads = true; - break; - case "dump-il": - rewritingOptions.IsLoggingAssemblyContents = true; - break; - case "dump-il-diff": - rewritingOptions.IsDiffingAssemblyContents = true; - break; - case "timeout-delay": - configuration.TimeoutDelay = (uint)option.Value; - break; - case "deadlock-timeout": - configuration.DeadlockTimeout = (uint)option.Value; - break; - case "skip-potential-deadlocks": - configuration.ReportPotentialDeadlocksAsBugs = false; - break; - case "uncontrolled-concurrency-timeout": - configuration.UncontrolledConcurrencyResolutionTimeout = (uint)option.Value; - break; - case "uncontrolled-concurrency-interval": - configuration.UncontrolledConcurrencyResolutionInterval = (uint)option.Value; - break; - case "max-steps": - { - uint[] values = (uint[])option.Value; - if (values.Length > 2) - { - Error.ReportAndExit("Invalid number of options supplied via '--max-steps'."); - } - - try - { - uint i = values[0]; - uint j; - if (values.Length is 2) - { - j = values[1]; - configuration.WithMaxSchedulingSteps(i, j); - } - else - { - configuration.WithMaxSchedulingSteps(i); - } - } - catch (ArgumentException) - { - Error.ReportAndExit("For the option '--max-steps N[,M]', please make sure that M >= N."); - } - } - - break; - case "fail-on-maxsteps": - configuration.ConsiderDepthBoundHitAsBug = true; - break; - case "liveness-temperature-threshold": - configuration.LivenessTemperatureThreshold = (int)(uint)option.Value; - configuration.UserExplicitlySetLivenessTemperatureThreshold = true; - break; - default: - throw new Exception(string.Format("Unhandled parsed argument: '{0}'", option.LongName)); - } - } - - private static void WriteVersion() - { - Console.WriteLine("Version: {0}", typeof(CommandLineOptions).Assembly.GetName().Version); - } - - /// - /// Sanitizes the configuration. - /// - private static void SanitizeConfiguration(Configuration configuration) - { - if (string.IsNullOrEmpty(configuration.AssemblyToBeAnalyzed) && - string.Compare(configuration.ToolCommand, "test", StringComparison.OrdinalIgnoreCase) is 0) - { - Error.ReportAndExit("Please give a valid path to a Coyote program's dll using 'test x'."); - } - - if (configuration.SchedulingStrategy != "portfolio" && - configuration.SchedulingStrategy != "random" && - configuration.SchedulingStrategy != "prioritization" && - configuration.SchedulingStrategy != "fair-prioritization" && - configuration.SchedulingStrategy != "probabilistic" && - configuration.SchedulingStrategy != "rl" && - configuration.SchedulingStrategy != "dfs") - { - Error.ReportAndExit("Please provide a scheduling strategy (see --sch* options)"); - } - } - } -} diff --git a/Tools/Coyote/Utilities/DependencyGraph.cs b/Tools/Coyote/Utilities/DependencyGraph.cs deleted file mode 100644 index 2cca703d9..000000000 --- a/Tools/Coyote/Utilities/DependencyGraph.cs +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using Microsoft.Coyote.IO; - -namespace Microsoft.Coyote.SystematicTesting.Utilities -{ - internal class DependencyGraph - { - private readonly Dictionary AssemblyNameToFullPathMap = new Dictionary(); - - public DependencyGraph(string rootFolder, HashSet additionalAssemblies) - { - // here we assume the dependencies we need to instrument for assemblyUnderTest all live in the - // same folder, or the user provides them with --instrument and --instrument-list options. - var allNames = new HashSet(Directory.GetFiles(rootFolder, "*.dll")); - allNames.UnionWith(additionalAssemblies); - - // Because Assembly.GetReferencedAssemblies does not yet have the path (assembly resolution is complex), we will assume that - // any assembly that matches a name in the executing directory is the referenced assembly that we need to also instrument. - foreach (var path in allNames) - { - // Note: we cannot use allNames.ToDictionary because in some cases we have a *.exe and *.dll with the same name. - var name = Path.GetFileNameWithoutExtension(path); - if (!this.AssemblyNameToFullPathMap.ContainsKey(name)) - { - this.AssemblyNameToFullPathMap[name] = path; - } - else - { - Debug.WriteLine("Skipping {0}", path); - } - } - } - - internal string[] GetDependencies(string assemblyUnderTest) - { - // Get the case-normalized directory name - var result = new HashSet(); - this.GetDependencies(assemblyUnderTest, result); - return result.ToArray(); - } - - private void GetDependencies(string assemblyPath, HashSet visited) - { - assemblyPath = Path.GetFullPath(assemblyPath); - var assembly = Assembly.LoadFrom(assemblyPath); - visited.Add(assemblyPath); - - foreach (var assemblyName in assembly.GetReferencedAssemblies()) - { - if (assemblyName.Name != "Microsoft.Coyote") - { - if (this.AssemblyNameToFullPathMap.ContainsKey(assemblyName.Name)) - { - var dependencyPath = this.AssemblyNameToFullPathMap[assemblyName.Name]; - if (!visited.Contains(dependencyPath)) - { - this.GetDependencies(dependencyPath, visited); - } - } - else if (assemblyName.Name != "mscorlib" && !assemblyName.Name.StartsWith("System")) - { - Error.Report($"Could not find dependent assembly '{assemblyName.ToString()}'"); - } - } - } - } - } -} diff --git a/Tools/Coyote/Utilities/ExitCode.cs b/Tools/Coyote/Utilities/ExitCode.cs deleted file mode 100644 index 684d6b0dc..000000000 --- a/Tools/Coyote/Utilities/ExitCode.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -namespace Microsoft.Coyote.SystematicTesting -{ - /// - /// The exit code returned by the tester. - /// - internal enum ExitCode - { - /// - /// Indicates that no bugs were found. - /// - Success = 0, - - /// - /// Indicates that a bug was found. - /// - BugFound = 1, - - /// - /// Indicates that an internal exception was thrown. - /// - InternalError = 2 - } -} diff --git a/Tools/Coyote/Utilities/Reporter.cs b/Tools/Coyote/Utilities/Reporter.cs deleted file mode 100644 index 8ad458997..000000000 --- a/Tools/Coyote/Utilities/Reporter.cs +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; -using System.IO; -using Microsoft.Coyote.Actors.Coverage; - -namespace Microsoft.Coyote.SystematicTesting -{ - /// - /// The Coyote testing reporter. - /// - internal static class Reporter - { - /// - /// Emits the testing coverage report. - /// - /// TestReport. - /// Optional process id that produced the report. - /// Is a debug report. - internal static void EmitTestingCoverageReport(TestReport report, uint? processId = null, bool isDebug = false) - { - string file = Path.GetFileNameWithoutExtension(report.Configuration.AssemblyToBeAnalyzed); - if (isDebug && processId != null) - { - file += "_" + processId; - } - - string directory = CodeCoverageInstrumentation.OutputDirectory; - if (isDebug) - { - directory += $"Debug{Path.DirectorySeparatorChar}"; - Directory.CreateDirectory(directory); - } - - EmitTestingCoverageOutputFiles(report, directory, file); - } - - /// - /// Returns (and creates if it does not exist) the output directory with an optional suffix. - /// - internal static string GetOutputDirectory(string userOutputDir, string assemblyPath, string suffix = "", bool createDir = true) - { - string directoryPath; - - if (!string.IsNullOrEmpty(userOutputDir)) - { - directoryPath = userOutputDir + Path.DirectorySeparatorChar; - } - else - { - var subpath = Path.GetDirectoryName(assemblyPath); - if (subpath.Length is 0) - { - subpath = "."; - } - - directoryPath = subpath + - Path.DirectorySeparatorChar + "Output" + Path.DirectorySeparatorChar + - Path.GetFileName(assemblyPath) + Path.DirectorySeparatorChar; - } - - if (suffix.Length > 0) - { - directoryPath += suffix + Path.DirectorySeparatorChar; - } - - if (createDir) - { - Directory.CreateDirectory(directoryPath); - } - - return directoryPath; - } - - /// - /// Emits all the testing coverage related output files. - /// - /// TestReport containing CoverageInfo. - /// Output directory name, unique for this run. - /// Output file name. - private static void EmitTestingCoverageOutputFiles(TestReport report, string directory, string file) - { - var codeCoverageReporter = new ActivityCoverageReporter(report.CoverageInfo); - var filePath = $"{directory}{file}"; - - string graphFilePath = $"{filePath}.dgml"; - Console.WriteLine($"..... Writing {graphFilePath}"); - codeCoverageReporter.EmitVisualizationGraph(graphFilePath); - - string coverageFilePath = $"{filePath}.coverage.txt"; - Console.WriteLine($"..... Writing {coverageFilePath}"); - codeCoverageReporter.EmitCoverageReport(coverageFilePath); - - string serFilePath = $"{filePath}.sci"; - Console.WriteLine($"..... Writing {serFilePath}"); - report.CoverageInfo.Save(serFilePath); - } - } -} diff --git a/docs/concepts/actors/state-machine-demo.md b/docs/concepts/actors/state-machine-demo.md index b95c8bc40..abe639f80 100644 --- a/docs/concepts/actors/state-machine-demo.md +++ b/docs/concepts/actors/state-machine-demo.md @@ -6,7 +6,7 @@ {% include 'player-controls.html' %} -This graph was generated from a `coyote test` with the `--xml-trace` and `--graph-bug` options on a +This graph was generated from a `coyote test` with the `--xml-trace` and `--graph` options on a `StateMachine` based coyote application that implements the `Raft` protocol. The fact that coyote `StateMachines` expose explicit state information makes it possible for `coyote` to visualize what is going on in a level of detail that is hard to extract from other kinds of C# code. This diff --git a/docs/get-started/install.md b/docs/get-started/install.md index 28e1d968b..2733a0a01 100644 --- a/docs/get-started/install.md +++ b/docs/get-started/install.md @@ -46,8 +46,8 @@ dotnet tool install --global Microsoft.Coyote.CLI ``` Now you can run the `coyote test` tool without having to build Coyote from source. Type `coyote ---help` to see if it is working. The dotnet tool install can also install coyote to a `--local` -folder if you prefer that. +--help` to see if it is working. The dotnet tool install can also install coyote to a local folder +if you prefer that. You can update the global `coyote` tool by running the following command: diff --git a/docs/get-started/telemetry.md b/docs/get-started/telemetry.md index 2985c2208..8eafbdeff 100644 --- a/docs/get-started/telemetry.md +++ b/docs/get-started/telemetry.md @@ -12,11 +12,11 @@ set COYOTE_CLI_TELEMETRY_OPTOUT=1 First time usage of `coyote` is detected by the presence of the following file: ```plain -[Windows] %USERPROFILE%\AppData\Local\Microsoft\Coyote\CoyoteMachineId.txt -[Linux] $(HOME)/.microsoft/coyote/CoyoteMachineId.txt +[Windows] %USERPROFILE%\AppData\Local\Microsoft\Coyote\device_id.txt +[Linux] $(HOME)/.microsoft/coyote/device_id.txt ``` -This file contains a generated GUID representing the local machine which helps telemetry get some +This file contains a generated GUID representing the local device which helps telemetry get some vague idea of the number of folks that are using the `coyote` tool. The following metrics are collected: diff --git a/docs/get-started/using-coyote.md b/docs/get-started/using-coyote.md index c93bf9c33..931837340 100644 --- a/docs/get-started/using-coyote.md +++ b/docs/get-started/using-coyote.md @@ -61,22 +61,6 @@ the specified `AssembliesPath`. Then pass this config file on the command line: `coyote rewrite config.json`. -### Strong name signing - -For .NET Framework, you may need to resign your rewritten binaries in order for tests to run -properly. This can be done by providing the same strong name key that you provided during the -original build. This can be done using the `--strong-name-key-file` command line argument (or -`-snk` for the abbreviated option name). - -For example, from your `coyote` repo: - -```plain -coyote rewrite d:\git\Coyote\Tests\Tests.BugFinding\bin\net462\rewrite.coyote.json - --strong-name-key-file Common\Key.snk -``` - -You can also provide this key in the JSON file using the `StrongNameKeyFile` property. - ### Test your binaries The `coyote` command line tool can be used to automatically test a Coyote program to find and @@ -168,17 +152,12 @@ non-terminating executions (like an infinite series of ping pong events, for exa cases, if you do not provide `max-steps` then the tester can appear to can get stuck running one iteration forever. This is related to [liveness checking](../how-to/liveness-checking.md). -### Parallel and portfolio testing - -The Coyote tester supports parallel testing, often used with a portfolio of different schedulers. - -To enable parallel testing, you must run `coyote`, and provide the flag `--parallel N` (where N > 0), -with N specifying the number of parallel testing processes to be spawned. By default, the tester -spawns the same testing process multiple times (using different random seeds). +### Portfolio testing -When doing parallel testing it is often useful to provide the `--sch-portfolio` flag. This option -allocates different exploration strategies to each spawned test process which increases the chance -that one of the test processes will find a particularly difficult bug. +The Coyote tester supports running a portfolio of different exploration strategies during testing. +To enable this provide the `--strategy portfolio` flag. This option allocates different exploration +strategies to each spawned test process which increases the chance that one of the test processes +will find a particularly difficult bug. ### Reproducing and debugging traces @@ -226,17 +205,14 @@ contribute a [PR](https://github.com/microsoft/coyote/compare)! ### Graphing the results The `--graph` command line option produces a [DGML diagram](../how-to/generate-dgml.md) containing a -graphical trace of all the state transitions that happened in all test iterations. The `--graph-bug` -command line option is similar but produces a graph only of the last test iteration leading up to a -bug. These graphs are different from the graph generated by `--coverage activity` because the +graphical trace of all the state transitions that happened in the last test iteration leading up to +a bug. These graphs are different from the graph generated by `--coverage activity` because the coverage graph collapses all machine instances into one group, so you can more easily see the whole -coverage of that machine type. The `--graph` options are handy when you need to see the difference -in state that happened in different machine instances. +coverage of that machine type. -See [animating state machine demo](../concepts/actors/state-machine-demo.md) for a -visual explanation of what `coyote test` does when it is looking for bugs. In the animation you will -see why the test failed, two of the server nodes have taken on the `Leader` role, which is not -allowed. +See [animating state machine demo](../concepts/actors/state-machine-demo.md) for a visual +explanation of what `coyote test` does when it is looking for bugs. In the animation you will see +why the test failed, two of the server nodes have taken on the `Leader` role, which is not allowed. See also the [DGML diagram](../assets/images/raft.dgml) which you can open in Visual Studio. Here the Server state machines are colored in green, and the Leader states in red to diff --git a/docs/how-to/coverage.md b/docs/how-to/coverage.md index 84974adb0..560649100 100644 --- a/docs/how-to/coverage.md +++ b/docs/how-to/coverage.md @@ -9,38 +9,20 @@ state transitions and the percentage of possible events that are actually execut ### Coyote coverage options Running `coyote /?` displays a summary of command-line options. Here is the section describing -options to report code and activity coverage: +options to report activity coverage: ```plain -Code and activity coverage options: +Coverage options: ----------------------------------- -c, --coverage string - : Generate code coverage statistics (via VS instrumentation) with zero - or more values equal to: - code: Generate code coverage statistics (via VS instrumentation) - activity: Generate activity (state machine, event, etc.) coverage statistics - activity-debug: Print activity coverage statistics with debug info - -instr, --instrument string - : Additional file spec(s) to instrument for code coverage (wildcards - supported) - -instr-list, --instrument-list string - : File containing the paths to additional file(s) to instrument for - code coverage, one per line, wildcards supported, lines starting - with '//' are skipped + : Generate coverage reports if supported for the programming model used by the test. ``` Detailed descriptions are provided in subsequent sections. The following provides a quick overview. -* Note that `--coverage` is the equivalent of specifying `--coverage code activity`. -* If `--coverage` or `--coverage code` is specified, all DLLs in the dependency chain between the - assembly being tested (specified by the `path` argument) and any `Microsoft.Coyote.*.dll` are - instrumented to collect code coverage data. -* The `--instrument` options allow you specify other DLLs that don't depend on Coyote but should - also be instrumented (for example, utility libraries). File names can be absolute or relative to - the assembly being tested (specified by the `path` argument). -* `--coverage activity` and `--coverage activity-debug` do not instrument assemblies. In this case - Coyote maintains the history of events and state transitions for reporting the coverage of the - actors and state machines being tested. +* If `--coverage` is specified, Coyote will collect the history of all events and state transitions + for reporting the coverage of the actors and state machines being tested. +* Coverage is not currently available for programming models other than actors. ### Output file locations @@ -97,57 +79,6 @@ machines, states and transitions witnessed during the testing of the program. Th inter-machine transitions. These transitions are usually auto-hidden when opened in Visual Studio, but visible when you click on a state. -### Code coverage - -For code coverage, `coyote` instruments the `path` assembly and the binaries it depends upon via -`VSInstr.exe`. `VSPerfCmd.exe` is launched while the test runs, and is terminated when the test is -complete. - -For code coverage to work you must ensure your project is built using **Full PDBs** which you can -do by specifying the following build properties: - -```xml - - full - true - -``` - -`VSPerfCmd.exe` collects data from all running processes, so do not run multiple coverage tests at -the same time. - -### Code coverage binary instrumentation - -`coyote` instruments the following binaries (via `VSInstr.exe`): -* `path`: this is the path to the assembly that is being tested. -* Each DLL in the dependency graph of the assembly specified by the `path` argument - not including - `Microsoft.Coyote.dll`, `mscorlib` or any `System*` assemblies. -* Any additional assemblies specified by one of the `--instrument` or `--instrument-list` options. - -By default the VS 2019 tools are used. These are set in `coyote.exe.config` and are based on the -environment variable $(DevEnvDir) which is automatically defined if you use a Visual Studio -Developer Command Prompt. The actual paths can be overridden by environment variables with the same -names as the app settings: - -- `VSInstrToolPath` -- `VSPerfCmdToolPath` - -### Code coverage output files - -If the option `--coverage` or `--coverage code` is passed to `coyote`, the following files will be -written to the [output directory](#output-file-locations) (for example, if `path` is -`PingPong.exe`): - -* `PingPong.coverage`. This file contains the code coverage data that can be read by Visual Studio. - To do so, load it as a file into VS, then select Mixed Debugging. -* The same Coyote output folder will contain all the instrumented binaries that were used to run the test. -The original binaries are left unchanged. - -The instrumented binaries are retained because VS requires the matching instrumented binaries to be -able to load the `.coverage` file. If you want keep track of code-coverage improvements over time -you can use the `coyote test --outdir` option to collect multiple coverage files in different -locations. - ### Coyote test examples First build the Coyote samples by following the instructions @@ -169,32 +100,3 @@ coyote test ./bin/net6.0/Monitors.exe -i 10 -coverage activity -o "/Coyote_Cove This will create the directory `/Coyote_Coverage/Monitors/CoyoteOutput`, then it generates only activity coverage. - -```plain -coyote test ./bin/net6.0/Monitors.exe -i 10 --coverage code activity-debug -``` - -This generates code and activity coverage, including debug activity output. - -### Troubleshooting - -#### Error VSP1394: Could not start profile monitor - -This could happen if you are trying to run `coyote test` from a current directory that contains -conflicting binaries from the ones you are testing. Try `cd` to some other location and run `coyote -test` with a full path to the binary being tested. - -#### Exception thrown: 'System.BadImageFormatException' in System.Private.CoreLib.dll - -This could happen on a .NET Core build if you are referencing a *.exe instead of the *.dll assembly -for testing. - -#### Error: Could not find dependent assembly ... - -You may need to add `--instrument` or `--instrument-list` option to specify the location of that -additional assembly. - -#### Code coverage is empty - -If a .coverage file is produced but it is empty, and contains no coverage information then try -running `VSInst` manually and check for any errors. diff --git a/docs/how-to/liveness-checking.md b/docs/how-to/liveness-checking.md index 457685663..9053fd17c 100644 --- a/docs/how-to/liveness-checking.md +++ b/docs/how-to/liveness-checking.md @@ -29,7 +29,7 @@ the [coyote tool](../get-started/using-coyote.md) as follows, setting N steps as From the [samples](https://github.com/microsoft/coyote/tree/main/Samples) directory: ```plain -coyote test ./Samples/bin/net6.0/CoffeeMachineActors.dll -i 10 -ms 200 -p 4 --sch-portfolio +coyote test ./Samples/bin/net6.0/CoffeeMachineActors.dll -i 10 -ms 200 -s portfolio ``` The `coyote test` tool will produce output, ending with something like the following: @@ -52,7 +52,7 @@ averaging 457 steps. Going by this output, let's decide to increase the bound to `coyote test`. ```plain -coyote test ./Samples/bin/net6.0/CoffeeMachineActors.dll -i 10 -ms 1000 -p 4 --sch-portfolio +coyote test ./Samples/bin/net6.0/CoffeeMachineActors.dll -i 10 -ms 1000 -s portfolio ``` This time the output will be something like: @@ -101,21 +101,22 @@ makes decisions on the next actor to schedule randomly, is fair. In the program is very likely that B will be given a chance to execute. Some schedulers don't have this property and are called _unfair_ schedulers. Unfair schedulers have a role to play in finding violations of safety properties, but not in finding violations of liveness properties. The `prioritization` -scheduler of Coyote (enabled with the `--sch-prioritization N` option) is unfair. +scheduler of Coyote (enabled with the `--strategy prioritization` option) is unfair. Because of their nature, unfair schedulers are expected to generate longer than usual executions. The unfairness in scheduling can lead to starvation of certain actors, which may stall progress. The expected length of a program's execution is best determined by looking at lengths of "fair terminating executions", i.e., executions that terminate under a fair scheduler. For this reason, we -provide the `fair-prioritization` scheduler (enabled with the `--sch-fair-prioritization N` option) -which uses the `prioritization` scheduler for a prefix of each execution and then switches to the -default fair `random` scheduler for the remaining of the execution. +provide the `fair-prioritization` scheduler (enabled with the `--strategy fair-prioritization` +option) which uses the `prioritization` scheduler for a prefix of each execution and then switches +to the default fair `random` scheduler for the remaining of the execution. When a user supplies the flag `--max-steps N`, executions under an unfair scheduler are forced to stop after N steps. Whereas, an execution under a fair scheduler can go to up 10N steps. Further, if -the execution stays in a hot state for more than 5N steps, a liveness bug is flagged. You can -additionally supply the flag `-max-steps N M` to limit fair schedulers to explore only up to M steps -(instead of 10N). +the execution stays in a hot state for more than 5N steps, a liveness bug is flagged. Alternatively, +you can supply the flag `--max-fair-steps M` to limit fair schedulers to explore only up to M steps +(instead of 10N). If you decide to use the `--max-fair-steps M` flag, you can optionally set the +unfair steps using the `--max-unfair-steps N` flag. There are other smarter heuristics available in the tester as well that do away with the need for such bounds by looking for _lasso_ shaped executions. If interested, read more about it in the @@ -125,6 +126,6 @@ following paper from Microsoft Research. 2017.](https://www.microsoft.com/en-us/research/publication/lasso-detection-using-partial-state-caching-2/) To avoid having to think which scheduler works best for which situation, we recommend running -`coyote test` in parallel (enabled with the `-p N` option), using the portfolio scheduler (enabled -with the `--sch-portfolio` option) which consists of a carefully tuned selection of fair schedulers -(including `random` and `fair-prioritization`). +`coyote test` using the portfolio scheduler (enabled with the `--strategy portfolio` option) which +consists of a carefully tuned selection of fair schedulers (including `random`, `prioritization` and +`fair-prioritization`). diff --git a/docs/how-to/unit-testing.md b/docs/how-to/unit-testing.md index 6f18b7ec2..337142f85 100644 --- a/docs/how-to/unit-testing.md +++ b/docs/how-to/unit-testing.md @@ -70,7 +70,7 @@ Coyote found 1 bug. Most of the command line options you see on `coyote test` are available in the `Configuration` class. Use the `With*` helper methods to set the various configurations, for example, to specify -`--sch-prioritization 10` use the following: +`--strategy prioritization` together with `--strategy-value 10` use the following: ```csharp var config = Configuration.Create().WithPrioritizationStrategy(false, 10); diff --git a/docs/ref/Microsoft.Coyote.Actors.CoverageNamespace.md b/docs/ref/Microsoft.Coyote.Actors.CoverageNamespace.md index a2032e9b5..e402919ba 100644 --- a/docs/ref/Microsoft.Coyote.Actors.CoverageNamespace.md +++ b/docs/ref/Microsoft.Coyote.Actors.CoverageNamespace.md @@ -2,7 +2,6 @@ | public type | description | | --- | --- | -| class [ActorRuntimeLogGraphBuilder](Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder.md) | Implements the [`IActorRuntimeLog`](Microsoft.Coyote.Actors/IActorRuntimeLog.md) and builds a directed graph from the recorded events and state transitions. | | class [CoverageInfo](Microsoft.Coyote.Actors.Coverage/CoverageInfo.md) | Class for storing actor coverage-specific data across multiple testing iterations. | | class [EventCoverage](Microsoft.Coyote.Actors.Coverage/EventCoverage.md) | This class maintains information about events received and sent from each state of each actor. | | class [Graph](Microsoft.Coyote.Actors.Coverage/Graph.md) | A directed graph made up of Nodes and Links. | diff --git a/docs/ref/Microsoft.Coyote.Rewriting/RewritingEngine.md b/docs/ref/Microsoft.Coyote.Rewriting/RewritingEngine.md new file mode 100644 index 000000000..d6e9ea630 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.Rewriting/RewritingEngine.md @@ -0,0 +1,24 @@ +# RewritingEngine class + +Engine that can rewrite a set of assemblies for systematic testing. + +```csharp +public class RewritingEngine +``` + +## Public Members + +| name | description | +| --- | --- | +| static [IsAssemblyRewritten](RewritingEngine/IsAssemblyRewritten.md)(…) | Checks if the specified assembly has been already rewritten with the current version. | + +## Remarks + +See [rewriting](/coyote/get-started/rewriting) for more information. + +## See Also + +* namespace [Microsoft.Coyote.Rewriting](../Microsoft.Coyote.RewritingNamespace.md) +* assembly [Microsoft.Coyote.Test](../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.Rewriting/RewritingEngine/IsAssemblyRewritten.md b/docs/ref/Microsoft.Coyote.Rewriting/RewritingEngine/IsAssemblyRewritten.md new file mode 100644 index 000000000..87022005f --- /dev/null +++ b/docs/ref/Microsoft.Coyote.Rewriting/RewritingEngine/IsAssemblyRewritten.md @@ -0,0 +1,23 @@ +# RewritingEngine.IsAssemblyRewritten method + +Checks if the specified assembly has been already rewritten with the current version. + +```csharp +public static bool IsAssemblyRewritten(Assembly assembly) +``` + +| parameter | description | +| --- | --- | +| assembly | The assembly to check. | + +## Return Value + +True if the assembly has been rewritten with the current version, else false. + +## See Also + +* class [RewritingEngine](../RewritingEngine.md) +* namespace [Microsoft.Coyote.Rewriting](../RewritingEngine.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.Rewriting/RewritingSignatureAttribute.md b/docs/ref/Microsoft.Coyote.Rewriting/RewritingSignatureAttribute.md new file mode 100644 index 000000000..9902f1971 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.Rewriting/RewritingSignatureAttribute.md @@ -0,0 +1,27 @@ +# RewritingSignatureAttribute class + +Attribute that contains a signature identifying the parameters used during binary rewriting of an assembly. + +```csharp +[AttributeUsage(AttributeTargets.Assembly)] +public sealed class RewritingSignatureAttribute : Attribute +``` + +## Public Members + +| name | description | +| --- | --- | +| [RewritingSignatureAttribute](RewritingSignatureAttribute/RewritingSignatureAttribute.md)(…) | Initializes a new instance of the [`RewritingSignatureAttribute`](RewritingSignatureAttribute.md) class. | +| readonly [Signature](RewritingSignatureAttribute/Signature.md) | Signature identifying parameters used during rewriting. | +| readonly [Version](RewritingSignatureAttribute/Version.md) | The version of Coyote used for the rewriting. | + +## Remarks + +If this attribute is applied to an assembly manifest, it denotes that the assembly has been rewritten. + +## See Also + +* namespace [Microsoft.Coyote.Rewriting](../Microsoft.Coyote.RewritingNamespace.md) +* assembly [Microsoft.Coyote.Test](../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.Rewriting/RewritingSignatureAttribute/RewritingSignatureAttribute.md b/docs/ref/Microsoft.Coyote.Rewriting/RewritingSignatureAttribute/RewritingSignatureAttribute.md new file mode 100644 index 000000000..84d2eef8c --- /dev/null +++ b/docs/ref/Microsoft.Coyote.Rewriting/RewritingSignatureAttribute/RewritingSignatureAttribute.md @@ -0,0 +1,15 @@ +# RewritingSignatureAttribute constructor + +Initializes a new instance of the [`RewritingSignatureAttribute`](../RewritingSignatureAttribute.md) class. + +```csharp +public RewritingSignatureAttribute(string version, string signature) +``` + +## See Also + +* class [RewritingSignatureAttribute](../RewritingSignatureAttribute.md) +* namespace [Microsoft.Coyote.Rewriting](../RewritingSignatureAttribute.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.Rewriting/RewritingSignatureAttribute/Signature.md b/docs/ref/Microsoft.Coyote.Rewriting/RewritingSignatureAttribute/Signature.md new file mode 100644 index 000000000..ec341b095 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.Rewriting/RewritingSignatureAttribute/Signature.md @@ -0,0 +1,15 @@ +# RewritingSignatureAttribute.Signature field + +Signature identifying parameters used during rewriting. + +```csharp +public readonly string Signature; +``` + +## See Also + +* class [RewritingSignatureAttribute](../RewritingSignatureAttribute.md) +* namespace [Microsoft.Coyote.Rewriting](../RewritingSignatureAttribute.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.Rewriting/RewritingSignatureAttribute/Version.md b/docs/ref/Microsoft.Coyote.Rewriting/RewritingSignatureAttribute/Version.md new file mode 100644 index 000000000..f91b6fc96 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.Rewriting/RewritingSignatureAttribute/Version.md @@ -0,0 +1,15 @@ +# RewritingSignatureAttribute.Version field + +The version of Coyote used for the rewriting. + +```csharp +public readonly string Version; +``` + +## See Also + +* class [RewritingSignatureAttribute](../RewritingSignatureAttribute.md) +* namespace [Microsoft.Coyote.Rewriting](../RewritingSignatureAttribute.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.RewritingNamespace.md b/docs/ref/Microsoft.Coyote.RewritingNamespace.md new file mode 100644 index 000000000..31ebf74a8 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.RewritingNamespace.md @@ -0,0 +1,8 @@ +## Microsoft.Coyote.Rewriting namespace + +| public type | description | +| --- | --- | +| class [RewritingEngine](Microsoft.Coyote.Rewriting/RewritingEngine.md) | Engine that can rewrite a set of assemblies for systematic testing. | +| class [RewritingSignatureAttribute](Microsoft.Coyote.Rewriting/RewritingSignatureAttribute.md) | Attribute that contains a signature identifying the parameters used during binary rewriting of an assembly. | + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestAttribute.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestAttribute.md new file mode 100644 index 000000000..9fa80fac1 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestAttribute.md @@ -0,0 +1,21 @@ +# TestAttribute class + +Attribute for declaring the entry point to a Coyote test. + +```csharp +[AttributeUsage(AttributeTargets.Method)] +public sealed class TestAttribute : Attribute +``` + +## Public Members + +| name | description | +| --- | --- | +| [TestAttribute](TestAttribute/TestAttribute.md)() | The default constructor. | + +## See Also + +* namespace [Microsoft.Coyote.SystematicTesting](../Microsoft.Coyote.SystematicTestingNamespace.md) +* assembly [Microsoft.Coyote.Test](../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestAttribute/TestAttribute.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestAttribute/TestAttribute.md new file mode 100644 index 000000000..0b9f875d6 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestAttribute/TestAttribute.md @@ -0,0 +1,15 @@ +# TestAttribute constructor + +The default constructor. + +```csharp +public TestAttribute() +``` + +## See Also + +* class [TestAttribute](../TestAttribute.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestAttribute.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestDisposeAttribute.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestDisposeAttribute.md new file mode 100644 index 000000000..6751c0e10 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestDisposeAttribute.md @@ -0,0 +1,21 @@ +# TestDisposeAttribute class + +Attribute for declaring a cleanup method to be called when all test iterations terminate. + +```csharp +[AttributeUsage(AttributeTargets.Method)] +public sealed class TestDisposeAttribute : Attribute +``` + +## Public Members + +| name | description | +| --- | --- | +| [TestDisposeAttribute](TestDisposeAttribute/TestDisposeAttribute.md)() | The default constructor. | + +## See Also + +* namespace [Microsoft.Coyote.SystematicTesting](../Microsoft.Coyote.SystematicTestingNamespace.md) +* assembly [Microsoft.Coyote.Test](../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestDisposeAttribute/TestDisposeAttribute.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestDisposeAttribute/TestDisposeAttribute.md new file mode 100644 index 000000000..4686aa152 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestDisposeAttribute/TestDisposeAttribute.md @@ -0,0 +1,15 @@ +# TestDisposeAttribute constructor + +The default constructor. + +```csharp +public TestDisposeAttribute() +``` + +## See Also + +* class [TestDisposeAttribute](../TestDisposeAttribute.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestDisposeAttribute.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestInitAttribute.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestInitAttribute.md new file mode 100644 index 000000000..5d07d0ff2 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestInitAttribute.md @@ -0,0 +1,21 @@ +# TestInitAttribute class + +Attribute for declaring the initialization method to be called before testing starts. + +```csharp +[AttributeUsage(AttributeTargets.Method)] +public sealed class TestInitAttribute : Attribute +``` + +## Public Members + +| name | description | +| --- | --- | +| [TestInitAttribute](TestInitAttribute/TestInitAttribute.md)() | The default constructor. | + +## See Also + +* namespace [Microsoft.Coyote.SystematicTesting](../Microsoft.Coyote.SystematicTestingNamespace.md) +* assembly [Microsoft.Coyote.Test](../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestInitAttribute/TestInitAttribute.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestInitAttribute/TestInitAttribute.md new file mode 100644 index 000000000..f6ac5b201 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestInitAttribute/TestInitAttribute.md @@ -0,0 +1,15 @@ +# TestInitAttribute constructor + +The default constructor. + +```csharp +public TestInitAttribute() +``` + +## See Also + +* class [TestInitAttribute](../TestInitAttribute.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestInitAttribute.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestIterationDisposeAttribute.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestIterationDisposeAttribute.md new file mode 100644 index 000000000..41bae1da6 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestIterationDisposeAttribute.md @@ -0,0 +1,21 @@ +# TestIterationDisposeAttribute class + +Attribute for declaring a cleanup method to be called when each test iteration terminates. + +```csharp +[AttributeUsage(AttributeTargets.Method)] +public sealed class TestIterationDisposeAttribute : Attribute +``` + +## Public Members + +| name | description | +| --- | --- | +| [TestIterationDisposeAttribute](TestIterationDisposeAttribute/TestIterationDisposeAttribute.md)() | The default constructor. | + +## See Also + +* namespace [Microsoft.Coyote.SystematicTesting](../Microsoft.Coyote.SystematicTestingNamespace.md) +* assembly [Microsoft.Coyote.Test](../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestIterationDisposeAttribute/TestIterationDisposeAttribute.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestIterationDisposeAttribute/TestIterationDisposeAttribute.md new file mode 100644 index 000000000..8d2aa7b00 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestIterationDisposeAttribute/TestIterationDisposeAttribute.md @@ -0,0 +1,15 @@ +# TestIterationDisposeAttribute constructor + +The default constructor. + +```csharp +public TestIterationDisposeAttribute() +``` + +## See Also + +* class [TestIterationDisposeAttribute](../TestIterationDisposeAttribute.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestIterationDisposeAttribute.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport.md new file mode 100644 index 000000000..a0e7b4d08 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport.md @@ -0,0 +1,43 @@ +# TestReport class + +Report containing information from a test run. + +```csharp +public class TestReport +``` + +## Public Members + +| name | description | +| --- | --- | +| [TestReport](TestReport/TestReport.md)(…) | Initializes a new instance of the [`TestReport`](TestReport.md) class. | +| [BugReports](TestReport/BugReports.md) { get; } | Set of bug reports. | +| [Configuration](TestReport/Configuration.md) { get; } | Configuration of the program-under-test. | +| [CoverageInfo](TestReport/CoverageInfo.md) { get; } | Information regarding code coverage. | +| [InternalErrors](TestReport/InternalErrors.md) { get; } | Set of internal errors. If no internal errors occurred, then this set is empty. | +| [MaxConcurrencyDegree](TestReport/MaxConcurrencyDegree.md) { get; } | The max degree of concurrency. | +| [MaxControlledOperations](TestReport/MaxControlledOperations.md) { get; } | The max number of controlled operations. | +| [MaxExploredFairSteps](TestReport/MaxExploredFairSteps.md) { get; } | The max explored scheduling steps in fair tests. | +| [MaxFairStepsHitInFairTests](TestReport/MaxFairStepsHitInFairTests.md) { get; } | Number of times the fair max steps bound was hit in fair tests. | +| [MaxUnfairStepsHitInFairTests](TestReport/MaxUnfairStepsHitInFairTests.md) { get; } | Number of times the unfair max steps bound was hit in fair tests. | +| [MaxUnfairStepsHitInUnfairTests](TestReport/MaxUnfairStepsHitInUnfairTests.md) { get; } | Number of times the unfair max steps bound was hit in unfair tests. | +| [MinConcurrencyDegree](TestReport/MinConcurrencyDegree.md) { get; } | The min degree of concurrency. | +| [MinControlledOperations](TestReport/MinControlledOperations.md) { get; } | The min number of controlled operations. | +| [MinExploredFairSteps](TestReport/MinExploredFairSteps.md) { get; } | The min explored scheduling steps in fair tests. | +| [NumOfExploredFairSchedules](TestReport/NumOfExploredFairSchedules.md) { get; } | Number of explored fair schedules. | +| [NumOfExploredUnfairSchedules](TestReport/NumOfExploredUnfairSchedules.md) { get; } | Number of explored unfair schedules. | +| [NumOfFoundBugs](TestReport/NumOfFoundBugs.md) { get; } | Number of found bugs. | +| [TotalConcurrencyDegree](TestReport/TotalConcurrencyDegree.md) { get; } | The total degree of concurrency (across all testing iterations). | +| [TotalControlledOperations](TestReport/TotalControlledOperations.md) { get; } | The total number of controlled operations. | +| [TotalExploredFairSteps](TestReport/TotalExploredFairSteps.md) { get; } | The total explored scheduling steps (across all testing iterations) in fair tests. | +| [UncontrolledInvocations](TestReport/UncontrolledInvocations.md) { get; } | Set of uncontrolled invocations. | +| [Clone](TestReport/Clone.md)() | Clones the test report. | +| [GetText](TestReport/GetText.md)(…) | Returns the testing report as a string, given a configuration and an optional prefix. | +| [Merge](TestReport/Merge.md)(…) | Merges the information from the specified test report. | + +## See Also + +* namespace [Microsoft.Coyote.SystematicTesting](../Microsoft.Coyote.SystematicTestingNamespace.md) +* assembly [Microsoft.Coyote.Test](../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/BugReports.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/BugReports.md new file mode 100644 index 000000000..cef7b67aa --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/BugReports.md @@ -0,0 +1,15 @@ +# TestReport.BugReports property + +Set of bug reports. + +```csharp +public HashSet BugReports { get; } +``` + +## See Also + +* class [TestReport](../TestReport.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestReport.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/Clone.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/Clone.md new file mode 100644 index 000000000..e75bbc39b --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/Clone.md @@ -0,0 +1,15 @@ +# TestReport.Clone method + +Clones the test report. + +```csharp +public TestReport Clone() +``` + +## See Also + +* class [TestReport](../TestReport.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestReport.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/Configuration.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/Configuration.md new file mode 100644 index 000000000..4a343158f --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/Configuration.md @@ -0,0 +1,15 @@ +# TestReport.Configuration property + +Configuration of the program-under-test. + +```csharp +public Configuration Configuration { get; } +``` + +## See Also + +* class [TestReport](../TestReport.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestReport.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/CoverageInfo.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/CoverageInfo.md new file mode 100644 index 000000000..8cd16837a --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/CoverageInfo.md @@ -0,0 +1,15 @@ +# TestReport.CoverageInfo property + +Information regarding code coverage. + +```csharp +public CoverageInfo CoverageInfo { get; } +``` + +## See Also + +* class [TestReport](../TestReport.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestReport.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/GetText.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/GetText.md new file mode 100644 index 000000000..bd7cfdcb7 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/GetText.md @@ -0,0 +1,15 @@ +# TestReport.GetText method + +Returns the testing report as a string, given a configuration and an optional prefix. + +```csharp +public string GetText(Configuration configuration, string prefix = "") +``` + +## See Also + +* class [TestReport](../TestReport.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestReport.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/InternalErrors.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/InternalErrors.md new file mode 100644 index 000000000..2a4754e2d --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/InternalErrors.md @@ -0,0 +1,15 @@ +# TestReport.InternalErrors property + +Set of internal errors. If no internal errors occurred, then this set is empty. + +```csharp +public HashSet InternalErrors { get; } +``` + +## See Also + +* class [TestReport](../TestReport.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestReport.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxConcurrencyDegree.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxConcurrencyDegree.md new file mode 100644 index 000000000..f312ddbbf --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxConcurrencyDegree.md @@ -0,0 +1,15 @@ +# TestReport.MaxConcurrencyDegree property + +The max degree of concurrency. + +```csharp +public int MaxConcurrencyDegree { get; } +``` + +## See Also + +* class [TestReport](../TestReport.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestReport.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxControlledOperations.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxControlledOperations.md new file mode 100644 index 000000000..9c50a1452 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxControlledOperations.md @@ -0,0 +1,15 @@ +# TestReport.MaxControlledOperations property + +The max number of controlled operations. + +```csharp +public int MaxControlledOperations { get; } +``` + +## See Also + +* class [TestReport](../TestReport.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestReport.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxExploredFairSteps.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxExploredFairSteps.md new file mode 100644 index 000000000..73d699965 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxExploredFairSteps.md @@ -0,0 +1,15 @@ +# TestReport.MaxExploredFairSteps property + +The max explored scheduling steps in fair tests. + +```csharp +public int MaxExploredFairSteps { get; } +``` + +## See Also + +* class [TestReport](../TestReport.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestReport.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxFairStepsHitInFairTests.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxFairStepsHitInFairTests.md new file mode 100644 index 000000000..bbf82a2e6 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxFairStepsHitInFairTests.md @@ -0,0 +1,15 @@ +# TestReport.MaxFairStepsHitInFairTests property + +Number of times the fair max steps bound was hit in fair tests. + +```csharp +public int MaxFairStepsHitInFairTests { get; } +``` + +## See Also + +* class [TestReport](../TestReport.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestReport.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxUnfairStepsHitInFairTests.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxUnfairStepsHitInFairTests.md new file mode 100644 index 000000000..11c2f3fdc --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxUnfairStepsHitInFairTests.md @@ -0,0 +1,15 @@ +# TestReport.MaxUnfairStepsHitInFairTests property + +Number of times the unfair max steps bound was hit in fair tests. + +```csharp +public int MaxUnfairStepsHitInFairTests { get; } +``` + +## See Also + +* class [TestReport](../TestReport.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestReport.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxUnfairStepsHitInUnfairTests.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxUnfairStepsHitInUnfairTests.md new file mode 100644 index 000000000..68141d2e9 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxUnfairStepsHitInUnfairTests.md @@ -0,0 +1,15 @@ +# TestReport.MaxUnfairStepsHitInUnfairTests property + +Number of times the unfair max steps bound was hit in unfair tests. + +```csharp +public int MaxUnfairStepsHitInUnfairTests { get; } +``` + +## See Also + +* class [TestReport](../TestReport.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestReport.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/Merge.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/Merge.md new file mode 100644 index 000000000..ec10a8a47 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/Merge.md @@ -0,0 +1,19 @@ +# TestReport.Merge method + +Merges the information from the specified test report. + +```csharp +public bool Merge(TestReport testReport) +``` + +## Return Value + +True if merged successfully. + +## See Also + +* class [TestReport](../TestReport.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestReport.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MinConcurrencyDegree.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MinConcurrencyDegree.md new file mode 100644 index 000000000..e9a2cd857 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MinConcurrencyDegree.md @@ -0,0 +1,15 @@ +# TestReport.MinConcurrencyDegree property + +The min degree of concurrency. + +```csharp +public int MinConcurrencyDegree { get; } +``` + +## See Also + +* class [TestReport](../TestReport.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestReport.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MinControlledOperations.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MinControlledOperations.md new file mode 100644 index 000000000..576b7e2b9 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MinControlledOperations.md @@ -0,0 +1,15 @@ +# TestReport.MinControlledOperations property + +The min number of controlled operations. + +```csharp +public int MinControlledOperations { get; } +``` + +## See Also + +* class [TestReport](../TestReport.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestReport.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MinExploredFairSteps.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MinExploredFairSteps.md new file mode 100644 index 000000000..974edb771 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/MinExploredFairSteps.md @@ -0,0 +1,15 @@ +# TestReport.MinExploredFairSteps property + +The min explored scheduling steps in fair tests. + +```csharp +public int MinExploredFairSteps { get; } +``` + +## See Also + +* class [TestReport](../TestReport.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestReport.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/NumOfExploredFairSchedules.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/NumOfExploredFairSchedules.md new file mode 100644 index 000000000..39ec90b16 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/NumOfExploredFairSchedules.md @@ -0,0 +1,15 @@ +# TestReport.NumOfExploredFairSchedules property + +Number of explored fair schedules. + +```csharp +public int NumOfExploredFairSchedules { get; } +``` + +## See Also + +* class [TestReport](../TestReport.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestReport.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/NumOfExploredUnfairSchedules.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/NumOfExploredUnfairSchedules.md new file mode 100644 index 000000000..ac5752cc7 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/NumOfExploredUnfairSchedules.md @@ -0,0 +1,15 @@ +# TestReport.NumOfExploredUnfairSchedules property + +Number of explored unfair schedules. + +```csharp +public int NumOfExploredUnfairSchedules { get; } +``` + +## See Also + +* class [TestReport](../TestReport.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestReport.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/NumOfFoundBugs.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/NumOfFoundBugs.md new file mode 100644 index 000000000..420acb5a0 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/NumOfFoundBugs.md @@ -0,0 +1,15 @@ +# TestReport.NumOfFoundBugs property + +Number of found bugs. + +```csharp +public int NumOfFoundBugs { get; } +``` + +## See Also + +* class [TestReport](../TestReport.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestReport.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/TestReport.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/TestReport.md new file mode 100644 index 000000000..ab4973452 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/TestReport.md @@ -0,0 +1,15 @@ +# TestReport constructor + +Initializes a new instance of the [`TestReport`](../TestReport.md) class. + +```csharp +public TestReport(Configuration configuration) +``` + +## See Also + +* class [TestReport](../TestReport.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestReport.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/TotalConcurrencyDegree.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/TotalConcurrencyDegree.md new file mode 100644 index 000000000..cd23a6322 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/TotalConcurrencyDegree.md @@ -0,0 +1,15 @@ +# TestReport.TotalConcurrencyDegree property + +The total degree of concurrency (across all testing iterations). + +```csharp +public int TotalConcurrencyDegree { get; } +``` + +## See Also + +* class [TestReport](../TestReport.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestReport.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/TotalControlledOperations.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/TotalControlledOperations.md new file mode 100644 index 000000000..56757a600 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/TotalControlledOperations.md @@ -0,0 +1,15 @@ +# TestReport.TotalControlledOperations property + +The total number of controlled operations. + +```csharp +public int TotalControlledOperations { get; } +``` + +## See Also + +* class [TestReport](../TestReport.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestReport.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/TotalExploredFairSteps.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/TotalExploredFairSteps.md new file mode 100644 index 000000000..eb534fdf3 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/TotalExploredFairSteps.md @@ -0,0 +1,15 @@ +# TestReport.TotalExploredFairSteps property + +The total explored scheduling steps (across all testing iterations) in fair tests. + +```csharp +public int TotalExploredFairSteps { get; } +``` + +## See Also + +* class [TestReport](../TestReport.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestReport.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/UncontrolledInvocations.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/UncontrolledInvocations.md new file mode 100644 index 000000000..0874385d6 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestReport/UncontrolledInvocations.md @@ -0,0 +1,15 @@ +# TestReport.UncontrolledInvocations property + +Set of uncontrolled invocations. + +```csharp +public HashSet UncontrolledInvocations { get; } +``` + +## See Also + +* class [TestReport](../TestReport.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestReport.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine.md new file mode 100644 index 000000000..c3ada826f --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine.md @@ -0,0 +1,32 @@ +# TestingEngine class + +Testing engine that can run a controlled concurrency test using a specified configuration. + +```csharp +public sealed class TestingEngine +``` + +## Public Members + +| name | description | +| --- | --- | +| static [Create](TestingEngine/Create.md)(…) | Creates a new systematic testing engine. (7 methods) | +| [Logger](TestingEngine/Logger.md) { get; set; } | Get or set the ILogger used to log messages during testing. | +| [ReadableTrace](TestingEngine/ReadableTrace.md) { get; } | The readable trace, if any. | +| [ReproducibleTrace](TestingEngine/ReproducibleTrace.md) { get; } | The reproducable trace, if any. | +| [TestReport](TestingEngine/TestReport.md) { get; set; } | Data structure containing information gathered during testing. | +| [GetReport](TestingEngine/GetReport.md)() | Returns a report with the testing results. | +| [IsTestRewritten](TestingEngine/IsTestRewritten.md)() | Checks if the test executed by the testing engine has been rewritten with the current version. | +| [RegisterPerIterationCallBack](TestingEngine/RegisterPerIterationCallBack.md)(…) | Registers a callback to invoke at the end of each iteration. The callback takes as a parameter an integer representing the current iteration. | +| [Run](TestingEngine/Run.md)() | Runs the testing engine. | +| [Stop](TestingEngine/Stop.md)() | Stops the testing engine. | +| [ThrowIfBugFound](TestingEngine/ThrowIfBugFound.md)() | Throws either an AssertionFailureException, if a bug was found, or an unhandled Exception, if one was thrown. | +| [TryEmitCoverageReports](TestingEngine/TryEmitCoverageReports.md)(…) | Tries to emit the available coverage reports to the specified directory with the given file name, and returns the paths of all emitted coverage reports. | +| [TryEmitReports](TestingEngine/TryEmitReports.md)(…) | Tries to emit the available reports to the specified directory with the given file name, and returns the paths of all emitted reports. | + +## See Also + +* namespace [Microsoft.Coyote.SystematicTesting](../Microsoft.Coyote.SystematicTestingNamespace.md) +* assembly [Microsoft.Coyote.Test](../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/Create.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/Create.md new file mode 100644 index 000000000..0d0dbeb0d --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/Create.md @@ -0,0 +1,111 @@ +# TestingEngine.Create method (1 of 7) + +Creates a new systematic testing engine. + +```csharp +public static TestingEngine Create(Configuration configuration) +``` + +## See Also + +* class [TestingEngine](../TestingEngine.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestingEngine.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + +--- + +# TestingEngine.Create method (2 of 7) + +Creates a new systematic testing engine. + +```csharp +public static TestingEngine Create(Configuration configuration, Action test) +``` + +## See Also + +* class [TestingEngine](../TestingEngine.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestingEngine.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + +--- + +# TestingEngine.Create method (3 of 7) + +Creates a new systematic testing engine. + +```csharp +public static TestingEngine Create(Configuration configuration, Action test) +``` + +## See Also + +* class [TestingEngine](../TestingEngine.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestingEngine.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + +--- + +# TestingEngine.Create method (4 of 7) + +Creates a new systematic testing engine. + +```csharp +public static TestingEngine Create(Configuration configuration, Action test) +``` + +## See Also + +* class [TestingEngine](../TestingEngine.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestingEngine.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + +--- + +# TestingEngine.Create method (5 of 7) + +Creates a new systematic testing engine. + +```csharp +public static TestingEngine Create(Configuration configuration, Func test) +``` + +## See Also + +* class [TestingEngine](../TestingEngine.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestingEngine.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + +--- + +# TestingEngine.Create method (6 of 7) + +Creates a new systematic testing engine. + +```csharp +public static TestingEngine Create(Configuration configuration, Func test) +``` + +## See Also + +* class [TestingEngine](../TestingEngine.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestingEngine.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + +--- + +# TestingEngine.Create method (7 of 7) + +Creates a new systematic testing engine. + +```csharp +public static TestingEngine Create(Configuration configuration, Func test) +``` + +## See Also + +* class [TestingEngine](../TestingEngine.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestingEngine.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/GetReport.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/GetReport.md new file mode 100644 index 000000000..4b9536643 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/GetReport.md @@ -0,0 +1,15 @@ +# TestingEngine.GetReport method + +Returns a report with the testing results. + +```csharp +public string GetReport() +``` + +## See Also + +* class [TestingEngine](../TestingEngine.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestingEngine.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/IsTestRewritten.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/IsTestRewritten.md new file mode 100644 index 000000000..ac8abdd63 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/IsTestRewritten.md @@ -0,0 +1,19 @@ +# TestingEngine.IsTestRewritten method + +Checks if the test executed by the testing engine has been rewritten with the current version. + +```csharp +public bool IsTestRewritten() +``` + +## Return Value + +True if the test has been rewritten, else false. + +## See Also + +* class [TestingEngine](../TestingEngine.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestingEngine.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/Logger.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/Logger.md new file mode 100644 index 000000000..6cdbfb39b --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/Logger.md @@ -0,0 +1,19 @@ +# TestingEngine.Logger property + +Get or set the ILogger used to log messages during testing. + +```csharp +public ILogger Logger { get; set; } +``` + +## Remarks + +See [Logging](/coyote/concepts/actors/logging) for more information. + +## See Also + +* class [TestingEngine](../TestingEngine.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestingEngine.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/ReadableTrace.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/ReadableTrace.md new file mode 100644 index 000000000..158b227ba --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/ReadableTrace.md @@ -0,0 +1,15 @@ +# TestingEngine.ReadableTrace property + +The readable trace, if any. + +```csharp +public string ReadableTrace { get; } +``` + +## See Also + +* class [TestingEngine](../TestingEngine.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestingEngine.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/RegisterPerIterationCallBack.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/RegisterPerIterationCallBack.md new file mode 100644 index 000000000..823919812 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/RegisterPerIterationCallBack.md @@ -0,0 +1,15 @@ +# TestingEngine.RegisterPerIterationCallBack method + +Registers a callback to invoke at the end of each iteration. The callback takes as a parameter an integer representing the current iteration. + +```csharp +public void RegisterPerIterationCallBack(Action callback) +``` + +## See Also + +* class [TestingEngine](../TestingEngine.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestingEngine.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/ReproducibleTrace.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/ReproducibleTrace.md new file mode 100644 index 000000000..a295626d3 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/ReproducibleTrace.md @@ -0,0 +1,15 @@ +# TestingEngine.ReproducibleTrace property + +The reproducable trace, if any. + +```csharp +public string ReproducibleTrace { get; } +``` + +## See Also + +* class [TestingEngine](../TestingEngine.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestingEngine.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/Run.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/Run.md new file mode 100644 index 000000000..e3ecb567d --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/Run.md @@ -0,0 +1,15 @@ +# TestingEngine.Run method + +Runs the testing engine. + +```csharp +public void Run() +``` + +## See Also + +* class [TestingEngine](../TestingEngine.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestingEngine.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/Stop.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/Stop.md new file mode 100644 index 000000000..b3d8e7012 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/Stop.md @@ -0,0 +1,15 @@ +# TestingEngine.Stop method + +Stops the testing engine. + +```csharp +public void Stop() +``` + +## See Also + +* class [TestingEngine](../TestingEngine.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestingEngine.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/TestReport.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/TestReport.md new file mode 100644 index 000000000..0b894a99d --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/TestReport.md @@ -0,0 +1,16 @@ +# TestingEngine.TestReport property + +Data structure containing information gathered during testing. + +```csharp +public TestReport TestReport { get; set; } +``` + +## See Also + +* class [TestReport](../TestReport.md) +* class [TestingEngine](../TestingEngine.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestingEngine.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/ThrowIfBugFound.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/ThrowIfBugFound.md new file mode 100644 index 000000000..59a9b2771 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/ThrowIfBugFound.md @@ -0,0 +1,15 @@ +# TestingEngine.ThrowIfBugFound method + +Throws either an AssertionFailureException, if a bug was found, or an unhandled Exception, if one was thrown. + +```csharp +public void ThrowIfBugFound() +``` + +## See Also + +* class [TestingEngine](../TestingEngine.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestingEngine.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/TryEmitCoverageReports.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/TryEmitCoverageReports.md new file mode 100644 index 000000000..bd527b6ac --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/TryEmitCoverageReports.md @@ -0,0 +1,16 @@ +# TestingEngine.TryEmitCoverageReports method + +Tries to emit the available coverage reports to the specified directory with the given file name, and returns the paths of all emitted coverage reports. + +```csharp +public bool TryEmitCoverageReports(string directory, string fileName, + out IEnumerable reportPaths) +``` + +## See Also + +* class [TestingEngine](../TestingEngine.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestingEngine.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/TryEmitReports.md b/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/TryEmitReports.md new file mode 100644 index 000000000..bfc706e1d --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTesting/TestingEngine/TryEmitReports.md @@ -0,0 +1,15 @@ +# TestingEngine.TryEmitReports method + +Tries to emit the available reports to the specified directory with the given file name, and returns the paths of all emitted reports. + +```csharp +public bool TryEmitReports(string directory, string fileName, out IEnumerable reportPaths) +``` + +## See Also + +* class [TestingEngine](../TestingEngine.md) +* namespace [Microsoft.Coyote.SystematicTesting](../TestingEngine.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.SystematicTestingNamespace.md b/docs/ref/Microsoft.Coyote.SystematicTestingNamespace.md new file mode 100644 index 000000000..85895b7f5 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.SystematicTestingNamespace.md @@ -0,0 +1,12 @@ +## Microsoft.Coyote.SystematicTesting namespace + +| public type | description | +| --- | --- | +| class [TestAttribute](Microsoft.Coyote.SystematicTesting/TestAttribute.md) | Attribute for declaring the entry point to a Coyote test. | +| class [TestDisposeAttribute](Microsoft.Coyote.SystematicTesting/TestDisposeAttribute.md) | Attribute for declaring a cleanup method to be called when all test iterations terminate. | +| class [TestingEngine](Microsoft.Coyote.SystematicTesting/TestingEngine.md) | Testing engine that can run a controlled concurrency test using a specified configuration. | +| class [TestInitAttribute](Microsoft.Coyote.SystematicTesting/TestInitAttribute.md) | Attribute for declaring the initialization method to be called before testing starts. | +| class [TestIterationDisposeAttribute](Microsoft.Coyote.SystematicTesting/TestIterationDisposeAttribute.md) | Attribute for declaring a cleanup method to be called when each test iteration terminates. | +| class [TestReport](Microsoft.Coyote.SystematicTesting/TestReport.md) | Report containing information from a test run. | + + diff --git a/docs/ref/Microsoft.Coyote.Test.md b/docs/ref/Microsoft.Coyote.Test.md new file mode 100644 index 000000000..b959f9656 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.Test.md @@ -0,0 +1,27 @@ +# Microsoft.Coyote.Test assembly + +## Microsoft.Coyote.Rewriting namespace + +| public type | description | +| --- | --- | +| class [RewritingEngine](Microsoft.Coyote.Rewriting/RewritingEngine.md) | Engine that can rewrite a set of assemblies for systematic testing. | +| class [RewritingSignatureAttribute](Microsoft.Coyote.Rewriting/RewritingSignatureAttribute.md) | Attribute that contains a signature identifying the parameters used during binary rewriting of an assembly. | + +## Microsoft.Coyote.SystematicTesting namespace + +| public type | description | +| --- | --- | +| class [TestAttribute](Microsoft.Coyote.SystematicTesting/TestAttribute.md) | Attribute for declaring the entry point to a Coyote test. | +| class [TestDisposeAttribute](Microsoft.Coyote.SystematicTesting/TestDisposeAttribute.md) | Attribute for declaring a cleanup method to be called when all test iterations terminate. | +| class [TestingEngine](Microsoft.Coyote.SystematicTesting/TestingEngine.md) | Testing engine that can run a controlled concurrency test using a specified configuration. | +| class [TestInitAttribute](Microsoft.Coyote.SystematicTesting/TestInitAttribute.md) | Attribute for declaring the initialization method to be called before testing starts. | +| class [TestIterationDisposeAttribute](Microsoft.Coyote.SystematicTesting/TestIterationDisposeAttribute.md) | Attribute for declaring a cleanup method to be called when each test iteration terminates. | +| class [TestReport](Microsoft.Coyote.SystematicTesting/TestReport.md) | Report containing information from a test run. | + +## Microsoft.Coyote.Web namespace + +| public type | description | +| --- | --- | +| static class [RequestControllerMiddlewareExtensions](Microsoft.Coyote.Web/RequestControllerMiddlewareExtensions.md) | Middleware for controlling an ASP.NET web application during testing. | + + diff --git a/docs/ref/Microsoft.Coyote.Web/RequestControllerMiddlewareExtensions.md b/docs/ref/Microsoft.Coyote.Web/RequestControllerMiddlewareExtensions.md new file mode 100644 index 000000000..fab5d21bb --- /dev/null +++ b/docs/ref/Microsoft.Coyote.Web/RequestControllerMiddlewareExtensions.md @@ -0,0 +1,20 @@ +# RequestControllerMiddlewareExtensions class + +Middleware for controlling an ASP.NET web application during testing. + +```csharp +public static class RequestControllerMiddlewareExtensions +``` + +## Public Members + +| name | description | +| --- | --- | +| static [UseRequestController](RequestControllerMiddlewareExtensions/UseRequestController.md)(…) | Adds the request controller middleware to the specified builder. | + +## See Also + +* namespace [Microsoft.Coyote.Web](../Microsoft.Coyote.WebNamespace.md) +* assembly [Microsoft.Coyote.Test](../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.Web/RequestControllerMiddlewareExtensions/UseRequestController.md b/docs/ref/Microsoft.Coyote.Web/RequestControllerMiddlewareExtensions/UseRequestController.md new file mode 100644 index 000000000..43c2fcd05 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.Web/RequestControllerMiddlewareExtensions/UseRequestController.md @@ -0,0 +1,19 @@ +# RequestControllerMiddlewareExtensions.UseRequestController method + +Adds the request controller middleware to the specified builder. + +```csharp +public static IApplicationBuilder UseRequestController(this IApplicationBuilder builder) +``` + +## Remarks + +This middleware should be added in the beginning of an ASP.NET middleware pipeline that should be controlled by Coyote during testing. + +## See Also + +* class [RequestControllerMiddlewareExtensions](../RequestControllerMiddlewareExtensions.md) +* namespace [Microsoft.Coyote.Web](../RequestControllerMiddlewareExtensions.md) +* assembly [Microsoft.Coyote.Test](../../Microsoft.Coyote.Test.md) + + diff --git a/docs/ref/Microsoft.Coyote.WebNamespace.md b/docs/ref/Microsoft.Coyote.WebNamespace.md new file mode 100644 index 000000000..b1724f974 --- /dev/null +++ b/docs/ref/Microsoft.Coyote.WebNamespace.md @@ -0,0 +1,7 @@ +## Microsoft.Coyote.Web namespace + +| public type | description | +| --- | --- | +| static class [RequestControllerMiddlewareExtensions](Microsoft.Coyote.Web/RequestControllerMiddlewareExtensions.md) | Middleware for controlling an ASP.NET web application during testing. | + + diff --git a/docs/ref/Microsoft.Coyote.md b/docs/ref/Microsoft.Coyote.md index 7fccda9cd..36888e631 100644 --- a/docs/ref/Microsoft.Coyote.md +++ b/docs/ref/Microsoft.Coyote.md @@ -4,7 +4,7 @@ | public type | description | | --- | --- | -| class [Configuration](Microsoft.Coyote/Configuration.md) | The Coyote project configurations. | +| class [Configuration](Microsoft.Coyote/Configuration.md) | The Coyote runtime and testing configuration. | | abstract class [Event](Microsoft.Coyote/Event.md) | Abstract class representing an event. | ## Microsoft.Coyote.Actors namespace @@ -33,7 +33,6 @@ | public type | description | | --- | --- | -| class [ActorRuntimeLogGraphBuilder](Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder.md) | Implements the [`IActorRuntimeLog`](Microsoft.Coyote.Actors/IActorRuntimeLog.md) and builds a directed graph from the recorded events and state transitions. | | class [CoverageInfo](Microsoft.Coyote.Actors.Coverage/CoverageInfo.md) | Class for storing actor coverage-specific data across multiple testing iterations. | | class [EventCoverage](Microsoft.Coyote.Actors.Coverage/EventCoverage.md) | This class maintains information about events received and sent from each state of each actor. | | class [Graph](Microsoft.Coyote.Actors.Coverage/Graph.md) | A directed graph made up of Nodes and Links. | diff --git a/docs/ref/Microsoft.Coyote/Configuration.md b/docs/ref/Microsoft.Coyote/Configuration.md index 0f782ec23..691fcb97b 100644 --- a/docs/ref/Microsoft.Coyote/Configuration.md +++ b/docs/ref/Microsoft.Coyote/Configuration.md @@ -1,6 +1,6 @@ # Configuration class -The Coyote project configurations. +The Coyote runtime and testing configuration. ```csharp public class Configuration @@ -22,7 +22,6 @@ public class Configuration | [TimeoutDelay](Configuration/TimeoutDelay.md) { get; } | Value that controls the probability of triggering a timeout each time an operation gets delayed or a built-in timer gets scheduled during systematic testing. Decrease the value to increase the frequency of timeouts (e.g. a value of 1 corresponds to a 50% probability), or increase the value to decrease the frequency (e.g. a value of 10 corresponds to a 10% probability). | | [WithActivityCoverageReported](Configuration/WithActivityCoverageReported.md)(…) | Updates the configuration to enable or disable reporting activity coverage. | | [WithDeadlockTimeout](Configuration/WithDeadlockTimeout.md)(…) | Updates the value that controls how much time the deadlock monitor should wait during concurrency testing before reporting a potential deadlock. | -| [WithDgmlGraphEnabled](Configuration/WithDgmlGraphEnabled.md)(…) | Updates the configuration with DGML graph generation enabled or disabled. | | [WithIncrementalSeedGenerationEnabled](Configuration/WithIncrementalSeedGenerationEnabled.md)(…) | Updates the configuration with incremental seed generation enabled or disabled. | | [WithLivenessTemperatureThreshold](Configuration/WithLivenessTemperatureThreshold.md)(…) | Updates the configuration with the specified liveness temperature threshold during systematic testing. If this value is 0 it disables liveness checking. It is not recommended to explicitly set this value, instead use the default value which is assigned to [`MaxFairSchedulingSteps`](Configuration/MaxFairSchedulingSteps.md) / 2. | | [WithMaxSchedulingSteps](Configuration/WithMaxSchedulingSteps.md)(…) | Updates the configuration with the specified number of maximum scheduling steps to explore per iteration during systematic testing. The [`MaxUnfairSchedulingSteps`](Configuration/MaxUnfairSchedulingSteps.md) is assigned the *maxSteps* value, whereas the [`MaxFairSchedulingSteps`](Configuration/MaxFairSchedulingSteps.md) is assigned a value using the default heuristic, which is 10 * *maxSteps*. (2 methods) | @@ -42,6 +41,7 @@ public class Configuration | [WithTestingIterations](Configuration/WithTestingIterations.md)(…) | Updates the configuration with the specified number of iterations to run during systematic testing. | | [WithTestingTimeout](Configuration/WithTestingTimeout.md)(…) | Updates the configuration with the specified systematic testing timeout in seconds. | | [WithTimeoutDelay](Configuration/WithTimeoutDelay.md)(…) | Updates the value that controls the probability of triggering a timeout each time an operation gets delayed or a built-in timer gets scheduled during systematic testing. | +| [WithTraceVisualizationEnabled](Configuration/WithTraceVisualizationEnabled.md)(…) | Updates the configuration with trace visualization enabled or disabled. If enabled, the testing engine can produce a DGML graph representing an execution leading up to a bug. | | [WithUncontrolledConcurrencyResolutionTimeout](Configuration/WithUncontrolledConcurrencyResolutionTimeout.md)(…) | Updates the value that controls how much time the runtime should wait for uncontrolled concurrency to resolve before continuing exploration. | | [WithVerbosityEnabled](Configuration/WithVerbosityEnabled.md)(…) | Updates the configuration with verbose output enabled or disabled. | | [WithXmlLogEnabled](Configuration/WithXmlLogEnabled.md)(…) | Updates the configuration with XML log generation enabled or disabled. | diff --git a/docs/ref/Microsoft.Coyote/Configuration/WithDgmlGraphEnabled.md b/docs/ref/Microsoft.Coyote/Configuration/WithDgmlGraphEnabled.md deleted file mode 100644 index 6397a12a5..000000000 --- a/docs/ref/Microsoft.Coyote/Configuration/WithDgmlGraphEnabled.md +++ /dev/null @@ -1,19 +0,0 @@ -# Configuration.WithDgmlGraphEnabled method - -Updates the configuration with DGML graph generation enabled or disabled. - -```csharp -public Configuration WithDgmlGraphEnabled(bool isEnabled = true) -``` - -| parameter | description | -| --- | --- | -| isEnabled | If true, then enables DGML graph generation. | - -## See Also - -* class [Configuration](../Configuration.md) -* namespace [Microsoft.Coyote](../Configuration.md) -* assembly [Microsoft.Coyote](../../Microsoft.Coyote.md) - - diff --git a/docs/ref/Microsoft.Coyote/Configuration/WithTraceVisualizationEnabled.md b/docs/ref/Microsoft.Coyote/Configuration/WithTraceVisualizationEnabled.md new file mode 100644 index 000000000..aedb83e8e --- /dev/null +++ b/docs/ref/Microsoft.Coyote/Configuration/WithTraceVisualizationEnabled.md @@ -0,0 +1,19 @@ +# Configuration.WithTraceVisualizationEnabled method + +Updates the configuration with trace visualization enabled or disabled. If enabled, the testing engine can produce a DGML graph representing an execution leading up to a bug. + +```csharp +public Configuration WithTraceVisualizationEnabled(bool isEnabled = true) +``` + +| parameter | description | +| --- | --- | +| isEnabled | If true, then enables trace visualization. | + +## See Also + +* class [Configuration](../Configuration.md) +* namespace [Microsoft.Coyote](../Configuration.md) +* assembly [Microsoft.Coyote](../../Microsoft.Coyote.md) + + diff --git a/docs/ref/Microsoft.CoyoteNamespace.md b/docs/ref/Microsoft.CoyoteNamespace.md index 43fbc37df..caeb48e50 100644 --- a/docs/ref/Microsoft.CoyoteNamespace.md +++ b/docs/ref/Microsoft.CoyoteNamespace.md @@ -2,7 +2,7 @@ | public type | description | | --- | --- | -| class [Configuration](Microsoft.Coyote/Configuration.md) | The Coyote project configurations. | +| class [Configuration](Microsoft.Coyote/Configuration.md) | The Coyote runtime and testing configuration. | | abstract class [Event](Microsoft.Coyote/Event.md) | Abstract class representing an event. | diff --git a/docs/ref/toc.yml b/docs/ref/toc.yml index 6a976a973..51c012b3a 100644 --- a/docs/ref/toc.yml +++ b/docs/ref/toc.yml @@ -59,8 +59,8 @@ toc: link: ref/Microsoft.Coyote/Configuration/WithVerbosityEnabled - name: WithActivityCoverageReported link: ref/Microsoft.Coyote/Configuration/WithActivityCoverageReported - - name: WithDgmlGraphEnabled - link: ref/Microsoft.Coyote/Configuration/WithDgmlGraphEnabled + - name: WithTraceVisualizationEnabled + link: ref/Microsoft.Coyote/Configuration/WithTraceVisualizationEnabled - name: WithXmlLogEnabled link: ref/Microsoft.Coyote/Configuration/WithXmlLogEnabled - name: WithTelemetryEnabled @@ -495,81 +495,6 @@ toc: link: ref/Microsoft.Coyote.Actors.Coverage/EventCoverage/GetEventsSent - name: EventCoverage link: ref/Microsoft.Coyote.Actors.Coverage/EventCoverage/EventCoverage - - name: ActorRuntimeLogGraphBuilder - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder - subfolderitems: - - name: OnCreateActor - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnCreateActor - - name: OnCreateStateMachine - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnCreateStateMachine - - name: OnSendEvent - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnSendEvent - - name: OnRaiseEvent - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnRaiseEvent - - name: OnHandleRaisedEvent - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnHandleRaisedEvent - - name: OnEnqueueEvent - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnEnqueueEvent - - name: OnDequeueEvent - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnDequeueEvent - - name: OnReceiveEvent - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnReceiveEvent - - name: OnWaitEvent - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnWaitEvent - - name: OnStateTransition - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnStateTransition - - name: OnExecuteAction - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnExecuteAction - - name: OnGotoState - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnGotoState - - name: OnPushState - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnPushState - - name: OnPopState - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnPopState - - name: OnHalt - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnHalt - - name: OnDefaultEventHandler - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnDefaultEventHandler - - name: OnEventHandlerTerminated - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnEventHandlerTerminated - - name: OnPopStateUnhandledEvent - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnPopStateUnhandledEvent - - name: OnExceptionThrown - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnExceptionThrown - - name: OnExceptionHandled - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnExceptionHandled - - name: OnCreateTimer - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnCreateTimer - - name: OnStopTimer - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnStopTimer - - name: OnCreateMonitor - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnCreateMonitor - - name: OnMonitorExecuteAction - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnMonitorExecuteAction - - name: OnMonitorProcessEvent - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnMonitorProcessEvent - - name: OnMonitorRaiseEvent - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnMonitorRaiseEvent - - name: OnMonitorStateTransition - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnMonitorStateTransition - - name: OnMonitorError - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnMonitorError - - name: OnRandom - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnRandom - - name: OnAssertionFailure - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnAssertionFailure - - name: OnCompleted - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnCompleted - - name: SnapshotGraph - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/SnapshotGraph - - name: ActorRuntimeLogGraphBuilder - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/ActorRuntimeLogGraphBuilder - - name: CollapseMachineInstances - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/CollapseMachineInstances - - name: Logger - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/Logger - - name: Graph - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/Graph - name: Graph link: ref/Microsoft.Coyote.Actors.Coverage/Graph subfolderitems: @@ -949,953 +874,134 @@ toc: subfolderitems: - name: HotAttribute link: ref/Microsoft.Coyote.Specifications/Monitor.State.HotAttribute/HotAttribute - - name: Microsoft.Coyote - link: ref/Microsoft.Coyote + - name: Microsoft.Coyote.Test + link: ref/Microsoft.Coyote.Test subfolderitems: - - name: Microsoft.Coyote - link: ref/Microsoft.CoyoteNamespace + - name: Microsoft.Coyote.Rewriting + link: ref/Microsoft.Coyote.RewritingNamespace subfolderitems: - - name: Event - link: ref/Microsoft.Coyote/Event - subfolderitems: - - name: Event - link: ref/Microsoft.Coyote/Event/Event - - name: Configuration - link: ref/Microsoft.Coyote/Configuration + - name: RewritingSignatureAttribute + link: ref/Microsoft.Coyote.Rewriting/RewritingSignatureAttribute + subfolderitems: + - name: RewritingSignatureAttribute + link: ref/Microsoft.Coyote.Rewriting/RewritingSignatureAttribute/RewritingSignatureAttribute + - name: Version + link: ref/Microsoft.Coyote.Rewriting/RewritingSignatureAttribute/Version + - name: Signature + link: ref/Microsoft.Coyote.Rewriting/RewritingSignatureAttribute/Signature + - name: RewritingEngine + link: ref/Microsoft.Coyote.Rewriting/RewritingEngine + subfolderitems: + - name: IsAssemblyRewritten + link: ref/Microsoft.Coyote.Rewriting/RewritingEngine/IsAssemblyRewritten + - name: Microsoft.Coyote.SystematicTesting + link: ref/Microsoft.Coyote.SystematicTestingNamespace + subfolderitems: + - name: TestReport + link: ref/Microsoft.Coyote.SystematicTesting/TestReport subfolderitems: - - name: Create - link: ref/Microsoft.Coyote/Configuration/Create - - name: WithRandomStrategy - link: ref/Microsoft.Coyote/Configuration/WithRandomStrategy - - name: WithProbabilisticStrategy - link: ref/Microsoft.Coyote/Configuration/WithProbabilisticStrategy - - name: WithPrioritizationStrategy - link: ref/Microsoft.Coyote/Configuration/WithPrioritizationStrategy - - name: WithRLStrategy - link: ref/Microsoft.Coyote/Configuration/WithRLStrategy - - name: WithReplayStrategy - link: ref/Microsoft.Coyote/Configuration/WithReplayStrategy - - name: WithTestingIterations - link: ref/Microsoft.Coyote/Configuration/WithTestingIterations - - name: WithTestingTimeout - link: ref/Microsoft.Coyote/Configuration/WithTestingTimeout - - name: WithPartiallyControlledConcurrencyAllowed - link: ref/Microsoft.Coyote/Configuration/WithPartiallyControlledConcurrencyAllowed - - name: WithSystematicFuzzingEnabled - link: ref/Microsoft.Coyote/Configuration/WithSystematicFuzzingEnabled - - name: WithSystematicFuzzingFallbackEnabled - link: ref/Microsoft.Coyote/Configuration/WithSystematicFuzzingFallbackEnabled - - name: WithSharedStateReductionEnabled - link: ref/Microsoft.Coyote/Configuration/WithSharedStateReductionEnabled - - name: WithNoBugTraceRepro - link: ref/Microsoft.Coyote/Configuration/WithNoBugTraceRepro - - name: WithMaxSchedulingSteps - link: ref/Microsoft.Coyote/Configuration/WithMaxSchedulingSteps - - name: WithLivenessTemperatureThreshold - link: ref/Microsoft.Coyote/Configuration/WithLivenessTemperatureThreshold - - name: WithTimeoutDelay - link: ref/Microsoft.Coyote/Configuration/WithTimeoutDelay - - name: WithDeadlockTimeout - link: ref/Microsoft.Coyote/Configuration/WithDeadlockTimeout - - name: WithPotentialDeadlocksReportedAsBugs - link: ref/Microsoft.Coyote/Configuration/WithPotentialDeadlocksReportedAsBugs - - name: WithUncontrolledConcurrencyResolutionTimeout - link: ref/Microsoft.Coyote/Configuration/WithUncontrolledConcurrencyResolutionTimeout - - name: WithRandomGeneratorSeed - link: ref/Microsoft.Coyote/Configuration/WithRandomGeneratorSeed - - name: WithIncrementalSeedGenerationEnabled - link: ref/Microsoft.Coyote/Configuration/WithIncrementalSeedGenerationEnabled - - name: WithVerbosityEnabled - link: ref/Microsoft.Coyote/Configuration/WithVerbosityEnabled - - name: WithActivityCoverageReported - link: ref/Microsoft.Coyote/Configuration/WithActivityCoverageReported - - name: WithDgmlGraphEnabled - link: ref/Microsoft.Coyote/Configuration/WithDgmlGraphEnabled - - name: WithXmlLogEnabled - link: ref/Microsoft.Coyote/Configuration/WithXmlLogEnabled - - name: WithTelemetryEnabled - link: ref/Microsoft.Coyote/Configuration/WithTelemetryEnabled + - name: Merge + link: ref/Microsoft.Coyote.SystematicTesting/TestReport/Merge + - name: GetText + link: ref/Microsoft.Coyote.SystematicTesting/TestReport/GetText + - name: Clone + link: ref/Microsoft.Coyote.SystematicTesting/TestReport/Clone + - name: TestReport + link: ref/Microsoft.Coyote.SystematicTesting/TestReport/TestReport - name: Configuration - link: ref/Microsoft.Coyote/Configuration/Configuration - - name: SchedulingStrategy - link: ref/Microsoft.Coyote/Configuration/SchedulingStrategy - - name: TestingIterations - link: ref/Microsoft.Coyote/Configuration/TestingIterations - - name: RandomGeneratorSeed - link: ref/Microsoft.Coyote/Configuration/RandomGeneratorSeed - - name: MaxUnfairSchedulingSteps - link: ref/Microsoft.Coyote/Configuration/MaxUnfairSchedulingSteps - - name: MaxFairSchedulingSteps - link: ref/Microsoft.Coyote/Configuration/MaxFairSchedulingSteps - - name: TimeoutDelay - link: ref/Microsoft.Coyote/Configuration/TimeoutDelay - - name: DeadlockTimeout - link: ref/Microsoft.Coyote/Configuration/DeadlockTimeout - - name: IsVerbose - link: ref/Microsoft.Coyote/Configuration/IsVerbose - - name: LogLevel - link: ref/Microsoft.Coyote/Configuration/LogLevel - - name: Microsoft.Coyote.Actors - link: ref/Microsoft.Coyote.ActorsNamespace - subfolderitems: - - name: Actor - link: ref/Microsoft.Coyote.Actors/Actor + link: ref/Microsoft.Coyote.SystematicTesting/TestReport/Configuration + - name: CoverageInfo + link: ref/Microsoft.Coyote.SystematicTesting/TestReport/CoverageInfo + - name: NumOfExploredFairSchedules + link: ref/Microsoft.Coyote.SystematicTesting/TestReport/NumOfExploredFairSchedules + - name: NumOfExploredUnfairSchedules + link: ref/Microsoft.Coyote.SystematicTesting/TestReport/NumOfExploredUnfairSchedules + - name: NumOfFoundBugs + link: ref/Microsoft.Coyote.SystematicTesting/TestReport/NumOfFoundBugs + - name: BugReports + link: ref/Microsoft.Coyote.SystematicTesting/TestReport/BugReports + - name: UncontrolledInvocations + link: ref/Microsoft.Coyote.SystematicTesting/TestReport/UncontrolledInvocations + - name: MinControlledOperations + link: ref/Microsoft.Coyote.SystematicTesting/TestReport/MinControlledOperations + - name: MaxControlledOperations + link: ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxControlledOperations + - name: TotalControlledOperations + link: ref/Microsoft.Coyote.SystematicTesting/TestReport/TotalControlledOperations + - name: MinConcurrencyDegree + link: ref/Microsoft.Coyote.SystematicTesting/TestReport/MinConcurrencyDegree + - name: MaxConcurrencyDegree + link: ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxConcurrencyDegree + - name: TotalConcurrencyDegree + link: ref/Microsoft.Coyote.SystematicTesting/TestReport/TotalConcurrencyDegree + - name: MinExploredFairSteps + link: ref/Microsoft.Coyote.SystematicTesting/TestReport/MinExploredFairSteps + - name: MaxExploredFairSteps + link: ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxExploredFairSteps + - name: TotalExploredFairSteps + link: ref/Microsoft.Coyote.SystematicTesting/TestReport/TotalExploredFairSteps + - name: MaxFairStepsHitInFairTests + link: ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxFairStepsHitInFairTests + - name: MaxUnfairStepsHitInFairTests + link: ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxUnfairStepsHitInFairTests + - name: MaxUnfairStepsHitInUnfairTests + link: ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxUnfairStepsHitInUnfairTests + - name: InternalErrors + link: ref/Microsoft.Coyote.SystematicTesting/TestReport/InternalErrors + - name: TestAttribute + link: ref/Microsoft.Coyote.SystematicTesting/TestAttribute + subfolderitems: + - name: TestAttribute + link: ref/Microsoft.Coyote.SystematicTesting/TestAttribute/TestAttribute + - name: TestInitAttribute + link: ref/Microsoft.Coyote.SystematicTesting/TestInitAttribute + subfolderitems: + - name: TestInitAttribute + link: ref/Microsoft.Coyote.SystematicTesting/TestInitAttribute/TestInitAttribute + - name: TestDisposeAttribute + link: ref/Microsoft.Coyote.SystematicTesting/TestDisposeAttribute + subfolderitems: + - name: TestDisposeAttribute + link: ref/Microsoft.Coyote.SystematicTesting/TestDisposeAttribute/TestDisposeAttribute + - name: TestIterationDisposeAttribute + link: ref/Microsoft.Coyote.SystematicTesting/TestIterationDisposeAttribute + subfolderitems: + - name: TestIterationDisposeAttribute + link: ref/Microsoft.Coyote.SystematicTesting/TestIterationDisposeAttribute/TestIterationDisposeAttribute + - name: TestingEngine + link: ref/Microsoft.Coyote.SystematicTesting/TestingEngine subfolderitems: - - name: CreateActor - link: ref/Microsoft.Coyote.Actors/Actor/CreateActor - - name: SendEvent - link: ref/Microsoft.Coyote.Actors/Actor/SendEvent - - name: ReceiveEventAsync - link: ref/Microsoft.Coyote.Actors/Actor/ReceiveEventAsync - - name: StartTimer - link: ref/Microsoft.Coyote.Actors/Actor/StartTimer - - name: StartPeriodicTimer - link: ref/Microsoft.Coyote.Actors/Actor/StartPeriodicTimer - - name: StopTimer - link: ref/Microsoft.Coyote.Actors/Actor/StopTimer - - name: RandomBoolean - link: ref/Microsoft.Coyote.Actors/Actor/RandomBoolean - - name: RandomInteger - link: ref/Microsoft.Coyote.Actors/Actor/RandomInteger - - name: Monitor - link: ref/Microsoft.Coyote.Actors/Actor/Monitor - - name: Assert - link: ref/Microsoft.Coyote.Actors/Actor/Assert - - name: RaiseHaltEvent - link: ref/Microsoft.Coyote.Actors/Actor/RaiseHaltEvent - - name: OnInitializeAsync - link: ref/Microsoft.Coyote.Actors/Actor/OnInitializeAsync - - name: OnEventDequeuedAsync - link: ref/Microsoft.Coyote.Actors/Actor/OnEventDequeuedAsync - - name: OnEventIgnored - link: ref/Microsoft.Coyote.Actors/Actor/OnEventIgnored - - name: OnEventDeferred - link: ref/Microsoft.Coyote.Actors/Actor/OnEventDeferred - - name: OnEventHandledAsync - link: ref/Microsoft.Coyote.Actors/Actor/OnEventHandledAsync - - name: OnEventUnhandledAsync - link: ref/Microsoft.Coyote.Actors/Actor/OnEventUnhandledAsync - - name: OnExceptionHandledAsync - link: ref/Microsoft.Coyote.Actors/Actor/OnExceptionHandledAsync - - name: OnHaltAsync - link: ref/Microsoft.Coyote.Actors/Actor/OnHaltAsync - - name: OnException - link: ref/Microsoft.Coyote.Actors/Actor/OnException - - name: Equals - link: ref/Microsoft.Coyote.Actors/Actor/Equals - - name: GetHashCode - link: ref/Microsoft.Coyote.Actors/Actor/GetHashCode - - name: ToString - link: ref/Microsoft.Coyote.Actors/Actor/ToString - - name: Actor - link: ref/Microsoft.Coyote.Actors/Actor/Actor - - name: Id - link: ref/Microsoft.Coyote.Actors/Actor/Id - - name: CurrentEventGroup - link: ref/Microsoft.Coyote.Actors/Actor/CurrentEventGroup + - name: Create + link: ref/Microsoft.Coyote.SystematicTesting/TestingEngine/Create + - name: Run + link: ref/Microsoft.Coyote.SystematicTesting/TestingEngine/Run + - name: Stop + link: ref/Microsoft.Coyote.SystematicTesting/TestingEngine/Stop + - name: GetReport + link: ref/Microsoft.Coyote.SystematicTesting/TestingEngine/GetReport + - name: ThrowIfBugFound + link: ref/Microsoft.Coyote.SystematicTesting/TestingEngine/ThrowIfBugFound + - name: TryEmitReports + link: ref/Microsoft.Coyote.SystematicTesting/TestingEngine/TryEmitReports + - name: TryEmitCoverageReports + link: ref/Microsoft.Coyote.SystematicTesting/TestingEngine/TryEmitCoverageReports + - name: RegisterPerIterationCallBack + link: ref/Microsoft.Coyote.SystematicTesting/TestingEngine/RegisterPerIterationCallBack + - name: IsTestRewritten + link: ref/Microsoft.Coyote.SystematicTesting/TestingEngine/IsTestRewritten + - name: TestReport + link: ref/Microsoft.Coyote.SystematicTesting/TestingEngine/TestReport - name: Logger - link: ref/Microsoft.Coyote.Actors/Actor/Logger - - name: HashedState - link: ref/Microsoft.Coyote.Actors/Actor/HashedState - - name: ActorId - link: ref/Microsoft.Coyote.Actors/ActorId - subfolderitems: - - name: Equals - link: ref/Microsoft.Coyote.Actors/ActorId/Equals - - name: GetHashCode - link: ref/Microsoft.Coyote.Actors/ActorId/GetHashCode - - name: ToString - link: ref/Microsoft.Coyote.Actors/ActorId/ToString - - name: CompareTo - link: ref/Microsoft.Coyote.Actors/ActorId/CompareTo - - name: Runtime - link: ref/Microsoft.Coyote.Actors/ActorId/Runtime - - name: IsNameUsedForHashing - link: ref/Microsoft.Coyote.Actors/ActorId/IsNameUsedForHashing - - name: Value - link: ref/Microsoft.Coyote.Actors/ActorId/Value - - name: NameValue - link: ref/Microsoft.Coyote.Actors/ActorId/NameValue - - name: Type - link: ref/Microsoft.Coyote.Actors/ActorId/Type - - name: Name - link: ref/Microsoft.Coyote.Actors/ActorId/Name - - name: DequeueStatus - link: ref/Microsoft.Coyote.Actors/DequeueStatus - - name: AwaitableEventGroup - link: ref/Microsoft.Coyote.Actors/AwaitableEventGroup-1 - subfolderitems: - - name: SetResult - link: ref/Microsoft.Coyote.Actors/AwaitableEventGroup-1/SetResult - - name: TrySetResult - link: ref/Microsoft.Coyote.Actors/AwaitableEventGroup-1/TrySetResult - - name: SetCancelled - link: ref/Microsoft.Coyote.Actors/AwaitableEventGroup-1/SetCancelled - - name: TrySetCanceled - link: ref/Microsoft.Coyote.Actors/AwaitableEventGroup-1/TrySetCanceled - - name: SetException - link: ref/Microsoft.Coyote.Actors/AwaitableEventGroup-1/SetException - - name: TrySetException - link: ref/Microsoft.Coyote.Actors/AwaitableEventGroup-1/TrySetException - - name: GetAwaiter - link: ref/Microsoft.Coyote.Actors/AwaitableEventGroup-1/GetAwaiter - - name: AwaitableEventGroup - link: ref/Microsoft.Coyote.Actors/AwaitableEventGroup-1/AwaitableEventGroup - - name: Task - link: ref/Microsoft.Coyote.Actors/AwaitableEventGroup-1/Task - - name: IsCompleted - link: ref/Microsoft.Coyote.Actors/AwaitableEventGroup-1/IsCompleted - - name: IsCanceled - link: ref/Microsoft.Coyote.Actors/AwaitableEventGroup-1/IsCanceled - - name: IsFaulted - link: ref/Microsoft.Coyote.Actors/AwaitableEventGroup-1/IsFaulted - - name: DefaultEvent - link: ref/Microsoft.Coyote.Actors/DefaultEvent - subfolderitems: - - name: Instance - link: ref/Microsoft.Coyote.Actors/DefaultEvent/Instance - - name: EventGroup - link: ref/Microsoft.Coyote.Actors/EventGroup - subfolderitems: - - name: EventGroup - link: ref/Microsoft.Coyote.Actors/EventGroup/EventGroup - - name: Id - link: ref/Microsoft.Coyote.Actors/EventGroup/Id - - name: Name - link: ref/Microsoft.Coyote.Actors/EventGroup/Name - - name: Null - link: ref/Microsoft.Coyote.Actors/EventGroup/Null - - name: HaltEvent - link: ref/Microsoft.Coyote.Actors/HaltEvent - subfolderitems: - - name: Instance - link: ref/Microsoft.Coyote.Actors/HaltEvent/Instance - - name: WildCardEvent - link: ref/Microsoft.Coyote.Actors/WildCardEvent + link: ref/Microsoft.Coyote.SystematicTesting/TestingEngine/Logger + - name: ReadableTrace + link: ref/Microsoft.Coyote.SystematicTesting/TestingEngine/ReadableTrace + - name: ReproducibleTrace + link: ref/Microsoft.Coyote.SystematicTesting/TestingEngine/ReproducibleTrace + - name: Microsoft.Coyote.Web + link: ref/Microsoft.Coyote.WebNamespace + subfolderitems: + - name: RequestControllerMiddlewareExtensions + link: ref/Microsoft.Coyote.Web/RequestControllerMiddlewareExtensions subfolderitems: - - name: WildCardEvent - link: ref/Microsoft.Coyote.Actors/WildCardEvent/WildCardEvent - - name: OnEventDroppedHandler - link: ref/Microsoft.Coyote.Actors/OnEventDroppedHandler - - name: OnExceptionOutcome - link: ref/Microsoft.Coyote.Actors/OnExceptionOutcome - - name: UnhandledEventException - link: ref/Microsoft.Coyote.Actors/UnhandledEventException - subfolderitems: - - name: UnhandledEvent - link: ref/Microsoft.Coyote.Actors/UnhandledEventException/UnhandledEvent - - name: CurrentStateName - link: ref/Microsoft.Coyote.Actors/UnhandledEventException/CurrentStateName - - name: IActorRuntime - link: ref/Microsoft.Coyote.Actors/IActorRuntime - subfolderitems: - - name: CreateActorId - link: ref/Microsoft.Coyote.Actors/IActorRuntime/CreateActorId - - name: CreateActorIdFromName - link: ref/Microsoft.Coyote.Actors/IActorRuntime/CreateActorIdFromName - - name: CreateActor - link: ref/Microsoft.Coyote.Actors/IActorRuntime/CreateActor - - name: SendEvent - link: ref/Microsoft.Coyote.Actors/IActorRuntime/SendEvent - - name: GetCurrentEventGroup - link: ref/Microsoft.Coyote.Actors/IActorRuntime/GetCurrentEventGroup - - name: RegisterLog - link: ref/Microsoft.Coyote.Actors/IActorRuntime/RegisterLog - - name: RemoveLog - link: ref/Microsoft.Coyote.Actors/IActorRuntime/RemoveLog - - name: OnEventDropped - link: ref/Microsoft.Coyote.Actors/IActorRuntime/OnEventDropped - - name: ActorRuntimeLogTextFormatter - link: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter - subfolderitems: - - name: OnAssertionFailure - link: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnAssertionFailure - - name: OnCreateActor - link: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnCreateActor - - name: OnCreateStateMachine - link: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnCreateStateMachine - - name: OnCreateMonitor - link: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnCreateMonitor - - name: OnCreateTimer - link: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnCreateTimer - - name: OnDefaultEventHandler - link: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnDefaultEventHandler - - name: OnEventHandlerTerminated - link: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnEventHandlerTerminated - - name: OnDequeueEvent - link: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnDequeueEvent - - name: OnEnqueueEvent - link: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnEnqueueEvent - - name: OnExceptionHandled - link: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnExceptionHandled - - name: OnExceptionThrown - link: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnExceptionThrown - - name: OnExecuteAction - link: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnExecuteAction - - name: OnGotoState - link: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnGotoState - - name: OnHalt - link: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnHalt - - name: OnMonitorExecuteAction - link: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnMonitorExecuteAction - - name: OnMonitorProcessEvent - link: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnMonitorProcessEvent - - name: OnMonitorRaiseEvent - link: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnMonitorRaiseEvent - - name: OnMonitorStateTransition - link: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnMonitorStateTransition - - name: OnMonitorError - link: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnMonitorError - - name: OnPopState - link: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnPopState - - name: OnPopStateUnhandledEvent - link: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnPopStateUnhandledEvent - - name: OnPushState - link: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnPushState - - name: OnRaiseEvent - link: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnRaiseEvent - - name: OnHandleRaisedEvent - link: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnHandleRaisedEvent - - name: OnReceiveEvent - link: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnReceiveEvent - - name: OnSendEvent - link: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnSendEvent - - name: OnStateTransition - link: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnStateTransition - - name: OnStopTimer - link: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnStopTimer - - name: OnWaitEvent - link: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnWaitEvent - - name: OnRandom - link: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnRandom - - name: OnCompleted - link: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnCompleted - - name: ActorRuntimeLogTextFormatter - link: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/ActorRuntimeLogTextFormatter - - name: Logger - link: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/Logger - - name: IActorRuntimeLog - link: ref/Microsoft.Coyote.Actors/IActorRuntimeLog - subfolderitems: - - name: OnCreateActor - link: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnCreateActor - - name: OnCreateStateMachine - link: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnCreateStateMachine - - name: OnExecuteAction - link: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnExecuteAction - - name: OnSendEvent - link: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnSendEvent - - name: OnRaiseEvent - link: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnRaiseEvent - - name: OnHandleRaisedEvent - link: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnHandleRaisedEvent - - name: OnEnqueueEvent - link: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnEnqueueEvent - - name: OnDequeueEvent - link: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnDequeueEvent - - name: OnReceiveEvent - link: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnReceiveEvent - - name: OnWaitEvent - link: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnWaitEvent - - name: OnStateTransition - link: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnStateTransition - - name: OnGotoState - link: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnGotoState - - name: OnPushState - link: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnPushState - - name: OnPopState - link: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnPopState - - name: OnDefaultEventHandler - link: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnDefaultEventHandler - - name: OnEventHandlerTerminated - link: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnEventHandlerTerminated - - name: OnHalt - link: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnHalt - - name: OnPopStateUnhandledEvent - link: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnPopStateUnhandledEvent - - name: OnExceptionThrown - link: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnExceptionThrown - - name: OnExceptionHandled - link: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnExceptionHandled - - name: OnCreateTimer - link: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnCreateTimer - - name: OnStopTimer - link: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnStopTimer - - name: OnCreateMonitor - link: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnCreateMonitor - - name: OnMonitorExecuteAction - link: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnMonitorExecuteAction - - name: OnMonitorProcessEvent - link: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnMonitorProcessEvent - - name: OnMonitorRaiseEvent - link: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnMonitorRaiseEvent - - name: OnMonitorStateTransition - link: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnMonitorStateTransition - - name: OnMonitorError - link: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnMonitorError - - name: OnRandom - link: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnRandom - - name: OnAssertionFailure - link: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnAssertionFailure - - name: OnCompleted - link: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnCompleted - - name: RuntimeFactory - link: ref/Microsoft.Coyote.Actors/RuntimeFactory - subfolderitems: - - name: Create - link: ref/Microsoft.Coyote.Actors/RuntimeFactory/Create - - name: SendOptions - link: ref/Microsoft.Coyote.Actors/SendOptions - subfolderitems: - - name: ToString - link: ref/Microsoft.Coyote.Actors/SendOptions/ToString - - name: SendOptions - link: ref/Microsoft.Coyote.Actors/SendOptions/SendOptions - - name: Default - link: ref/Microsoft.Coyote.Actors/SendOptions/Default - - name: MustHandle - link: ref/Microsoft.Coyote.Actors/SendOptions/MustHandle - - name: Assert - link: ref/Microsoft.Coyote.Actors/SendOptions/Assert - - name: HashedState - link: ref/Microsoft.Coyote.Actors/SendOptions/HashedState - - name: StateMachine - link: ref/Microsoft.Coyote.Actors/StateMachine - subfolderitems: - - name: RaiseEvent - link: ref/Microsoft.Coyote.Actors/StateMachine/RaiseEvent - - name: RaiseGotoStateEvent - link: ref/Microsoft.Coyote.Actors/StateMachine/RaiseGotoStateEvent - - name: RaisePushStateEvent - link: ref/Microsoft.Coyote.Actors/StateMachine/RaisePushStateEvent - - name: RaisePopStateEvent - link: ref/Microsoft.Coyote.Actors/StateMachine/RaisePopStateEvent - - name: RaiseHaltEvent - link: ref/Microsoft.Coyote.Actors/StateMachine/RaiseHaltEvent - - name: OnEventHandledAsync - link: ref/Microsoft.Coyote.Actors/StateMachine/OnEventHandledAsync - - name: StateMachine - link: ref/Microsoft.Coyote.Actors/StateMachine/StateMachine - - name: CurrentState - link: ref/Microsoft.Coyote.Actors/StateMachine/CurrentState - - name: Actor.OnEventDoActionAttribute - link: ref/Microsoft.Coyote.Actors/Actor.OnEventDoActionAttribute - subfolderitems: - - name: OnEventDoActionAttribute - link: ref/Microsoft.Coyote.Actors/Actor.OnEventDoActionAttribute/OnEventDoActionAttribute - - name: StateMachine.State - link: ref/Microsoft.Coyote.Actors/StateMachine.State - subfolderitems: - - name: State - link: ref/Microsoft.Coyote.Actors/StateMachine.State/State - - name: StateMachine.StateGroup - link: ref/Microsoft.Coyote.Actors/StateMachine.StateGroup - subfolderitems: - - name: StateGroup - link: ref/Microsoft.Coyote.Actors/StateMachine.StateGroup/StateGroup - - name: StateMachine.State.StartAttribute - link: ref/Microsoft.Coyote.Actors/StateMachine.State.StartAttribute - subfolderitems: - - name: StartAttribute - link: ref/Microsoft.Coyote.Actors/StateMachine.State.StartAttribute/StartAttribute - - name: StateMachine.State.OnEntryAttribute - link: ref/Microsoft.Coyote.Actors/StateMachine.State.OnEntryAttribute - subfolderitems: - - name: OnEntryAttribute - link: ref/Microsoft.Coyote.Actors/StateMachine.State.OnEntryAttribute/OnEntryAttribute - - name: StateMachine.State.OnExitAttribute - link: ref/Microsoft.Coyote.Actors/StateMachine.State.OnExitAttribute - subfolderitems: - - name: OnExitAttribute - link: ref/Microsoft.Coyote.Actors/StateMachine.State.OnExitAttribute/OnExitAttribute - - name: StateMachine.State.OnEventGotoStateAttribute - link: ref/Microsoft.Coyote.Actors/StateMachine.State.OnEventGotoStateAttribute - subfolderitems: - - name: OnEventGotoStateAttribute - link: ref/Microsoft.Coyote.Actors/StateMachine.State.OnEventGotoStateAttribute/OnEventGotoStateAttribute - - name: StateMachine.State.OnEventPushStateAttribute - link: ref/Microsoft.Coyote.Actors/StateMachine.State.OnEventPushStateAttribute - subfolderitems: - - name: OnEventPushStateAttribute - link: ref/Microsoft.Coyote.Actors/StateMachine.State.OnEventPushStateAttribute/OnEventPushStateAttribute - - name: StateMachine.State.OnEventDoActionAttribute - link: ref/Microsoft.Coyote.Actors/StateMachine.State.OnEventDoActionAttribute - subfolderitems: - - name: OnEventDoActionAttribute - link: ref/Microsoft.Coyote.Actors/StateMachine.State.OnEventDoActionAttribute/OnEventDoActionAttribute - - name: StateMachine.State.DeferEventsAttribute - link: ref/Microsoft.Coyote.Actors/StateMachine.State.DeferEventsAttribute - subfolderitems: - - name: DeferEventsAttribute - link: ref/Microsoft.Coyote.Actors/StateMachine.State.DeferEventsAttribute/DeferEventsAttribute - - name: StateMachine.State.IgnoreEventsAttribute - link: ref/Microsoft.Coyote.Actors/StateMachine.State.IgnoreEventsAttribute - subfolderitems: - - name: IgnoreEventsAttribute - link: ref/Microsoft.Coyote.Actors/StateMachine.State.IgnoreEventsAttribute/IgnoreEventsAttribute - - name: Microsoft.Coyote.Actors.Coverage - link: ref/Microsoft.Coyote.Actors.CoverageNamespace - subfolderitems: - - name: EventCoverage - link: ref/Microsoft.Coyote.Actors.Coverage/EventCoverage - subfolderitems: - - name: GetEventsReceived - link: ref/Microsoft.Coyote.Actors.Coverage/EventCoverage/GetEventsReceived - - name: GetEventsSent - link: ref/Microsoft.Coyote.Actors.Coverage/EventCoverage/GetEventsSent - - name: EventCoverage - link: ref/Microsoft.Coyote.Actors.Coverage/EventCoverage/EventCoverage - - name: ActorRuntimeLogGraphBuilder - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder - subfolderitems: - - name: OnCreateActor - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnCreateActor - - name: OnCreateStateMachine - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnCreateStateMachine - - name: OnSendEvent - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnSendEvent - - name: OnRaiseEvent - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnRaiseEvent - - name: OnHandleRaisedEvent - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnHandleRaisedEvent - - name: OnEnqueueEvent - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnEnqueueEvent - - name: OnDequeueEvent - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnDequeueEvent - - name: OnReceiveEvent - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnReceiveEvent - - name: OnWaitEvent - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnWaitEvent - - name: OnStateTransition - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnStateTransition - - name: OnExecuteAction - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnExecuteAction - - name: OnGotoState - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnGotoState - - name: OnPushState - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnPushState - - name: OnPopState - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnPopState - - name: OnHalt - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnHalt - - name: OnDefaultEventHandler - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnDefaultEventHandler - - name: OnEventHandlerTerminated - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnEventHandlerTerminated - - name: OnPopStateUnhandledEvent - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnPopStateUnhandledEvent - - name: OnExceptionThrown - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnExceptionThrown - - name: OnExceptionHandled - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnExceptionHandled - - name: OnCreateTimer - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnCreateTimer - - name: OnStopTimer - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnStopTimer - - name: OnCreateMonitor - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnCreateMonitor - - name: OnMonitorExecuteAction - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnMonitorExecuteAction - - name: OnMonitorProcessEvent - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnMonitorProcessEvent - - name: OnMonitorRaiseEvent - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnMonitorRaiseEvent - - name: OnMonitorStateTransition - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnMonitorStateTransition - - name: OnMonitorError - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnMonitorError - - name: OnRandom - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnRandom - - name: OnAssertionFailure - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnAssertionFailure - - name: OnCompleted - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnCompleted - - name: SnapshotGraph - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/SnapshotGraph - - name: ActorRuntimeLogGraphBuilder - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/ActorRuntimeLogGraphBuilder - - name: CollapseMachineInstances - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/CollapseMachineInstances - - name: Logger - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/Logger - - name: Graph - link: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/Graph - - name: Graph - link: ref/Microsoft.Coyote.Actors.Coverage/Graph - subfolderitems: - - name: GetNode - link: ref/Microsoft.Coyote.Actors.Coverage/Graph/GetNode - - name: GetOrCreateNode - link: ref/Microsoft.Coyote.Actors.Coverage/Graph/GetOrCreateNode - - name: GetOrCreateLink - link: ref/Microsoft.Coyote.Actors.Coverage/Graph/GetOrCreateLink - - name: ToString - link: ref/Microsoft.Coyote.Actors.Coverage/Graph/ToString - - name: WriteDgml - link: ref/Microsoft.Coyote.Actors.Coverage/Graph/WriteDgml - - name: LoadDgml - link: ref/Microsoft.Coyote.Actors.Coverage/Graph/LoadDgml - - name: Merge - link: ref/Microsoft.Coyote.Actors.Coverage/Graph/Merge - - name: Graph - link: ref/Microsoft.Coyote.Actors.Coverage/Graph/Graph - - name: Nodes - link: ref/Microsoft.Coyote.Actors.Coverage/Graph/Nodes - - name: Links - link: ref/Microsoft.Coyote.Actors.Coverage/Graph/Links - - name: GraphObject - link: ref/Microsoft.Coyote.Actors.Coverage/GraphObject - subfolderitems: - - name: AddAttribute - link: ref/Microsoft.Coyote.Actors.Coverage/GraphObject/AddAttribute - - name: AddListAttribute - link: ref/Microsoft.Coyote.Actors.Coverage/GraphObject/AddListAttribute - - name: GraphObject - link: ref/Microsoft.Coyote.Actors.Coverage/GraphObject/GraphObject - - name: Attributes - link: ref/Microsoft.Coyote.Actors.Coverage/GraphObject/Attributes - - name: AttributeLists - link: ref/Microsoft.Coyote.Actors.Coverage/GraphObject/AttributeLists - - name: GraphNode - link: ref/Microsoft.Coyote.Actors.Coverage/GraphNode - subfolderitems: - - name: AddDgmlProperties - link: ref/Microsoft.Coyote.Actors.Coverage/GraphNode/AddDgmlProperties - - name: GraphNode - link: ref/Microsoft.Coyote.Actors.Coverage/GraphNode/GraphNode - - name: Id - link: ref/Microsoft.Coyote.Actors.Coverage/GraphNode/Id - - name: Label - link: ref/Microsoft.Coyote.Actors.Coverage/GraphNode/Label - - name: Category - link: ref/Microsoft.Coyote.Actors.Coverage/GraphNode/Category - - name: GraphLink - link: ref/Microsoft.Coyote.Actors.Coverage/GraphLink - subfolderitems: - - name: AddDgmlProperties - link: ref/Microsoft.Coyote.Actors.Coverage/GraphLink/AddDgmlProperties - - name: GraphLink - link: ref/Microsoft.Coyote.Actors.Coverage/GraphLink/GraphLink - - name: Label - link: ref/Microsoft.Coyote.Actors.Coverage/GraphLink/Label - - name: Category - link: ref/Microsoft.Coyote.Actors.Coverage/GraphLink/Category - - name: Source - link: ref/Microsoft.Coyote.Actors.Coverage/GraphLink/Source - - name: Target - link: ref/Microsoft.Coyote.Actors.Coverage/GraphLink/Target - - name: Index - link: ref/Microsoft.Coyote.Actors.Coverage/GraphLink/Index - - name: CoverageInfo - link: ref/Microsoft.Coyote.Actors.Coverage/CoverageInfo - subfolderitems: - - name: IsMachineDeclared - link: ref/Microsoft.Coyote.Actors.Coverage/CoverageInfo/IsMachineDeclared - - name: DeclareMachineState - link: ref/Microsoft.Coyote.Actors.Coverage/CoverageInfo/DeclareMachineState - - name: DeclareStateEvent - link: ref/Microsoft.Coyote.Actors.Coverage/CoverageInfo/DeclareStateEvent - - name: Merge - link: ref/Microsoft.Coyote.Actors.Coverage/CoverageInfo/Merge - - name: Load - link: ref/Microsoft.Coyote.Actors.Coverage/CoverageInfo/Load - - name: Save - link: ref/Microsoft.Coyote.Actors.Coverage/CoverageInfo/Save - - name: CoverageInfo - link: ref/Microsoft.Coyote.Actors.Coverage/CoverageInfo/CoverageInfo - - name: Machines - link: ref/Microsoft.Coyote.Actors.Coverage/CoverageInfo/Machines - - name: MachinesToStates - link: ref/Microsoft.Coyote.Actors.Coverage/CoverageInfo/MachinesToStates - - name: RegisteredEvents - link: ref/Microsoft.Coyote.Actors.Coverage/CoverageInfo/RegisteredEvents - - name: CoverageGraph - link: ref/Microsoft.Coyote.Actors.Coverage/CoverageInfo/CoverageGraph - - name: EventInfo - link: ref/Microsoft.Coyote.Actors.Coverage/CoverageInfo/EventInfo - - name: Microsoft.Coyote.Actors.SharedObjects - link: ref/Microsoft.Coyote.Actors.SharedObjectsNamespace - subfolderitems: - - name: SharedCounter - link: ref/Microsoft.Coyote.Actors.SharedObjects/SharedCounter - subfolderitems: - - name: Create - link: ref/Microsoft.Coyote.Actors.SharedObjects/SharedCounter/Create - - name: Increment - link: ref/Microsoft.Coyote.Actors.SharedObjects/SharedCounter/Increment - - name: Decrement - link: ref/Microsoft.Coyote.Actors.SharedObjects/SharedCounter/Decrement - - name: GetValue - link: ref/Microsoft.Coyote.Actors.SharedObjects/SharedCounter/GetValue - - name: Add - link: ref/Microsoft.Coyote.Actors.SharedObjects/SharedCounter/Add - - name: Exchange - link: ref/Microsoft.Coyote.Actors.SharedObjects/SharedCounter/Exchange - - name: CompareExchange - link: ref/Microsoft.Coyote.Actors.SharedObjects/SharedCounter/CompareExchange - - name: SharedDictionary - link: ref/Microsoft.Coyote.Actors.SharedObjects/SharedDictionary - subfolderitems: - - name: Create - link: ref/Microsoft.Coyote.Actors.SharedObjects/SharedDictionary/Create - - name: SharedDictionary - link: ref/Microsoft.Coyote.Actors.SharedObjects/SharedDictionary-2 - subfolderitems: - - name: TryAdd - link: ref/Microsoft.Coyote.Actors.SharedObjects/SharedDictionary-2/TryAdd - - name: TryUpdate - link: ref/Microsoft.Coyote.Actors.SharedObjects/SharedDictionary-2/TryUpdate - - name: TryGetValue - link: ref/Microsoft.Coyote.Actors.SharedObjects/SharedDictionary-2/TryGetValue - - name: TryRemove - link: ref/Microsoft.Coyote.Actors.SharedObjects/SharedDictionary-2/TryRemove - - name: Item - link: ref/Microsoft.Coyote.Actors.SharedObjects/SharedDictionary-2/Item - - name: Count - link: ref/Microsoft.Coyote.Actors.SharedObjects/SharedDictionary-2/Count - - name: SharedRegister - link: ref/Microsoft.Coyote.Actors.SharedObjects/SharedRegister - subfolderitems: - - name: Create - link: ref/Microsoft.Coyote.Actors.SharedObjects/SharedRegister/Create - - name: SharedRegister - link: ref/Microsoft.Coyote.Actors.SharedObjects/SharedRegister-1 - subfolderitems: - - name: Update - link: ref/Microsoft.Coyote.Actors.SharedObjects/SharedRegister-1/Update - - name: GetValue - link: ref/Microsoft.Coyote.Actors.SharedObjects/SharedRegister-1/GetValue - - name: SetValue - link: ref/Microsoft.Coyote.Actors.SharedObjects/SharedRegister-1/SetValue - - name: Microsoft.Coyote.Actors.Timers - link: ref/Microsoft.Coyote.Actors.TimersNamespace - subfolderitems: - - name: TimerElapsedEvent - link: ref/Microsoft.Coyote.Actors.Timers/TimerElapsedEvent - subfolderitems: - - name: TimerElapsedEvent - link: ref/Microsoft.Coyote.Actors.Timers/TimerElapsedEvent/TimerElapsedEvent - - name: Info - link: ref/Microsoft.Coyote.Actors.Timers/TimerElapsedEvent/Info - - name: TimerInfo - link: ref/Microsoft.Coyote.Actors.Timers/TimerInfo - subfolderitems: - - name: Equals - link: ref/Microsoft.Coyote.Actors.Timers/TimerInfo/Equals - - name: GetHashCode - link: ref/Microsoft.Coyote.Actors.Timers/TimerInfo/GetHashCode - - name: ToString - link: ref/Microsoft.Coyote.Actors.Timers/TimerInfo/ToString - - name: OwnerId - link: ref/Microsoft.Coyote.Actors.Timers/TimerInfo/OwnerId - - name: DueTime - link: ref/Microsoft.Coyote.Actors.Timers/TimerInfo/DueTime - - name: Period - link: ref/Microsoft.Coyote.Actors.Timers/TimerInfo/Period - - name: CustomEvent - link: ref/Microsoft.Coyote.Actors.Timers/TimerInfo/CustomEvent - - name: Microsoft.Coyote.IO - link: ref/Microsoft.Coyote.IONamespace - subfolderitems: - - name: ConsoleLogger - link: ref/Microsoft.Coyote.IO/ConsoleLogger - subfolderitems: - - name: Write - link: ref/Microsoft.Coyote.IO/ConsoleLogger/Write - - name: WriteLine - link: ref/Microsoft.Coyote.IO/ConsoleLogger/WriteLine - - name: ConsoleLogger - link: ref/Microsoft.Coyote.IO/ConsoleLogger/ConsoleLogger - - name: TextWriter - link: ref/Microsoft.Coyote.IO/ConsoleLogger/TextWriter - - name: Encoding - link: ref/Microsoft.Coyote.IO/ConsoleLogger/Encoding - - name: LogLevel - link: ref/Microsoft.Coyote.IO/ConsoleLogger/LogLevel - - name: ILogger - link: ref/Microsoft.Coyote.IO/ILogger - subfolderitems: - - name: Write - link: ref/Microsoft.Coyote.IO/ILogger/Write - - name: WriteLine - link: ref/Microsoft.Coyote.IO/ILogger/WriteLine - - name: TextWriter - link: ref/Microsoft.Coyote.IO/ILogger/TextWriter - - name: InMemoryLogger - link: ref/Microsoft.Coyote.IO/InMemoryLogger - subfolderitems: - - name: Write - link: ref/Microsoft.Coyote.IO/InMemoryLogger/Write - - name: WriteLine - link: ref/Microsoft.Coyote.IO/InMemoryLogger/WriteLine - - name: ToString - link: ref/Microsoft.Coyote.IO/InMemoryLogger/ToString - - name: Dispose - link: ref/Microsoft.Coyote.IO/InMemoryLogger/Dispose - - name: InMemoryLogger - link: ref/Microsoft.Coyote.IO/InMemoryLogger/InMemoryLogger - - name: TextWriter - link: ref/Microsoft.Coyote.IO/InMemoryLogger/TextWriter - - name: Encoding - link: ref/Microsoft.Coyote.IO/InMemoryLogger/Encoding - - name: LogSeverity - link: ref/Microsoft.Coyote.IO/LogSeverity - - name: TextWriterLogger - link: ref/Microsoft.Coyote.IO/TextWriterLogger - subfolderitems: - - name: Write - link: ref/Microsoft.Coyote.IO/TextWriterLogger/Write - - name: WriteLine - link: ref/Microsoft.Coyote.IO/TextWriterLogger/WriteLine - - name: TextWriterLogger - link: ref/Microsoft.Coyote.IO/TextWriterLogger/TextWriterLogger - - name: TextWriter - link: ref/Microsoft.Coyote.IO/TextWriterLogger/TextWriter - - name: Encoding - link: ref/Microsoft.Coyote.IO/TextWriterLogger/Encoding - - name: Microsoft.Coyote.Random - link: ref/Microsoft.Coyote.RandomNamespace - subfolderitems: - - name: Generator - link: ref/Microsoft.Coyote.Random/Generator - subfolderitems: - - name: Create - link: ref/Microsoft.Coyote.Random/Generator/Create - - name: NextBoolean - link: ref/Microsoft.Coyote.Random/Generator/NextBoolean - - name: NextInteger - link: ref/Microsoft.Coyote.Random/Generator/NextInteger - - name: Microsoft.Coyote.Runtime - link: ref/Microsoft.Coyote.RuntimeNamespace - subfolderitems: - - name: AssertionFailureException - link: ref/Microsoft.Coyote.Runtime/AssertionFailureException - - name: RuntimeException - link: ref/Microsoft.Coyote.Runtime/RuntimeException - subfolderitems: - - name: RuntimeException - link: ref/Microsoft.Coyote.Runtime/RuntimeException/RuntimeException - - name: ICoyoteRuntime - link: ref/Microsoft.Coyote.Runtime/ICoyoteRuntime - subfolderitems: - - name: RegisterMonitor - link: ref/Microsoft.Coyote.Runtime/ICoyoteRuntime/RegisterMonitor - - name: Monitor - link: ref/Microsoft.Coyote.Runtime/ICoyoteRuntime/Monitor - - name: RandomBoolean - link: ref/Microsoft.Coyote.Runtime/ICoyoteRuntime/RandomBoolean - - name: RandomInteger - link: ref/Microsoft.Coyote.Runtime/ICoyoteRuntime/RandomInteger - - name: Assert - link: ref/Microsoft.Coyote.Runtime/ICoyoteRuntime/Assert - - name: Stop - link: ref/Microsoft.Coyote.Runtime/ICoyoteRuntime/Stop - - name: Logger - link: ref/Microsoft.Coyote.Runtime/ICoyoteRuntime/Logger - - name: OnFailure - link: ref/Microsoft.Coyote.Runtime/ICoyoteRuntime/OnFailure - - name: OnFailureHandler - link: ref/Microsoft.Coyote.Runtime/OnFailureHandler - - name: RuntimeProvider - link: ref/Microsoft.Coyote.Runtime/RuntimeProvider - subfolderitems: - - name: Create - link: ref/Microsoft.Coyote.Runtime/RuntimeProvider/Create - - name: SchedulingPoint - link: ref/Microsoft.Coyote.Runtime/SchedulingPoint - subfolderitems: - - name: Interleave - link: ref/Microsoft.Coyote.Runtime/SchedulingPoint/Interleave - - name: Yield - link: ref/Microsoft.Coyote.Runtime/SchedulingPoint/Yield - - name: Read - link: ref/Microsoft.Coyote.Runtime/SchedulingPoint/Read - - name: Write - link: ref/Microsoft.Coyote.Runtime/SchedulingPoint/Write - - name: Suppress - link: ref/Microsoft.Coyote.Runtime/SchedulingPoint/Suppress - - name: Resume - link: ref/Microsoft.Coyote.Runtime/SchedulingPoint/Resume - - name: Microsoft.Coyote.Specifications - link: ref/Microsoft.Coyote.SpecificationsNamespace - subfolderitems: - - name: Monitor - link: ref/Microsoft.Coyote.Specifications/Monitor - subfolderitems: - - name: RaiseEvent - link: ref/Microsoft.Coyote.Specifications/Monitor/RaiseEvent - - name: RaiseGotoStateEvent - link: ref/Microsoft.Coyote.Specifications/Monitor/RaiseGotoStateEvent - - name: Assert - link: ref/Microsoft.Coyote.Specifications/Monitor/Assert - - name: ToString - link: ref/Microsoft.Coyote.Specifications/Monitor/ToString - - name: Monitor - link: ref/Microsoft.Coyote.Specifications/Monitor/Monitor - - name: Logger - link: ref/Microsoft.Coyote.Specifications/Monitor/Logger - - name: CurrentState - link: ref/Microsoft.Coyote.Specifications/Monitor/CurrentState - - name: HashedState - link: ref/Microsoft.Coyote.Specifications/Monitor/HashedState - - name: Specification - link: ref/Microsoft.Coyote.Specifications/Specification - subfolderitems: - - name: Assert - link: ref/Microsoft.Coyote.Specifications/Specification/Assert - - name: IsEventuallyCompletedSuccessfully - link: ref/Microsoft.Coyote.Specifications/Specification/IsEventuallyCompletedSuccessfully - - name: RegisterMonitor - link: ref/Microsoft.Coyote.Specifications/Specification/RegisterMonitor - - name: Monitor - link: ref/Microsoft.Coyote.Specifications/Specification/Monitor - - name: Monitor.State - link: ref/Microsoft.Coyote.Specifications/Monitor.State - subfolderitems: - - name: State - link: ref/Microsoft.Coyote.Specifications/Monitor.State/State - - name: Monitor.StateGroup - link: ref/Microsoft.Coyote.Specifications/Monitor.StateGroup - subfolderitems: - - name: StateGroup - link: ref/Microsoft.Coyote.Specifications/Monitor.StateGroup/StateGroup - - name: Monitor.State.StartAttribute - link: ref/Microsoft.Coyote.Specifications/Monitor.State.StartAttribute - subfolderitems: - - name: StartAttribute - link: ref/Microsoft.Coyote.Specifications/Monitor.State.StartAttribute/StartAttribute - - name: Monitor.State.OnEntryAttribute - link: ref/Microsoft.Coyote.Specifications/Monitor.State.OnEntryAttribute - subfolderitems: - - name: OnEntryAttribute - link: ref/Microsoft.Coyote.Specifications/Monitor.State.OnEntryAttribute/OnEntryAttribute - - name: Monitor.State.OnExitAttribute - link: ref/Microsoft.Coyote.Specifications/Monitor.State.OnExitAttribute - subfolderitems: - - name: OnExitAttribute - link: ref/Microsoft.Coyote.Specifications/Monitor.State.OnExitAttribute/OnExitAttribute - - name: Monitor.State.OnEventGotoStateAttribute - link: ref/Microsoft.Coyote.Specifications/Monitor.State.OnEventGotoStateAttribute - subfolderitems: - - name: OnEventGotoStateAttribute - link: ref/Microsoft.Coyote.Specifications/Monitor.State.OnEventGotoStateAttribute/OnEventGotoStateAttribute - - name: Monitor.State.OnEventDoActionAttribute - link: ref/Microsoft.Coyote.Specifications/Monitor.State.OnEventDoActionAttribute - subfolderitems: - - name: OnEventDoActionAttribute - link: ref/Microsoft.Coyote.Specifications/Monitor.State.OnEventDoActionAttribute/OnEventDoActionAttribute - - name: Monitor.State.IgnoreEventsAttribute - link: ref/Microsoft.Coyote.Specifications/Monitor.State.IgnoreEventsAttribute - subfolderitems: - - name: IgnoreEventsAttribute - link: ref/Microsoft.Coyote.Specifications/Monitor.State.IgnoreEventsAttribute/IgnoreEventsAttribute - - name: Monitor.State.ColdAttribute - link: ref/Microsoft.Coyote.Specifications/Monitor.State.ColdAttribute - subfolderitems: - - name: ColdAttribute - link: ref/Microsoft.Coyote.Specifications/Monitor.State.ColdAttribute/ColdAttribute - - name: Monitor.State.HotAttribute - link: ref/Microsoft.Coyote.Specifications/Monitor.State.HotAttribute - subfolderitems: - - name: HotAttribute - link: ref/Microsoft.Coyote.Specifications/Monitor.State.HotAttribute/HotAttribute + - name: UseRequestController + link: ref/Microsoft.Coyote.Web/RequestControllerMiddlewareExtensions/UseRequestController diff --git a/docs/samples/actors/failover-robot-navigator.md b/docs/samples/actors/failover-robot-navigator.md index abe78efa9..68505d0cd 100644 --- a/docs/samples/actors/failover-robot-navigator.md +++ b/docs/samples/actors/failover-robot-navigator.md @@ -238,7 +238,7 @@ You can now use `coyote test` to test the code and see if any bugs can be found. `CoyoteSamples` folder enter this command: ```plain -coyote test ./Samples/bin/net6.0/DrinksServingRobotActors.dll -i 1000 -ms 2000 --sch-prioritization 10 +coyote test ./Samples/bin/net6.0/DrinksServingRobotActors.dll -i 1000 -ms 2000 -s prioritization -sv 10 ``` Chances are this will find a bug quickly, and you will see output from the test like this: @@ -468,10 +468,10 @@ Remember the last lines of the coyote test execution log file: liveness bug in hot state 'Busy' at the end of program execution. ``` -If you add to the coyote test command line `--graph-bug`, and test again: +If you add to the coyote test command line `--graph`, and test again: ```plain -coyote test .\Samples\bin\net6.0\DrinksServingRobotActors.dll -i 1000 -ms 2000 --sch-prioritization 10 --graph-bug +coyote test .\Samples\bin\net6.0\DrinksServingRobotActors.dll -i 1000 -ms 2000 -s prioritization -sv 10 --graph ``` you'll see in the output of the tester that a DGML diagram has been produced: @@ -640,7 +640,7 @@ After you perform this fix and rebuild the sample, try running coyote test again command line which previously reported the liveness bug: ```plain -coyote test ./Samples/bin/net6.0/DrinksServingRobotActors.dll -i 1000 -ms 2000 --sch-prioritization 10 +coyote test ./Samples/bin/net6.0/DrinksServingRobotActors.dll -i 1000 -ms 2000 -s prioritization -sv 10 ``` And now no bug will be found -- you should get result similar to this: @@ -662,11 +662,7 @@ And now no bug will be found -- you should get result similar to this: ``` If you want to have a high degree of certainty that no bug is found, run the coyote tester with a -sufficiently big number of iterations, say 100,000 and `--parallel N` where N is a number that -works well on your computer. If N is too high it will thrash your CPU and the test will run slowly. -A good rule of thumb is to use `ceiling(0.65 * NUMBER_OF_PROCESSORS)`. NUMBER_OF_PROCESSORS is a -system environment variable, typically equal to the number of cores in the computer. But sometimes -this number is doubled if your computer supports hyper-threading. +sufficiently big number of iterations, say 100,000. ## Summary @@ -680,9 +676,9 @@ In this tutorial you learned: 1. How to do failover testing using a Coyote `FailoverDriver` state machine. 2. How to use Coyote to test failover in a service. -3. How to use `--sch-prioritization` testing on multiple processes to find tricky bugs more quickly. -4. How to specify the `--graph-bug` argument so that the coyote test tool would produce a - snapshot-DGML diagram of the final state of the system when the bug was found. +3. How to use `--strategy prioritization` testing to find tricky bugs. +4. How to specify the `--graph` argument so that the coyote test tool would produce a snapshot-DGML + diagram of the final state of the system when the bug was found. 5. How to use `RaisePushStateEvent()` and `RaisePopStateEvent()` to achieve additional simplicity in handling common events in one place. 6. How `Assert` helps find violations of safety properties during testing. diff --git a/docs/samples/actors/failure-detector.md b/docs/samples/actors/failure-detector.md index 0ea523c0f..08090b21a 100644 --- a/docs/samples/actors/failure-detector.md +++ b/docs/samples/actors/failure-detector.md @@ -26,24 +26,24 @@ Let's see if Coyote can find the bug in this sample. Type `coyote -?` to see the sure you have installed it correctly. Now you are ready to run a `coyote` test as follows: ```plain -coyote test ./Samples/bin/net6.0/Monitors.dll --iterations 1000 --max-steps 200 +coyote test ./Samples/bin/net6.0/Monitors.dll --iterations 1000 -ms 200 ``` This also runs perfectly up to 1000 iterations. So this is indeed a hard bug to find. It can be found using the `prioritization` exploration strategy with a given maximum number of priority switch -points `--sch-prioritization` (or with the default `random` exploration strategy, but with a much -larger number of iterations, typically more than 100,000 of them). +points `--strategy prioritization` (or with the default `random` exploration strategy, but with a +much larger number of iterations, typically more than 100,000 of them). ```plain -coyote test ./Samples/bin/net6.0/Monitors.dll --iterations 1000 --max-steps 200 --sch-prioritization 10 +coyote test ./Samples/bin/net6.0/Monitors.dll --iterations 1000 -ms 200 -s prioritization -sv 10 ``` Even then you might need to run it a few times to catch the bug. Set `--iterations` to a bigger number if necessary. You can also let `coyote` decide which exploration strategy to use. Just use -`--sch-portfolio` and size `--parallel N` and Coyote will run `N` different exploration strategies -for you, in parallel. `coyote` manages the portfolio to give you the best chance of revealing bugs. -These strategies were developed from real-world experience on large products in Microsoft Azure. -When you use the right scheduling strategy, you will see a bug report: +`--strategy portfolio` Coyote will select and run different exploration strategies for you. `coyote` +manages the portfolio to give you the best chance of revealing bugs. These strategies were developed +from real-world experience on large products in Microsoft Azure. When you use the right scheduling +strategy, you will see a bug report: ```plain ... Task 0 found a bug. diff --git a/docs/tutorials/actors/raft-mocking.md b/docs/tutorials/actors/raft-mocking.md index 97bbe4b0c..24aeecdbe 100644 --- a/docs/tutorials/actors/raft-mocking.md +++ b/docs/tutorials/actors/raft-mocking.md @@ -117,19 +117,17 @@ test scheduling options you can play with: | Option | Description | | ------ | ----------- | -| `--sch-random` | Choose the random scheduling strategy (this is the default) | -| `--sch-prioritization uint` | Choose the priority-based scheduling strategy with given maximum number of priority switch points | -| `--sch-fair-prioritization uint` | Choose the fair priority-based scheduling strategy with given maximum number of priority switch points | -| `--sch-portfolio` | Choose the portfolio scheduling strategy in combination with parallel testing | - +| `--strategy random` | Choose the random scheduling strategy (this is the default) | +| `--strategy prioritization` `--strategy-value N` | Choose the priority-based scheduling strategy with `N` maximum number of priority switch points | +| `--strategy fair-prioritization` `--strategy-value N` | Choose the fair priority-based scheduling strategy with `N` maximum number of priority switch points | +| `--strategy portfolio` | Choose the portfolio scheduling strategy | These options change how `coyote test` explores the large state space of possible schedules for your async operations. The last option is interesting because it allows you to test many different -scheduling strategies at once, this is used in combination with the `--parallel` test option, so the following, - for example, would run 5 parallel test processes using different scheduling strategies: +scheduling strategies at once: ```plain -coyote test ./Samples/bin/net6.0/Raft.Mocking.dll -i 1000 -ms 200 --coverage activity --sch-portfolio --parallel 5 +coyote test ./Samples/bin/net6.0/Raft.Mocking.dll -i 1000 -ms 200 --coverage activity -s portfolio ``` When you use this the test will print the chosen strategies at the top of the test output: diff --git a/docs/tutorials/actors/test-failover.md b/docs/tutorials/actors/test-failover.md index 932e56f1d..91d8d613e 100644 --- a/docs/tutorials/actors/test-failover.md +++ b/docs/tutorials/actors/test-failover.md @@ -189,7 +189,7 @@ You can now use [coyote test](../../get-started/using-coyote.md) to exercise the can be found. From the [samples](https://github.com/microsoft/coyote/tree/main/Samples) directory: ```plain -coyote test ./Samples/bin/net6.0/CoffeeMachineActors.dll -i 100 -ms 2000 --sch-prioritization 10 --graph-bug +coyote test ./Samples/bin/net6.0/CoffeeMachineActors.dll -i 100 -ms 2000 -s prioritization -sv 10 --graph ``` Chances are this will find a bug quickly, one of the safety assertions will fire and you will see @@ -289,38 +289,11 @@ based eventing is used to model the `ShotCompleteEvent`, `WaterHotEvent`, `Water This shows how Coyote can help find actual design flaws in your code so you can design a system that is more robust in the face of unexpected faults. The `coyote test` engine provides several different `scheduling strategies` that test different kinds of fairness algorithms. These are -designed to find different kinds of bugs. The following command line shows how to use -`--sch-portfolio` and the `--parallel` options to test a bunch of different strategies in parallel, -each in different test processes: +designed to find different kinds of bugs. -```plain -coyote test ./Samples/bin/net6.0/CoffeeMachineActors.dll -i 100 -ms 2000 --sch-prioritization 10 --graph-bug --sch-portfolio --parallel 8 -``` - -which outputs the following: -```plain -. Testing .\Samples\bin\net6.0\CoffeeMachineActors.dll -Starting TestingProcessScheduler in process 42036 -... Created '8' testing tasks. -... Task 3 is using 'fair-prioritization' strategy (seed:2143). -... Task 5 is using 'fair-prioritization' strategy (seed:3489). -... Task 2 is using 'probabilistic' strategy (seed:1470). -... Task 7 is using 'fair-prioritization' strategy (seed:4835). -... Task 0 is using 'random' strategy (seed:124). -... Task 6 is using 'probabilistic' strategy (seed:4162). -... Task 4 is using 'probabilistic' strategy (seed:2816). -... Task 1 is using 'fair-prioritization' strategy (seed:797). -... -``` - -The `--parallel 8` option means use 8 test processes in parallel with each one being assigned a -random scheduling strategy. Each process runs until the first bug is found by some process, then -they are all terminated and the bug is reported. This can be useful when you want to leverage the -full power of your computer to find those bugs that are particularly hard to find more quickly. - -You can find out how much testing was actually done during this parallel test operation by adding -`--coverage activity`. The [coverage report](../../how-to/coverage.md) summarizes how many -of the possible events were covered. +You can find out how much testing was actually done during testing by setting the `--coverage` flag. +The [coverage report](../../how-to/coverage.md) summarizes how many of the possible events were +covered. ### Liveness monitor @@ -406,7 +379,7 @@ In this tutorial you learned: 1. How to do failover testing using Coyote `FailoverDriver` state machines. 2. How to use Coyote in a firmware/sensor scenario. -3. How to use `--sch-portfolio` testing on multiple processes to find tricky bugs more quickly. +3. How to use `--strategy portfolio` testing to find tricky bugs more quickly. 4. How `Assert` helps find violations of safety properties during testing. 5. How to ensure full termination of one state machine before creating a new one. 6. How to use class level event handlers in a `StateMachine` to define an event handler diff --git a/docs/tutorials/test-failover.md b/docs/tutorials/test-failover.md index 38be4eb4f..f8b4c6ad9 100644 --- a/docs/tutorials/test-failover.md +++ b/docs/tutorials/test-failover.md @@ -188,7 +188,7 @@ coyote rewrite ./Samples/bin/net6.0/CoffeeMachineTasks.dll Then you can run the test: ```plain -coyote test ./Samples/bin/net6.0/CoffeeMachineTasks.dll -i 1000 -ms 500 --sch-fair-prioritization 10 +coyote test ./Samples/bin/net6.0/CoffeeMachineTasks.dll -i 1000 -ms 500 -s fair-prioritization -sv 10 ``` Chances are this will find a bug quickly, one of the safety assertions will fire and you will see @@ -276,35 +276,7 @@ This style of `interrupt` based eventing is used to model the `ShotCompleteEvent This shows how Coyote can help find actual design flaws in your code so you can design a system that is more robust in the face of unexpected faults. The `coyote test` engine provides several different `scheduling strategies` that test different kinds of fairness algorithms. These are designed to find -different kinds of bugs. The following command line shows how to use `--sch-portfolio` and the -`--parallel` options to test a bunch of different strategies in parallel, each in different test -processes: - -```plain -coyote test ./Samples/bin/net6.0/CoffeeMachineTasks.dll -i 1000 -ms 500 --sch-portfolio --parallel 8 -``` - -which outputs the following: - -```plain -. Testing .\Samples\bin\net6.0\CoffeeMachineTasks.dll -Starting TestingProcessScheduler in process 42036 -... Created '8' testing tasks. -... Task 3 is using 'fair-prioritization' strategy (seed:2143). -... Task 5 is using 'fair-prioritization' strategy (seed:3489). -... Task 2 is using 'probabilistic' strategy (seed:1470). -... Task 7 is using 'fair-prioritization' strategy (seed:4835). -... Task 0 is using 'random' strategy (seed:124). -... Task 6 is using 'probabilistic' strategy (seed:4162). -... Task 4 is using 'probabilistic' strategy (seed:2816). -... Task 1 is using 'fair-prioritization' strategy (seed:797). -... -``` - -The `--parallel 8` option means use 8 test processes in parallel, each one is assigned a random -scheduling strategy. Each process runs until the first one finds a bug, then they are all terminated -and the bug is reported. This can be useful when you want to leverage the full power of your -computer to find those bugs that are particularly hard to find more quickly. +different kinds of bugs. ### Liveness monitor @@ -377,6 +349,6 @@ In this tutorial you learned: 1. How to do failover testing in the Coyote controlled `Task` programming model. 2. How to use Coyote in a firmware/sensor scenario. -3. How to use `--sch-portfolio` testing on multiple processes to find tricky bugs more quickly. +3. How to use `--strategy portfolio` testing to find tricky bugs more quickly. 4. How `Assert` helps find violations of safety properties during testing. 5. How to write a `LivenessMonitor`. diff --git a/mkdocs.yml b/mkdocs.yml index d3e1256dc..163e314b7 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -131,7 +131,7 @@ nav: - WithIncrementalSeedGenerationEnabled: ref/Microsoft.Coyote/Configuration/WithIncrementalSeedGenerationEnabled.md - WithVerbosityEnabled: ref/Microsoft.Coyote/Configuration/WithVerbosityEnabled.md - WithActivityCoverageReported: ref/Microsoft.Coyote/Configuration/WithActivityCoverageReported.md - - WithDgmlGraphEnabled: ref/Microsoft.Coyote/Configuration/WithDgmlGraphEnabled.md + - WithTraceVisualizationEnabled: ref/Microsoft.Coyote/Configuration/WithTraceVisualizationEnabled.md - WithXmlLogEnabled: ref/Microsoft.Coyote/Configuration/WithXmlLogEnabled.md - WithTelemetryEnabled: ref/Microsoft.Coyote/Configuration/WithTelemetryEnabled.md - Configuration: ref/Microsoft.Coyote/Configuration/Configuration.md @@ -363,555 +363,6 @@ nav: - GetEventsReceived: ref/Microsoft.Coyote.Actors.Coverage/EventCoverage/GetEventsReceived.md - GetEventsSent: ref/Microsoft.Coyote.Actors.Coverage/EventCoverage/GetEventsSent.md - EventCoverage: ref/Microsoft.Coyote.Actors.Coverage/EventCoverage/EventCoverage.md - - ActorRuntimeLogGraphBuilder: - - Overview: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder.md - - OnCreateActor: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnCreateActor.md - - OnCreateStateMachine: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnCreateStateMachine.md - - OnSendEvent: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnSendEvent.md - - OnRaiseEvent: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnRaiseEvent.md - - OnHandleRaisedEvent: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnHandleRaisedEvent.md - - OnEnqueueEvent: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnEnqueueEvent.md - - OnDequeueEvent: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnDequeueEvent.md - - OnReceiveEvent: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnReceiveEvent.md - - OnWaitEvent: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnWaitEvent.md - - OnStateTransition: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnStateTransition.md - - OnExecuteAction: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnExecuteAction.md - - OnGotoState: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnGotoState.md - - OnPushState: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnPushState.md - - OnPopState: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnPopState.md - - OnHalt: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnHalt.md - - OnDefaultEventHandler: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnDefaultEventHandler.md - - OnEventHandlerTerminated: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnEventHandlerTerminated.md - - OnPopStateUnhandledEvent: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnPopStateUnhandledEvent.md - - OnExceptionThrown: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnExceptionThrown.md - - OnExceptionHandled: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnExceptionHandled.md - - OnCreateTimer: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnCreateTimer.md - - OnStopTimer: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnStopTimer.md - - OnCreateMonitor: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnCreateMonitor.md - - OnMonitorExecuteAction: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnMonitorExecuteAction.md - - OnMonitorProcessEvent: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnMonitorProcessEvent.md - - OnMonitorRaiseEvent: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnMonitorRaiseEvent.md - - OnMonitorStateTransition: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnMonitorStateTransition.md - - OnMonitorError: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnMonitorError.md - - OnRandom: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnRandom.md - - OnAssertionFailure: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnAssertionFailure.md - - OnCompleted: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnCompleted.md - - SnapshotGraph: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/SnapshotGraph.md - - ActorRuntimeLogGraphBuilder: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/ActorRuntimeLogGraphBuilder.md - - CollapseMachineInstances: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/CollapseMachineInstances.md - - Logger: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/Logger.md - - Graph: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/Graph.md - - Graph: - - Overview: ref/Microsoft.Coyote.Actors.Coverage/Graph.md - - GetNode: ref/Microsoft.Coyote.Actors.Coverage/Graph/GetNode.md - - GetOrCreateNode: ref/Microsoft.Coyote.Actors.Coverage/Graph/GetOrCreateNode.md - - GetOrCreateLink: ref/Microsoft.Coyote.Actors.Coverage/Graph/GetOrCreateLink.md - - ToString: ref/Microsoft.Coyote.Actors.Coverage/Graph/ToString.md - - WriteDgml: ref/Microsoft.Coyote.Actors.Coverage/Graph/WriteDgml.md - - LoadDgml: ref/Microsoft.Coyote.Actors.Coverage/Graph/LoadDgml.md - - Merge: ref/Microsoft.Coyote.Actors.Coverage/Graph/Merge.md - - Graph: ref/Microsoft.Coyote.Actors.Coverage/Graph/Graph.md - - Nodes: ref/Microsoft.Coyote.Actors.Coverage/Graph/Nodes.md - - Links: ref/Microsoft.Coyote.Actors.Coverage/Graph/Links.md - - GraphObject: - - Overview: ref/Microsoft.Coyote.Actors.Coverage/GraphObject.md - - AddAttribute: ref/Microsoft.Coyote.Actors.Coverage/GraphObject/AddAttribute.md - - AddListAttribute: ref/Microsoft.Coyote.Actors.Coverage/GraphObject/AddListAttribute.md - - GraphObject: ref/Microsoft.Coyote.Actors.Coverage/GraphObject/GraphObject.md - - Attributes: ref/Microsoft.Coyote.Actors.Coverage/GraphObject/Attributes.md - - AttributeLists: ref/Microsoft.Coyote.Actors.Coverage/GraphObject/AttributeLists.md - - GraphNode: - - Overview: ref/Microsoft.Coyote.Actors.Coverage/GraphNode.md - - AddDgmlProperties: ref/Microsoft.Coyote.Actors.Coverage/GraphNode/AddDgmlProperties.md - - GraphNode: ref/Microsoft.Coyote.Actors.Coverage/GraphNode/GraphNode.md - - Id: ref/Microsoft.Coyote.Actors.Coverage/GraphNode/Id.md - - Label: ref/Microsoft.Coyote.Actors.Coverage/GraphNode/Label.md - - Category: ref/Microsoft.Coyote.Actors.Coverage/GraphNode/Category.md - - GraphLink: - - Overview: ref/Microsoft.Coyote.Actors.Coverage/GraphLink.md - - AddDgmlProperties: ref/Microsoft.Coyote.Actors.Coverage/GraphLink/AddDgmlProperties.md - - GraphLink: ref/Microsoft.Coyote.Actors.Coverage/GraphLink/GraphLink.md - - Label: ref/Microsoft.Coyote.Actors.Coverage/GraphLink/Label.md - - Category: ref/Microsoft.Coyote.Actors.Coverage/GraphLink/Category.md - - Source: ref/Microsoft.Coyote.Actors.Coverage/GraphLink/Source.md - - Target: ref/Microsoft.Coyote.Actors.Coverage/GraphLink/Target.md - - Index: ref/Microsoft.Coyote.Actors.Coverage/GraphLink/Index.md - - CoverageInfo: - - Overview: ref/Microsoft.Coyote.Actors.Coverage/CoverageInfo.md - - IsMachineDeclared: ref/Microsoft.Coyote.Actors.Coverage/CoverageInfo/IsMachineDeclared.md - - DeclareMachineState: ref/Microsoft.Coyote.Actors.Coverage/CoverageInfo/DeclareMachineState.md - - DeclareStateEvent: ref/Microsoft.Coyote.Actors.Coverage/CoverageInfo/DeclareStateEvent.md - - Merge: ref/Microsoft.Coyote.Actors.Coverage/CoverageInfo/Merge.md - - Load: ref/Microsoft.Coyote.Actors.Coverage/CoverageInfo/Load.md - - Save: ref/Microsoft.Coyote.Actors.Coverage/CoverageInfo/Save.md - - CoverageInfo: ref/Microsoft.Coyote.Actors.Coverage/CoverageInfo/CoverageInfo.md - - Machines: ref/Microsoft.Coyote.Actors.Coverage/CoverageInfo/Machines.md - - MachinesToStates: ref/Microsoft.Coyote.Actors.Coverage/CoverageInfo/MachinesToStates.md - - RegisteredEvents: ref/Microsoft.Coyote.Actors.Coverage/CoverageInfo/RegisteredEvents.md - - CoverageGraph: ref/Microsoft.Coyote.Actors.Coverage/CoverageInfo/CoverageGraph.md - - EventInfo: ref/Microsoft.Coyote.Actors.Coverage/CoverageInfo/EventInfo.md - - Microsoft.Coyote.Actors.SharedObjects: - - Namespace Overview: ref/Microsoft.Coyote.Actors.SharedObjectsNamespace.md - - SharedCounter: - - Overview: ref/Microsoft.Coyote.Actors.SharedObjects/SharedCounter.md - - Create: ref/Microsoft.Coyote.Actors.SharedObjects/SharedCounter/Create.md - - Increment: ref/Microsoft.Coyote.Actors.SharedObjects/SharedCounter/Increment.md - - Decrement: ref/Microsoft.Coyote.Actors.SharedObjects/SharedCounter/Decrement.md - - GetValue: ref/Microsoft.Coyote.Actors.SharedObjects/SharedCounter/GetValue.md - - Add: ref/Microsoft.Coyote.Actors.SharedObjects/SharedCounter/Add.md - - Exchange: ref/Microsoft.Coyote.Actors.SharedObjects/SharedCounter/Exchange.md - - CompareExchange: ref/Microsoft.Coyote.Actors.SharedObjects/SharedCounter/CompareExchange.md - - SharedDictionary: - - Overview: ref/Microsoft.Coyote.Actors.SharedObjects/SharedDictionary.md - - Create: ref/Microsoft.Coyote.Actors.SharedObjects/SharedDictionary/Create.md - - SharedDictionary: - - Overview: ref/Microsoft.Coyote.Actors.SharedObjects/SharedDictionary-2.md - - TryAdd: ref/Microsoft.Coyote.Actors.SharedObjects/SharedDictionary-2/TryAdd.md - - TryUpdate: ref/Microsoft.Coyote.Actors.SharedObjects/SharedDictionary-2/TryUpdate.md - - TryGetValue: ref/Microsoft.Coyote.Actors.SharedObjects/SharedDictionary-2/TryGetValue.md - - TryRemove: ref/Microsoft.Coyote.Actors.SharedObjects/SharedDictionary-2/TryRemove.md - - Item: ref/Microsoft.Coyote.Actors.SharedObjects/SharedDictionary-2/Item.md - - Count: ref/Microsoft.Coyote.Actors.SharedObjects/SharedDictionary-2/Count.md - - SharedRegister: - - Overview: ref/Microsoft.Coyote.Actors.SharedObjects/SharedRegister.md - - Create: ref/Microsoft.Coyote.Actors.SharedObjects/SharedRegister/Create.md - - SharedRegister: - - Overview: ref/Microsoft.Coyote.Actors.SharedObjects/SharedRegister-1.md - - Update: ref/Microsoft.Coyote.Actors.SharedObjects/SharedRegister-1/Update.md - - GetValue: ref/Microsoft.Coyote.Actors.SharedObjects/SharedRegister-1/GetValue.md - - SetValue: ref/Microsoft.Coyote.Actors.SharedObjects/SharedRegister-1/SetValue.md - - Microsoft.Coyote.Actors.Timers: - - Namespace Overview: ref/Microsoft.Coyote.Actors.TimersNamespace.md - - TimerElapsedEvent: - - Overview: ref/Microsoft.Coyote.Actors.Timers/TimerElapsedEvent.md - - TimerElapsedEvent: ref/Microsoft.Coyote.Actors.Timers/TimerElapsedEvent/TimerElapsedEvent.md - - Info: ref/Microsoft.Coyote.Actors.Timers/TimerElapsedEvent/Info.md - - TimerInfo: - - Overview: ref/Microsoft.Coyote.Actors.Timers/TimerInfo.md - - Equals: ref/Microsoft.Coyote.Actors.Timers/TimerInfo/Equals.md - - GetHashCode: ref/Microsoft.Coyote.Actors.Timers/TimerInfo/GetHashCode.md - - ToString: ref/Microsoft.Coyote.Actors.Timers/TimerInfo/ToString.md - - OwnerId: ref/Microsoft.Coyote.Actors.Timers/TimerInfo/OwnerId.md - - DueTime: ref/Microsoft.Coyote.Actors.Timers/TimerInfo/DueTime.md - - Period: ref/Microsoft.Coyote.Actors.Timers/TimerInfo/Period.md - - CustomEvent: ref/Microsoft.Coyote.Actors.Timers/TimerInfo/CustomEvent.md - - Microsoft.Coyote.IO: - - Namespace Overview: ref/Microsoft.Coyote.IONamespace.md - - ConsoleLogger: - - Overview: ref/Microsoft.Coyote.IO/ConsoleLogger.md - - Write: ref/Microsoft.Coyote.IO/ConsoleLogger/Write.md - - WriteLine: ref/Microsoft.Coyote.IO/ConsoleLogger/WriteLine.md - - ConsoleLogger: ref/Microsoft.Coyote.IO/ConsoleLogger/ConsoleLogger.md - - TextWriter: ref/Microsoft.Coyote.IO/ConsoleLogger/TextWriter.md - - Encoding: ref/Microsoft.Coyote.IO/ConsoleLogger/Encoding.md - - LogLevel: ref/Microsoft.Coyote.IO/ConsoleLogger/LogLevel.md - - ILogger: - - Overview: ref/Microsoft.Coyote.IO/ILogger.md - - Write: ref/Microsoft.Coyote.IO/ILogger/Write.md - - WriteLine: ref/Microsoft.Coyote.IO/ILogger/WriteLine.md - - TextWriter: ref/Microsoft.Coyote.IO/ILogger/TextWriter.md - - InMemoryLogger: - - Overview: ref/Microsoft.Coyote.IO/InMemoryLogger.md - - Write: ref/Microsoft.Coyote.IO/InMemoryLogger/Write.md - - WriteLine: ref/Microsoft.Coyote.IO/InMemoryLogger/WriteLine.md - - ToString: ref/Microsoft.Coyote.IO/InMemoryLogger/ToString.md - - Dispose: ref/Microsoft.Coyote.IO/InMemoryLogger/Dispose.md - - InMemoryLogger: ref/Microsoft.Coyote.IO/InMemoryLogger/InMemoryLogger.md - - TextWriter: ref/Microsoft.Coyote.IO/InMemoryLogger/TextWriter.md - - Encoding: ref/Microsoft.Coyote.IO/InMemoryLogger/Encoding.md - - LogSeverity: ref/Microsoft.Coyote.IO/LogSeverity.md - - TextWriterLogger: - - Overview: ref/Microsoft.Coyote.IO/TextWriterLogger.md - - Write: ref/Microsoft.Coyote.IO/TextWriterLogger/Write.md - - WriteLine: ref/Microsoft.Coyote.IO/TextWriterLogger/WriteLine.md - - TextWriterLogger: ref/Microsoft.Coyote.IO/TextWriterLogger/TextWriterLogger.md - - TextWriter: ref/Microsoft.Coyote.IO/TextWriterLogger/TextWriter.md - - Encoding: ref/Microsoft.Coyote.IO/TextWriterLogger/Encoding.md - - Microsoft.Coyote.Random: - - Namespace Overview: ref/Microsoft.Coyote.RandomNamespace.md - - Generator: - - Overview: ref/Microsoft.Coyote.Random/Generator.md - - Create: ref/Microsoft.Coyote.Random/Generator/Create.md - - NextBoolean: ref/Microsoft.Coyote.Random/Generator/NextBoolean.md - - NextInteger: ref/Microsoft.Coyote.Random/Generator/NextInteger.md - - Microsoft.Coyote.Runtime: - - Namespace Overview: ref/Microsoft.Coyote.RuntimeNamespace.md - - AssertionFailureException: ref/Microsoft.Coyote.Runtime/AssertionFailureException.md - - RuntimeException: - - Overview: ref/Microsoft.Coyote.Runtime/RuntimeException.md - - RuntimeException: ref/Microsoft.Coyote.Runtime/RuntimeException/RuntimeException.md - - ICoyoteRuntime: - - Overview: ref/Microsoft.Coyote.Runtime/ICoyoteRuntime.md - - RegisterMonitor: ref/Microsoft.Coyote.Runtime/ICoyoteRuntime/RegisterMonitor.md - - Monitor: ref/Microsoft.Coyote.Runtime/ICoyoteRuntime/Monitor.md - - RandomBoolean: ref/Microsoft.Coyote.Runtime/ICoyoteRuntime/RandomBoolean.md - - RandomInteger: ref/Microsoft.Coyote.Runtime/ICoyoteRuntime/RandomInteger.md - - Assert: ref/Microsoft.Coyote.Runtime/ICoyoteRuntime/Assert.md - - Stop: ref/Microsoft.Coyote.Runtime/ICoyoteRuntime/Stop.md - - Logger: ref/Microsoft.Coyote.Runtime/ICoyoteRuntime/Logger.md - - OnFailure: ref/Microsoft.Coyote.Runtime/ICoyoteRuntime/OnFailure.md - - OnFailureHandler: ref/Microsoft.Coyote.Runtime/OnFailureHandler.md - - RuntimeProvider: - - Overview: ref/Microsoft.Coyote.Runtime/RuntimeProvider.md - - Create: ref/Microsoft.Coyote.Runtime/RuntimeProvider/Create.md - - SchedulingPoint: - - Overview: ref/Microsoft.Coyote.Runtime/SchedulingPoint.md - - Interleave: ref/Microsoft.Coyote.Runtime/SchedulingPoint/Interleave.md - - Yield: ref/Microsoft.Coyote.Runtime/SchedulingPoint/Yield.md - - Read: ref/Microsoft.Coyote.Runtime/SchedulingPoint/Read.md - - Write: ref/Microsoft.Coyote.Runtime/SchedulingPoint/Write.md - - Suppress: ref/Microsoft.Coyote.Runtime/SchedulingPoint/Suppress.md - - Resume: ref/Microsoft.Coyote.Runtime/SchedulingPoint/Resume.md - - Microsoft.Coyote.Specifications: - - Namespace Overview: ref/Microsoft.Coyote.SpecificationsNamespace.md - - Monitor: - - Overview: ref/Microsoft.Coyote.Specifications/Monitor.md - - RaiseEvent: ref/Microsoft.Coyote.Specifications/Monitor/RaiseEvent.md - - RaiseGotoStateEvent: ref/Microsoft.Coyote.Specifications/Monitor/RaiseGotoStateEvent.md - - Assert: ref/Microsoft.Coyote.Specifications/Monitor/Assert.md - - ToString: ref/Microsoft.Coyote.Specifications/Monitor/ToString.md - - Monitor: ref/Microsoft.Coyote.Specifications/Monitor/Monitor.md - - Logger: ref/Microsoft.Coyote.Specifications/Monitor/Logger.md - - CurrentState: ref/Microsoft.Coyote.Specifications/Monitor/CurrentState.md - - HashedState: ref/Microsoft.Coyote.Specifications/Monitor/HashedState.md - - Specification: - - Overview: ref/Microsoft.Coyote.Specifications/Specification.md - - Assert: ref/Microsoft.Coyote.Specifications/Specification/Assert.md - - IsEventuallyCompletedSuccessfully: ref/Microsoft.Coyote.Specifications/Specification/IsEventuallyCompletedSuccessfully.md - - RegisterMonitor: ref/Microsoft.Coyote.Specifications/Specification/RegisterMonitor.md - - Monitor: ref/Microsoft.Coyote.Specifications/Specification/Monitor.md - - Monitor.State: - - Overview: ref/Microsoft.Coyote.Specifications/Monitor.State.md - - State: ref/Microsoft.Coyote.Specifications/Monitor.State/State.md - - Monitor.StateGroup: - - Overview: ref/Microsoft.Coyote.Specifications/Monitor.StateGroup.md - - StateGroup: ref/Microsoft.Coyote.Specifications/Monitor.StateGroup/StateGroup.md - - Monitor.State.StartAttribute: - - Overview: ref/Microsoft.Coyote.Specifications/Monitor.State.StartAttribute.md - - StartAttribute: ref/Microsoft.Coyote.Specifications/Monitor.State.StartAttribute/StartAttribute.md - - Monitor.State.OnEntryAttribute: - - Overview: ref/Microsoft.Coyote.Specifications/Monitor.State.OnEntryAttribute.md - - OnEntryAttribute: ref/Microsoft.Coyote.Specifications/Monitor.State.OnEntryAttribute/OnEntryAttribute.md - - Monitor.State.OnExitAttribute: - - Overview: ref/Microsoft.Coyote.Specifications/Monitor.State.OnExitAttribute.md - - OnExitAttribute: ref/Microsoft.Coyote.Specifications/Monitor.State.OnExitAttribute/OnExitAttribute.md - - Monitor.State.OnEventGotoStateAttribute: - - Overview: ref/Microsoft.Coyote.Specifications/Monitor.State.OnEventGotoStateAttribute.md - - OnEventGotoStateAttribute: ref/Microsoft.Coyote.Specifications/Monitor.State.OnEventGotoStateAttribute/OnEventGotoStateAttribute.md - - Monitor.State.OnEventDoActionAttribute: - - Overview: ref/Microsoft.Coyote.Specifications/Monitor.State.OnEventDoActionAttribute.md - - OnEventDoActionAttribute: ref/Microsoft.Coyote.Specifications/Monitor.State.OnEventDoActionAttribute/OnEventDoActionAttribute.md - - Monitor.State.IgnoreEventsAttribute: - - Overview: ref/Microsoft.Coyote.Specifications/Monitor.State.IgnoreEventsAttribute.md - - IgnoreEventsAttribute: ref/Microsoft.Coyote.Specifications/Monitor.State.IgnoreEventsAttribute/IgnoreEventsAttribute.md - - Monitor.State.ColdAttribute: - - Overview: ref/Microsoft.Coyote.Specifications/Monitor.State.ColdAttribute.md - - ColdAttribute: ref/Microsoft.Coyote.Specifications/Monitor.State.ColdAttribute/ColdAttribute.md - - Monitor.State.HotAttribute: - - Overview: ref/Microsoft.Coyote.Specifications/Monitor.State.HotAttribute.md - - HotAttribute: ref/Microsoft.Coyote.Specifications/Monitor.State.HotAttribute/HotAttribute.md - - Microsoft.Coyote: - - Overview: ref/Microsoft.Coyote.md - - Microsoft.Coyote: - - Namespace Overview: ref/Microsoft.CoyoteNamespace.md - - Event: - - Overview: ref/Microsoft.Coyote/Event.md - - Event: ref/Microsoft.Coyote/Event/Event.md - - Configuration: - - Overview: ref/Microsoft.Coyote/Configuration.md - - Create: ref/Microsoft.Coyote/Configuration/Create.md - - WithRandomStrategy: ref/Microsoft.Coyote/Configuration/WithRandomStrategy.md - - WithProbabilisticStrategy: ref/Microsoft.Coyote/Configuration/WithProbabilisticStrategy.md - - WithPrioritizationStrategy: ref/Microsoft.Coyote/Configuration/WithPrioritizationStrategy.md - - WithRLStrategy: ref/Microsoft.Coyote/Configuration/WithRLStrategy.md - - WithReplayStrategy: ref/Microsoft.Coyote/Configuration/WithReplayStrategy.md - - WithTestingIterations: ref/Microsoft.Coyote/Configuration/WithTestingIterations.md - - WithTestingTimeout: ref/Microsoft.Coyote/Configuration/WithTestingTimeout.md - - WithPartiallyControlledConcurrencyAllowed: ref/Microsoft.Coyote/Configuration/WithPartiallyControlledConcurrencyAllowed.md - - WithSystematicFuzzingEnabled: ref/Microsoft.Coyote/Configuration/WithSystematicFuzzingEnabled.md - - WithSystematicFuzzingFallbackEnabled: ref/Microsoft.Coyote/Configuration/WithSystematicFuzzingFallbackEnabled.md - - WithSharedStateReductionEnabled: ref/Microsoft.Coyote/Configuration/WithSharedStateReductionEnabled.md - - WithNoBugTraceRepro: ref/Microsoft.Coyote/Configuration/WithNoBugTraceRepro.md - - WithMaxSchedulingSteps: ref/Microsoft.Coyote/Configuration/WithMaxSchedulingSteps.md - - WithLivenessTemperatureThreshold: ref/Microsoft.Coyote/Configuration/WithLivenessTemperatureThreshold.md - - WithTimeoutDelay: ref/Microsoft.Coyote/Configuration/WithTimeoutDelay.md - - WithDeadlockTimeout: ref/Microsoft.Coyote/Configuration/WithDeadlockTimeout.md - - WithPotentialDeadlocksReportedAsBugs: ref/Microsoft.Coyote/Configuration/WithPotentialDeadlocksReportedAsBugs.md - - WithUncontrolledConcurrencyResolutionTimeout: ref/Microsoft.Coyote/Configuration/WithUncontrolledConcurrencyResolutionTimeout.md - - WithRandomGeneratorSeed: ref/Microsoft.Coyote/Configuration/WithRandomGeneratorSeed.md - - WithIncrementalSeedGenerationEnabled: ref/Microsoft.Coyote/Configuration/WithIncrementalSeedGenerationEnabled.md - - WithVerbosityEnabled: ref/Microsoft.Coyote/Configuration/WithVerbosityEnabled.md - - WithActivityCoverageReported: ref/Microsoft.Coyote/Configuration/WithActivityCoverageReported.md - - WithDgmlGraphEnabled: ref/Microsoft.Coyote/Configuration/WithDgmlGraphEnabled.md - - WithXmlLogEnabled: ref/Microsoft.Coyote/Configuration/WithXmlLogEnabled.md - - WithTelemetryEnabled: ref/Microsoft.Coyote/Configuration/WithTelemetryEnabled.md - - Configuration: ref/Microsoft.Coyote/Configuration/Configuration.md - - SchedulingStrategy: ref/Microsoft.Coyote/Configuration/SchedulingStrategy.md - - TestingIterations: ref/Microsoft.Coyote/Configuration/TestingIterations.md - - RandomGeneratorSeed: ref/Microsoft.Coyote/Configuration/RandomGeneratorSeed.md - - MaxUnfairSchedulingSteps: ref/Microsoft.Coyote/Configuration/MaxUnfairSchedulingSteps.md - - MaxFairSchedulingSteps: ref/Microsoft.Coyote/Configuration/MaxFairSchedulingSteps.md - - TimeoutDelay: ref/Microsoft.Coyote/Configuration/TimeoutDelay.md - - DeadlockTimeout: ref/Microsoft.Coyote/Configuration/DeadlockTimeout.md - - IsVerbose: ref/Microsoft.Coyote/Configuration/IsVerbose.md - - LogLevel: ref/Microsoft.Coyote/Configuration/LogLevel.md - - Microsoft.Coyote.Actors: - - Namespace Overview: ref/Microsoft.Coyote.ActorsNamespace.md - - Actor: - - Overview: ref/Microsoft.Coyote.Actors/Actor.md - - CreateActor: ref/Microsoft.Coyote.Actors/Actor/CreateActor.md - - SendEvent: ref/Microsoft.Coyote.Actors/Actor/SendEvent.md - - ReceiveEventAsync: ref/Microsoft.Coyote.Actors/Actor/ReceiveEventAsync.md - - StartTimer: ref/Microsoft.Coyote.Actors/Actor/StartTimer.md - - StartPeriodicTimer: ref/Microsoft.Coyote.Actors/Actor/StartPeriodicTimer.md - - StopTimer: ref/Microsoft.Coyote.Actors/Actor/StopTimer.md - - RandomBoolean: ref/Microsoft.Coyote.Actors/Actor/RandomBoolean.md - - RandomInteger: ref/Microsoft.Coyote.Actors/Actor/RandomInteger.md - - Monitor: ref/Microsoft.Coyote.Actors/Actor/Monitor.md - - Assert: ref/Microsoft.Coyote.Actors/Actor/Assert.md - - RaiseHaltEvent: ref/Microsoft.Coyote.Actors/Actor/RaiseHaltEvent.md - - OnInitializeAsync: ref/Microsoft.Coyote.Actors/Actor/OnInitializeAsync.md - - OnEventDequeuedAsync: ref/Microsoft.Coyote.Actors/Actor/OnEventDequeuedAsync.md - - OnEventIgnored: ref/Microsoft.Coyote.Actors/Actor/OnEventIgnored.md - - OnEventDeferred: ref/Microsoft.Coyote.Actors/Actor/OnEventDeferred.md - - OnEventHandledAsync: ref/Microsoft.Coyote.Actors/Actor/OnEventHandledAsync.md - - OnEventUnhandledAsync: ref/Microsoft.Coyote.Actors/Actor/OnEventUnhandledAsync.md - - OnExceptionHandledAsync: ref/Microsoft.Coyote.Actors/Actor/OnExceptionHandledAsync.md - - OnHaltAsync: ref/Microsoft.Coyote.Actors/Actor/OnHaltAsync.md - - OnException: ref/Microsoft.Coyote.Actors/Actor/OnException.md - - Equals: ref/Microsoft.Coyote.Actors/Actor/Equals.md - - GetHashCode: ref/Microsoft.Coyote.Actors/Actor/GetHashCode.md - - ToString: ref/Microsoft.Coyote.Actors/Actor/ToString.md - - Actor: ref/Microsoft.Coyote.Actors/Actor/Actor.md - - Id: ref/Microsoft.Coyote.Actors/Actor/Id.md - - CurrentEventGroup: ref/Microsoft.Coyote.Actors/Actor/CurrentEventGroup.md - - Logger: ref/Microsoft.Coyote.Actors/Actor/Logger.md - - HashedState: ref/Microsoft.Coyote.Actors/Actor/HashedState.md - - ActorId: - - Overview: ref/Microsoft.Coyote.Actors/ActorId.md - - Equals: ref/Microsoft.Coyote.Actors/ActorId/Equals.md - - GetHashCode: ref/Microsoft.Coyote.Actors/ActorId/GetHashCode.md - - ToString: ref/Microsoft.Coyote.Actors/ActorId/ToString.md - - CompareTo: ref/Microsoft.Coyote.Actors/ActorId/CompareTo.md - - Runtime: ref/Microsoft.Coyote.Actors/ActorId/Runtime.md - - IsNameUsedForHashing: ref/Microsoft.Coyote.Actors/ActorId/IsNameUsedForHashing.md - - Value: ref/Microsoft.Coyote.Actors/ActorId/Value.md - - NameValue: ref/Microsoft.Coyote.Actors/ActorId/NameValue.md - - Type: ref/Microsoft.Coyote.Actors/ActorId/Type.md - - Name: ref/Microsoft.Coyote.Actors/ActorId/Name.md - - DequeueStatus: ref/Microsoft.Coyote.Actors/DequeueStatus.md - - AwaitableEventGroup: - - Overview: ref/Microsoft.Coyote.Actors/AwaitableEventGroup-1.md - - SetResult: ref/Microsoft.Coyote.Actors/AwaitableEventGroup-1/SetResult.md - - TrySetResult: ref/Microsoft.Coyote.Actors/AwaitableEventGroup-1/TrySetResult.md - - SetCancelled: ref/Microsoft.Coyote.Actors/AwaitableEventGroup-1/SetCancelled.md - - TrySetCanceled: ref/Microsoft.Coyote.Actors/AwaitableEventGroup-1/TrySetCanceled.md - - SetException: ref/Microsoft.Coyote.Actors/AwaitableEventGroup-1/SetException.md - - TrySetException: ref/Microsoft.Coyote.Actors/AwaitableEventGroup-1/TrySetException.md - - GetAwaiter: ref/Microsoft.Coyote.Actors/AwaitableEventGroup-1/GetAwaiter.md - - AwaitableEventGroup: ref/Microsoft.Coyote.Actors/AwaitableEventGroup-1/AwaitableEventGroup.md - - Task: ref/Microsoft.Coyote.Actors/AwaitableEventGroup-1/Task.md - - IsCompleted: ref/Microsoft.Coyote.Actors/AwaitableEventGroup-1/IsCompleted.md - - IsCanceled: ref/Microsoft.Coyote.Actors/AwaitableEventGroup-1/IsCanceled.md - - IsFaulted: ref/Microsoft.Coyote.Actors/AwaitableEventGroup-1/IsFaulted.md - - DefaultEvent: - - Overview: ref/Microsoft.Coyote.Actors/DefaultEvent.md - - Instance: ref/Microsoft.Coyote.Actors/DefaultEvent/Instance.md - - EventGroup: - - Overview: ref/Microsoft.Coyote.Actors/EventGroup.md - - EventGroup: ref/Microsoft.Coyote.Actors/EventGroup/EventGroup.md - - Id: ref/Microsoft.Coyote.Actors/EventGroup/Id.md - - Name: ref/Microsoft.Coyote.Actors/EventGroup/Name.md - - '': ref/Microsoft.Coyote.Actors/EventGroup/Null.md - - HaltEvent: - - Overview: ref/Microsoft.Coyote.Actors/HaltEvent.md - - Instance: ref/Microsoft.Coyote.Actors/HaltEvent/Instance.md - - WildCardEvent: - - Overview: ref/Microsoft.Coyote.Actors/WildCardEvent.md - - WildCardEvent: ref/Microsoft.Coyote.Actors/WildCardEvent/WildCardEvent.md - - OnEventDroppedHandler: ref/Microsoft.Coyote.Actors/OnEventDroppedHandler.md - - OnExceptionOutcome: ref/Microsoft.Coyote.Actors/OnExceptionOutcome.md - - UnhandledEventException: - - Overview: ref/Microsoft.Coyote.Actors/UnhandledEventException.md - - UnhandledEvent: ref/Microsoft.Coyote.Actors/UnhandledEventException/UnhandledEvent.md - - CurrentStateName: ref/Microsoft.Coyote.Actors/UnhandledEventException/CurrentStateName.md - - IActorRuntime: - - Overview: ref/Microsoft.Coyote.Actors/IActorRuntime.md - - CreateActorId: ref/Microsoft.Coyote.Actors/IActorRuntime/CreateActorId.md - - CreateActorIdFromName: ref/Microsoft.Coyote.Actors/IActorRuntime/CreateActorIdFromName.md - - CreateActor: ref/Microsoft.Coyote.Actors/IActorRuntime/CreateActor.md - - SendEvent: ref/Microsoft.Coyote.Actors/IActorRuntime/SendEvent.md - - GetCurrentEventGroup: ref/Microsoft.Coyote.Actors/IActorRuntime/GetCurrentEventGroup.md - - RegisterLog: ref/Microsoft.Coyote.Actors/IActorRuntime/RegisterLog.md - - RemoveLog: ref/Microsoft.Coyote.Actors/IActorRuntime/RemoveLog.md - - OnEventDropped: ref/Microsoft.Coyote.Actors/IActorRuntime/OnEventDropped.md - - ActorRuntimeLogTextFormatter: - - Overview: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter.md - - OnAssertionFailure: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnAssertionFailure.md - - OnCreateActor: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnCreateActor.md - - OnCreateStateMachine: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnCreateStateMachine.md - - OnCreateMonitor: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnCreateMonitor.md - - OnCreateTimer: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnCreateTimer.md - - OnDefaultEventHandler: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnDefaultEventHandler.md - - OnEventHandlerTerminated: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnEventHandlerTerminated.md - - OnDequeueEvent: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnDequeueEvent.md - - OnEnqueueEvent: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnEnqueueEvent.md - - OnExceptionHandled: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnExceptionHandled.md - - OnExceptionThrown: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnExceptionThrown.md - - OnExecuteAction: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnExecuteAction.md - - OnGotoState: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnGotoState.md - - OnHalt: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnHalt.md - - OnMonitorExecuteAction: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnMonitorExecuteAction.md - - OnMonitorProcessEvent: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnMonitorProcessEvent.md - - OnMonitorRaiseEvent: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnMonitorRaiseEvent.md - - OnMonitorStateTransition: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnMonitorStateTransition.md - - OnMonitorError: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnMonitorError.md - - OnPopState: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnPopState.md - - OnPopStateUnhandledEvent: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnPopStateUnhandledEvent.md - - OnPushState: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnPushState.md - - OnRaiseEvent: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnRaiseEvent.md - - OnHandleRaisedEvent: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnHandleRaisedEvent.md - - OnReceiveEvent: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnReceiveEvent.md - - OnSendEvent: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnSendEvent.md - - OnStateTransition: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnStateTransition.md - - OnStopTimer: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnStopTimer.md - - OnWaitEvent: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnWaitEvent.md - - OnRandom: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnRandom.md - - OnCompleted: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/OnCompleted.md - - ActorRuntimeLogTextFormatter: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/ActorRuntimeLogTextFormatter.md - - Logger: ref/Microsoft.Coyote.Actors/ActorRuntimeLogTextFormatter/Logger.md - - IActorRuntimeLog: - - Overview: ref/Microsoft.Coyote.Actors/IActorRuntimeLog.md - - OnCreateActor: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnCreateActor.md - - OnCreateStateMachine: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnCreateStateMachine.md - - OnExecuteAction: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnExecuteAction.md - - OnSendEvent: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnSendEvent.md - - OnRaiseEvent: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnRaiseEvent.md - - OnHandleRaisedEvent: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnHandleRaisedEvent.md - - OnEnqueueEvent: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnEnqueueEvent.md - - OnDequeueEvent: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnDequeueEvent.md - - OnReceiveEvent: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnReceiveEvent.md - - OnWaitEvent: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnWaitEvent.md - - OnStateTransition: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnStateTransition.md - - OnGotoState: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnGotoState.md - - OnPushState: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnPushState.md - - OnPopState: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnPopState.md - - OnDefaultEventHandler: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnDefaultEventHandler.md - - OnEventHandlerTerminated: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnEventHandlerTerminated.md - - OnHalt: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnHalt.md - - OnPopStateUnhandledEvent: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnPopStateUnhandledEvent.md - - OnExceptionThrown: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnExceptionThrown.md - - OnExceptionHandled: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnExceptionHandled.md - - OnCreateTimer: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnCreateTimer.md - - OnStopTimer: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnStopTimer.md - - OnCreateMonitor: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnCreateMonitor.md - - OnMonitorExecuteAction: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnMonitorExecuteAction.md - - OnMonitorProcessEvent: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnMonitorProcessEvent.md - - OnMonitorRaiseEvent: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnMonitorRaiseEvent.md - - OnMonitorStateTransition: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnMonitorStateTransition.md - - OnMonitorError: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnMonitorError.md - - OnRandom: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnRandom.md - - OnAssertionFailure: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnAssertionFailure.md - - OnCompleted: ref/Microsoft.Coyote.Actors/IActorRuntimeLog/OnCompleted.md - - RuntimeFactory: - - Overview: ref/Microsoft.Coyote.Actors/RuntimeFactory.md - - Create: ref/Microsoft.Coyote.Actors/RuntimeFactory/Create.md - - SendOptions: - - Overview: ref/Microsoft.Coyote.Actors/SendOptions.md - - ToString: ref/Microsoft.Coyote.Actors/SendOptions/ToString.md - - SendOptions: ref/Microsoft.Coyote.Actors/SendOptions/SendOptions.md - - Default: ref/Microsoft.Coyote.Actors/SendOptions/Default.md - - MustHandle: ref/Microsoft.Coyote.Actors/SendOptions/MustHandle.md - - Assert: ref/Microsoft.Coyote.Actors/SendOptions/Assert.md - - HashedState: ref/Microsoft.Coyote.Actors/SendOptions/HashedState.md - - StateMachine: - - Overview: ref/Microsoft.Coyote.Actors/StateMachine.md - - RaiseEvent: ref/Microsoft.Coyote.Actors/StateMachine/RaiseEvent.md - - RaiseGotoStateEvent: ref/Microsoft.Coyote.Actors/StateMachine/RaiseGotoStateEvent.md - - RaisePushStateEvent: ref/Microsoft.Coyote.Actors/StateMachine/RaisePushStateEvent.md - - RaisePopStateEvent: ref/Microsoft.Coyote.Actors/StateMachine/RaisePopStateEvent.md - - RaiseHaltEvent: ref/Microsoft.Coyote.Actors/StateMachine/RaiseHaltEvent.md - - OnEventHandledAsync: ref/Microsoft.Coyote.Actors/StateMachine/OnEventHandledAsync.md - - StateMachine: ref/Microsoft.Coyote.Actors/StateMachine/StateMachine.md - - CurrentState: ref/Microsoft.Coyote.Actors/StateMachine/CurrentState.md - - Actor.OnEventDoActionAttribute: - - Overview: ref/Microsoft.Coyote.Actors/Actor.OnEventDoActionAttribute.md - - OnEventDoActionAttribute: ref/Microsoft.Coyote.Actors/Actor.OnEventDoActionAttribute/OnEventDoActionAttribute.md - - StateMachine.State: - - Overview: ref/Microsoft.Coyote.Actors/StateMachine.State.md - - State: ref/Microsoft.Coyote.Actors/StateMachine.State/State.md - - StateMachine.StateGroup: - - Overview: ref/Microsoft.Coyote.Actors/StateMachine.StateGroup.md - - StateGroup: ref/Microsoft.Coyote.Actors/StateMachine.StateGroup/StateGroup.md - - StateMachine.State.StartAttribute: - - Overview: ref/Microsoft.Coyote.Actors/StateMachine.State.StartAttribute.md - - StartAttribute: ref/Microsoft.Coyote.Actors/StateMachine.State.StartAttribute/StartAttribute.md - - StateMachine.State.OnEntryAttribute: - - Overview: ref/Microsoft.Coyote.Actors/StateMachine.State.OnEntryAttribute.md - - OnEntryAttribute: ref/Microsoft.Coyote.Actors/StateMachine.State.OnEntryAttribute/OnEntryAttribute.md - - StateMachine.State.OnExitAttribute: - - Overview: ref/Microsoft.Coyote.Actors/StateMachine.State.OnExitAttribute.md - - OnExitAttribute: ref/Microsoft.Coyote.Actors/StateMachine.State.OnExitAttribute/OnExitAttribute.md - - StateMachine.State.OnEventGotoStateAttribute: - - Overview: ref/Microsoft.Coyote.Actors/StateMachine.State.OnEventGotoStateAttribute.md - - OnEventGotoStateAttribute: ref/Microsoft.Coyote.Actors/StateMachine.State.OnEventGotoStateAttribute/OnEventGotoStateAttribute.md - - StateMachine.State.OnEventPushStateAttribute: - - Overview: ref/Microsoft.Coyote.Actors/StateMachine.State.OnEventPushStateAttribute.md - - OnEventPushStateAttribute: ref/Microsoft.Coyote.Actors/StateMachine.State.OnEventPushStateAttribute/OnEventPushStateAttribute.md - - StateMachine.State.OnEventDoActionAttribute: - - Overview: ref/Microsoft.Coyote.Actors/StateMachine.State.OnEventDoActionAttribute.md - - OnEventDoActionAttribute: ref/Microsoft.Coyote.Actors/StateMachine.State.OnEventDoActionAttribute/OnEventDoActionAttribute.md - - StateMachine.State.DeferEventsAttribute: - - Overview: ref/Microsoft.Coyote.Actors/StateMachine.State.DeferEventsAttribute.md - - DeferEventsAttribute: ref/Microsoft.Coyote.Actors/StateMachine.State.DeferEventsAttribute/DeferEventsAttribute.md - - StateMachine.State.IgnoreEventsAttribute: - - Overview: ref/Microsoft.Coyote.Actors/StateMachine.State.IgnoreEventsAttribute.md - - IgnoreEventsAttribute: ref/Microsoft.Coyote.Actors/StateMachine.State.IgnoreEventsAttribute/IgnoreEventsAttribute.md - - Microsoft.Coyote.Actors.Coverage: - - Namespace Overview: ref/Microsoft.Coyote.Actors.CoverageNamespace.md - - EventCoverage: - - Overview: ref/Microsoft.Coyote.Actors.Coverage/EventCoverage.md - - GetEventsReceived: ref/Microsoft.Coyote.Actors.Coverage/EventCoverage/GetEventsReceived.md - - GetEventsSent: ref/Microsoft.Coyote.Actors.Coverage/EventCoverage/GetEventsSent.md - - EventCoverage: ref/Microsoft.Coyote.Actors.Coverage/EventCoverage/EventCoverage.md - - ActorRuntimeLogGraphBuilder: - - Overview: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder.md - - OnCreateActor: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnCreateActor.md - - OnCreateStateMachine: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnCreateStateMachine.md - - OnSendEvent: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnSendEvent.md - - OnRaiseEvent: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnRaiseEvent.md - - OnHandleRaisedEvent: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnHandleRaisedEvent.md - - OnEnqueueEvent: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnEnqueueEvent.md - - OnDequeueEvent: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnDequeueEvent.md - - OnReceiveEvent: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnReceiveEvent.md - - OnWaitEvent: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnWaitEvent.md - - OnStateTransition: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnStateTransition.md - - OnExecuteAction: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnExecuteAction.md - - OnGotoState: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnGotoState.md - - OnPushState: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnPushState.md - - OnPopState: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnPopState.md - - OnHalt: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnHalt.md - - OnDefaultEventHandler: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnDefaultEventHandler.md - - OnEventHandlerTerminated: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnEventHandlerTerminated.md - - OnPopStateUnhandledEvent: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnPopStateUnhandledEvent.md - - OnExceptionThrown: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnExceptionThrown.md - - OnExceptionHandled: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnExceptionHandled.md - - OnCreateTimer: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnCreateTimer.md - - OnStopTimer: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnStopTimer.md - - OnCreateMonitor: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnCreateMonitor.md - - OnMonitorExecuteAction: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnMonitorExecuteAction.md - - OnMonitorProcessEvent: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnMonitorProcessEvent.md - - OnMonitorRaiseEvent: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnMonitorRaiseEvent.md - - OnMonitorStateTransition: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnMonitorStateTransition.md - - OnMonitorError: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnMonitorError.md - - OnRandom: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnRandom.md - - OnAssertionFailure: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnAssertionFailure.md - - OnCompleted: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/OnCompleted.md - - SnapshotGraph: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/SnapshotGraph.md - - ActorRuntimeLogGraphBuilder: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/ActorRuntimeLogGraphBuilder.md - - CollapseMachineInstances: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/CollapseMachineInstances.md - - Logger: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/Logger.md - - Graph: ref/Microsoft.Coyote.Actors.Coverage/ActorRuntimeLogGraphBuilder/Graph.md - Graph: - Overview: ref/Microsoft.Coyote.Actors.Coverage/Graph.md - GetNode: ref/Microsoft.Coyote.Actors.Coverage/Graph/GetNode.md @@ -1121,4 +572,76 @@ nav: - Monitor.State.HotAttribute: - Overview: ref/Microsoft.Coyote.Specifications/Monitor.State.HotAttribute.md - HotAttribute: ref/Microsoft.Coyote.Specifications/Monitor.State.HotAttribute/HotAttribute.md + - Microsoft.Coyote.Test: + - Overview: ref/Microsoft.Coyote.Test.md + - Microsoft.Coyote.Rewriting: + - Namespace Overview: ref/Microsoft.Coyote.RewritingNamespace.md + - RewritingSignatureAttribute: + - Overview: ref/Microsoft.Coyote.Rewriting/RewritingSignatureAttribute.md + - RewritingSignatureAttribute: ref/Microsoft.Coyote.Rewriting/RewritingSignatureAttribute/RewritingSignatureAttribute.md + - Version: ref/Microsoft.Coyote.Rewriting/RewritingSignatureAttribute/Version.md + - Signature: ref/Microsoft.Coyote.Rewriting/RewritingSignatureAttribute/Signature.md + - RewritingEngine: + - Overview: ref/Microsoft.Coyote.Rewriting/RewritingEngine.md + - IsAssemblyRewritten: ref/Microsoft.Coyote.Rewriting/RewritingEngine/IsAssemblyRewritten.md + - Microsoft.Coyote.SystematicTesting: + - Namespace Overview: ref/Microsoft.Coyote.SystematicTestingNamespace.md + - TestReport: + - Overview: ref/Microsoft.Coyote.SystematicTesting/TestReport.md + - Merge: ref/Microsoft.Coyote.SystematicTesting/TestReport/Merge.md + - GetText: ref/Microsoft.Coyote.SystematicTesting/TestReport/GetText.md + - Clone: ref/Microsoft.Coyote.SystematicTesting/TestReport/Clone.md + - TestReport: ref/Microsoft.Coyote.SystematicTesting/TestReport/TestReport.md + - Configuration: ref/Microsoft.Coyote.SystematicTesting/TestReport/Configuration.md + - CoverageInfo: ref/Microsoft.Coyote.SystematicTesting/TestReport/CoverageInfo.md + - NumOfExploredFairSchedules: ref/Microsoft.Coyote.SystematicTesting/TestReport/NumOfExploredFairSchedules.md + - NumOfExploredUnfairSchedules: ref/Microsoft.Coyote.SystematicTesting/TestReport/NumOfExploredUnfairSchedules.md + - NumOfFoundBugs: ref/Microsoft.Coyote.SystematicTesting/TestReport/NumOfFoundBugs.md + - BugReports: ref/Microsoft.Coyote.SystematicTesting/TestReport/BugReports.md + - UncontrolledInvocations: ref/Microsoft.Coyote.SystematicTesting/TestReport/UncontrolledInvocations.md + - MinControlledOperations: ref/Microsoft.Coyote.SystematicTesting/TestReport/MinControlledOperations.md + - MaxControlledOperations: ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxControlledOperations.md + - TotalControlledOperations: ref/Microsoft.Coyote.SystematicTesting/TestReport/TotalControlledOperations.md + - MinConcurrencyDegree: ref/Microsoft.Coyote.SystematicTesting/TestReport/MinConcurrencyDegree.md + - MaxConcurrencyDegree: ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxConcurrencyDegree.md + - TotalConcurrencyDegree: ref/Microsoft.Coyote.SystematicTesting/TestReport/TotalConcurrencyDegree.md + - MinExploredFairSteps: ref/Microsoft.Coyote.SystematicTesting/TestReport/MinExploredFairSteps.md + - MaxExploredFairSteps: ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxExploredFairSteps.md + - TotalExploredFairSteps: ref/Microsoft.Coyote.SystematicTesting/TestReport/TotalExploredFairSteps.md + - MaxFairStepsHitInFairTests: ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxFairStepsHitInFairTests.md + - MaxUnfairStepsHitInFairTests: ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxUnfairStepsHitInFairTests.md + - MaxUnfairStepsHitInUnfairTests: ref/Microsoft.Coyote.SystematicTesting/TestReport/MaxUnfairStepsHitInUnfairTests.md + - InternalErrors: ref/Microsoft.Coyote.SystematicTesting/TestReport/InternalErrors.md + - TestAttribute: + - Overview: ref/Microsoft.Coyote.SystematicTesting/TestAttribute.md + - TestAttribute: ref/Microsoft.Coyote.SystematicTesting/TestAttribute/TestAttribute.md + - TestInitAttribute: + - Overview: ref/Microsoft.Coyote.SystematicTesting/TestInitAttribute.md + - TestInitAttribute: ref/Microsoft.Coyote.SystematicTesting/TestInitAttribute/TestInitAttribute.md + - TestDisposeAttribute: + - Overview: ref/Microsoft.Coyote.SystematicTesting/TestDisposeAttribute.md + - TestDisposeAttribute: ref/Microsoft.Coyote.SystematicTesting/TestDisposeAttribute/TestDisposeAttribute.md + - TestIterationDisposeAttribute: + - Overview: ref/Microsoft.Coyote.SystematicTesting/TestIterationDisposeAttribute.md + - TestIterationDisposeAttribute: ref/Microsoft.Coyote.SystematicTesting/TestIterationDisposeAttribute/TestIterationDisposeAttribute.md + - TestingEngine: + - Overview: ref/Microsoft.Coyote.SystematicTesting/TestingEngine.md + - Create: ref/Microsoft.Coyote.SystematicTesting/TestingEngine/Create.md + - Run: ref/Microsoft.Coyote.SystematicTesting/TestingEngine/Run.md + - Stop: ref/Microsoft.Coyote.SystematicTesting/TestingEngine/Stop.md + - GetReport: ref/Microsoft.Coyote.SystematicTesting/TestingEngine/GetReport.md + - ThrowIfBugFound: ref/Microsoft.Coyote.SystematicTesting/TestingEngine/ThrowIfBugFound.md + - TryEmitReports: ref/Microsoft.Coyote.SystematicTesting/TestingEngine/TryEmitReports.md + - TryEmitCoverageReports: ref/Microsoft.Coyote.SystematicTesting/TestingEngine/TryEmitCoverageReports.md + - RegisterPerIterationCallBack: ref/Microsoft.Coyote.SystematicTesting/TestingEngine/RegisterPerIterationCallBack.md + - IsTestRewritten: ref/Microsoft.Coyote.SystematicTesting/TestingEngine/IsTestRewritten.md + - TestReport: ref/Microsoft.Coyote.SystematicTesting/TestingEngine/TestReport.md + - Logger: ref/Microsoft.Coyote.SystematicTesting/TestingEngine/Logger.md + - ReadableTrace: ref/Microsoft.Coyote.SystematicTesting/TestingEngine/ReadableTrace.md + - ReproducibleTrace: ref/Microsoft.Coyote.SystematicTesting/TestingEngine/ReproducibleTrace.md + - Microsoft.Coyote.Web: + - Namespace Overview: ref/Microsoft.Coyote.WebNamespace.md + - RequestControllerMiddlewareExtensions: + - Overview: ref/Microsoft.Coyote.Web/RequestControllerMiddlewareExtensions.md + - UseRequestController: ref/Microsoft.Coyote.Web/RequestControllerMiddlewareExtensions/UseRequestController.md ...