diff --git a/src/Aspire.CommunityToolkit.Hosting.Java/JavaAppHostingExtension.cs b/src/Aspire.CommunityToolkit.Hosting.Java/JavaAppHostingExtension.cs index 29e61e58..ab06304e 100644 --- a/src/Aspire.CommunityToolkit.Hosting.Java/JavaAppHostingExtension.cs +++ b/src/Aspire.CommunityToolkit.Hosting.Java/JavaAppHostingExtension.cs @@ -19,27 +19,21 @@ public static class JavaAppHostingExtension /// A reference to the . public static IResourceBuilder AddJavaApp(this IDistributedApplicationBuilder builder, string name, JavaAppContainerResourceOptions options) { - if (string.IsNullOrWhiteSpace(options.ContainerImageName) == true) - { - throw new ArgumentException("Container image name must be specified.", nameof(options)); - } + ArgumentNullException.ThrowIfNull(builder, nameof(builder)); + ArgumentNullException.ThrowIfNull(options, nameof(options)); + ArgumentException.ThrowIfNullOrWhiteSpace(name, nameof(name)); + ArgumentException.ThrowIfNullOrWhiteSpace(options.ContainerImageName, nameof(options.ContainerImageName)); var resource = new JavaAppContainerResource(name); - var rb = builder.AddResource(resource); - if (string.IsNullOrWhiteSpace(options.ContainerRegistry) == false) - { - rb.WithImageRegistry(options.ContainerRegistry); - } - rb.WithImage(options.ContainerImageName) - .WithImageTag(options.ContainerImageTag) + var rb = builder.AddResource(resource) + .WithAnnotation(new ContainerImageAnnotation { Image = options.ContainerImageName, Tag = options.ContainerImageTag, Registry = options.ContainerRegistry }) .WithHttpEndpoint(port: options.Port, targetPort: options.TargetPort, name: JavaAppContainerResource.HttpEndpointName) .WithJavaDefaults(options); + if (options.Args is { Length: > 0 }) { -#pragma warning disable CS8604 // Possible null reference argument. rb.WithArgs(options.Args); -#pragma warning restore CS8604 // Possible null reference argument. } return rb; @@ -52,10 +46,8 @@ public static IResourceBuilder AddJavaApp(this IDistri /// The name of the resource. /// The to configure the Java application." /// A reference to the . - public static IResourceBuilder AddSpringApp(this IDistributedApplicationBuilder builder, string name, JavaAppContainerResourceOptions options) - { - return builder.AddJavaApp(name, options); - } + public static IResourceBuilder AddSpringApp(this IDistributedApplicationBuilder builder, string name, JavaAppContainerResourceOptions options) => + builder.AddJavaApp(name, options); /// /// Adds a Java application to the application model. Executes the executable Java app. @@ -67,6 +59,11 @@ public static IResourceBuilder AddSpringApp(this IDist /// A reference to the . public static IResourceBuilder AddJavaApp(this IDistributedApplicationBuilder builder, string name, string workingDirectory, JavaAppExecutableResourceOptions options) { + ArgumentNullException.ThrowIfNull(builder, nameof(builder)); + ArgumentNullException.ThrowIfNull(options, nameof(options)); + ArgumentException.ThrowIfNullOrWhiteSpace(name, nameof(name)); + ArgumentException.ThrowIfNullOrWhiteSpace(workingDirectory, nameof(workingDirectory)); + #pragma warning disable CS8601 // Possible null reference assignment. string[] allArgs = options.Args is { Length: > 0 } ? ["-jar", options.ApplicationName, .. options.Args] @@ -90,10 +87,8 @@ public static IResourceBuilder AddJavaApp(this IDistr /// The working directory to use for the command. If null, the working directory of the current process is used. /// The to configure the Java application." /// A reference to the . - public static IResourceBuilder AddSpringApp(this IDistributedApplicationBuilder builder, string name, string workingDirectory, JavaAppExecutableResourceOptions options) - { - return builder.AddJavaApp(name, workingDirectory, options); - } + public static IResourceBuilder AddSpringApp(this IDistributedApplicationBuilder builder, string name, string workingDirectory, JavaAppExecutableResourceOptions options) => + builder.AddJavaApp(name, workingDirectory, options); private static IResourceBuilder WithJavaDefaults( this IResourceBuilder builder, diff --git a/tests/Aspire.CommunityToolkit.Hosting.Java.Tests/ContainerResourceCreationTests.cs b/tests/Aspire.CommunityToolkit.Hosting.Java.Tests/ContainerResourceCreationTests.cs new file mode 100644 index 00000000..b29ba492 --- /dev/null +++ b/tests/Aspire.CommunityToolkit.Hosting.Java.Tests/ContainerResourceCreationTests.cs @@ -0,0 +1,104 @@ +namespace Aspire.CommunityToolkit.Hosting.Java.Tests; +public class ContainerResourceCreationTests +{ + [Fact] + public void AddJavaAppBuilderShouldNotBeNull() + { + IDistributedApplicationBuilder builder = null!; + + Assert.Throws(() => builder.AddJavaApp("java", new JavaAppContainerResourceOptions())); + } + + [Fact] + public void AddSpringAppBuilderShouldNotBeNull() + { + IDistributedApplicationBuilder builder = null!; + + Assert.Throws(() => builder.AddSpringApp("spring", new JavaAppContainerResourceOptions())); + } + + [Fact] + public void AddJavaAppNameShouldNotBeNullOrWhiteSpace() + { + IDistributedApplicationBuilder builder = DistributedApplication.CreateBuilder(); + + Assert.Throws(() => builder.AddJavaApp(null!, new JavaAppContainerResourceOptions())); + Assert.Throws(() => builder.AddJavaApp("", new JavaAppContainerResourceOptions())); + } + + [Fact] + public void AddSpringAppNameShouldNotBeNullOrWhiteSpace() + { + IDistributedApplicationBuilder builder = DistributedApplication.CreateBuilder(); + + Assert.Throws(() => builder.AddSpringApp(null!, new JavaAppContainerResourceOptions())); + Assert.Throws(() => builder.AddSpringApp("", new JavaAppContainerResourceOptions())); + } + + [Fact] + public void AddJavaAppContainerImageNameShouldNotBeNullOrWhiteSpace() + { + IDistributedApplicationBuilder builder = DistributedApplication.CreateBuilder(); + + Assert.Throws(() => builder.AddJavaApp("java", new JavaAppContainerResourceOptions { ContainerImageName = null! })); + Assert.Throws(() => builder.AddJavaApp("java", new JavaAppContainerResourceOptions { ContainerImageName = "" })); + } + + [Fact] + public void AddJavaAppContainerResourceOptionsShouldNotBeNull() + { + IDistributedApplicationBuilder builder = DistributedApplication.CreateBuilder(); + + Assert.Throws(() => builder.AddJavaApp("java", null!)); + } + + [Fact] + public void AddSpringAppContainerResourceOptionsShouldNotBeNull() + { + IDistributedApplicationBuilder builder = DistributedApplication.CreateBuilder(); + + Assert.Throws(() => builder.AddSpringApp("spring", null!)); + } + + [Fact] + public async Task AddJavaAppContainerDetailsSetOnResource() + { + IDistributedApplicationBuilder builder = DistributedApplication.CreateBuilder(); + + var options = new JavaAppContainerResourceOptions + { + ContainerImageName = "java-app", + ContainerRegistry = "docker.io", + ContainerImageTag = "latest", + Port = 8080, + TargetPort = 8080, + OtelAgentPath = "path/to/otel", + Args = ["arg1", "arg2"] + }; + + builder.AddJavaApp("java", options); + + using var app = builder.Build(); + + var appModel = app.Services.GetRequiredService(); + + var resource = appModel.Resources.OfType().SingleOrDefault(); + + Assert.NotNull(resource); + Assert.Equal("java", resource.Name); + + Assert.True(resource.TryGetLastAnnotation(out ContainerImageAnnotation? imageAnnotations)); + Assert.Equal(options.ContainerImageName, imageAnnotations.Image); + Assert.Equal(options.ContainerRegistry, imageAnnotations.Registry); + Assert.Equal(options.ContainerImageTag, imageAnnotations.Tag); + + Assert.True(resource.TryGetLastAnnotation(out EndpointAnnotation? httpEndpointAnnotations)); + Assert.Equal(options.Port, httpEndpointAnnotations.Port); + Assert.Equal(options.TargetPort, httpEndpointAnnotations.TargetPort); + + Assert.True(resource.TryGetLastAnnotation(out CommandLineArgsCallbackAnnotation? argsAnnotations)); + CommandLineArgsCallbackContext context = new([]); + await argsAnnotations.Callback(context); + Assert.All(options.Args, arg => Assert.Contains(arg, context.Args)); + } +} diff --git a/tests/Aspire.CommunityToolkit.Hosting.Java.Tests/ExecutableResourceCreationTests.cs b/tests/Aspire.CommunityToolkit.Hosting.Java.Tests/ExecutableResourceCreationTests.cs new file mode 100644 index 00000000..f4825540 --- /dev/null +++ b/tests/Aspire.CommunityToolkit.Hosting.Java.Tests/ExecutableResourceCreationTests.cs @@ -0,0 +1,101 @@ +namespace Aspire.CommunityToolkit.Hosting.Java.Tests; + +public class ExecutableResourceCreationTests +{ + [Fact] + public void AddJavaAppBuilderShouldNotBeNull() + { + IDistributedApplicationBuilder builder = null!; + + Assert.Throws(() => builder.AddJavaApp("java", Environment.CurrentDirectory, new JavaAppExecutableResourceOptions())); + } + + [Fact] + public void AddSpringAppBuilderShouldNotBeNull() + { + IDistributedApplicationBuilder builder = null!; + + Assert.Throws(() => builder.AddSpringApp("spring", Environment.CurrentDirectory, new JavaAppExecutableResourceOptions())); + } + + [Fact] + public void AddJavaAppNameShouldNotBeNullOrWhiteSpace() + { + IDistributedApplicationBuilder builder = DistributedApplication.CreateBuilder(); + + Assert.Throws(() => builder.AddJavaApp(null!, Environment.CurrentDirectory, new JavaAppExecutableResourceOptions())); + Assert.Throws(() => builder.AddJavaApp("", Environment.CurrentDirectory, new JavaAppExecutableResourceOptions())); + } + + [Fact] + public void AddSpringAppNameShouldNotBeNullOrWhiteSpace() + { + IDistributedApplicationBuilder builder = DistributedApplication.CreateBuilder(); + + Assert.Throws(() => builder.AddSpringApp(null!, Environment.CurrentDirectory, new JavaAppExecutableResourceOptions())); + Assert.Throws(() => builder.AddSpringApp("", Environment.CurrentDirectory, new JavaAppExecutableResourceOptions())); + } + + [Fact] + public void AddJavaAppWorkingDirectoryShouldNotBeNullOrWhiteSpace() + { + IDistributedApplicationBuilder builder = DistributedApplication.CreateBuilder(); + + Assert.Throws(() => builder.AddJavaApp("java", null!, new JavaAppExecutableResourceOptions())); + Assert.Throws(() => builder.AddJavaApp("java", "", new JavaAppExecutableResourceOptions())); + } + + [Fact] + public void AddJavaAppExecutableResourceOptionsShouldNotBeNull() + { + IDistributedApplicationBuilder builder = DistributedApplication.CreateBuilder(); + + Assert.Throws(() => builder.AddJavaApp("java", Environment.CurrentDirectory, null!)); + } + + [Fact] + public void AddSpringAppContainerResourceOptionsShouldNotBeNull() + { + IDistributedApplicationBuilder builder = DistributedApplication.CreateBuilder(); + + Assert.Throws(() => builder.AddSpringApp("spring", Environment.CurrentDirectory, null!)); + } + + [Fact] + public async Task AddJavaAppContainerDetailsSetOnResource() + { + IDistributedApplicationBuilder builder = DistributedApplication.CreateBuilder(); + + var options = new JavaAppExecutableResourceOptions + { + ApplicationName = "test.jar", + Args = ["--test"], + OtelAgentPath = "otel-agent", + Port = 8080 + }; + + builder.AddJavaApp("java", Environment.CurrentDirectory, options); + + using var app = builder.Build(); + + var appModel = app.Services.GetRequiredService(); + + var resource = appModel.Resources.OfType().SingleOrDefault(); + + Assert.NotNull(resource); + Assert.Equal("java", resource.Name); + + Assert.Equal(Environment.CurrentDirectory, resource.WorkingDirectory); + Assert.Equal("java", resource.Command); + + Assert.True(resource.TryGetLastAnnotation(out EndpointAnnotation? httpEndpointAnnotations)); + Assert.Equal(options.Port, httpEndpointAnnotations.Port); + + Assert.True(resource.TryGetLastAnnotation(out CommandLineArgsCallbackAnnotation? argsAnnotations)); + CommandLineArgsCallbackContext context = new([]); + await argsAnnotations.Callback(context); + Assert.All(options.Args, arg => Assert.Contains(arg, context.Args)); + Assert.Contains("-jar", context.Args); + Assert.Contains(options.ApplicationName, context.Args); + } +}