// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System.Text.Json;
using AzureMcp.Core.Models;
using AzureMcp.Tests;
using AzureMcp.Tests.Client;
using AzureMcp.Tests.Client.Helpers;
using Xunit;
namespace AzureMcp.Acr.LiveTests;
[Trait("Area", "Acr")]
[Trait("Category", "Live")]
public class AcrCommandTests(LiveTestFixture liveTestFixture, ITestOutputHelper output)
: CommandTestsBase(liveTestFixture, output), IClassFixture<LiveTestFixture>
{
[Theory]
[InlineData(AuthMethod.Credential)]
public async Task Should_list_acr_registries_by_subscription(AuthMethod authMethod)
{
// Arrange & Act
var result = await CallToolAsync(
"azmcp_acr_registry_list",
new()
{
{ "subscription", Settings.SubscriptionId },
{ "auth-method", authMethod.ToString() }
});
// Assert
var registries = result.AssertProperty("registries");
Assert.Equal(JsonValueKind.Array, registries.ValueKind);
var registryItems = registries.EnumerateArray().ToList();
if (registryItems.Count == 0)
{
// Fallback: attempt with resource group filter (test RG hosts the registry via bicep)
var rgResult = await CallToolAsync(
"azmcp_acr_registry_list",
new()
{
{ "subscription", Settings.SubscriptionId },
{ "resource-group", Settings.ResourceGroupName },
{ "auth-method", authMethod.ToString() }
});
var rgRegistries = rgResult.AssertProperty("registries");
Assert.Equal(JsonValueKind.Array, rgRegistries.ValueKind);
registryItems = [.. rgRegistries.EnumerateArray()];
}
Assert.NotEmpty(registryItems); // After fallback we must have at least one registry
// Validate that the test registry exists (created by bicep as baseName)
var hasTestRegistry = registryItems.Any(item =>
item.TryGetProperty("name", out var nameProp) &&
string.Equals(nameProp.GetString(), Settings.ResourceBaseName, StringComparison.OrdinalIgnoreCase));
Assert.True(hasTestRegistry, $"Expected test registry '{Settings.ResourceBaseName}' to exist.");
foreach (var item in registryItems)
{
// Enforce new object shape { name, location?, loginServer?, skuName?, skuTier? }
Assert.Equal(JsonValueKind.Object, item.ValueKind);
Assert.True(item.TryGetProperty("name", out var nameProp));
var objName = nameProp.GetString();
Assert.False(string.IsNullOrWhiteSpace(objName));
Assert.Matches("^[a-z0-9]+(-[a-z0-9]+)*$", objName!); // Basic ACR naming pattern
if (item.TryGetProperty("location", out var locationProp))
{
Assert.False(string.IsNullOrWhiteSpace(locationProp.GetString()));
}
if (item.TryGetProperty("loginServer", out var loginServerProp))
{
Assert.False(string.IsNullOrWhiteSpace(loginServerProp.GetString()));
}
}
}
[Theory]
[InlineData(AuthMethod.Credential)]
public async Task Should_list_repositories_for_registries(AuthMethod authMethod)
{
var result = await CallToolAsync(
"azmcp_acr_registry_repository_list",
new()
{
{ "subscription", Settings.SubscriptionId },
{ "resource-group", Settings.ResourceGroupName },
{ "auth-method", authMethod.ToString() }
});
if (result is null)
{
// No registries or repos found in the test RG/subscription; treat as pass with null results
return;
}
var map = result.AssertProperty("repositoriesByRegistry");
Assert.True(map.ValueKind == JsonValueKind.Object);
// Validate we have entries for the test registry and the seeded 'testrepo'
Assert.True(map.TryGetProperty(Settings.ResourceBaseName, out var repoArray));
Assert.Equal(JsonValueKind.Array, repoArray.ValueKind);
var repos = repoArray.EnumerateArray().Select(e => e.GetString()).Where(s => !string.IsNullOrWhiteSpace(s)).ToList();
Assert.Contains("testrepo", repos);
}
[Fact]
public async Task Should_handle_empty_subscription_gracefully()
{
// Empty subscription should trigger validation failure (400) -> null results
var result = await CallToolAsync(
"azmcp_acr_registry_list",
new()
{
{ "subscription", "" }
});
Assert.Null(result);
}
[Fact]
public async Task Should_handle_invalid_subscription_gracefully()
{
// Invalid identifier should reach execution and return structured error details (HasValue)
var result = await CallToolAsync(
"azmcp_acr_registry_list",
new()
{
{ "subscription", "invalid-subscription" }
});
Assert.NotNull(result);
var message = result.AssertProperty("message");
Assert.Contains("invalid-subscription", message.GetString(), StringComparison.OrdinalIgnoreCase);
}
[Fact]
public async Task Should_validate_required_subscription_parameter()
{
// Missing subscription option entirely should behave like other areas (validation -> null)
var result = await CallToolAsync(
"azmcp_acr_registry_list",
new Dictionary<string, object?>());
Assert.Null(result);
}
}