public static RunTestInBackgroundThread ( Action test ) : void | ||
test | Action | |
return | void |
public void CrossProcess_NamedMutex_ProtectedFileAccessAtomic(string prefix) { ThreadTestHelpers.RunTestInBackgroundThread(() => { string mutexName = prefix + Guid.NewGuid().ToString("N"); string fileName = GetTestFilePath(); Action <string, string> otherProcess = (m, f) => { using (var mutex = Mutex.OpenExisting(m)) { mutex.CheckedWait(); try { File.WriteAllText(f, "0"); } finally { mutex.ReleaseMutex(); } IncrementValueInFileNTimes(mutex, f, 10); } }; using (var mutex = new Mutex(false, mutexName)) using (var remote = RemoteExecutor.Invoke(otherProcess, mutexName, fileName)) { SpinWait.SpinUntil(() => File.Exists(fileName), ThreadTestHelpers.UnexpectedTimeoutMilliseconds); IncrementValueInFileNTimes(mutex, fileName, 10); } Assert.Equal(20, int.Parse(File.ReadAllText(fileName))); }); }
public void AbandonExisting(string name, int waitType) { ThreadTestHelpers.RunTestInBackgroundThread(() => { using (var m = new Mutex(false, name)) { Task t = Task.Factory.StartNew(() => { Assert.True(m.WaitOne(FailedWaitTimeout)); // don't release the mutex; abandon it on this thread }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default); Assert.True(t.Wait(FailedWaitTimeout)); switch (waitType) { case 0: // WaitOne Assert.Throws <AbandonedMutexException>(() => m.WaitOne(FailedWaitTimeout)); break; case 1: // WaitAny AbandonedMutexException ame = Assert.Throws <AbandonedMutexException>(() => WaitHandle.WaitAny(new[] { m }, FailedWaitTimeout)); Assert.Equal(0, ame.MutexIndex); Assert.Equal(m, ame.Mutex); break; } } }); }
public void CrossProcess_NamedMutex_ProtectedFileAccessAtomic(string prefix) { ThreadTestHelpers.RunTestInBackgroundThread(() => { string mutexName = prefix + Guid.NewGuid().ToString("N"); string fileName = GetTestFilePath(); Func <string, string, int> otherProcess = (m, f) => { using (var mutex = Mutex.OpenExisting(m)) { mutex.WaitOne(); try { File.WriteAllText(f, "0"); } finally { mutex.ReleaseMutex(); } IncrementValueInFileNTimes(mutex, f, 10); } return(SuccessExitCode); }; using (var mutex = new Mutex(false, mutexName)) using (var remote = RemoteInvoke(otherProcess, mutexName, $"\"{fileName}\"")) { SpinWait.SpinUntil(() => File.Exists(fileName)); IncrementValueInFileNTimes(mutex, fileName, 10); } Assert.Equal(20, int.Parse(File.ReadAllText(fileName))); }); }
private static void VerifyExecutionContextFlow(AsyncLocal <int> asyncLocal, int expectedValue) { Assert.Equal(expectedValue == 0, ExecutionContext.IsFlowSuppressed()); if (ExecutionContext.IsFlowSuppressed()) { Assert.Null(ExecutionContext.Capture()); } VerifyExecutionContext(ExecutionContext.Capture(), asyncLocal, expectedValue); // Creating a thread flows context if and only if flow is not suppressed int asyncLocalValue = -1; ThreadTestHelpers.RunTestInBackgroundThread(() => asyncLocalValue = asyncLocal.Value); Assert.Equal(expectedValue, asyncLocalValue); // Queueing a thread pool work item flows context if and only if flow is not suppressed asyncLocalValue = -1; var done = new AutoResetEvent(false); ThreadPool.QueueUserWorkItem(state => { asyncLocalValue = asyncLocal.Value; done.Set(); }); done.CheckedWait(); Assert.Equal(expectedValue, asyncLocalValue); }
public static void InvalidLockCookieTest() { // Invalid lock cookie created by using one up with Upgrade/Downgrade var trwl = new TestReaderWriterLock(); TestLockCookie tlc = trwl.UpgradeToWriterLock(); trwl.DowngradeFromWriterLock(tlc); trwl.AcquireWriterLock(); trwl.DowngradeFromWriterLock(tlc, InvalidLockCookieExceptionHResult); trwl.ReleaseWriterLock(); trwl.RestoreLock(tlc, InvalidLockCookieExceptionHResult); // Invalid lock cookie created by using one up with Release/Restore tlc = trwl.ReleaseLock(); trwl.RestoreLock(tlc); trwl.AcquireWriterLock(); trwl.DowngradeFromWriterLock(tlc, InvalidLockCookieExceptionHResult); trwl.ReleaseWriterLock(); trwl.RestoreLock(tlc, InvalidLockCookieExceptionHResult); // Lock cookie owned by another thread ThreadTestHelpers.RunTestInBackgroundThread(() => { TestLockCookie tlc2 = trwl.UpgradeToWriterLock(); tlc = tlc2.Clone(); trwl.DowngradeFromWriterLock(tlc2); }); trwl.AcquireWriterLock(); trwl.DowngradeFromWriterLock(tlc, InvalidLockCookieExceptionHResult); trwl.ReleaseWriterLock(); trwl.RestoreLock(tlc, InvalidLockCookieExceptionHResult); trwl.Dispose(); }
public static void BasicTest() { ThreadTestHelpers.RunTestInBackgroundThread(() => { var hecm = new HostExecutionContextManager(); Assert.Null(hecm.Capture()); Assert.Throws <InvalidOperationException>(() => hecm.SetHostExecutionContext(null)); var hec0 = new HostExecutionContext(); var hec1 = new HostExecutionContext(); object previousState0 = hecm.SetHostExecutionContext(hec0); ExecutionContext ec = ExecutionContext.Capture(); object previousState1 = hecm.SetHostExecutionContext(hec1); Assert.Throws <InvalidOperationException>(() => hecm.Revert(null)); Assert.Throws <InvalidOperationException>(() => hecm.Revert(new object())); Assert.Throws <InvalidOperationException>(() => hecm.Revert(previousState0)); object otherThreadState = null; ThreadTestHelpers.RunTestInBackgroundThread( () => otherThreadState = hecm.SetHostExecutionContext(new HostExecutionContext())); Assert.Throws <InvalidOperationException>(() => hecm.Revert(otherThreadState)); ExecutionContext.Run( ec, state => Assert.Throws <InvalidOperationException>(() => hecm.Revert(previousState1)), null); hecm.Revert(previousState1); Assert.Throws <InvalidOperationException>(() => hecm.Revert(previousState1)); // Revert always reverts to a null host execution context when it's not hosted Assert.Throws <InvalidOperationException>(() => hecm.Revert(previousState0)); }); }
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotInAppContainer))] // Can't create global objects in appcontainer public void Ctor_ImpersonateAnonymousAndTryCreateGlobalMutexTest() { ThreadTestHelpers.RunTestInBackgroundThread(() => { if (!ImpersonateAnonymousToken(GetCurrentThread())) { // Impersonation is not allowed in the current context, this test is inappropriate in such a case return; } Assert.Throws <UnauthorizedAccessException>(() => new Mutex(false, "Global\\" + Guid.NewGuid().ToString("N"))); Assert.True(RevertToSelf()); }); }
public static void CreateCopyTest() { ThreadTestHelpers.RunTestInBackgroundThread(() => { var asyncLocal = new AsyncLocal <int>(); ExecutionContext executionContext = ExecutionContext.Capture(); VerifyExecutionContext(executionContext, asyncLocal, 0); executionContext = ExecutionContext.Capture(); ExecutionContext executionContextCopy0 = executionContext.CreateCopy(); asyncLocal.Value = 1; executionContext = ExecutionContext.Capture(); VerifyExecutionContext(executionContext, asyncLocal, 1); VerifyExecutionContext(executionContextCopy0, asyncLocal, 0); executionContext = ExecutionContext.Capture(); ExecutionContext executionContextCopy1 = executionContext.CreateCopy(); VerifyExecutionContext(executionContextCopy1, asyncLocal, 1); }); }
public static void CaptureThenSuppressThenRunFlowTest() { ThreadTestHelpers.RunTestInBackgroundThread(() => { var asyncLocal = new AsyncLocal <int>(); asyncLocal.Value = 1; ExecutionContext executionContext = ExecutionContext.Capture(); ExecutionContext.SuppressFlow(); ExecutionContext.Run( executionContext, state => { Assert.Equal(1, asyncLocal.Value); VerifyExecutionContextFlow(asyncLocal, 1); }, null); Assert.Equal(1, asyncLocal.Value); VerifyExecutionContextFlow(asyncLocal, 0); ExecutionContext.RestoreFlow(); VerifyExecutionContextFlow(asyncLocal, 1); executionContext = ExecutionContext.Capture(); asyncLocal.Value = 2; ExecutionContext.SuppressFlow(); Assert.True(ExecutionContext.IsFlowSuppressed()); ExecutionContext.Run( executionContext, state => { Assert.Equal(1, asyncLocal.Value); VerifyExecutionContextFlow(asyncLocal, 1); }, null); Assert.Equal(2, asyncLocal.Value); VerifyExecutionContextFlow(asyncLocal, 0); ExecutionContext.RestoreFlow(); VerifyExecutionContextFlow(asyncLocal, 2); }); }
public static void SerializationTest() { ThreadTestHelpers.RunTestInBackgroundThread(() => { var asyncLocal = new AsyncLocal <int>(); asyncLocal.Value = 1; ExecutionContext executionContext = ExecutionContext.Capture(); VerifyExecutionContext(executionContext, asyncLocal, 1); Assert.Throws <ArgumentNullException>(() => executionContext.GetObjectData(null, new StreamingContext())); var binaryFormatter = new BinaryFormatter(); var memoryStream = new MemoryStream(); binaryFormatter.Serialize(memoryStream, executionContext); memoryStream.Close(); byte[] binaryData = memoryStream.ToArray(); memoryStream = new MemoryStream(binaryData); executionContext = (ExecutionContext)binaryFormatter.Deserialize(memoryStream); memoryStream.Close(); }); }
public static void AsyncFlowControlTest() { ThreadTestHelpers.RunTestInBackgroundThread(() => { Action <AsyncFlowControl, AsyncFlowControl, bool> verifyEquality = (afc0, afc1, areExpectedToBeEqual) => { Assert.Equal(areExpectedToBeEqual, afc0.Equals(afc1)); Assert.Equal(areExpectedToBeEqual, afc0.Equals((object)afc1)); Assert.Equal(areExpectedToBeEqual, afc0 == afc1); Assert.NotEqual(areExpectedToBeEqual, afc0 != afc1); }; AsyncFlowControl asyncFlowControl0 = ExecutionContext.SuppressFlow(); ExecutionContext.RestoreFlow(); AsyncFlowControl asyncFlowControl1 = ExecutionContext.SuppressFlow(); ExecutionContext.RestoreFlow(); verifyEquality(asyncFlowControl0, asyncFlowControl1, true); verifyEquality(asyncFlowControl1, asyncFlowControl0, true); var asyncLocal = new AsyncLocal <int>(); asyncLocal.Value = 1; asyncFlowControl1 = ExecutionContext.SuppressFlow(); ExecutionContext.RestoreFlow(); verifyEquality(asyncFlowControl0, asyncFlowControl1, true); verifyEquality(asyncFlowControl1, asyncFlowControl0, true); asyncFlowControl1 = new AsyncFlowControl(); verifyEquality(asyncFlowControl0, asyncFlowControl1, false); verifyEquality(asyncFlowControl1, asyncFlowControl0, false); ThreadTestHelpers.RunTestInBackgroundThread(() => asyncFlowControl1 = ExecutionContext.SuppressFlow()); verifyEquality(asyncFlowControl0, asyncFlowControl1, false); verifyEquality(asyncFlowControl1, asyncFlowControl0, false); }); }
public void Ctor_TryCreateGlobalMutexTest_Uwp() { ThreadTestHelpers.RunTestInBackgroundThread(() => Assert.Throws <UnauthorizedAccessException>(() => new Mutex(false, "Global\\" + Guid.NewGuid().ToString("N")))); }
public static void WaitNotificationTest() { ThreadTestHelpers.RunTestInBackgroundThread(() => { var tsc = new TestSynchronizationContext(); SynchronizationContext.SetSynchronizationContext(tsc); Assert.Same(tsc, SynchronizationContext.Current); var e = new ManualResetEvent(false); tsc.WaitAction = () => e.Set(); Assert.False(tsc.IsWaitNotificationRequired()); Assert.False(e.WaitOne(0)); tsc.SetWaitNotificationRequired(); Assert.True(tsc.IsWaitNotificationRequired()); Assert.True(e.WaitOne(0)); var mres = new ManualResetEventSlim(); tsc.WaitAction = () => mres.Set(); mres.Reset(); mres.CheckedWait(); e.Reset(); tsc.WaitAction = () => e.Set(); SynchronizationContext.SetSynchronizationContext(new TestSynchronizationContext()); Assert.False(e.WaitOne(0)); SynchronizationContext.SetSynchronizationContext(tsc); Assert.True(e.WaitOne(0)); e.Reset(); e.CheckedWait(); e.Reset(); var lockObj = new object(); var lockAcquiredFromBackground = new AutoResetEvent(false); Action waitForThread; Thread t = ThreadTestHelpers.CreateGuardedThread(out waitForThread, () => { lock (lockObj) { lockAcquiredFromBackground.Set(); e.CheckedWait(); } }); t.IsBackground = true; t.Start(); lockAcquiredFromBackground.CheckedWait(); Assert.True(Monitor.TryEnter(lockObj, ThreadTestHelpers.UnexpectedTimeoutMilliseconds)); Monitor.Exit(lockObj); waitForThread(); e.Reset(); var m = new Mutex(); t = ThreadTestHelpers.CreateGuardedThread(out waitForThread, () => { m.CheckedWait(); try { lockAcquiredFromBackground.Set(); e.CheckedWait(); } finally { m.ReleaseMutex(); } }); t.IsBackground = true; t.Start(); lockAcquiredFromBackground.CheckedWait(); m.CheckedWait(); m.ReleaseMutex(); waitForThread(); }); }
public static void FlowTest() { ThreadTestHelpers.RunTestInBackgroundThread(() => { var asyncLocal = new AsyncLocal <int>(); asyncLocal.Value = 1; var asyncFlowControl = default(AsyncFlowControl); Action <Action, Action> verifySuppressRestore = (suppressFlow, restoreFlow) => { VerifyExecutionContextFlow(asyncLocal, 1); ExecutionContext executionContext2 = ExecutionContext.Capture(); suppressFlow(); VerifyExecutionContextFlow(asyncLocal, 0); VerifyExecutionContext(executionContext2, asyncLocal, 1); executionContext2 = ExecutionContext.Capture(); restoreFlow(); VerifyExecutionContextFlow(asyncLocal, 1); VerifyExecutionContext(executionContext2, asyncLocal, 0); }; verifySuppressRestore( () => asyncFlowControl = ExecutionContext.SuppressFlow(), () => asyncFlowControl.Undo()); verifySuppressRestore( () => asyncFlowControl = ExecutionContext.SuppressFlow(), () => asyncFlowControl.Dispose()); verifySuppressRestore( () => ExecutionContext.SuppressFlow(), () => ExecutionContext.RestoreFlow()); Assert.Throws <InvalidOperationException>(() => ExecutionContext.RestoreFlow()); asyncFlowControl = ExecutionContext.SuppressFlow(); Assert.Throws <InvalidOperationException>(() => ExecutionContext.SuppressFlow()); ThreadTestHelpers.RunTestInBackgroundThread(() => { ExecutionContext.SuppressFlow(); Assert.Throws <InvalidOperationException>(() => asyncFlowControl.Undo()); Assert.Throws <InvalidOperationException>(() => asyncFlowControl.Dispose()); ExecutionContext.RestoreFlow(); }); asyncFlowControl.Undo(); Assert.Throws <InvalidOperationException>(() => asyncFlowControl.Undo()); Assert.Throws <InvalidOperationException>(() => asyncFlowControl.Dispose()); // Changing an async local value does not prevent undoing a flow-suppressed execution context. In .NET Core, the // execution context is immutable, so changing an async local value changes the execution context instance, // contrary to the .NET Framework. asyncFlowControl = ExecutionContext.SuppressFlow(); asyncLocal.Value = 2; asyncFlowControl.Undo(); VerifyExecutionContextFlow(asyncLocal, 2); asyncFlowControl = ExecutionContext.SuppressFlow(); asyncLocal.Value = 3; asyncFlowControl.Dispose(); VerifyExecutionContextFlow(asyncLocal, 3); ExecutionContext.SuppressFlow(); asyncLocal.Value = 4; ExecutionContext.RestoreFlow(); VerifyExecutionContextFlow(asyncLocal, 4); // An async flow control cannot be undone when a different execution context is applied. The .NET Framework // mutates the execution context when its state changes, and only changes the instance when an execution context // is applied (for instance, through ExecutionContext.Run). The framework prevents a suppressed-flow execution // context from being applied by returning null from ExecutionContext.Capture, so the only type of execution // context that can be applied is one whose flow is not suppressed. After suppressing flow and changing an async // local's value, the .NET Framework verifies that a different execution context has not been applied by // checking the execution context instance against the one saved from when flow was suppressed. In .NET Core, // since the execution context instance will change after changing the async local's value, it verifies that a // different execution context has not been applied, by instead ensuring that the current execution context's // flow is suppressed. { ExecutionContext executionContext = null; Action verifyCannotUndoAsyncFlowControlAfterChangingExecutionContext = () => { ExecutionContext.Run( executionContext, state => { Assert.Throws <InvalidOperationException>(() => asyncFlowControl.Undo()); Assert.Throws <InvalidOperationException>(() => asyncFlowControl.Dispose()); }, null); }; executionContext = ExecutionContext.Capture(); asyncFlowControl = ExecutionContext.SuppressFlow(); verifyCannotUndoAsyncFlowControlAfterChangingExecutionContext(); asyncFlowControl.Undo(); executionContext = ExecutionContext.Capture(); asyncFlowControl = ExecutionContext.SuppressFlow(); asyncLocal.Value = 5; verifyCannotUndoAsyncFlowControlAfterChangingExecutionContext(); asyncFlowControl.Undo(); VerifyExecutionContextFlow(asyncLocal, 5); } }); }