File: Model\ResourceGraphMapperTests.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.Collections.Immutable;
using System.Xml.Linq;
using Aspire.Dashboard.Model;
using Aspire.Dashboard.Model.ResourceGraph;
using Aspire.Dashboard.Resources;
using Aspire.Tests.Shared.DashboardModel;
using Microsoft.Extensions.Logging.Abstractions;
using Xunit;
using Icons = Microsoft.FluentUI.AspNetCore.Components.Icons;
 
namespace Aspire.Dashboard.Tests.Model;
 
public class ResourceGraphMapperTests
{
    private readonly IconResolver _iconResolver = new IconResolver(NullLogger<IconResolver>.Instance);
 
    [Fact]
    public void MapResource_HasReference_Added()
    {
        // Arrange
        var resource1 = ModelTestHelpers.CreateResource("app1-abcxyc", displayName: "app1", relationships: [new RelationshipViewModel("app2", "Reference")]);
        var resource2 = ModelTestHelpers.CreateResource("app2-123456", displayName: "app2", relationships: ImmutableArray<RelationshipViewModel>.Empty);
        var resources = new Dictionary<string, ResourceViewModel>
        {
            [resource1.Name] = resource1,
            [resource2.Name] = resource2,
        };
 
        // Act
        var dto = ResourceGraphMapper.MapResource(resource1, resources.Values, resources, new TestStringLocalizer<Columns>(), showHiddenResources: false, _iconResolver);
 
        // Assert
        var referencedName = Assert.Single(dto.ReferencedNames);
        Assert.Equal("app2-123456", referencedName);
    }
 
    [Fact]
    public void MapResource_HasReferenceToReplicas_MultipleAdded()
    {
        // Arrange
        var resource1 = ModelTestHelpers.CreateResource("app1-abcxyc", displayName: "app1", relationships: [new RelationshipViewModel("app2", "Reference")]);
        var resource21 = ModelTestHelpers.CreateResource("app2-123456", displayName: "app2", relationships: ImmutableArray<RelationshipViewModel>.Empty);
        var resource22 = ModelTestHelpers.CreateResource("app2-654321", displayName: "app2", relationships: ImmutableArray<RelationshipViewModel>.Empty);
        var resources = new Dictionary<string, ResourceViewModel>
        {
            [resource1.Name] = resource1,
            [resource21.Name] = resource21,
            [resource22.Name] = resource22,
        };
 
        // Act
        var dto = ResourceGraphMapper.MapResource(resource1, resources.Values, resources, new TestStringLocalizer<Columns>(), showHiddenResources: false, _iconResolver);
 
        // Assert
        Assert.Collection(dto.ReferencedNames,
            r => Assert.Equal("app2-123456", r),
            r => Assert.Equal("app2-654321", r));
    }
 
    [Fact]
    public void MapResource_HasSelfReference_Ignored()
    {
        // Arrange
        var resource = ModelTestHelpers.CreateResource("app1-abcxyc", displayName: "app1", relationships: ImmutableArray<RelationshipViewModel>.Empty);
        var resources = new Dictionary<string, ResourceViewModel>
        {
            [resource.Name] = resource,
        };
 
        // Act
        var dto = ResourceGraphMapper.MapResource(resource, resources.Values, resources, new TestStringLocalizer<Columns>(), showHiddenResources: false, _iconResolver);
 
        // Assert
        Assert.Empty(dto.ReferencedNames);
    }
 
