using DodoSSH.Client.App.Platform; using DodoSSH.Client.Session; using NSubstitute; namespace DodoSSH.Client.App.Tests; /// /// That the slow probe choosing a device key store runs once, and not on the thread that asked. /// /// /// On Windows the probe creates and deletes a TPM key, and it used to run synchronously on the UI thread at /// startup and again after every unlock. See . /// public sealed class ProbedDeviceKeyStoreTests { private static CancellationToken Token => TestContext.Current.CancellationToken; [Fact] public async Task TheChoiceIsMadeOnce_OffTheCallersThread() { var asking = Environment.CurrentManagedThreadId; var probes = 0; var probedOn = 0; var inner = Substitute.For(); var store = new ProbedDeviceKeyStore(() => { Interlocked.Increment(ref probes); probedOn = Environment.CurrentManagedThreadId; return inner; }); (await store.IsAvailableAsync(Token)).ShouldBeTrue(); (await store.IsAvailableAsync(Token)).ShouldBeTrue(); await store.TryLoadAsync(Token); probes.ShouldBe(1); probedOn.ShouldNotBe(asking); // Availability is the choice, not a second probe through the store it chose. await inner.DidNotReceive().IsAvailableAsync(Arg.Any()); await inner.Received(1).TryLoadAsync(Arg.Any()); } [Fact] public async Task AMachineWithNoStore_IsUnavailable_AndForgettingIsHarmless() { var store = new ProbedDeviceKeyStore(static () => new UnavailableDeviceKeyStore()); (await store.IsAvailableAsync(Token)).ShouldBeFalse(); (await store.TryLoadAsync(Token)).ShouldBeNull(); await store.ForgetAsync(Token); } }