Skip to content

Commit aac4336

Browse files
committed
Add Experimental attribute. Add more tests.
1 parent 81e3363 commit aac4336

File tree

5 files changed

+197
-37
lines changed

5 files changed

+197
-37
lines changed

src/Aspire.Hosting.Azure.AppContainers/AzureContainerAppContainerExtensions.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using Aspire.Hosting.ApplicationModel;
55
using Aspire.Hosting.Azure;
66
using Azure.Provisioning.AppContainers;
7+
using System.Diagnostics.CodeAnalysis;
78

89
namespace Aspire.Hosting;
910

@@ -56,6 +57,7 @@ public static IResourceBuilder<T> PublishAsAzureContainerApp<T>(this IResourceBu
5657
/// <param name="container"></param>
5758
/// <param name="configure"></param>
5859
/// <returns></returns>
60+
[Experimental("ASPIREAZURE002", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")]
5961
public static IResourceBuilder<T> PublishAsAzureContainerAppJob<T>(this IResourceBuilder<T> container, Action<AzureResourceInfrastructure, ContainerAppJob> configure)
6062
where T : ContainerResource
6163
{

src/Aspire.Hosting.Azure.AppContainers/AzureContainerAppProjectExtensions.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using Aspire.Hosting.ApplicationModel;
55
using Aspire.Hosting.Azure;
66
using Azure.Provisioning.AppContainers;
7+
using System.Diagnostics.CodeAnalysis;
78

89
namespace Aspire.Hosting;
910

@@ -56,6 +57,7 @@ public static IResourceBuilder<T> PublishAsAzureContainerApp<T>(this IResourceBu
5657
/// <param name="project"></param>
5758
/// <param name="configure"></param>
5859
/// <returns></returns>
60+
[Experimental("ASPIREAZURE002", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")]
5961
public static IResourceBuilder<T> PublishAsAzureContainerAppJob<T>(this IResourceBuilder<T> project, Action<AzureResourceInfrastructure, ContainerAppJob> configure)
6062
where T : ProjectResource
6163
{

src/Aspire.Hosting.Azure.AppContainers/ContainerAppJobContext.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,8 @@ private ContainerAppJob CreateContainerAppJob()
9797

9898
var configuration = new ContainerAppJobConfiguration()
9999
{
100-
ReplicaTimeout = 1800
100+
ReplicaTimeout = 1800,
101+
TriggerType = ContainerAppJobTriggerType.Manual,
101102
};
102103
containerApp.Configuration = configuration;
103104

tests/Aspire.Hosting.Azure.Tests/AzureContainerAppsTests.cs

Lines changed: 133 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#pragma warning disable ASPIREACADOMAINS001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
55
#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.
6+
#pragma warning disable ASPIREAZURE002 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
67

78
using System.Text.Json.Nodes;
89
using Aspire.Hosting.ApplicationModel;
@@ -516,40 +517,6 @@ await Verify(manifest.ToString(), "json")
516517
.AppendContentAsFile(bicep, "bicep");
517518
}
518519

519-
[Fact]
520-
public async Task PublishAsContainerAppJobInfluencesContainerAppDefinition()
521-
{
522-
var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Publish);
523-
524-
builder.AddAzureContainerAppEnvironment("env");
525-
builder.AddContainer("api", "myimage")
526-
.PublishAsAzureContainerAppJob((module, j) =>
527-
{
528-
Assert.Contains(j, module.GetProvisionableResources());
529-
530-
j.Configuration.TriggerType = ContainerAppJobTriggerType.Schedule;
531-
j.Configuration.ScheduleTriggerConfig.CronExpression = "*/5 * * * *";
532-
});
533-
534-
using var app = builder.Build();
535-
536-
await ExecuteBeforeStartHooksAsync(app, default);
537-
538-
var model = app.Services.GetRequiredService<DistributedApplicationModel>();
539-
540-
var container = Assert.Single(model.GetContainerResources());
541-
542-
container.TryGetLastAnnotation<DeploymentTargetAnnotation>(out var target);
543-
544-
var resource = target?.DeploymentTarget as AzureProvisioningResource;
545-
546-
Assert.NotNull(resource);
547-
548-
var (manifest, bicep) = await GetManifestWithBicep(resource);
549-
550-
await Verify(bicep, "bicep");
551-
}
552-
553520
[Fact]
554521
public async Task ConfigureCustomDomainMutatesIngress()
555522
{
@@ -729,11 +696,11 @@ public async Task MultipleVolumesHaveUniqueNamesInBicep()
729696
Assert.Contains("my_ace_outputs_volumes_druid_0", bicep);
730697
Assert.Contains("my_ace_outputs_volumes_druid_1", bicep);
731698
Assert.Contains("my_ace_outputs_bindmounts_druid_0", bicep);
732-
699+
733700
// Also verify the container app environment resource output
734701
var containerAppEnvResource = Assert.Single(model.Resources.OfType<AzureContainerAppEnvironmentResource>());
735702
var (envManifest, envBicep) = await GetManifestWithBicep(containerAppEnvResource);
736-
703+
737704
await Verify(manifest.ToString())
738705
.AppendContentAsFile(bicep)
739706
.AppendContentAsFile(envManifest.ToString())
@@ -1650,4 +1617,134 @@ public async Task MultipleAzureContainerAppEnvironmentsSupported()
16501617

16511618
await VerifyFile(Path.Combine(tempDir.Path, "aspire-manifest.json"));
16521619
}
1620+
1621+
[Fact]
1622+
public async Task PublishAsContainerAppJobInfluencesContainerAppDefinition()
1623+
{
1624+
var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Publish);
1625+
builder.AddAzureContainerAppEnvironment("env");
1626+
builder.AddContainer("api", "myimage")
1627+
.PublishAsAzureContainerAppJob((module, j) =>
1628+
{
1629+
Assert.Contains(j, module.GetProvisionableResources());
1630+
1631+
j.Configuration.TriggerType = ContainerAppJobTriggerType.Schedule;
1632+
j.Configuration.ScheduleTriggerConfig.CronExpression = "*/5 * * * *";
1633+
});
1634+
1635+
using var app = builder.Build();
1636+
1637+
await ExecuteBeforeStartHooksAsync(app, default);
1638+
1639+
var model = app.Services.GetRequiredService<DistributedApplicationModel>();
1640+
var container = Assert.Single(model.GetContainerResources());
1641+
container.TryGetLastAnnotation<DeploymentTargetAnnotation>(out var target);
1642+
var resource = target?.DeploymentTarget as AzureProvisioningResource;
1643+
Assert.NotNull(resource);
1644+
1645+
var (manifest, bicep) = await GetManifestWithBicep(resource);
1646+
1647+
await Verify(bicep, "bicep");
1648+
}
1649+
1650+
[Fact]
1651+
public async Task PublishAsContainerAppJob_WorksForProjectResource()
1652+
{
1653+
var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Publish);
1654+
builder.AddAzureContainerAppEnvironment("env");
1655+
builder.AddProject<Project>("job", launchProfileName: null)
1656+
.PublishAsAzureContainerAppJob((infra, job) => { });
1657+
1658+
using var app = builder.Build();
1659+
await ExecuteBeforeStartHooksAsync(app, default);
1660+
1661+
var model = app.Services.GetRequiredService<DistributedApplicationModel>();
1662+
var project = Assert.Single(model.GetProjectResources());
1663+
project.TryGetLastAnnotation<DeploymentTargetAnnotation>(out var target);
1664+
var resource = target?.DeploymentTarget as AzureProvisioningResource;
1665+
Assert.NotNull(resource);
1666+
1667+
var (manifest, bicep) = await GetManifestWithBicep(resource);
1668+
1669+
await Verify(bicep, "bicep");
1670+
}
1671+
1672+
[Fact]
1673+
public async Task PublishAsContainerAppJob_ThrowsForAzureFunctions()
1674+
{
1675+
var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Publish);
1676+
builder.AddAzureContainerAppEnvironment("env");
1677+
1678+
builder.AddAzureFunctionsProject<TestFunctionsProject>("funcjob")
1679+
.PublishAsAzureContainerAppJob((infra, job) => { });
1680+
1681+
using var app = builder.Build();
1682+
await ExecuteBeforeStartHooksAsync(app, default);
1683+
1684+
var model = app.Services.GetRequiredService<DistributedApplicationModel>();
1685+
var funcjob = model.Resources.Single(r => r.Name == "funcjob");
1686+
funcjob.TryGetLastAnnotation<DeploymentTargetAnnotation>(out var target);
1687+
var resource = target?.DeploymentTarget as AzureProvisioningResource;
1688+
Assert.NotNull(resource);
1689+
1690+
await Assert.ThrowsAsync<NotSupportedException>(async () => await GetManifestWithBicep(resource));
1691+
}
1692+
1693+
private sealed class TestFunctionsProject : IProjectMetadata
1694+
{
1695+
public string ProjectPath => "functions-project";
1696+
1697+
public LaunchSettings LaunchSettings => new()
1698+
{
1699+
Profiles = new Dictionary<string, LaunchProfile>
1700+
{
1701+
["funcapp"] = new()
1702+
{
1703+
CommandLineArgs = "--port 7071",
1704+
LaunchBrowser = false,
1705+
}
1706+
}
1707+
};
1708+
}
1709+
1710+
[Fact]
1711+
public async Task CanMixContainerAppsAndJobsInSameManifest()
1712+
{
1713+
var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Publish);
1714+
builder.AddAzureContainerAppEnvironment("env");
1715+
1716+
builder.AddContainer("web", "nginx:latest")
1717+
.PublishAsAzureContainerApp((infra, app) => { });
1718+
1719+
builder.AddContainer("batch", "image:latest")
1720+
.PublishAsAzureContainerAppJob((infra, job) =>
1721+
{
1722+
job.Configuration.TriggerType = ContainerAppJobTriggerType.Manual;
1723+
});
1724+
1725+
using var app = builder.Build();
1726+
await ExecuteBeforeStartHooksAsync(app, default);
1727+
1728+
var model = app.Services.GetRequiredService<DistributedApplicationModel>();
1729+
var containers = model.GetContainerResources().ToArray();
1730+
Assert.Equal(2, containers.Length);
1731+
1732+
var batch = containers.First(c => c.Name == "batch");
1733+
var web = containers.First(c => c.Name == "web");
1734+
1735+
var batchTarget = batch.Annotations.OfType<DeploymentTargetAnnotation>().FirstOrDefault();
1736+
var webTarget = web.Annotations.OfType<DeploymentTargetAnnotation>().FirstOrDefault();
1737+
1738+
var batchResource = batchTarget?.DeploymentTarget as AzureProvisioningResource;
1739+
var webResource = webTarget?.DeploymentTarget as AzureProvisioningResource;
1740+
1741+
Assert.NotNull(batchResource);
1742+
Assert.NotNull(webResource);
1743+
1744+
var (batchManifest, batchBicep) = await GetManifestWithBicep(batchResource);
1745+
var (webManifest, webBicep) = await GetManifestWithBicep(webResource);
1746+
1747+
Assert.Contains("Microsoft.App/jobs", batchBicep);
1748+
Assert.Contains("Microsoft.App/containerApps", webBicep);
1749+
}
16531750
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
@description('The location for the resource(s) to be deployed.')
2+
param location string = resourceGroup().location
3+
4+
param env_outputs_azure_container_apps_environment_default_domain string
5+
6+
param env_outputs_azure_container_apps_environment_id string
7+
8+
param env_outputs_azure_container_registry_endpoint string
9+
10+
param env_outputs_azure_container_registry_managed_identity_id string
11+
12+
param job_containerimage string
13+
14+
resource job 'Microsoft.App/jobs@2025-01-01' = {
15+
name: 'job'
16+
location: location
17+
properties: {
18+
configuration: {
19+
triggerType: 'Manual'
20+
replicaTimeout: 1800
21+
registries: [
22+
{
23+
server: env_outputs_azure_container_registry_endpoint
24+
identity: env_outputs_azure_container_registry_managed_identity_id
25+
}
26+
]
27+
}
28+
environmentId: env_outputs_azure_container_apps_environment_id
29+
template: {
30+
containers: [
31+
{
32+
image: job_containerimage
33+
name: 'job'
34+
env: [
35+
{
36+
name: 'OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EXCEPTION_LOG_ATTRIBUTES'
37+
value: 'true'
38+
}
39+
{
40+
name: 'OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EVENT_LOG_ATTRIBUTES'
41+
value: 'true'
42+
}
43+
{
44+
name: 'OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY'
45+
value: 'in_memory'
46+
}
47+
]
48+
}
49+
]
50+
}
51+
}
52+
identity: {
53+
type: 'UserAssigned'
54+
userAssignedIdentities: {
55+
'${env_outputs_azure_container_registry_managed_identity_id}': { }
56+
}
57+
}
58+
}

0 commit comments

Comments
 (0)