File: FakeHostTests.cs
Web Access
Project: src\test\Libraries\Microsoft.Extensions.Hosting.Testing.Tests\Microsoft.Extensions.Hosting.Testing.Tests.csproj (Microsoft.Extensions.Hosting.Testing.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Testing;
using Microsoft.Extensions.Time.Testing;
using Moq;
using Xunit;
 
namespace Microsoft.Extensions.Hosting.Testing.Test;
 
public class FakeHostTests
{
    [Fact]
    public async Task CreateBuilder_AddsFakeLogging()
    {
        using var host = await FakeHost.CreateBuilder().StartAsync();
        Assert.Contains(host.Services.GetServices<ILoggerProvider>(), x => x is FakeLoggerProvider);
    }
 
    [Fact]
    public async Task Host_ShutsDownAfterTimeout()
    {
        using var host = await FakeHost
            .CreateBuilder(x =>
            {
                x.FakeRedaction = false;
                x.TimeToLive = TimeSpan.Zero;
            })
            .StartAsync();
 
        Assert.Throws<ObjectDisposedException>(() => host.Services.GetService<IHost>());
    }
 
    [Fact]
    public async Task StartAsync_NoTokenProvided_UsesDefaultTimeout()
    {
        var hostMock = new Mock<IHost>(MockBehavior.Strict);
        hostMock
            .Setup(x => x.StartAsync(It.Is<CancellationToken>(y => y != default)))
            .Returns(Task.CompletedTask);
 
#pragma warning disable CA2000
        var sut = new FakeHost(hostMock.Object, new FakeHostOptions { StartUpTimeout = TimeSpan.Zero });
#pragma warning restore CA2000
        await sut.StartAsync();
        await Task.Delay(TimeSpan.FromMilliseconds(100));
 
        hostMock.VerifyAll();
    }
 
    [Fact]
    public async Task StartAsync_TokenProvided_Starts()
    {
        using var tokenSource = new CancellationTokenSource();
        var hostMock = new Mock<IHost>(MockBehavior.Strict);
        hostMock
            .Setup(x => x.StartAsync(It.Is<CancellationToken>(y => y != tokenSource.Token)))
            .Returns(Task.CompletedTask);
 
#pragma warning disable CA2000
        var sut = new FakeHost(hostMock.Object, new FakeHostOptions { StartUpTimeout = TimeSpan.Zero });
#pragma warning restore CA2000
        await sut.StartAsync(tokenSource.Token);
        hostMock.VerifyAll();
    }
 
    [Fact]
    public void StartAsync_TokenProvided_LinksTheToken()
    {
        var timeProvider = new FakeTimeProvider();
        var task = new Task(() => { });
        var cancellationTokenSource = timeProvider.CreateCancellationTokenSource(TimeSpan.FromMilliseconds(1));
        CancellationToken receivedToken = default;
        var hostMock = new Mock<IHost>(MockBehavior.Strict);
        hostMock
            .Setup(x => x.StartAsync(It.Is<CancellationToken>(y => y != cancellationTokenSource.Token)))
            .Callback<CancellationToken>(x => receivedToken = x)
            .Returns(task);
 
#pragma warning disable CA2000
        var sut = new FakeHost(hostMock.Object, new FakeHostOptions { StartUpTimeout = TimeSpan.FromMilliseconds(-1) });
#pragma warning restore CA2000
        _ = sut.StartAsync(cancellationTokenSource.Token);
 
        Assert.False(receivedToken.IsCancellationRequested);
        cancellationTokenSource.Cancel();
        Assert.True(receivedToken.IsCancellationRequested);
 
        hostMock.VerifyAll();
 
        cancellationTokenSource.Dispose();
    }
 
    [Fact]
    public async Task StopAsync_NoTokenProvided_UsesDefaultTimeout()
    {
        var hostMock = new Mock<IHost>(MockBehavior.Strict);
        hostMock
            .Setup(x => x.StopAsync(It.Is<CancellationToken>(y => y != default)))
            .Returns(Task.CompletedTask);
 
#pragma warning disable CA2000
        var sut = new FakeHost(hostMock.Object, new FakeHostOptions { ShutDownTimeout = TimeSpan.Zero });
#pragma warning restore CA2000
        await sut.StopAsync();
 
        hostMock.VerifyAll();
    }
 
    [Fact]
    public async Task StopAsync_TokenProvided_Stops()
    {
        using var tokenSource = new CancellationTokenSource();
        var hostMock = new Mock<IHost>(MockBehavior.Strict);
        hostMock
            .Setup(x => x.StopAsync(It.Is<CancellationToken>(y => y != tokenSource.Token)))
            .Returns(Task.CompletedTask);
 
#pragma warning disable CA2000
        var sut = new FakeHost(hostMock.Object, new FakeHostOptions { StartUpTimeout = TimeSpan.Zero });
#pragma warning restore CA2000
        await sut.StopAsync(tokenSource.Token);
        hostMock.VerifyAll();
    }
 
    [Fact]
    public void StopAsync_TokenProvided_LinksTheToken()
    {
        var timeProvider = new FakeTimeProvider();
        var task = new Task(() => { });
 
        var cancellationTokenSource = timeProvider.CreateCancellationTokenSource(TimeSpan.FromMilliseconds(1));
        CancellationToken receivedToken = default;
        var hostMock = new Mock<IHost>(MockBehavior.Strict);
        hostMock
            .Setup(x => x.StopAsync(It.Is<CancellationToken>(y => y != cancellationTokenSource.Token)))
            .Callback<CancellationToken>(x => receivedToken = x)
            .Returns(task);
 
#pragma warning disable CA2000
        var sut = new FakeHost(hostMock.Object, new FakeHostOptions { StartUpTimeout = TimeSpan.FromMilliseconds(-1) });
#pragma warning restore CA2000
        _ = sut.StopAsync(cancellationTokenSource.Token);
 
        Assert.False(receivedToken.IsCancellationRequested);
        cancellationTokenSource.Cancel();
        Assert.True(receivedToken.IsCancellationRequested);
 
        hostMock.VerifyAll();
 
        cancellationTokenSource.Dispose();
    }
 
    [Fact]
    public void Dispose_ShutsDownHost()
    {
        var hostMock = new Mock<IHost>(MockBehavior.Strict);
        hostMock.Setup(x => x.StopAsync(It.IsAny<CancellationToken>())).Returns(Task.CompletedTask);
        hostMock.Setup(x => x.Dispose());
 
        var sut = new FakeHost(hostMock.Object, new FakeHostOptions()) { TimeProvider = new FakeTimeProvider() };
        sut.Dispose();
 
        hostMock.VerifyAll();
    }
 
    [Fact]
    public void Dispose_RunsOnlyOnce()
    {
        var hostMock = new Mock<IHost>();
        hostMock.Setup(x => x.StopAsync(It.IsAny<CancellationToken>())).Returns(Task.CompletedTask);
        hostMock.Setup(x => x.Dispose());
 
        var sut = new FakeHost(hostMock.Object, new FakeHostOptions()) { TimeProvider = new FakeTimeProvider() };
        sut.Dispose();
#pragma warning disable S3966
        sut.Dispose();
#pragma warning restore S3966
 
        hostMock.Verify(x => x.Dispose(), Times.Once);
    }
}