diff --git a/src/Aspire.Hosting.Python/PythonProjectResource.cs b/src/Aspire.Hosting.Python/PythonProjectResource.cs index d50fa3b0dfe..0b00879b374 100644 --- a/src/Aspire.Hosting.Python/PythonProjectResource.cs +++ b/src/Aspire.Hosting.Python/PythonProjectResource.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; using Aspire.Hosting.ApplicationModel; namespace Aspire.Hosting.Python; @@ -12,7 +14,8 @@ namespace Aspire.Hosting.Python; /// The path to the executable used to run the python project. /// The path to the directory containing the python project. public class PythonProjectResource(string name, string executablePath, string projectDirectory) - : ExecutableResource(name, executablePath, projectDirectory), IResourceWithServiceDiscovery + : ExecutableResource(ThrowIfNull(name), ThrowIfNull(executablePath), ThrowIfNull(projectDirectory)), IResourceWithServiceDiscovery { - + private static string ThrowIfNull([NotNull] string? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) + => argument ?? throw new ArgumentNullException(paramName); } diff --git a/src/Aspire.Hosting.Python/PythonProjectResourceBuilderExtensions.cs b/src/Aspire.Hosting.Python/PythonProjectResourceBuilderExtensions.cs index c1a04d78d7b..0e4734137b9 100644 --- a/src/Aspire.Hosting.Python/PythonProjectResourceBuilderExtensions.cs +++ b/src/Aspire.Hosting.Python/PythonProjectResourceBuilderExtensions.cs @@ -60,6 +60,8 @@ public static class PythonProjectResourceBuilderExtensions public static IResourceBuilder AddPythonProject( this IDistributedApplicationBuilder builder, string name, string projectDirectory, string scriptPath, params string[] scriptArgs) { + ArgumentNullException.ThrowIfNull(builder); + return builder.AddPythonProject(name, projectDirectory, scriptPath, ".venv", scriptArgs); } @@ -108,7 +110,12 @@ public static IResourceBuilder AddPythonProject( this IDistributedApplicationBuilder builder, string name, string projectDirectory, string scriptPath, string virtualEnvironmentPath, params string[] scriptArgs) { + ArgumentNullException.ThrowIfNull(builder); + ArgumentNullException.ThrowIfNull(name); + ArgumentNullException.ThrowIfNull(projectDirectory); + ArgumentNullException.ThrowIfNull(scriptPath); ArgumentNullException.ThrowIfNull(virtualEnvironmentPath); + ArgumentNullException.ThrowIfNull(scriptArgs); projectDirectory = PathNormalizer.NormalizePathForCurrentPlatform(Path.Combine(builder.AppHostDirectory, projectDirectory)); var virtualEnvironment = new VirtualEnvironment(Path.IsPathRooted(virtualEnvironmentPath) diff --git a/tests/Aspire.Hosting.Python.Tests/PythonPublicApiTests.cs b/tests/Aspire.Hosting.Python.Tests/PythonPublicApiTests.cs new file mode 100644 index 00000000000..cd74a091324 --- /dev/null +++ b/tests/Aspire.Hosting.Python.Tests/PythonPublicApiTests.cs @@ -0,0 +1,270 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Aspire.Hosting.Utils; +using Xunit; + +namespace Aspire.Hosting.Python.Tests; + +public class PythonPublicApiTests +{ + [Fact] + public void CtorPythonProjectResourceShouldThrowWhenNameIsNull() + { + string name = null!; + const string executablePath = "/src/python"; + const string projectDirectory = "/data/python"; + + var action = () => new PythonProjectResource(name, executablePath, projectDirectory); + + var exception = Assert.Throws(action); + Assert.Equal(nameof(name), exception.ParamName); + } + + [Fact] + public void CtorPythonProjectResourceShouldThrowWhenExecutablePathIsNull() + { + const string name = "Python"; + string executablePath = null!; + const string projectDirectory = "/data/python"; + + var action = () => new PythonProjectResource(name, executablePath, projectDirectory); + + var exception = Assert.Throws(action); + Assert.Equal(nameof(executablePath), exception.ParamName); + } + + [Fact] + public void CtorPythonProjectResourceShouldThrowWhenProjectDirectoryIsNull() + { + const string name = "Python"; + const string executablePath = "/src/python"; + string projectDirectory = null!; + + var action = () => new PythonProjectResource(name, executablePath, projectDirectory); + + var exception = Assert.Throws(action); + Assert.Equal(nameof(projectDirectory), exception.ParamName); + } + + [Fact] + public void AddPythonProjectShouldThrowWhenBuilderIsNull() + { + IDistributedApplicationBuilder builder = null!; + const string name = "Python"; + const string projectDirectory = "/src/python"; + const string scriptPath = "scripts"; + string[] scriptArgs = ["--traces"]; + + var action = () => builder.AddPythonProject( + name, + projectDirectory, + scriptPath, + scriptArgs); + + var exception = Assert.Throws(action); + Assert.Equal(nameof(builder), exception.ParamName); + } + + [Fact] + public void AddPythonProjectShouldThrowWhenNameIsNull() + { + var builder = TestDistributedApplicationBuilder.Create(); + string name = null!; + const string projectDirectory = "/src/python"; + const string scriptPath = "scripts"; + string[] scriptArgs = ["--traces"]; + + var action = () => builder.AddPythonProject( + name, + projectDirectory, + scriptPath, + scriptArgs); + + var exception = Assert.Throws(action); + Assert.Equal(nameof(name), exception.ParamName); + } + + [Fact] + public void AddPythonProjectShouldThrowWhenProjectDirectoryIsNull() + { + var builder = TestDistributedApplicationBuilder.Create(); + const string name = "Python"; + string projectDirectory = null!; + const string scriptPath = "scripts"; + string[] scriptArgs = ["--traces"]; + + var action = () => builder.AddPythonProject( + name, + projectDirectory, + scriptPath, + scriptArgs); + + var exception = Assert.Throws(action); + Assert.Equal(nameof(projectDirectory), exception.ParamName); + } + + [Fact] + public void AddPythonProjectShouldThrowWhenScriptPathIsNull() + { + var builder = TestDistributedApplicationBuilder.Create(); + const string name = "Python"; + const string projectDirectory = "/src/python"; + string scriptPath = null!; + string[] scriptArgs = ["--traces"]; + + var action = () => builder.AddPythonProject( + name, + projectDirectory, + scriptPath, + scriptArgs); + + var exception = Assert.Throws(action); + Assert.Equal(nameof(scriptPath), exception.ParamName); + } + + [Fact] + public void AddPythonProjectShouldThrowWhenScriptArgsIsNull() + { + var builder = TestDistributedApplicationBuilder.Create(); + const string name = "Python"; + const string projectDirectory = "/src/python"; + const string scriptPath = "scripts"; + string[] scriptArgs = null!; + + var action = () => builder.AddPythonProject( + name, + projectDirectory, + scriptPath, + scriptArgs); + + var exception = Assert.Throws(action); + Assert.Equal(nameof(scriptArgs), exception.ParamName); + } + + [Fact] + public void AddPythonProjectWithVirtualEnvironmentPathShouldThrowWhenBuilderIsNull() + { + IDistributedApplicationBuilder builder = null!; + const string name = "Python"; + const string projectDirectory = "/src/python"; + const string scriptPath = "scripts"; + var virtualEnvironmentPath = ".venv"; + string[] scriptArgs = ["--traces"]; ; + + var action = () => builder.AddPythonProject( + name, + projectDirectory, + scriptPath, + virtualEnvironmentPath, + scriptArgs); + + var exception = Assert.Throws(action); + Assert.Equal(nameof(builder), exception.ParamName); + } + + [Fact] + public void AddPythonProjectWithVirtualEnvironmentPathShouldThrowWhenNameIsNull() + { + var builder = TestDistributedApplicationBuilder.Create(); + string name = null!; + const string projectDirectory = "/src/python"; + const string scriptPath = "scripts"; + const string virtualEnvironmentPath = ".venv"; + string[] scriptArgs = ["--traces"]; ; + + var action = () => builder.AddPythonProject( + name, + projectDirectory, + scriptPath, + virtualEnvironmentPath, + scriptArgs); + + var exception = Assert.Throws(action); + Assert.Equal(nameof(name), exception.ParamName); + } + + [Fact] + public void AddPythonProjectWithVirtualEnvironmentPathShouldThrowWhenProjectDirectoryIsNull() + { + var builder = TestDistributedApplicationBuilder.Create(); + const string name = "Python"; + string projectDirectory = null!; + const string scriptPath = "scripts"; + const string virtualEnvironmentPath = ".venv"; + string[] scriptArgs = ["--traces"]; ; + + var action = () => builder.AddPythonProject( + name, + projectDirectory, + scriptPath, + virtualEnvironmentPath, + scriptArgs); + + var exception = Assert.Throws(action); + Assert.Equal(nameof(projectDirectory), exception.ParamName); + } + + [Fact] + public void AddPythonProjectWithVirtualEnvironmentPathShouldThrowWhenScriptPathIsNull() + { + var builder = TestDistributedApplicationBuilder.Create(); + const string name = "Python"; + const string projectDirectory = "/src/python"; + string scriptPath = null!; + const string virtualEnvironmentPath = ".venv"; + string[] scriptArgs = ["--traces"]; ; + + var action = () => builder.AddPythonProject( + name, + projectDirectory, + scriptPath, + virtualEnvironmentPath, + scriptArgs); + + var exception = Assert.Throws(action); + Assert.Equal(nameof(scriptPath), exception.ParamName); + } + + [Fact] + public void AddPythonProjectWithVirtualEnvironmentPathShouldThrowWhenVirtualEnvironmentPathIsNull() + { + var builder = TestDistributedApplicationBuilder.Create(); + const string name = "Python"; + const string projectDirectory = "/src/python"; + const string scriptPath = "scripts"; + string virtualEnvironmentPath = null!; + string[] scriptArgs = ["--traces"]; ; + + var action = () => builder.AddPythonProject( + name, + projectDirectory, + scriptPath, + virtualEnvironmentPath, + scriptArgs); + + var exception = Assert.Throws(action); + Assert.Equal(nameof(virtualEnvironmentPath), exception.ParamName); + } + + [Fact] + public void AddPythonProjectWithVirtualEnvironmentPathShouldThrowWhenScriptArgsIsNull() + { + var builder = TestDistributedApplicationBuilder.Create(); + const string name = "Python"; + const string projectDirectory = "/src/python"; + const string scriptPath = "scripts"; + const string virtualEnvironmentPath = ".venv"; + string[] scriptArgs = null!; + + var action = () => builder.AddPythonProject( + name, + projectDirectory, + scriptPath, + virtualEnvironmentPath, + scriptArgs); + + var exception = Assert.Throws(action); + Assert.Equal(nameof(scriptArgs), exception.ParamName); + } +}