    [Fact]
    public void MapResource_ShowHiddenResources_IncludesHiddenResources()
    {
        // Arrange
        var resource1 = ModelTestHelpers.CreateResource("app1-abcxyc", displayName: "app1", relationships: [new RelationshipViewModel("hidden-app", "Reference")]);
        var hiddenResource = ModelTestHelpers.CreateResource("hidden-app", displayName: "hidden-app", relationships: ImmutableArray<RelationshipViewModel>.Empty, hidden: true);
        var resources = new Dictionary<string, ResourceViewModel>
        {
            [resource1.Name] = resource1,
            [hiddenResource.Name] = hiddenResource,
        };
 
        // Act
        var dto = ResourceGraphMapper.MapResource(resource1, resources.Values, resources, new TestStringLocalizer<Columns>(), showHiddenResources: true, _iconResolver);
 
        // Assert
        Assert.Contains("hidden-app", dto.ReferencedNames);
    }
 
    [Fact]
    public void MapResource_ParameterResource_NoEndpoint()
    {
        // Arrange
        var resource = ModelTestHelpers.CreateResource(
            "api-key",
            displayName: "api-key",
            resourceType: KnownResourceTypes.Parameter,
            relationships: ImmutableArray<RelationshipViewModel>.Empty);
        var resources = new Dictionary<string, ResourceViewModel>
        {
            [resource.Name] = resource,
        };
 
        // Act
        var dto = ResourceGraphMapper.MapResource(resource, resources.Values, resources, new TestStringLocalizer<Columns>(), showHiddenResources: false, _iconResolver);
 
        // Assert
        Assert.Null(dto.EndpointUrl);
        Assert.Null(dto.EndpointText);
    }
 
    [Fact]
    public void MapResource_NonParameterResource_HasEndpointText()
    {
        // Arrange
        var resource = ModelTestHelpers.CreateResource(
            "app1",
            displayName: "app1",
            resourceType: KnownResourceTypes.Container,
            relationships: ImmutableArray<RelationshipViewModel>.Empty);
        var resources = new Dictionary<string, ResourceViewModel>
        {
            [resource.Name] = resource,
        };
 
        // Act
        var dto = ResourceGraphMapper.MapResource(resource, resources.Values, resources, new TestStringLocalizer<Columns>(), showHiddenResources: false, _iconResolver);
 
        // Assert - non-parameter resources should always have endpoint text (even if "No endpoints")
        Assert.NotNull(dto.EndpointText);
    }
 
    [Fact]
    public void MapResource_ReferenceToResourceExcludedFromGraph_Ignored()
    {
        var resource = ModelTestHelpers.CreateResource("app", displayName: "app", relationships: [new RelationshipViewModel("api-key", "Reference")]);
        var parameter = ModelTestHelpers.CreateResource(
            "api-key",
            displayName: "api-key",
            resourceType: KnownResourceTypes.Parameter,
            relationships: ImmutableArray<RelationshipViewModel>.Empty);
        var resources = new Dictionary<string, ResourceViewModel>
        {
            [resource.Name] = resource,
            [parameter.Name] = parameter,
        };
 
        var dto = ResourceGraphMapper.MapResource(resource, [resource], resources, new TestStringLocalizer<Columns>(), showHiddenResources: false, _iconResolver);
 
        Assert.Empty(dto.ReferencedNames);
    }
 
    [Fact]
    public void GetIconPathData_SinglePath_ReturnsPathData()
    {
        var icon = new Icons.Filled.Size24.Box();
        var expectedPathData = XElement.Parse(icon.Content).Attribute("d")!.Value;
 
        var pathData = ResourceGraphMapper.GetIconPathData(icon);
 
        Assert.Equal(expectedPathData, pathData);
    }
 
    [Fact]
    public void GetIconPathData_MultiplePaths_ReturnsCombinedPathData()
    {
        var icon = new Icons.Filled.Size24.DocumentMultiple();
        var iconContent = XElement.Parse($"<svg>{icon.Content}</svg>");
        var expectedPaths = iconContent.Elements().Select(e => e.Attribute("d")!.Value).ToArray();
        Assert.Equal(3, expectedPaths.Length);
 
        var pathData = ResourceGraphMapper.GetIconPathData(icon);
 
        Assert.Equal(string.Join(' ', expectedPaths), pathData);
    }
}