/// <summary> /// Runs the next testing iteration. /// </summary> /// <param name="iteration">Iteration</param> private void RunNextIteration(int iteration) { if (this.ShouldPrintIteration(iteration + 1)) { base.Logger.WriteLine($"..... Iteration #{iteration + 1}"); } // Runtime used to serialize and test the program in this iteration. BugFindingRuntime runtime = null; // Logger used to intercept the program output if no custom logger // is installed and if verbosity is turned off. InMemoryLogger runtimeLogger = null; // Gets a handle to the standard output and error streams. var stdOut = Console.Out; var stdErr = Console.Error; try { // Creates a new instance of the bug-finding runtime. runtime = new BugFindingRuntime(base.Configuration, base.Strategy); // If verbosity is turned off, then intercept the program log, and also dispose // the standard output and error streams. if (base.Configuration.Verbose < 2) { runtimeLogger = new InMemoryLogger(); runtime.SetLogger(runtimeLogger); var writer = new LogWriter(new DisposingLogger()); Console.SetOut(writer); Console.SetError(writer); } // Runs the test inside the P# test-harness machine. runtime.RunTestHarness(base.TestMethod, base.TestAction); // Wait for the test to terminate. runtime.Wait(); if (runtime.Scheduler.BugFound) { base.ErrorReporter.WriteErrorLine(runtime.Scheduler.BugReport); } if (this.Configuration.EnableDataRaceDetection) { this.EmitRaceInstrumentationTraces(runtime, iteration); } // Invokes user-provided cleanup for this iteration. if (base.TestIterationDisposeMethod != null) { // Disposes the test state. base.TestIterationDisposeMethod.Invoke(null, null); } // Invoke the per iteration callbacks, if any. foreach (var callback in base.PerIterationCallbacks) { callback(iteration); } // TODO: Clean this up. base.Configuration.RaceDetectionCallback?.Invoke(); if (base.Configuration.RaceFound) { string message = IO.Utilities.Format("Found a race"); runtime.Scheduler.NotifyAssertionFailure(message, false); } // Checks for any liveness property violations. Requires // that the program has terminated and no safety property // violations have been found. if (!runtime.Scheduler.BugFound) { runtime.LivenessChecker.CheckLivenessAtTermination(); } this.GatherIterationStatistics(runtime); if (runtimeLogger != null && base.TestReport.NumOfFoundBugs > 0 && !base.Configuration.PerformFullExploration && !base.Configuration.SuppressTrace) { this.ConstructReproducableTrace(runtime, runtimeLogger); } else if (runtimeLogger != null && base.Configuration.PrintTrace) { this.ConstructReproducableTrace(runtime, runtimeLogger); } } finally { if (base.Configuration.Verbose < 2) { // Restores the standard output and error streams. Console.SetOut(stdOut); Console.SetError(stdErr); } if (base.Configuration.PerformFullExploration && runtime.Scheduler.BugFound) { base.Logger.WriteLine($"..... Iteration #{iteration + 1} " + $"triggered bug #{base.TestReport.NumOfFoundBugs} " + $"[task-{this.Configuration.TestingProcessId}]"); } // Cleans up the runtime before the next iteration starts. runtimeLogger?.Dispose(); runtime?.Dispose(); } }
/// <summary> /// Runs the next testing iteration. /// </summary> /// <param name="iteration">Iteration</param> private void RunNextIteration(int iteration) { if (this.ShouldPrintIteration(iteration + 1)) { base.Logger.WriteLine($"..... Iteration #{iteration + 1}"); } // Runtime used to serialize and test the program in this iteration. BugFindingRuntime runtime = null; // Logger used to intercept the program output if no custom logger // is installed and if verbosity is turned off. InMemoryLogger runtimeLogger = null; // Gets a handle to the standard output and error streams. var stdOut = Console.Out; var stdErr = Console.Error; try { // Creates a new instance of the bug-finding runtime. runtime = new BugFindingRuntime(base.Configuration, base.Strategy, base.Reporter); if (base.Configuration.EnableDataRaceDetection) { // Create a reporter to monitor interesting operations for race detection this.Reporter.SetRuntime(runtime); } // If verbosity is turned off, then intercept the program log, and also dispose // the standard output and error streams. if (base.Configuration.Verbose < 2) { runtimeLogger = new InMemoryLogger(); runtime.SetLogger(runtimeLogger); // Sets the scheduling strategy logger to the in-memory logger. base.SchedulingStrategyLogger.SetLogger(runtimeLogger); var writer = new LogWriter(new DisposingLogger()); Console.SetOut(writer); Console.SetError(writer); } // Runs the test inside the P# test-harness machine. runtime.RunTestHarness(base.TestMethod, base.TestAction); // Wait for the test to terminate. runtime.Wait(); if (runtime.Scheduler.BugFound) { base.ErrorReporter.WriteErrorLine(runtime.Scheduler.BugReport); } // Invokes user-provided cleanup for this iteration. if (base.TestIterationDisposeMethod != null) { // Disposes the test state. base.TestIterationDisposeMethod.Invoke(null, null); } // Invoke the per iteration callbacks, if any. foreach (var callback in base.PerIterationCallbacks) { callback(iteration); } if (base.Configuration.RaceFound) { string message = IO.Utilities.Format("Found a race"); runtime.Scheduler.NotifyAssertionFailure(message, false); foreach (var report in this.TestReport.BugReports) { runtime.Logger.WriteLine(report); } } // Checks that no monitor is in a hot state at termination. Only // checked if no safety property violations have been found. if (!runtime.Scheduler.BugFound) { runtime.AssertNoMonitorInHotStateAtTermination(); } this.GatherIterationStatistics(runtime); if (base.TestReport.NumOfFoundBugs > 0) { if (runtimeLogger != null) { this.ReadableTrace = runtimeLogger.ToString(); this.ReadableTrace += this.TestReport.GetText(base.Configuration, "<StrategyLog>"); } this.BugTrace = runtime.BugTrace; this.ConstructReproducableTrace(runtime); } } finally { if (base.Configuration.Verbose < 2) { // Restores the standard output and error streams. Console.SetOut(stdOut); Console.SetError(stdErr); } if (base.Configuration.PerformFullExploration && runtime.Scheduler.BugFound) { base.Logger.WriteLine($"..... Iteration #{iteration + 1} " + $"triggered bug #{base.TestReport.NumOfFoundBugs} " + $"[task-{this.Configuration.TestingProcessId}]"); } // Resets the scheduling strategy logger to the default logger. base.SchedulingStrategyLogger.ResetToDefaultLogger(); // Cleans up the runtime before the next iteration starts. runtimeLogger?.Dispose(); runtime?.Dispose(); } }
/// <summary> /// Creates a bug-reproducing task. /// </summary> /// <returns>Task</returns> private Task CreateBugReproducingTask() { Task task = new Task(() => { // Runtime used to serialize and test the program. BugFindingRuntime runtime = null; // Logger used to intercept the program output if no custom logger // is installed and if verbosity is turned off. InMemoryLogger runtimeLogger = null; // Gets a handle to the standard output and error streams. var stdOut = Console.Out; var stdErr = Console.Error; try { if (base.TestInitMethod != null) { // Initializes the test state. base.TestInitMethod.Invoke(null, new object[] { }); } // Creates a new instance of the bug-finding runtime. runtime = new BugFindingRuntime(base.Configuration, base.Strategy, base.Reporter); // If verbosity is turned off, then intercept the program log, and also redirect // the standard output and error streams into the runtime logger. if (base.Configuration.Verbose < 2) { runtimeLogger = new InMemoryLogger(); runtime.SetLogger(runtimeLogger); var writer = new LogWriter(new DisposingLogger()); Console.SetOut(writer); Console.SetError(writer); } // Runs the test inside the P# test-harness machine. runtime.RunTestHarness(base.TestMethod, base.TestAction); // Wait for the test to terminate. runtime.Wait(); this.InternalError = (base.Strategy as ReplayStrategy).ErrorText; if (runtime.Scheduler.BugFound && this.InternalError.Length == 0) { base.ErrorReporter.WriteErrorLine(runtime.Scheduler.BugReport); } // Invokes user-provided cleanup for this iteration. if (base.TestIterationDisposeMethod != null) { // Disposes the test state. base.TestIterationDisposeMethod.Invoke(null, new object[] { }); } // Invokes user-provided cleanup for all iterations. if (base.TestDisposeMethod != null) { // Disposes the test state. base.TestDisposeMethod.Invoke(null, new object[] { }); } // Checks that no monitor is in a hot state at termination. Only // checked if no safety property violations have been found. if (!runtime.Scheduler.BugFound && this.InternalError.Length == 0) { runtime.AssertNoMonitorInHotStateAtTermination(); } TestReport report = runtime.Scheduler.GetReport(); report.CoverageInfo.Merge(runtime.CoverageInfo); this.TestReport.Merge(report); } catch (TargetInvocationException ex) { if (!(ex.InnerException is TaskCanceledException)) { ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); } } finally { if (base.Configuration.Verbose < 2) { // Restores the standard output and error streams. Console.SetOut(stdOut); Console.SetError(stdErr); } // Cleans up the runtime. runtimeLogger?.Dispose(); runtime?.Dispose(); } }, base.CancellationTokenSource.Token); return(task); }