|
// 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 ASPIREAZURE001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
#pragma warning disable ASPIRECOMPUTE001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
using Aspire.Hosting.ApplicationModel;
using Aspire.Hosting.Utils;
using Azure.Provisioning;
using Azure.Provisioning.Storage;
namespace Aspire.Hosting.Azure.Tests;
public class AzureEnvironmentResourceTests(ITestOutputHelper output)
{
[Fact]
public async Task WhenUsedWithAzureContainerAppsEnvironment_GeneratesProperBicep()
{
// Arrange
var tempDir = Directory.CreateTempSubdirectory(".azure-environment-resource-test");
output.WriteLine($"Temp directory: {tempDir.FullName}");
using var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Publish, publisher: "default", outputPath: tempDir.FullName);
var containerAppEnv = builder.AddAzureContainerAppEnvironment("env");
// Add a container that will use the container app environment
builder.AddContainer("api", "my-api-image:latest")
.WithHttpEndpoint();
// Act
using var app = builder.Build();
app.Run();
var mainBicepPath = Path.Combine(tempDir.FullName, "main.bicep");
Assert.True(File.Exists(mainBicepPath));
var mainBicep = File.ReadAllText(mainBicepPath);
var envBicepPath = Path.Combine(tempDir.FullName, "env", "env.bicep");
Assert.True(File.Exists(envBicepPath));
var envBicep = File.ReadAllText(envBicepPath);
await Verifier.Verify(mainBicep, "bicep")
.AppendContentAsFile(envBicep, "bicep")
.UseHelixAwareDirectory();
tempDir.Delete(recursive: true);
}
[Fact]
public async Task WhenUsedWithAzureContainerAppsEnvironment_RespectsStronglyTypedProperties()
{
// Arrange
var tempDir = Directory.CreateTempSubdirectory(".azure-environment-resource-test");
output.WriteLine($"Temp directory: {tempDir.FullName}");
using var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Publish, publisher: "default", outputPath: tempDir.FullName);
var locationParam = builder.AddParameter("location", "eastus2");
var resourceGroupParam = builder.AddParameter("resourceGroup", "my-rg");
builder.AddAzureEnvironment()
.WithLocation(locationParam)
.WithResourceGroup(resourceGroupParam);
var containerAppEnv = builder.AddAzureContainerAppEnvironment("env");
// Add a container that will use the container app environment
builder.AddContainer("api", "my-api-image:latest")
.WithHttpEndpoint();
// Act
using var app = builder.Build();
app.Run();
var mainBicepPath = Path.Combine(tempDir.FullName, "main.bicep");
Assert.True(File.Exists(mainBicepPath));
var mainBicep = File.ReadAllText(mainBicepPath);
await Verify(mainBicep, "bicep")
.UseHelixAwareDirectory();
tempDir.Delete(recursive: true);
}
[Fact]
public async Task PublishAsync_GeneratesMainBicep_WithSnapshots()
{
// Arrange
var tempDir = Directory.CreateTempSubdirectory(".azure-environment-resource-test");
output.WriteLine($"Temp directory: {tempDir.FullName}");
var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Publish,
publisher: "default",
outputPath: tempDir.FullName);
builder.AddAzureContainerAppEnvironment("acaEnv");
var storageSku = builder.AddParameter("storageSku", "Standard_LRS", publishValueAsDefault: true);
var description = builder.AddParameter("skuDescription", "The sku is ", publishValueAsDefault: true);
var skuDescriptionExpr = ReferenceExpression.Create($"{description} {storageSku}");
var kvName = builder.AddParameter("kvName");
var kvRg = builder.AddParameter("kvRg", "rg-shared");
builder.AddAzureKeyVault("kv").AsExisting(kvName, kvRg);
builder.AddAzureStorage("existing-storage").PublishAsExisting("images", "rg-shared");
var pgdb = builder.AddAzurePostgresFlexibleServer("pg").AddDatabase("pgdb");
var cosmos = builder.AddAzureCosmosDB("account").AddCosmosDatabase("db");
var blobs = builder.AddAzureStorage("storage")
.ConfigureInfrastructure(c =>
{
var storageAccount = c.GetProvisionableResources().OfType<StorageAccount>().FirstOrDefault();
storageAccount!.Sku.Name = storageSku.AsProvisioningParameter(c);
var output = new ProvisioningOutput("description", typeof(string))
{
Value = skuDescriptionExpr.AsProvisioningParameter(c, "sku_description")
};
c.Add(output);
})
.AddBlobs("blobs");
builder.AddAzureInfrastructure("mod", infra => { })
.WithParameter("pgdb", pgdb.Resource.ConnectionStringExpression);
builder.AddContainer("myapp", "mcr.microsoft.com/dotnet/aspnet:8.0")
.WithReference(cosmos);
builder.AddProject<TestProject>("fe", launchProfileName: null)
.WithEnvironment("BLOB_CONTAINER_URL", $"{blobs}/container");
var app = builder.Build();
app.Run();
var mainBicepPath = Path.Combine(tempDir.FullName, "main.bicep");
Assert.True(File.Exists(mainBicepPath));
var content = File.ReadAllText(mainBicepPath);
await Verifier.Verify(content, extension: "bicep").UseHelixAwareDirectory();
}
[Fact]
public async Task AzurePublishingContext_CapturesParametersAndOutputsCorrectly_WithSnapshot()
{
var tempDir = Directory.CreateTempSubdirectory(".azure-environment-resource-test");
output.WriteLine($"Temp directory: {tempDir.FullName}");
var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Publish,
publisher: "default",
outputPath: tempDir.FullName);
builder.AddAzureContainerAppEnvironment("acaEnv");
var storageSku = builder.AddParameter("storage-Sku", "Standard_LRS", publishValueAsDefault: true);
var description = builder.AddParameter("skuDescription", "The sku is ", publishValueAsDefault: true);
var skuDescriptionExpr = ReferenceExpression.Create($"{description} {storageSku}");
var kv = builder.AddAzureKeyVault("kv");
var cosmos = builder.AddAzureCosmosDB("account").AddCosmosDatabase("db");
var blobs = builder.AddAzureStorage("storage")
.ConfigureInfrastructure(c =>
{
var storageAccount = c.GetProvisionableResources().OfType<StorageAccount>().FirstOrDefault();
storageAccount!.Sku.Name = storageSku.AsProvisioningParameter(c);
var output = new ProvisioningOutput("description", typeof(string))
{
Value = skuDescriptionExpr.AsProvisioningParameter(c, "sku_description")
};
c.Add(output);
})
.AddBlobs("blobs");
builder.AddProject<TestProject>("fe", launchProfileName: null)
.WithEnvironment("BLOB_CONTAINER_URL", $"{blobs}/container")
.WithReference(cosmos);
var externalResource = new ExternalResourceWithParameters("external")
{
Parameters =
{
["kvUri"] = kv.Resource.VaultUri,
["blob"] = blobs.Resource.ConnectionStringExpression,
}
};
builder.AddResource(externalResource);
var app = builder.Build();
app.Run();
var mainBicep = File.ReadAllText(Path.Combine(tempDir.FullName, "main.bicep"));
var storageBicep = File.ReadAllText(Path.Combine(tempDir.FullName, "storage", "storage.bicep"));
await Verify(mainBicep, "bicep")
.AppendContentAsFile(storageBicep, "bicep")
.UseHelixAwareDirectory();
}
private sealed class TestProject : IProjectMetadata
{
public string ProjectPath => "another-path";
public LaunchSettings? LaunchSettings { get; set; }
}
private sealed class ExternalResourceWithParameters(string name) : Resource(name), IResourceWithParameters
{
public IDictionary<string, object?> Parameters { get; } = new Dictionary<string, object?>();
}
}
|