Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions SemanticKernelPooling.Tests.Mocks/MockAIConfiguration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
namespace SemanticKernelPooling.Tests.Mocks;

/// <summary>
/// Represents a mock configuration for testing kernel pool behavior.
/// This configuration simulates the settings required for AI service providers without actual credentials.
/// </summary>
/// <remarks>
/// This mock configuration is used in unit tests to verify the kernel pooling behavior
/// without requiring actual AI service provider credentials or connections.
/// </remarks>
public record MockAIConfiguration : AIServiceProviderConfiguration
{
/// <summary>
/// Gets or initializes the API key used for testing.
/// In mock scenarios, this can be any non-null string.
/// </summary>
public required string ApiKey { get; init; }

/// <summary>
/// Gets or initializes the model identifier used for testing.
/// In mock scenarios, this can be any non-null string.
/// </summary>
public required string ModelId { get; init; }

/// <summary>
/// Gets or initializes the service identifier used for testing.
/// In mock scenarios, this can be any non-null string.
/// </summary>
public required string ServiceId { get; init; }

/// <summary>
/// Gets or initializes the endpoint URL used for testing.
/// In mock scenarios, this can be any valid URL string.
/// </summary>
public required string Endpoint { get; init; }
}
63 changes: 63 additions & 0 deletions SemanticKernelPooling.Tests.Mocks/MockKernelPool.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using Microsoft.Extensions.Logging;
using Microsoft.SemanticKernel;

namespace SemanticKernelPooling.Tests.Mocks;

/// <summary>
/// Provides a mock implementation of the kernel pool for testing purposes.
/// This implementation simulates the behavior of a real kernel pool without requiring actual AI service connections.
/// </summary>
/// <remarks>
/// <para>
/// The mock kernel pool tracks kernel creation and provides a controllable environment for testing
/// kernel pool behaviors including creation, disposal, and reuse patterns.
/// </para>
/// <para>
/// Example usage:
/// <code>
/// var config = new MockAIConfiguration { ... };
/// var pool = new MockKernelPool(config, loggerFactory, "path/to/responses");
/// </code>
/// </para>
/// </remarks>
public class MockKernelPool : AIServicePool<MockAIConfiguration>
{
private readonly ILoggerFactory _loggerFactory;
private int _kernelCreationCount;

/// <summary>
/// Initializes a new instance of the <see cref="MockKernelPool"/> class.
/// </summary>
/// <param name="config">The configuration for the mock kernel pool.</param>
/// <param name="loggerFactory">The factory for creating loggers.</param>
/// <param name="responsesPath">The path to mock response files. Defaults to "MockResponses".</param>
public MockKernelPool(
MockAIConfiguration config,
ILoggerFactory loggerFactory)
: base(config)
{
_loggerFactory = loggerFactory;
}

/// <summary>
/// Registers a mock chat completion service with the kernel builder.
/// </summary>
/// <param name="kernelBuilder">The kernel builder to configure.</param>
/// <param name="config">The mock configuration to use.</param>
/// <param name="httpClient">Optional HTTP client to use. If null, a mock client will be created.</param>
protected override void RegisterChatCompletionService(
IKernelBuilder kernelBuilder,
MockAIConfiguration config,
HttpClient? httpClient)
{
Interlocked.Increment(ref _kernelCreationCount);
}

/// <inheritdoc/>
protected override ILogger Logger => _loggerFactory.CreateLogger<MockKernelPool>();

/// <summary>
/// Gets the number of kernels that have been created by this pool.
/// </summary>
public int KernelCreationCount => _kernelCreationCount;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\SemanticKernelPooling\SemanticKernelPooling.csproj" />
</ItemGroup>

</Project>
58 changes: 58 additions & 0 deletions SemanticKernelPooling.Tests.Mocks/ServiceExtension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace SemanticKernelPooling.Tests.Mocks;

/// <summary>
/// Provides extension methods for registering mock kernel pools with the service collection.
/// </summary>
/// <remarks>
/// This extension follows the same pattern as the production service extensions but provides
/// mock implementations for testing purposes.
/// </remarks>
public static class ServiceExtension
{
/// <summary>
/// Registers mock kernel pool implementations for testing purposes.
/// </summary>
/// <param name="serviceProvider">The DI service provider.</param>
/// <returns>The service provider to enable method chaining.</returns>
/// <remarks>
/// <para>
/// This method registers mock implementations for both OpenAI and Azure OpenAI service types,
/// allowing tests to run without actual service dependencies.
/// </para>
/// <para>
/// Example usage:
/// <code>
/// services.AddSingleton(mockConfiguration.Object);
/// services.UseSemanticKernelPooling();
/// serviceProvider.UseMockKernelPool();
/// </code>
/// </para>
/// </remarks>
public static IServiceProvider UseMockKernelPool(
this IServiceProvider serviceProvider,
string responsesPath = "MockResponses")
{
var registrar = serviceProvider.GetRequiredService<IKernelPoolFactoryRegistrar>();

// Register factory for both mock providers
var factory = (AIServiceProviderConfiguration config, ILoggerFactory loggerFactory) =>
new MockKernelPool((MockAIConfiguration)config, loggerFactory);

registrar.RegisterKernelPoolFactory(AIServiceProviderType.OpenAI, factory);
registrar.RegisterKernelPoolFactory(AIServiceProviderType.AzureOpenAI, factory);

// Register configuration readers
var configReader = (IConfigurationSection section) =>
section.Get<MockAIConfiguration>() ??
throw new InvalidOperationException("Mock configuration not found.");

registrar.RegisterConfigurationReader(AIServiceProviderType.OpenAI, configReader);
registrar.RegisterConfigurationReader(AIServiceProviderType.AzureOpenAI, configReader);

return serviceProvider;
}
}
Loading