FileSystemListCommandTests.cs•8.41 kB
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System.CommandLine.Parsing;
using System.Text.Json;
using System.Text.Json.Serialization;
using AzureMcp.AzureManagedLustre.Commands.FileSystem;
using AzureMcp.AzureManagedLustre.Models;
using AzureMcp.AzureManagedLustre.Services;
using AzureMcp.Core.Models.Command;
using AzureMcp.Core.Options;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using NSubstitute;
using NSubstitute.ExceptionExtensions;
namespace AzureMcp.AzureManagedLustre.UnitTests.FileSystem;
public class FileSystemListCommandTests
{
    private readonly IServiceProvider _serviceProvider;
    private readonly IAzureManagedLustreService _amlfsService;
    private readonly ILogger<FileSystemListCommand> _logger;
    private readonly FileSystemListCommand _command;
    private readonly CommandContext _context;
    private readonly Parser _parser;
    private readonly string _knownSubscriptionId = "sub123";
    private readonly string _knownResourceIdRg1 = "/subscriptions/sub123/resourceGroups/rg1/providers/Microsoft.Lustre/amlfs/fs1";
    private readonly string _knownResourceIdRg2 = "/subscriptions/sub123/resourceGroups/rg2/providers/Microsoft.Lustre/amlfs/fs2";
    public FileSystemListCommandTests()
    {
        _amlfsService = Substitute.For<IAzureManagedLustreService>();
        _logger = Substitute.For<ILogger<FileSystemListCommand>>();
        var services = new ServiceCollection().AddSingleton(_amlfsService);
        _serviceProvider = services.BuildServiceProvider();
        _command = new(_logger);
        _context = new(_serviceProvider);
        _parser = new(_command.GetCommand());
    }
    [Fact]
    public void Constructor_InitializesCommandCorrectly()
    {
        var command = _command.GetCommand();
        Assert.Equal("list", command.Name);
        Assert.NotNull(command.Description);
        Assert.NotEmpty(command.Description);
    }
    [Fact]
    public async Task ExecuteAsync_ReturnsFileSystems()
    {
        // Arrange
        var expected = new List<LustreFileSystem>
        {
            new LustreFileSystem(
                "fs1",
                _knownResourceIdRg1,
                _knownSubscriptionId,
                "rg1",
                "eastus",
                "Succeeded",
                "Available",
                "10.0.0.5",
                "AMLFS-Durable-Premium-40",
                48,
                null,
                "Monday",
                "01:00"
            ),
            new LustreFileSystem(
                "fs2",
                _knownResourceIdRg2,
                _knownSubscriptionId,
                "rg2",
                "eastus",
                "Succeeded",
                "Available",
                "10.0.0.20",
                "AMLFS-Durable-Premium-40",
                48,
                null,
                "Monday",
                "01:00"
            ),
        };
        _amlfsService.ListFileSystemsAsync(
            Arg.Is(_knownSubscriptionId),
            Arg.Any<string>(),
            Arg.Any<string>(),
            Arg.Any<RetryPolicyOptions?>())
            .Returns(expected);
        var args = _parser.Parse([
            "--subscription", _knownSubscriptionId
        ]);
        // Act
        var response = await _command.ExecuteAsync(_context, args);
        // Assert
        Assert.NotNull(response);
        Assert.NotNull(response.Results);
        var json = JsonSerializer.Serialize(response.Results);
        var result = JsonSerializer.Deserialize<FileSystemListResultJson>(json);
        Assert.NotNull(result);
        Assert.NotNull(result!.FileSystems);
        Assert.Equal(2, result.FileSystems.Count);
        Assert.Equal("fs1", result.FileSystems[0].Name);
    }
    [Theory]
    [InlineData("--resource-group testrg", false)] // Missing subscription
    [InlineData("--subscription sub123", true)] // Missing resource group
    [InlineData(" --resource-group testrg --subscription sub123", true)]
    [InlineData("", false)] // No parameters
    public async Task ExecuteAsync_ValidatesInputCorrectly(string args, bool shouldSucceed)
    {
        // Arrange
        if (shouldSucceed)
        {
            var expected = new List<LustreFileSystem>
        {
            new LustreFileSystem(
                "fs1",
                _knownResourceIdRg1,
                _knownSubscriptionId,
                "rg1",
                "eastus",
                "Succeeded",
                "Available",
                "10.0.0.5",
                "AMLFS-Durable-Premium-40",
                48,
                null,
                "Monday",
                "01:00"
            ),
        };
            _amlfsService.ListFileSystemsAsync(
            Arg.Is(_knownSubscriptionId),
            Arg.Any<string>(),
            Arg.Any<string>(),
            Arg.Any<RetryPolicyOptions?>())
            .Returns(expected);
        }
        var parseResult = _parser.Parse(args.Split(' ', StringSplitOptions.RemoveEmptyEntries));
        // 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);
            var json = JsonSerializer.Serialize(response.Results);
            var result = JsonSerializer.Deserialize<FileSystemListResultJson>(json);
            Assert.NotNull(result!.FileSystems);
            Assert.NotNull(result.FileSystems[0].Name);
            Assert.Equal("fs1", result.FileSystems[0].Name);
        }
        else
        {
            Assert.Contains("required", response.Message.ToLower());
        }
    }
    [Fact]
    public async Task ExecuteAsync_ReturnsNull_WhenNoItems()
    {
        // Arrange
        _amlfsService.ListFileSystemsAsync(
            Arg.Is(_knownSubscriptionId),
            Arg.Is<string?>(x => x == null),
            Arg.Any<string?>(),
            Arg.Any<RetryPolicyOptions?>())
            .Returns([]);
        var args = _parser.Parse([
            "--subscription", _knownSubscriptionId
        ]);
        // Act
        var response = await _command.ExecuteAsync(_context, args);
        // Assert
        Assert.NotNull(response);
        Assert.Null(response.Results);
    }
    [Fact]
    public async Task ExecuteAsync_HandlesRequestFailedException_NotFound()
    {
        // Arrange - 404 Not Found
        _amlfsService.ListFileSystemsAsync(
            Arg.Any<string>(), Arg.Any<string?>(), Arg.Any<string?>(), Arg.Any<RetryPolicyOptions?>())
            .ThrowsAsync(new Azure.RequestFailedException(404, "not found"));
        var args = _parser.Parse(["--subscription", _knownSubscriptionId]);
        var response = await _command.ExecuteAsync(_context, args);
        // Assert
        Assert.Equal(404, response.Status);
        Assert.Contains("not found", response.Message, StringComparison.OrdinalIgnoreCase);
    }
    [Fact]
    public async Task ExecuteAsync_HandlesRequestFailedException_Forbidden()
    {
        // Arrange - 403 Forbidden
        _amlfsService.ListFileSystemsAsync(
            Arg.Any<string>(), Arg.Any<string?>(), Arg.Any<string?>(), Arg.Any<RetryPolicyOptions?>())
            .ThrowsAsync(new Azure.RequestFailedException(403, "forbidden"));
        var args = _parser.Parse(["--subscription", _knownSubscriptionId]);
        var response = await _command.ExecuteAsync(_context, args);
        // Assert
        Assert.Equal(403, response.Status);
        Assert.Contains("forbidden", response.Message, StringComparison.OrdinalIgnoreCase);
    }
    private class FileSystemListResultJson
    {
        [JsonPropertyName("fileSystems")]
        public List<LustreFileSystemJson> FileSystems { get; set; } = [];
    }
    private class LustreFileSystemJson
    {
        [JsonPropertyName("name")]
        public string Name { get; set; } = string.Empty;
        [JsonPropertyName("id")]
        public string Id { get; set; } = string.Empty;
        [JsonPropertyName("resourceGroupName")]
        public string ResourceGroupName { get; set; } = string.Empty;
        [JsonPropertyName("subscriptionId")]
        public string SubscriptionId { get; set; } = string.Empty;
    }
}