File: AzurePrivateEndpointExtensionsTests.cs
Web Access
Project: src\tests\Aspire.Hosting.Azure.Tests\Aspire.Hosting.Azure.Tests.csproj (Aspire.Hosting.Azure.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
#pragma warning disable ASPIREAZURE003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
 
using Aspire.Hosting.Utils;
 
namespace Aspire.Hosting.Azure.Tests;
 
public class AzurePrivateEndpointExtensionsTests
{
    [Fact]
    public void AddPrivateEndpoint_CreatesResource()
    {
        using var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Publish);
 
        var vnet = builder.AddAzureVirtualNetwork("myvnet");
        var subnet = vnet.AddSubnet("pesubnet", "10.0.1.0/24");
        var storage = builder.AddAzureStorage("storage");
        var blobs = storage.AddBlobs("blobs");
 
        var pe = subnet.AddPrivateEndpoint(blobs);
 
        Assert.NotNull(pe);
        Assert.Equal("pesubnet-blobs-pe", pe.Resource.Name);
        Assert.IsType<AzurePrivateEndpointResource>(pe.Resource);
        Assert.Same(subnet.Resource, pe.Resource.Subnet);
        Assert.Same(blobs.Resource, pe.Resource.Target);
    }
 
    [Fact]
    public void AddPrivateEndpoint_AddsAnnotationToParentStorage()
    {
        using var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Publish);
 
        var vnet = builder.AddAzureVirtualNetwork("myvnet");
        var subnet = vnet.AddSubnet("pesubnet", "10.0.1.0/24");
        var storage = builder.AddAzureStorage("storage");
        var blobs = storage.AddBlobs("blobs");
 
        // Before adding PE, no annotation
        Assert.Empty(storage.Resource.Annotations.OfType<PrivateEndpointTargetAnnotation>());
 
        subnet.AddPrivateEndpoint(blobs);
 
        // After adding PE, annotation should be on parent storage
        var annotation = storage.Resource.Annotations.OfType<PrivateEndpointTargetAnnotation>().SingleOrDefault();
        Assert.NotNull(annotation);
    }
 
    [Fact]
    public void AddPrivateEndpoint_ForQueues_AddsAnnotationToParentStorage()
    {
        using var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Publish);
 
        var vnet = builder.AddAzureVirtualNetwork("myvnet");
        var subnet = vnet.AddSubnet("pesubnet", "10.0.1.0/24");
        var storage = builder.AddAzureStorage("storage");
        var queues = storage.AddQueues("queues");
 
        subnet.AddPrivateEndpoint(queues);
 
        var annotation = storage.Resource.Annotations.OfType<PrivateEndpointTargetAnnotation>().SingleOrDefault();
        Assert.NotNull(annotation);
    }
 
    [Fact]
    public async Task AddPrivateEndpoint_GeneratesBicep()
    {
        using var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Publish);
 
        var vnet = builder.AddAzureVirtualNetwork("myvnet");
        var subnet = vnet.AddSubnet("pesubnet", "10.0.1.0/24");
        var storage = builder.AddAzureStorage("storage");
        var blobs = storage.AddBlobs("blobs");
 
        var pe = subnet.AddPrivateEndpoint(blobs);
 
        var manifest = await AzureManifestUtils.GetManifestWithBicep(pe.Resource);
 
        await Verify(manifest.BicepText, extension: "bicep");
    }
 
    [Fact]
    public async Task AddPrivateEndpoint_ForQueues_GeneratesBicep()
    {
        using var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Publish);
 
        var vnet = builder.AddAzureVirtualNetwork("myvnet");
        var subnet = vnet.AddSubnet("pesubnet", "10.0.1.0/24");
        var storage = builder.AddAzureStorage("storage");
        var queues = storage.AddQueues("queues");
 
        var pe = subnet.AddPrivateEndpoint(queues);
 
        var manifest = await AzureManifestUtils.GetManifestWithBicep(pe.Resource);
 
        await Verify(manifest.BicepText, extension: "bicep");
    }
 
    [Fact]
    public void AddPrivateEndpoint_InRunMode_DoesNotAddToBuilder()
    {
        using var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Run);
 
        var vnet = builder.AddAzureVirtualNetwork("myvnet");
        var subnet = vnet.AddSubnet("pesubnet", "10.0.1.0/24");
        var storage = builder.AddAzureStorage("storage");
        var blobs = storage.AddBlobs("blobs");
 
        var pe = subnet.AddPrivateEndpoint(blobs);
 
        // In run mode, the PE resource should not be added to the builder's resources
        Assert.DoesNotContain(pe.Resource, builder.Resources);
    }
 
    [Fact]
    public void AzureBlobStorageResource_ImplementsIAzurePrivateEndpointTarget()
    {
        using var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Publish);
 
        var storage = builder.AddAzureStorage("storage");
        var blobs = storage.AddBlobs("blobs");
 
        Assert.IsAssignableFrom<IAzurePrivateEndpointTarget>(blobs.Resource);
 
        var target = (IAzurePrivateEndpointTarget)blobs.Resource;
        Assert.Equal(["blob"], target.GetPrivateLinkGroupIds());
        Assert.Equal("privatelink.blob.core.windows.net", target.GetPrivateDnsZoneName());
    }
 
    [Fact]
    public void AzureQueueStorageResource_ImplementsIAzurePrivateEndpointTarget()
    {
        using var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Publish);
 
        var storage = builder.AddAzureStorage("storage");
        var queues = storage.AddQueues("queues");
 
        Assert.IsAssignableFrom<IAzurePrivateEndpointTarget>(queues.Resource);
 
        var target = (IAzurePrivateEndpointTarget)queues.Resource;
        Assert.Equal(["queue"], target.GetPrivateLinkGroupIds());
        Assert.Equal("privatelink.queue.core.windows.net", target.GetPrivateDnsZoneName());
    }
 
    [Fact]
    public async Task AddPrivateEndpoint_ReusesDnsZone_ForSameZoneName()
    {
        using var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Publish);
 
        var vnet = builder.AddAzureVirtualNetwork("myvnet");
        var subnet = vnet.AddSubnet("pesubnet", "10.0.1.0/24");
 
        // Two storage accounts with blob endpoints (same DNS zone name)
        var storage1 = builder.AddAzureStorage("storage1");
        var blobs1 = storage1.AddBlobs("blobs1");
 
        var storage2 = builder.AddAzureStorage("storage2");
        var blobs2 = storage2.AddBlobs("blobs2");
 
        // Create two private endpoints for the same DNS zone type
        var pe1 = subnet.AddPrivateEndpoint(blobs1);
        var pe2 = subnet.AddPrivateEndpoint(blobs2);
 
        // Should only have one DNS Zone resource
        var dnsZones = builder.Resources.OfType<AzurePrivateDnsZoneResource>().ToList();
        Assert.Single(dnsZones);
        Assert.Equal("privatelink.blob.core.windows.net", dnsZones[0].ZoneName);
 
        // Should only have one VNet Link
        Assert.Single(dnsZones[0].VNetLinks);
        var vnetLinks = builder.Resources.OfType<AzurePrivateDnsZoneVNetLinkResource>().ToList();
        Assert.Single(vnetLinks);
 
        // Verify the bicep for DNS Zone, VNet Link, and both PEs
        var (_, dnsZoneBicep) = await AzureManifestUtils.GetManifestWithBicep(dnsZones[0]);
        var (_, pe1Bicep) = await AzureManifestUtils.GetManifestWithBicep(pe1.Resource);
        var (_, pe2Bicep) = await AzureManifestUtils.GetManifestWithBicep(pe2.Resource);
 
        await Verify(dnsZoneBicep, extension: "bicep")
            .AppendContentAsFile(pe1Bicep, "bicep", "pe1")
            .AppendContentAsFile(pe2Bicep, "bicep", "pe2");
    }
 
    [Fact]
    public void AddPrivateEndpoint_CreatesSeparateDnsZones_ForDifferentZoneNames()
    {
        using var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Publish);
 
        var vnet = builder.AddAzureVirtualNetwork("myvnet");
        var subnet = vnet.AddSubnet("pesubnet", "10.0.1.0/24");
 
        var storage = builder.AddAzureStorage("storage");
        var blobs = storage.AddBlobs("blobs");
        var queues = storage.AddQueues("queues");
 
        // Create two private endpoints for different DNS zone types
        subnet.AddPrivateEndpoint(blobs);
        subnet.AddPrivateEndpoint(queues);
 
        // Should have two DNS Zone resources
        var dnsZones = builder.Resources.OfType<AzurePrivateDnsZoneResource>().ToList();
        Assert.Equal(2, dnsZones.Count);
        Assert.Contains(dnsZones, z => z.ZoneName == "privatelink.blob.core.windows.net");
        Assert.Contains(dnsZones, z => z.ZoneName == "privatelink.queue.core.windows.net");
 
        // Each DNS Zone should have one VNet Link
        Assert.All(dnsZones, z => Assert.Single(z.VNetLinks));
    }
}