File: Model\AIAssistant\AIContextProviderTests.cs
Web Access
Project: src\tests\Aspire.Dashboard.Tests\Aspire.Dashboard.Tests.csproj (Aspire.Dashboard.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.Threading.Channels;
using Aspire.Dashboard.Configuration;
using Aspire.Dashboard.Model.Assistant;
using Aspire.Dashboard.Model.Assistant.Prompts;
using Aspire.Dashboard.Resources;
using Microsoft.AspNetCore.InternalTesting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Abstractions;
using Xunit;
 
namespace Aspire.Dashboard.Tests.Model.AIAssistant;
 
public class AIContextProviderTests
{
    [Fact]
    public void Add_Context_IncreasesCount()
    {
        // Arrange
        var provider = CreateAIContextProvider();
 
        // Act
        var context = provider.AddNew("test", c => { });
 
        // Assert
        Assert.Equal(1, provider.ProviderCount);
        Assert.Equal(context, provider.GetContext());
    }
 
    [Fact]
    public void Dispose_Context_DecreasesCount()
    {
        // Arrange
        var provider = CreateAIContextProvider();
        var context = provider.AddNew("test", c => { });
 
        // Act
        context.Dispose();
 
        // Assert
        Assert.Equal(0, provider.ProviderCount);
        Assert.Null(provider.GetContext());
    }
 
    [Fact]
    public void Remove_Context_OutOfOrder_RemovesSuccessfully()
    {
        // Arrange
        var provider = CreateAIContextProvider();
 
        // Act 1
        var context1 = provider.AddNew("test1", c => { });
        var context2 = provider.AddNew("test2", c => { });
 
        // Assert 1
        Assert.Equal(context2, provider.GetContext());
        Assert.Equal(2, provider.ProviderCount);
 
        // Act 2
        context1.Dispose();
 
        // Assert 2
        Assert.Equal(context2, provider.GetContext());
        Assert.Equal(1, provider.ProviderCount);
 
        // Act 3
        context2.Dispose();
 
        // Assert 3
        Assert.Null(provider.GetContext());
        Assert.Equal(0, provider.ProviderCount);
    }
 
    [Fact]
    public async Task Subscribe_Context_OutOfOrder_RemovesSuccessfully()
    {
        // Arrange
        var changeChannel = Channel.CreateUnbounded<AIContext?>();
 
        var provider = CreateAIContextProvider();
        var subscription = provider.OnContextChanged(() =>
        {
            changeChannel.Writer.TryWrite(provider.GetContext());
            return Task.CompletedTask;
        });
        Assert.Equal(1, provider.SubscriptionCount);
 
        // Act & Assert
        var context1 = provider.AddNew("test1", c => { });
        var newContext = await changeChannel.Reader.ReadAsync().DefaultTimeout();
        Assert.Equal(context1, newContext);
 
        var context2 = provider.AddNew("test2", c => { });
        newContext = await changeChannel.Reader.ReadAsync().DefaultTimeout();
        Assert.Equal(context2, newContext);
 
        Assert.Equal(context2, provider.GetContext());
 
        context1.Dispose();
        var newContextTask = changeChannel.Reader.ReadAsync();
        Assert.False(newContextTask.IsCompleted);
 
        Assert.Equal(context2, provider.GetContext());
 
        context2.Dispose();
        newContext = await newContextTask.DefaultTimeout();
        Assert.Null(newContext);
 
        Assert.Null(provider.GetContext());
 
        changeChannel.Writer.Complete();
        Assert.False(await changeChannel.Reader.WaitToReadAsync().DefaultTimeout());
 
        subscription.Dispose();
        Assert.Equal(0, provider.SubscriptionCount);
    }
 
    private static AIContextProvider CreateAIContextProvider()
    {
        var testOptionsMonitor = new TestOptionsMonitor<DashboardOptions>(new DashboardOptions());
 
        return new AIContextProvider(
            new ServiceCollection().BuildServiceProvider(),
            NullLogger<AIContextProvider>.Instance,
            testOptionsMonitor,
            new ChatClientFactory(new ConfigurationManager(), NullLoggerFactory.Instance, testOptionsMonitor),
            new IceBreakersBuilder(new TestStringLocalizer<AIPrompts>()));
    }
}