[TestCategory("Scheduler_NonDeterministic_Strong")] // Tests timing. public void Scheduler_RecursiveTimerEvent() { const int Count = 3; var period = TimeSpan.FromSeconds(0.1); var beforeAllAreDue = TimeSpan.FromSeconds(0.3); var afterAllWereDue = TimeSpan.FromSeconds(0.5); using var scheduler = _root.CreateChildScheduler(); int recursiveCall = 0; var worked = new AutoResetEvent(false); bool action(IScheduler s) { if (recursiveCall < Count) { recursiveCall++; s.Schedule(period, ActionTask.Create(action, 0)); } else { worked.Set(); } return(true); } var task = ActionTask.Create(action, 0); scheduler.Schedule(period, task); Assert.IsFalse(worked.WaitOne(beforeAllAreDue)); // NB: This is non-deterministic. Assert.IsTrue(worked.WaitOne(afterAllWereDue)); // NB: This is non-deterministic. }
[TestCategory("Scheduler_NonDeterministic_Strong")] // Tests timing. public void Scheduler_TwoTimerEventsInReverseOrder() { var task1Due = TimeSpan.FromSeconds(0.3); var task2Due = TimeSpan.FromSeconds(0.1); using var scheduler = _root.CreateChildScheduler(); var worked1 = new AutoResetEvent(false); var task1 = ActionTask.Create( s => { worked1.Set(); return(true); }, 0); var worked2 = new AutoResetEvent(false); var task2 = ActionTask.Create( s => { worked2.Set(); return(true); }, 0); scheduler.Schedule(task1Due, task1); scheduler.Schedule(task2Due, task2); // NB: This is non-deterministic. Assert.AreEqual(1, WaitHandle.WaitAny(new[] { worked1, worked2 })); worked1.WaitOne(); // REVIEW: We don't really test the order the tasks executed in. }
public void Scheduler_Access_Physical() { using var ph = PhysicalScheduler.Create(); Assert.IsFalse(ph.CheckAccess()); Assert.ThrowsException <InvalidOperationException>(() => ph.VerifyAccess()); using var l = new LogicalScheduler(ph); Assert.IsFalse(l.CheckAccess()); Assert.ThrowsException <InvalidOperationException>(() => l.VerifyAccess()); var e = new ManualResetEvent(false); var b = false; l.Schedule(ActionTask.Create(_ => { b = l.CheckAccess() && ph.CheckAccess(); l.VerifyAccess(); ph.VerifyAccess(); e.Set(); return(true); }, 1)); e.WaitOne(); Assert.IsTrue(b); }
protected override void InitializeModules() { Core.Initialize(new CoreSupport()); LoadingManager.Instance.Enqueue(ActionTask.Create("initializeModules", this.DoInitializeModules)); LoadingManager.Instance.Enqueue(new RepositoryManager.LoadRepositoriesTask(RepositoryManager.Instance)); LoadingManager.Instance.Enqueue( new DockingViewManager.DocumentManagerImpl.RestoreDocumentsTask( (DockingViewManager.DocumentManagerImpl)DockingViewManager.Instance.DocumentManager)); LoadingManager.Instance.Enqueue(ActionTask.Create("onModulesLoaded", this.OnModulesLoaded)); var shell = (Shell)this.Shell; shell.Hide(); this.CreateSplash(); while (!_isSplashCreated) { Thread.Sleep(100); } LoadingManager.Instance.BeginLoad() .ContinueWith( t => { App.BeginInvokeBackground(this.ShowShell); }); }
public void Scheduler_WorkItemBase_Order() { var s = new Scheduler(); var d = new Disposable(); var a1 = ActionTask.Create(_ => true, 17); var t1 = 42; var a2 = ActionTask.Create(_ => true, 18); var t2 = 41; var a3 = ActionTask.Create(_ => true, 19); var t3 = 43; var a4 = ActionTask.Create(_ => true, 16); var t4 = 41; var w1 = new WorkItemBase <int>(s, a1, t1, d); var w2 = new WorkItemBase <int>(s, a2, t2, d); var w3 = new WorkItemBase <int>(s, a3, t3, d); var w4 = new WorkItemBase <int>(s, a4, t4, d); var res = new[] { w1, w2, w3, w4 }.OrderBy(x => x).ToList(); Assert.IsTrue(new[] { w4, w2, w1, w3 }.SequenceEqual(res)); }
[TestCategory("Scheduler_NonDeterministic_Weak")] // May time-out and be inconclusive. public void Scheduler_1000TimerTasks() { const int NumberOfTasks = 1000; using var scheduler = _root.CreateChildScheduler(); int count = 0; var worked = new AutoResetEvent(false); var task = ActionTask.Create( s => { if (Interlocked.Increment(ref count) == NumberOfTasks) { worked.Set(); } return(true); }, 0); var random = new Random(Seed); for (int i = 0; i < NumberOfTasks; ++i) { scheduler.Schedule(TimeSpan.FromMilliseconds(random.Next(5, 900)), task); } WaitForSoon(worked); // NB: This is non-deterministic. }
[TestCategory("Scheduler_NonDeterministic_Weak")] // May time-out and be inconclusive. public void Scheduler_TestRunnableStateChange() { using var scheduler = _root.CreateChildScheduler(); var worked = new AutoResetEvent(false); var task = ActionTask.Create( s => { worked.Set(); return(true); }, 0); task.IsRunnable = false; scheduler.Schedule(task); WaitForNever(worked); // NB: This is non-deterministic, but should not be flaky in the happy case. task.IsRunnable = true; scheduler.RecalculatePriority(); WaitForSoon(worked); // NB: This is non-deterministic. }
public void Scheduler_ErrorHandling_HandlePhysical() { using var ph = PhysicalScheduler.Create(); var ex = new Exception(); var err = default(Exception); var evt = new ManualResetEvent(false); var sh = default(IScheduler); var fs = default(IScheduler); ph.UnhandledException += (o, e) => { err = e.Exception; e.Handled = true; sh = e.Scheduler; evt.Set(); }; using (var s = new LogicalScheduler(ph)) { s.Schedule(ActionTask.Create(_ => { fs = s; throw ex; }, 1)); evt.WaitOne(); } Assert.AreSame(ex, err); Assert.AreSame(fs, sh); }
[TestCategory("Scheduler_NonDeterministic_Weak")] // May time-out and be inconclusive. public void Scheduler_TestMultipleLogicalSchedulers() { const int NumberOfTasks = 100; const int NumberOfSchedulers = 5; using var scheduler = _root.CreateChildScheduler(); var schedulers = new List <IScheduler>(); for (int i = 0; i < NumberOfSchedulers; ++i) { schedulers.Add(scheduler.CreateChildScheduler()); } var started = new AutoResetEvent(false); var worked = new AutoResetEvent(false); int counter = 0; for (int i = 0; i < NumberOfTasks; ++i) { var j = i; schedulers[j % NumberOfSchedulers].Schedule(ActionTask.Create( s => { if (Interlocked.Increment(ref counter) == NumberOfTasks) { worked.Set(); } started.Set(); Thread.Sleep(TimeSpan.FromMilliseconds(new Random(Seed + j).Next(10, 20))); return(true); }, 0)); } WaitWithTimeout(started); scheduler.PauseAsync().Wait(); int intermediateCounter = counter; Assert.AreNotEqual(0, counter); Assert.AreNotEqual(NumberOfTasks, counter); started.Reset(); WaitForNever(started); // NB: This is non-deterministic, but should not be flaky in the happy case. Assert.AreEqual(intermediateCounter, counter); scheduler.Continue(); WaitWithTimeout(worked); }
public void Scheduler_PerformanceCounters_Time() { using var scheduler = _root.CreateChildScheduler(); const int N = 4; const int DelayInMs = 50; // NB: See remarks on AssertTimerTickCount. for (var i = 0; i < N; i++) { var worked = new AutoResetEvent(false); // // Schedule work with a due time. // scheduler.Schedule(TimeSpan.FromMilliseconds(DelayInMs), ActionTask.Create( s => { worked.Set(); return(true); }, 0)); // // Resume the scheduler if we were previously paused. This accummulates PausedTime to assert on. // if (i > 0) { scheduler.Continue(); } // // Wait for the work to be completed. // worked.WaitOne(); // // Pause the scheduler to wait for all the worker threads to stop processing work. // // NB: This is critical for the asserts, because accounting happens after the user work completes, // and our user code signals an event, so we end up with a race between threads. By pausing, we // ensure the tasks have drained completely. // scheduler.PauseAsync().Wait(); } // // Check the counters of the child scheduler. // var childCounters = ((ISchedulerPerformanceCountersProvider)scheduler).QueryPerformanceCounters(includeChildren: false);
public void Scheduler_WorkItemBase_ArgumentChecking() { var s = new Scheduler(); var a = ActionTask.Create(_ => true, 1); var d = new Disposable(); #pragma warning disable IDE0034 // Simplify 'default' expression (documents the signature) Assert.ThrowsException <ArgumentNullException>(() => new WorkItemBase <int>(default(IScheduler), a, 0, d)); Assert.ThrowsException <ArgumentNullException>(() => new WorkItemBase <int>(s, default(ISchedulerTask), 0, d)); Assert.ThrowsException <ArgumentNullException>(() => new WorkItemBase <int>(s, a, 0, default(IDisposable))); #pragma warning restore IDE0034 // Simplify 'default' expression }
public void NopScheduler_SwallowAllWork() { using var p = PhysicalScheduler.Create(); var l = new LogicalScheduler(p); l.Dispose(); var n = l.CreateChildScheduler(); var o = n.CreateChildScheduler(); Assert.IsTrue(n.CheckAccess()); Assert.IsTrue(o.CheckAccess()); n.VerifyAccess(); o.VerifyAccess(); var hasError = false; var h = new EventHandler <SchedulerUnhandledExceptionEventArgs>((_, e) => { hasError = true; }); n.UnhandledException += h; var failed = false; var fail = ActionTask.Create(s => { failed = true; throw new Exception(); }, 1); o.Schedule(fail); o.Schedule(TimeSpan.Zero, fail); o.Schedule(DateTimeOffset.UtcNow, fail); o.RecalculatePriority(); Task.Run(async() => { await o.PauseAsync(); o.Continue(); }).Wait(); n.UnhandledException -= h; Assert.IsFalse(failed); Assert.IsFalse(hasError); var d = o.Now - DateTimeOffset.UtcNow; Assert.IsTrue(d < TimeSpan.FromMinutes(1)); n.Dispose(); o.Dispose(); }
public void Scheduler_ErrorHandling_Logical_Chain() { using var ph = PhysicalScheduler.Create(); var ex = new Exception(); var err = default(Exception); var evt = new ManualResetEvent(false); var log = new List <string>(); var sh = default(IScheduler); var fs = default(IScheduler); ph.UnhandledException += (o, e) => { log.Add("ph"); }; using (var s = new LogicalScheduler(ph)) { s.UnhandledException += (o, e) => { log.Add("s"); err = e.Exception; e.Handled = true; sh = e.Scheduler; evt.Set(); }; #pragma warning disable IDE0063 // Use simple 'using' statement (indentation helps to document the parent-child relationship) using (var c1 = s.CreateChildScheduler()) { c1.UnhandledException += (o, e) => { log.Add("c1"); }; using (var c2 = c1.CreateChildScheduler()) { c2.UnhandledException += (o, e) => { log.Add("c2"); }; c2.Schedule(ActionTask.Create(_ => { fs = c2; throw ex; }, 1)); evt.WaitOne(); } } #pragma warning restore IDE0063 // Use simple 'using' statement } Assert.IsTrue(new[] { "c2", "c1", "s" }.SequenceEqual(log)); Assert.AreSame(ex, err); Assert.AreSame(fs, sh); }
[TestCategory("Scheduler_NonDeterministic_Weak")] // May time-out and be inconclusive. public void Scheduler_TestPauseContinue() { const int NumberOfTasks = 100; using var scheduler = _root.CreateChildScheduler(); var worked = new AutoResetEvent(false); var started = new AutoResetEvent(false); var @continue = new ManualResetEvent(false); int counter = 0; for (int i = 0; i < NumberOfTasks; ++i) { scheduler.Schedule(ActionTask.Create( s => { started.Set(); if (Interlocked.Increment(ref counter) == NumberOfTasks) { worked.Set(); } WaitWithTimeout(@continue); return(true); }, 0)); } WaitForSoon(started); // NB: This is non-deterministic. var pauseTask = scheduler.PauseAsync(); @continue.Set(); pauseTask.Wait(); int intermediateValue = counter; Assert.AreNotEqual(0, counter); Assert.AreNotEqual(NumberOfTasks, counter); started.Reset(); WaitForNever(started); // NB: This is non-deterministic, but should not be flaky in the happy case. Assert.AreEqual(intermediateValue, counter); scheduler.Continue(); WaitWithTimeout(worked); }
[TestCategory("Scheduler_NonDeterministic_Weak")] // May time-out and be inconclusive. public void Scheduler_PauseFromWithinATask() { using var scheduler = _root.CreateChildScheduler(); var worked = new AutoResetEvent(false); scheduler.Schedule(ActionTask.Create( s => { scheduler.PauseAsync().ContinueWith(_ => { worked.Set(); }); return(true); }, 0)); WaitForSoon(worked); // NB: This is non-deterministic. }
[TestCategory("Scheduler_NonDeterministic_Weak")] // May time-out and be inconclusive. public void Scheduler_NegativeTimer() { using var scheduler = _root.CreateChildScheduler(); var worked = new AutoResetEvent(false); scheduler.Schedule(TimeSpan.FromSeconds(-2), ActionTask.Create( s => { worked.Set(); return(true); }, 0)); WaitForVerySoon(worked); // NB: This is non-deterministic. }
[TestCategory("Scheduler_NonDeterministic_Weak")] // May time-out and be inconclusive. public void Scheduler_TestSimpleTask() { using var scheduler = _root.CreateChildScheduler(); var worked = new AutoResetEvent(false); scheduler.Schedule(ActionTask.Create( s => { worked.Set(); return(true); }, 0)); WaitForSoon(worked); // NB: This is non-deterministic. }
public void Scheduler_ThrowingTask() { const int NumberOfTasks = 1000; const int NumberOfExceptions = 10; using var scheduler = _root.CreateChildScheduler(); var ex = new ArgumentNullException(); scheduler.UnhandledException += (o, e) => { Assert.AreSame(ex, e.Exception); e.Handled = true; }; int counter = 0; int exceptionCounter = 0; var worked = new AutoResetEvent(false); for (int i = 0; i < NumberOfTasks; ++i) { scheduler.Schedule(ActionTask.Create( s => { lock (worked) { counter++; if (counter % 3 == 0 && exceptionCounter < NumberOfExceptions) { exceptionCounter++; throw ex; } if (counter == NumberOfTasks - NumberOfExceptions) { worked.Set(); } } return(true); }, 0)); } WaitWithTimeout(worked); }
public void Scheduler_WorkItemBase_Simple() { var s = new Scheduler(); var a = ActionTask.Create(_ => true, 17); var t = 42; var d = new Disposable(); var w = new WorkItemBase <int>(s, a, t, d); Assert.AreSame(s, w.Scheduler); Assert.AreSame(a, w.Task); Assert.AreEqual(t, w.DueTime); Assert.AreEqual(a.Priority, w.Priority); w.DueTime = 43; Assert.AreEqual(43, w.DueTime); }
[TestCategory("Scheduler_NonDeterministic_Strong")] // Relies on small delay timing. public void Scheduler_PauseWithAsyncContinue() { // // 0.000 0.010 0.110 0.200 ~0.200 // ------+--------------+--------------+------+----------+ // | | | | | // Schedule PauseAsync^ | done PauseAsync$ // | | | | // |<-pauseDelay-> <-pauseCheck-> | // | | // |<--------workCompletionDelay------->| // var workCompletionDelay = TimeSpan.FromSeconds(0.2); var pauseDelay = TimeSpan.FromSeconds(0.01); var pauseCheck = TimeSpan.FromSeconds(0.1); using var scheduler = _root.CreateChildScheduler(); var worked = new AutoResetEvent(false); scheduler.Schedule(ActionTask.Create( s => { Thread.Sleep(workCompletionDelay); worked.Set(); return(true); }, 0)); Thread.Sleep(pauseDelay); // NB: This is non-deterministic. Task paused = scheduler.PauseAsync(); Assert.IsFalse(worked.WaitOne(pauseCheck)); // NB: This is non-deterministic. Assert.IsFalse(paused.IsCompleted); paused.Wait(); Assert.IsTrue(worked.WaitOne(TimeSpan.Zero)); }
[TestCategory("Scheduler_NonDeterministic_Strong")] // Tests timing. public void Scheduler_SingleTimerEvent() { var ltDueTime = TimeSpan.FromSeconds(0.1); var eqDueTime = TimeSpan.FromSeconds(0.2); var gtDueTime = TimeSpan.FromSeconds(0.3); using var scheduler = _root.CreateChildScheduler(); var worked = new AutoResetEvent(false); scheduler.Schedule(eqDueTime, ActionTask.Create( s => { worked.Set(); return(true); }, 0)); Assert.IsFalse(worked.WaitOne(ltDueTime)); // NB: This is non-deterministic. Assert.IsTrue(worked.WaitOne(gtDueTime)); // NB: This is non-deterministic. }
[TestCategory("Scheduler_NonDeterministic_Weak")] // May time-out and be inconclusive. public void Scheduler_MillionTasks() { const int NumberOfTasks = 1_000_000; using var scheduler = _root.CreateChildScheduler(); var threadIds = new HashSet <int>(); int counter = 0; var worked = new AutoResetEvent(false); for (int i = 0; i < NumberOfTasks; ++i) { scheduler.Schedule(ActionTask.Create( s => { lock (threadIds) { threadIds.Add(Thread.CurrentThread.ManagedThreadId); counter++; if (counter == NumberOfTasks) { worked.Set(); } } return(true); }, 0)); } WaitWithTimeout(worked); Assert.AreEqual(NumberOfTasks, counter); if (Environment.ProcessorCount != threadIds.Count) { Assert.Inconclusive($"Not all CPUs did perform scheduled work; please review if this is a glitch. CPU count = {Environment.ProcessorCount}, Unique thread IDs = {threadIds.Count}."); } }
[TestCategory("Scheduler_NonDeterministic_Weak")] // May time-out and be inconclusive. public void Scheduler_TestPausedScheduler() { using var scheduler = _root.CreateChildScheduler(); scheduler.PauseAsync().Wait(); var worked = new AutoResetEvent(false); scheduler.Schedule(ActionTask.Create( s => { worked.Set(); return(true); }, 0)); WaitForNever(worked); // NB: This is non-deterministic, but should not be flaky in the happy case. scheduler.Continue(); WaitForSoon(worked); // NB: This is non-deterministic. }
[TestCategory("Scheduler_NonDeterministic_Strong")] // Relies on timing. public void Scheduler_DisposeChildSchedulers() { IScheduler parent, child; using var ev = new AutoResetEvent(false); using (parent = _root.CreateChildScheduler()) { child = parent.CreateChildScheduler(); child.Schedule( DateTimeOffset.Now.AddMilliseconds(200), ActionTask.Create( s => { ev.Set(); return(true); }, 0)); } Assert.IsTrue(!ev.WaitOne(1000)); }
public void Scheduler_BigStepForHumanKindSmallStepForTimerKind() { var err = default(Exception); var h = new UnhandledExceptionEventHandler((o, e) => { err = (Exception)e.ExceptionObject; }); try { AppDomain.CurrentDomain.UnhandledException += h; using var ph = PhysicalScheduler.Create(); using var lg = new LogicalScheduler(ph); // The BCL has a limit on 0xfffffffe milliseconds, which is some 49 days (see Worker.NormalizeForTimer). // If not handled correctly in Worker.cs, those attempts at scheduling would cause the worker to die. lg.Schedule(TimeSpan.FromDays(50), ActionTask.Create(_ => true, 1)); lg.Schedule(DateTimeOffset.Now.AddDays(50), ActionTask.Create(_ => true, 1)); // Ensure disposal doesn't happen before the worker thread had a chance to evaluate timer expirations, // which is what would cause the test process to die on an invalid call to Timer.Change. var e = new ManualResetEvent(false); lg.Schedule(ActionTask.Create(_ => { e.Set(); return(true); }, 1)); e.WaitOne(); } finally { AppDomain.CurrentDomain.UnhandledException -= h; } if (err != null) { ExceptionDispatchInfo.Capture(err).Throw(); } }
public override void BeginCapture(ISnapshotProvider snapshotProvider, TankInstance tank, Rect clippingRectangle, Color shadeColor, string outputFilename) { DialogManager.Instance.ShowProgressAsync(this.CaptureDialogTitle, string.Format(this.CaptureDialogMessage, tank.Name), isCancellable: true) .ContinueWith(t => { Thread.Sleep(500); DialogManager.AssignTask( t.Result, ActionTask.Create("ExportAnimationCapture", progress => { Application.Current.Dispatcher.Invoke(new Action(() => { var takeSnapshotProgress = progress.AddChildScope("TakeSnapshot", 80); var encodeProgress = progress.AddChildScope("EncodeGIF", 20); var frameSources = this.CaptureFrames(snapshotProvider, clippingRectangle, shadeColor, takeSnapshotProgress, () => t.Result.IsCanceled); if (t.Result.IsCanceled) { return; } var encoder = new AnimatedGifEncoder(); using (var file = File.OpenWrite(outputFilename)) { encoder.Start(file); encoder.SetRepeat(0); encoder.SetDelay((int)(this.FrameTime * 1000)); for (var i = 0; i < frameSources.Length; ++i) { encodeProgress.ReportProgress((double)i / frameSources.Length); if (t.Result.IsCanceled) { return; } if (this.IsBackgroundTransparent) { encoder.SetTransparentColor(shadeColor); } encoder.AddFrame(frameSources[i]); } encoder.Finish(); } progress.ReportIsIndetermine(); t.Result.SetTitle(this.CaptureCompletedDialogTitle); t.Result.SetMessage(string.Format(this.CaptureCompletedDialogMessage, outputFilename)); Thread.Sleep(1000); progress.ReportProgress(1.0); })); })); }); }
public void Scheduler_PerformanceCounters_NoTime() { using var scheduler = _root.CreateChildScheduler(); const int N = 10; for (var i = 0; i < N; i++) { var worked = new AutoResetEvent(false); // // Schedule work without due time, and wait for its completion. // scheduler.Schedule(ActionTask.Create( s => { worked.Set(); return(true); }, 0)); // // Resume the scheduler if we were previously paused. This accummulates PausedTime to assert on. // if (i > 0) { scheduler.Continue(); } // // Wait for the work to be completed. // worked.WaitOne(); // // Pause the scheduler to wait for all the worker threads to stop processing work. // // NB: This is critical for the asserts, because accounting happens after the user work completes, // and our user code signals an event, so we end up with a race between threads. By pausing, we // ensure the tasks have drained completely. // scheduler.PauseAsync().Wait(); } // // Check the counters of the child scheduler. // var childCounters = ((ISchedulerPerformanceCountersProvider)scheduler).QueryPerformanceCounters(includeChildren: false); Assert.AreEqual(N, childCounters.TaskExecutionCount); Assert.AreEqual(0, childCounters.TimerTickCount); Assert.IsTrue(childCounters.Uptime > TimeSpan.Zero); Assert.IsTrue(childCounters.PausedTime > TimeSpan.Zero); // // Check the counters of the root scheduler. // var rootCounters = _root.QueryPerformanceCounters(includeChildren: true); Assert.AreEqual(N, rootCounters.TaskExecutionCount); Assert.AreEqual(0, rootCounters.TimerTickCount); // // Assert struct math on SchedulerPerformanceCounters. // AssertStructMath(childCounters); AssertStructMath(rootCounters); }