public void MultiAccessSerializationAsync() { var cache1 = new MockTokenCache(); var helper1 = new MsalCacheHelper( cache1, new MsalCacheStorage(s_storageCreationProperties, _logger), _logger); var cache2 = new MockTokenCache(); var helper2 = new MsalCacheHelper( cache2, new MsalCacheStorage(s_storageCreationProperties, _logger), _logger); //Test signalling thread 1 var resetEvent1 = new ManualResetEventSlim(initialState: false); //Test signalling thread 2 var resetEvent2 = new ManualResetEventSlim(initialState: false); //Thread 1 signalling test var resetEvent3 = new ManualResetEventSlim(initialState: false); // Thread 2 signalling test var resetEvent4 = new ManualResetEventSlim(initialState: false); var thread1 = new Thread(() => { var args = new TokenCacheNotificationArgs { TokenCache = cache1 }; helper1.BeforeAccessNotification(args); resetEvent3.Set(); resetEvent1.Wait(); helper1.AfterAccessNotification(args); }); var thread2 = new Thread(() => { var args = new TokenCacheNotificationArgs { TokenCache = cache2 }; helper2.BeforeAccessNotification(args); resetEvent4.Set(); resetEvent2.Wait(); helper2.AfterAccessNotification(args); resetEvent4.Set(); }); // Let thread 1 start and get the lock thread1.Start(); resetEvent3.Wait(); // Start thread 2 and give it enough time to get blocked on the lock thread2.Start(); Thread.Sleep(5000); // Make sure helper1 has the lock still, and helper2 doesn't Assert.IsNotNull(helper1.CacheLock); Assert.IsNull(helper2.CacheLock); // Allow thread1 to give up the lock, and wait for helper2 to get it resetEvent1.Set(); resetEvent4.Wait(); resetEvent4.Reset(); // Make sure helper1 gave it up properly, and helper2 now owns the lock Assert.IsNull(helper1.CacheLock); Assert.IsNotNull(helper2.CacheLock); // Allow thread2 to give up the lock, and wait for it to complete resetEvent2.Set(); resetEvent4.Wait(); // Make sure thread2 cleaned up after itself as well Assert.IsNull(helper2.CacheLock); }
public void LockTimeoutTest() { // Total of 1000ms delay _storageCreationPropertiesBuilder.CustomizeLockRetry(20, 100); var properties = _storageCreationPropertiesBuilder.Build(); var cache1 = new MockTokenCache(); var helper1 = new MsalCacheHelper( cache1, new MsalCacheStorage(properties, _logger), _logger); var cache2 = new MockTokenCache(); var helper2 = new MsalCacheHelper( cache2, new MsalCacheStorage(properties, _logger), _logger); //Test signalling thread 1 var resetEvent1 = new ManualResetEventSlim(initialState: false); //Test signalling thread 2 var resetEvent2 = new ManualResetEventSlim(initialState: false); //Thread 1 signalling test var resetEvent3 = new ManualResetEventSlim(initialState: false); // Thread 2 signalling test var resetEvent4 = new ManualResetEventSlim(initialState: false); var thread1 = new Thread(() => { var args = new TokenCacheNotificationArgs(cache1, string.Empty, null, false); helper1.BeforeAccessNotification(args); // Indicate we are waiting resetEvent2.Set(); resetEvent1.Wait(); helper1.AfterAccessNotification(args); // Let thread 1 exit resetEvent3.Set(); }); Stopwatch getTime = new Stopwatch(); var thread2 = new Thread(() => { var args = new TokenCacheNotificationArgs(cache2, string.Empty, null, false); getTime.Start(); try { helper2.BeforeAccessNotification(args); } catch (InvalidOperationException) { // Invalid operation is the exception thrown if the lock cannot be acquired getTime.Stop(); } resetEvent1.Set(); }); // Let thread 1 start and get the lock thread1.Start(); // Wait for thread one to get into the lock resetEvent2.Wait(); // Start thread 2 and give it enough time to get blocked on the lock thread2.Start(); // Wait for the seconf thread to finish resetEvent1.Wait(); Assert.IsTrue(getTime.ElapsedMilliseconds > 2000); }