File: LiveShare\Guest\RazorGuestInitializationServiceTest.cs
Web Access
Project: src\src\Razor\src\Razor\test\Microsoft.VisualStudio.LanguageServices.Razor.UnitTests\Microsoft.VisualStudio.LanguageServices.Razor.UnitTests.csproj (Microsoft.VisualStudio.LanguageServices.Razor.UnitTests)
// 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.AspNetCore.Razor.Test.Common;
using Microsoft.VisualStudio.LiveShare;
using Moq;
using Xunit;
using Xunit.Abstractions;
 
namespace Microsoft.VisualStudio.Razor.LiveShare.Guest;
 
public class RazorGuestInitializationServiceTest(ITestOutputHelper testOutput) : ToolingTestBase(testOutput)
{
    private readonly LiveShareSessionAccessor _liveShareSessionAccessor = new();
 
    [Fact]
    public async Task CreateServiceAsync_StartsViewImportsCopy()
    {
        // Arrange
        var service = new RazorGuestInitializationService(_liveShareSessionAccessor);
        var serviceAccessor = service.GetTestAccessor();
        var session = new StrictMock<CollaborationSession>();
        session
            .Setup(s => s.ListRootsAsync(It.IsAny<CancellationToken>()))
            .ReturnsAsync([])
            .Verifiable();
 
        // Act
        await service.CreateServiceAsync(session.Object, DisposalToken);
 
        // Assert
        Assert.NotNull(serviceAccessor.ViewImportsCopyTask);
        await serviceAccessor.ViewImportsCopyTask;
 
        session.VerifyAll();
    }
 
    [Fact]
    public async Task CreateServiceAsync_SessionDispose_CancelsListRootsToken()
    {
        // Arrange
        var service = new RazorGuestInitializationService(_liveShareSessionAccessor);
        var serviceAccessor = service.GetTestAccessor();
        var session = new StrictMock<CollaborationSession>();
        using var disposedServiceGate = new ManualResetEventSlim();
        var disposedService = false;
        session
            .Setup(s => s.ListRootsAsync(It.IsAny<CancellationToken>()))
            .Returns<CancellationToken>((cancellationToken) => Task.Run(() =>
                {
                    cancellationToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5));
 
                    // Make sure we don't assert the value of 'disposedService' before we know it was set
                    disposedServiceGate.Wait();
 
                    Assert.True(disposedService);
                    return Array.Empty<Uri>();
                }))
            .Verifiable();
        var sessionService = Assert.IsAssignableFrom<IDisposable>(await service.CreateServiceAsync(session.Object, DisposalToken));
 
        // Act
        Assert.NotNull(sessionService);
        sessionService.Dispose();
        disposedService = true;
        disposedServiceGate.Set();
 
        // Assert
        Assert.NotNull(serviceAccessor.ViewImportsCopyTask);
        await serviceAccessor.ViewImportsCopyTask;
 
        session.VerifyAll();
    }
 
    [Fact]
    public async Task CreateServiceAsync_InitializationDispose_CancelsListRootsToken()
    {
        // Arrange
        var service = new RazorGuestInitializationService(_liveShareSessionAccessor);
        var serviceAccessor = service.GetTestAccessor();
        var session = new StrictMock<CollaborationSession>();
        using var cts = new CancellationTokenSource();
        session
            .Setup(s => s.ListRootsAsync(It.IsAny<CancellationToken>()))
            .Returns<CancellationToken>((cancellationToken) => Task.Run(() =>
                {
                    cancellationToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(3));
 
                    Assert.True(cts.IsCancellationRequested);
                    return Array.Empty<Uri>();
                }))
            .Verifiable();
        var sessionService = Assert.IsAssignableFrom<IDisposable>(await service.CreateServiceAsync(session.Object, cts.Token));
 
        // Act
        cts.Cancel();
 
        // Assert
        Assert.NotNull(serviceAccessor.ViewImportsCopyTask);
        await serviceAccessor.ViewImportsCopyTask;
 
        session.VerifyAll();
    }
 
    [Fact]
    public async Task CreateServiceAsync_EnsureViewImportsCopiedAsync_CancellationExceptionsGetSwallowed()
    {
        // Arrange
        var service = new RazorGuestInitializationService(_liveShareSessionAccessor);
        var serviceAcessor = service.GetTestAccessor();
        var session = new StrictMock<CollaborationSession>();
        using var cts = new CancellationTokenSource();
        session
            .Setup(s => s.ListRootsAsync(It.IsAny<CancellationToken>()))
            .Returns<CancellationToken>((cancellationToken) => Task.Run(() =>
                {
                    cancellationToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(3));
 
                    cancellationToken.ThrowIfCancellationRequested();
 
                    return Array.Empty<Uri>();
                }))
            .Verifiable();
        var sessionService = Assert.IsAssignableFrom<IDisposable>(await service.CreateServiceAsync(session.Object, cts.Token));
 
        // Act
        cts.Cancel();
 
        // Assert
        Assert.NotNull(serviceAcessor.ViewImportsCopyTask);
        await serviceAcessor.ViewImportsCopyTask;
 
        session.VerifyAll();
    }
}