FunctionAppListCommandTests.cs•6.09 kB
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System.CommandLine;
using System.Text.Json;
using AzureMcp.Core.Models.Command;
using AzureMcp.Core.Options;
using AzureMcp.FunctionApp.Commands;
using AzureMcp.FunctionApp.Commands.FunctionApp;
using AzureMcp.FunctionApp.Models;
using AzureMcp.FunctionApp.Services;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using NSubstitute;
using Xunit;
namespace AzureMcp.FunctionApp.UnitTests;
public sealed class FunctionAppListCommandTests
{
    private readonly IServiceProvider _serviceProvider;
    private readonly IFunctionAppService _functionAppService;
    private readonly ILogger<FunctionAppListCommand> _logger;
    private readonly FunctionAppListCommand _command;
    public FunctionAppListCommandTests()
    {
        _functionAppService = Substitute.For<IFunctionAppService>();
        _logger = Substitute.For<ILogger<FunctionAppListCommand>>();
        var collection = new ServiceCollection();
        collection.AddSingleton(_functionAppService);
        _serviceProvider = collection.BuildServiceProvider();
        _command = new(_logger);
    }
    [Fact]
    public void Constructor_InitializesCommandCorrectly()
    {
        var command = _command.GetCommand();
        Assert.Equal("list", command.Name);
        Assert.NotNull(command.Description);
        Assert.NotEmpty(command.Description);
    }
    [Theory]
    [InlineData("--subscription sub123", true)]
    [InlineData("--subscription sub123 --tenant tenant123", true)]
    [InlineData("", false)]
    public async Task ExecuteAsync_ValidatesInputCorrectly(string args, bool shouldSucceed)
    {
        // Arrange
        if (shouldSucceed)
        {
            var testFunctionApps = new List<FunctionAppInfo>
            {
                new("functionApp1", null, "eastus", "plan1", "Running", "functionapp1.azurewebsites.net", null),
                new("functionApp2", null, "westus", "plan2", "Stopped", "functionapp2.azurewebsites.net", null)
            };
            _functionAppService.ListFunctionApps(Arg.Any<string>(), Arg.Any<string?>(), Arg.Any<RetryPolicyOptions?>())
                .Returns(testFunctionApps);
        }
        var context = new CommandContext(_serviceProvider);
        var parseResult = _command.GetCommand().Parse(args);
        // Act
        var response = await _command.ExecuteAsync(context, parseResult);
        // Assert
        Assert.Equal(shouldSucceed ? 200 : 400, response.Status);
        if (shouldSucceed)
        {
            Assert.NotNull(response.Results);
            Assert.Equal("Success", response.Message);
        }
        else
        {
            Assert.Contains("required", response.Message.ToLower());
        }
    }
    [Fact]
    public async Task ExecuteAsync_ReturnsFunctionAppList()
    {
        // Arrange
        var expectedFunctionApps = new List<FunctionAppInfo>
        {
            new("functionApp1", "rg1", "eastus", "plan1", "Running", "functionapp1.azurewebsites.net", null),
            new("functionApp2", "rg2", "westus", "plan2", "Stopped", "functionapp2.azurewebsites.net", null)
        };
        _functionAppService.ListFunctionApps(Arg.Any<string>(), Arg.Any<string?>(), Arg.Any<RetryPolicyOptions?>())
            .Returns(expectedFunctionApps);
        var context = new CommandContext(_serviceProvider);
        var parseResult = _command.GetCommand().Parse("--subscription sub123");
        // Act
        var response = await _command.ExecuteAsync(context, parseResult);
        // Assert
        Assert.Equal(200, response.Status);
        Assert.NotNull(response.Results);
        // Verify the mock was called
        await _functionAppService.Received(1).ListFunctionApps(Arg.Any<string>(), Arg.Any<string?>(), Arg.Any<RetryPolicyOptions?>());
        var json = JsonSerializer.Serialize(response.Results);
        var result = JsonSerializer.Deserialize<FunctionAppListCommand.FunctionAppListCommandResult>(json, FunctionAppJsonContext.Default.FunctionAppListCommandResult);
        Assert.NotNull(result);
        Assert.Equal(expectedFunctionApps.Count, result.Results.Count);
        Assert.Equal(expectedFunctionApps[0].Name, result.Results[0].Name);
        Assert.Equal(expectedFunctionApps[0].ResourceGroupName, result.Results[0].ResourceGroupName);
        Assert.Equal(expectedFunctionApps[0].AppServicePlanName, result.Results[0].AppServicePlanName);
        Assert.Equal(expectedFunctionApps[0].Location, result.Results[0].Location);
        Assert.Equal(expectedFunctionApps[0].Status, result.Results[0].Status);
        Assert.Equal(expectedFunctionApps[0].DefaultHostName, result.Results[0].DefaultHostName);
    }
    [Fact]
    public async Task ExecuteAsync_ReturnsNullWhenNoFunctionApp()
    {
        // Arrange
        _functionAppService.ListFunctionApps(Arg.Any<string>(), Arg.Any<string?>(), Arg.Any<RetryPolicyOptions?>())
            .Returns(new List<FunctionAppInfo>());
        var context = new CommandContext(_serviceProvider);
        var parseResult = _command.GetCommand().Parse("--subscription sub123");
        // Act
        var response = await _command.ExecuteAsync(context, parseResult);
        // Assert
        Assert.Equal(200, response.Status);
        Assert.Null(response.Results);
    }
    [Fact]
    public async Task ExecuteAsync_HandlesServiceErrors()
    {
        // Arrange
        _functionAppService.ListFunctionApps(Arg.Any<string>(), Arg.Any<string?>(), Arg.Any<RetryPolicyOptions?>())
            .Returns(Task.FromException<List<FunctionAppInfo>?>(new Exception("Test error")));
        var context = new CommandContext(_serviceProvider);
        var parseResult = _command.GetCommand().Parse("--subscription sub123");
        // Act
        var response = await _command.ExecuteAsync(context, parseResult);
        // Assert
        Assert.Equal(500, response.Status);
        Assert.Contains("Test error", response.Message);
        Assert.Contains("troubleshooting", response.Message);
    }
}