|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Text.Json.Nodes;
using Aspire.Hosting.ApplicationModel;
using Aspire.Hosting.Azure.Provisioning;
using Aspire.Hosting.Utils;
using Microsoft.Extensions.Configuration;
using Xunit;
namespace Aspire.Hosting.Azure.Tests;
public class AzureBicepProvisionerTests
{
[Fact]
public async Task SetParametersTranslatesParametersToARMCompatibleJsonParameters()
{
using var builder = TestDistributedApplicationBuilder.Create();
var bicep0 = builder.AddBicepTemplateString("bicep0", "param name string")
.WithParameter("name", "david");
var parameters = new JsonObject();
await BicepProvisioner.SetParametersAsync(parameters, bicep0.Resource);
Assert.Single(parameters);
Assert.Equal("david", parameters["name"]?["value"]?.ToString());
}
[Fact]
public async Task SetParametersTranslatesCompatibleParameterTypes()
{
using var builder = TestDistributedApplicationBuilder.Create();
var container = builder.AddContainer("foo", "image")
.WithHttpEndpoint()
.WithEndpoint("http", e =>
{
e.AllocatedEndpoint = new(e, "localhost", 1023);
});
builder.Configuration["Parameters:param"] = "paramValue";
var connectionStringResource = builder.CreateResourceBuilder(
new ResourceWithConnectionString("A", "connection string"));
var param = builder.AddParameter("param");
var bicep0 = builder.AddBicepTemplateString("bicep0", "param name string")
.WithParameter("name", "john")
.WithParameter("age", () => 20)
.WithParameter("values", ["a", "b", "c"])
.WithParameter("conn", connectionStringResource)
.WithParameter("jsonObj", new JsonObject { ["key"] = "value" })
.WithParameter("param", param)
.WithParameter("expr", ReferenceExpression.Create($"{param.Resource}/1"))
.WithParameter("endpoint", container.GetEndpoint("http"));
var parameters = new JsonObject();
await BicepProvisioner.SetParametersAsync(parameters, bicep0.Resource);
Assert.Equal(8, parameters.Count);
Assert.Equal("john", parameters["name"]?["value"]?.ToString());
Assert.Equal(20, parameters["age"]?["value"]?.GetValue<int>());
Assert.Equal(["a", "b", "c"], parameters["values"]?["value"]?.AsArray()?.Select(v => v?.ToString()) ?? []);
Assert.Equal("connection string", parameters["conn"]?["value"]?.ToString());
Assert.Equal("value", parameters["jsonObj"]?["value"]?["key"]?.ToString());
Assert.Equal("paramValue", parameters["param"]?["value"]?.ToString());
Assert.Equal("paramValue/1", parameters["expr"]?["value"]?.ToString());
Assert.Equal("http://localhost:1023", parameters["endpoint"]?["value"]?.ToString());
}
[Fact]
public async Task ResourceWithTheSameBicepTemplateAndParametersHaveTheSameCheckSum()
{
using var builder = TestDistributedApplicationBuilder.Create();
var bicep0 = builder.AddBicepTemplateString("bicep0", "param name string")
.WithParameter("name", "david")
.WithParameter("age", () => 20)
.WithParameter("values", ["a", "b", "c"])
.WithParameter("jsonObj", new JsonObject { ["key"] = "value" });
var bicep1 = builder.AddBicepTemplateString("bicep1", "param name string")
.WithParameter("name", "david")
.WithParameter("age", () => 20)
.WithParameter("values", ["a", "b", "c"])
.WithParameter("jsonObj", new JsonObject { ["key"] = "value" });
var parameters0 = new JsonObject();
await BicepProvisioner.SetParametersAsync(parameters0, bicep0.Resource);
var checkSum0 = BicepProvisioner.GetChecksum(bicep0.Resource, parameters0);
var parameters1 = new JsonObject();
await BicepProvisioner.SetParametersAsync(parameters1, bicep1.Resource);
var checkSum1 = BicepProvisioner.GetChecksum(bicep1.Resource, parameters1);
Assert.Equal(checkSum0, checkSum1);
}
[Theory]
[InlineData("1alpha")]
[InlineData("-alpha")]
[InlineData("")]
[InlineData(" alpha")]
[InlineData("alpha 123")]
public void WithParameterDoesNotAllowParameterNamesWhichAreInvalidBicepIdentifiers(string bicepParameterName)
{
Assert.Throws<ArgumentException>(() =>
{
using var builder = TestDistributedApplicationBuilder.Create();
builder.AddAzureInfrastructure("infrastructure", _ => { })
.WithParameter(bicepParameterName);
});
}
[Theory]
[InlineData("alpha")]
[InlineData("a1pha")]
[InlineData("_alpha")]
[InlineData("__alpha")]
[InlineData("alpha1_")]
[InlineData("Alpha1_A")]
public void WithParameterAllowsParameterNamesWhichAreValidBicepIdentifiers(string bicepParameterName)
{
using var builder = TestDistributedApplicationBuilder.Create();
builder.AddAzureInfrastructure("infrastructure", _ => { })
.WithParameter(bicepParameterName);
}
[Fact]
public async Task ResourceWithSameTemplateButDifferentParametersHaveDifferentChecksums()
{
using var builder = TestDistributedApplicationBuilder.Create();
var bicep0 = builder.AddBicepTemplateString("bicep0", "param name string")
.WithParameter("name", "david")
.WithParameter("age", () => 20)
.WithParameter("values", ["a", "b", "c"]);
var bicep1 = builder.AddBicepTemplateString("bicep1", "param name string")
.WithParameter("name", "david")
.WithParameter("age", () => 20)
.WithParameter("values", ["a", "b", "c"])
.WithParameter("jsonObj", new JsonObject { ["key"] = "value" });
var parameters0 = new JsonObject();
await BicepProvisioner.SetParametersAsync(parameters0, bicep0.Resource);
var checkSum0 = BicepProvisioner.GetChecksum(bicep0.Resource, parameters0);
var parameters1 = new JsonObject();
await BicepProvisioner.SetParametersAsync(parameters1, bicep1.Resource);
var checkSum1 = BicepProvisioner.GetChecksum(bicep1.Resource, parameters1);
Assert.NotEqual(checkSum0, checkSum1);
}
[Fact]
public async Task GetCurrentChecksumSkipsKnownValuesForCheckSumCreation()
{
using var builder = TestDistributedApplicationBuilder.Create();
var bicep0 = builder.AddBicepTemplateString("bicep0", "param name string")
.WithParameter("name", "david")
.WithParameter(AzureBicepResource.KnownParameters.KeyVaultName);
// Simulate the case where a known parameter has a value
var bicep1 = builder.AddBicepTemplateString("bicep1", "param name string")
.WithParameter("name", "david")
.WithParameter(AzureBicepResource.KnownParameters.KeyVaultName, "blah")
.WithParameter(AzureBicepResource.KnownParameters.PrincipalId, "id")
.WithParameter(AzureBicepResource.KnownParameters.Location, "tomorrow")
.WithParameter(AzureBicepResource.KnownParameters.PrincipalType, "type");
var parameters0 = new JsonObject();
await BicepProvisioner.SetParametersAsync(parameters0, bicep0.Resource);
var checkSum0 = BicepProvisioner.GetChecksum(bicep0.Resource, parameters0);
// Save the old version of this resource's parameters to config
var config = new ConfigurationManager();
config["Parameters"] = parameters0.ToJsonString();
var checkSum1 = await BicepProvisioner.GetCurrentChecksumAsync(bicep1.Resource, config);
Assert.Equal(checkSum0, checkSum1);
}
private sealed class ResourceWithConnectionString(string name, string connectionString) :
Resource(name),
IResourceWithConnectionString
{
public ReferenceExpression ConnectionStringExpression =>
ReferenceExpression.Create($"{connectionString}");
}
}
|