public void WaitForAllWork_should_return_immediately_if_no_work_queued() { var stopWatch = new Stopwatch(); "Given no work going on".Context(() => { Assert.False(ParallelWork.IsWorkOrTimerQueued()); }); var result = default(bool); "When WaitForAllWork is called".Do(() => { stopWatch.Start(); result = ParallelWork.WaitForAllWork(TimeSpan.FromSeconds(1)); }); "It should return immediately without going into any wait period".Assert(() => { Assert.True(stopWatch.Elapsed < TimeSpan.FromSeconds(1)); }); "It should return true".Assert(() => { Assert.True(result); }); }
public void Should_fire_onprogress_on_UI_thread() { var onprogressMessages = new List <string>(); var callerThreadId = default(int); var onprogressCalledOnThreadId = default(int); var frame = default(DispatcherFrame); "Given no parallel work running".Context(() => { Assert.False(ParallelWork.IsWorkOrTimerQueued()); callerThreadId = Thread.CurrentThread.ManagedThreadId; onprogressCalledOnThreadId = default(int); frame = new DispatcherFrame(); }); Func <int, string> getMessage = (progress) => "Message " + progress.ToString(); "When a parallel work is queued and onprogress callback is fired".Do(() => { Start.Work((onprogress) => { for (int i = 0; i < 10; i++) { Thread.Sleep(100); onprogress(getMessage(i), i); } }) .OnProgress((msg, progress) => { onprogressCalledOnThreadId = Thread.CurrentThread.ManagedThreadId; onprogressMessages.Add(msg); }) .OnComplete(() => { frame.Continue = false; }) .Run(); }); "It should fire onprogress callback on the UI thread".Assert(() => { WaitForWorkDoneAndFireCallback(TimeSpan.FromSeconds(5), frame); Assert.Equal(10, onprogressMessages.Count); Assert.Equal(callerThreadId, onprogressCalledOnThreadId); }); }
public void DoWork_should_return_objects_from_parallel_thread_to_callbacks() { TimeSpan howLongWorkTakes = TimeSpan.FromSeconds(1); TimeSpan timeout = howLongWorkTakes.Add(TimeSpan.FromMilliseconds(500)); DispatcherFrame frame = default(DispatcherFrame); "Given no parallel work running".Context(() => { Assert.False(ParallelWork.IsWorkOrTimerQueued()); frame = new DispatcherFrame(); }); var test = default(Dictionary <string, string>); var output = default(Dictionary <string, string>); "When StartNow<> is called".Do(() => { Start <Dictionary <string, string> > .Work(() => { test = new Dictionary <string, string>(); test.Add("test", "test"); return(test); }) .OnComplete((result) => { output = result; frame.Continue = false; }) .Run(); }); @"It should return the object produced in separate thread and the object should be modifiable" .Assert(() => { Assert.True(WaitForWorkDoneAndFireCallback(timeout, frame)); Assert.True(output.ContainsKey("test")); Assert.DoesNotThrow(() => output.Add("another key", "another value")); }); }
public void StartNow_should_queue_a_new_thread_to_do_the_work() { TimeSpan howLongWorkTakes = TimeSpan.FromSeconds(2); TimeSpan timeout = howLongWorkTakes.Add(TimeSpan.FromMilliseconds(500)); var doWorkCalled = false; var successCallbackFired = false; var onExceptionFired = false; var doWorkThreadId = default(int); var onCompleteThreadId = default(int); var onExceptionThreadId = default(int); var letsThrowException = false; Stopwatch stopWatch = new Stopwatch(); DispatcherFrame frame = default(DispatcherFrame); Action callbackFiredOnDispatcher = () => { frame.Continue = false; // Dispatcher should stop now }; "Given no parallel work running".Context(() => { Assert.False(ParallelWork.IsWorkOrTimerQueued()); frame = new DispatcherFrame(); doWorkCalled = false; successCallbackFired = false; onExceptionFired = false; doWorkThreadId = default(int); onCompleteThreadId = default(int); onExceptionThreadId = default(int); stopWatch.Reset(); }); "When a new work is started by Start.Work().Run()".Do(() => { var shouldThrowException = letsThrowException; Start.Work(() => { doWorkThreadId = Thread.CurrentThread.ManagedThreadId; doWorkCalled = true; // Simulate some delay in background work Thread.Sleep(howLongWorkTakes); if (shouldThrowException) { throw new ApplicationException("Exception"); } }) .OnComplete(() => { onCompleteThreadId = Thread.CurrentThread.ManagedThreadId; successCallbackFired = true; callbackFiredOnDispatcher(); }) .OnException((x) => { onExceptionThreadId = Thread.CurrentThread.ManagedThreadId; onExceptionFired = true; callbackFiredOnDispatcher(); }) .Run(); stopWatch.Start(); }); "It should return control immediately without blocking the current thread".Assert(() => { Assert.True(stopWatch.Elapsed < howLongWorkTakes, string.Format("{0}<{1}", stopWatch.Elapsed, howLongWorkTakes)); Assert.True(WaitForWorkDoneAndFireCallback(timeout, frame)); }); "It should return true if IsWorkQueued is called".Assert(() => { Assert.True(ParallelWork.IsWorkOrTimerQueued()); Assert.True(WaitForWorkDoneAndFireCallback(timeout, frame)); }); "It should wait for the work to complete if WaitForAllWork is called".Assert(() => { Assert.True(WaitForWorkDoneAndFireCallback(timeout, frame)); // The work should finish within the duration it takes with max 1 sec buffer // for additional stuff xunit does. Assert.True(stopWatch.Elapsed < howLongWorkTakes.Add(TimeSpan.FromSeconds(1))); }); "It should execute the work in a separate thread".Assert(() => { Assert.True(WaitForWorkDoneAndFireCallback(timeout, frame)); Assert.True(doWorkCalled); Assert.NotEqual(Thread.CurrentThread.ManagedThreadId, doWorkThreadId); }); "It should fire onComplete on the same thread as the UI thread".Assert(() => { Assert.True(WaitForWorkDoneAndFireCallback(timeout, frame)); Assert.True(successCallbackFired); Assert.Equal(Thread.CurrentThread.ManagedThreadId, onCompleteThreadId); }); "It should not fire onException if there's no exception".Assert(() => { Assert.True(WaitForWorkDoneAndFireCallback(timeout, frame)); Assert.False(onExceptionFired); letsThrowException = true; // This is for next assert }); "It should fire exception on UI thread".Assert(() => { Assert.True(WaitForWorkDoneAndFireCallback(timeout, frame)); Assert.False(successCallbackFired); Assert.True(onExceptionFired); Assert.Equal(Thread.CurrentThread.ManagedThreadId, onExceptionThreadId); }); }