From d5a99e9dff8d4b80696be685f6444fb89456257f Mon Sep 17 00:00:00 2001 From: Alireza Baloochi Date: Fri, 9 Aug 2024 22:04:55 +0330 Subject: [PATCH] Adding public API test coverage for Aspire.Hosting.SqlServer (#5241) --- .../SqlServerBuilderExtensions.cs | 15 +- .../SqlServerDatabaseResource.cs | 22 +- .../SqlServerPublicApiTests.cs | 198 ++++++++++++++++++ 3 files changed, 228 insertions(+), 7 deletions(-) create mode 100644 tests/Aspire.Hosting.SqlServer.Tests/SqlServerPublicApiTests.cs diff --git a/src/Aspire.Hosting.SqlServer/SqlServerBuilderExtensions.cs b/src/Aspire.Hosting.SqlServer/SqlServerBuilderExtensions.cs index 9a5128ff27..41f454431b 100644 --- a/src/Aspire.Hosting.SqlServer/SqlServerBuilderExtensions.cs +++ b/src/Aspire.Hosting.SqlServer/SqlServerBuilderExtensions.cs @@ -21,6 +21,9 @@ public static class SqlServerBuilderExtensions /// A reference to the . public static IResourceBuilder AddSqlServer(this IDistributedApplicationBuilder builder, string name, IResourceBuilder? password = null, int? port = null) { + ArgumentNullException.ThrowIfNull(builder); + ArgumentException.ThrowIfNullOrEmpty(name); + // The password must be at least 8 characters long and contain characters from three of the following four sets: Uppercase letters, Lowercase letters, Base 10 digits, and Symbols var passwordParameter = password?.Resource ?? ParameterResourceBuilderExtensions.CreateDefaultPasswordParameter(builder, $"{name}-password", minLower: 1, minUpper: 1, minNumeric: 1); @@ -45,6 +48,9 @@ public static IResourceBuilder AddSqlServer(this IDistr /// A reference to the . public static IResourceBuilder AddDatabase(this IResourceBuilder builder, string name, string? databaseName = null) { + ArgumentNullException.ThrowIfNull(builder); + ArgumentException.ThrowIfNullOrEmpty(name); + // Use the resource name as the database name if it's not provided databaseName ??= name; @@ -61,7 +67,11 @@ public static IResourceBuilder AddDatabase(this IReso /// A flag that indicates if this is a read-only volume. /// The . public static IResourceBuilder WithDataVolume(this IResourceBuilder builder, string? name = null, bool isReadOnly = false) - => builder.WithVolume(name ?? VolumeNameGenerator.CreateVolumeName(builder, "data"), "/var/opt/mssql", isReadOnly); + { + ArgumentNullException.ThrowIfNull(builder); + + return builder.WithVolume(name ?? VolumeNameGenerator.CreateVolumeName(builder, "data"), "/var/opt/mssql", isReadOnly); + } /// /// Adds a bind mount for the data folder to a SQL Server resource. @@ -72,6 +82,9 @@ public static IResourceBuilder WithDataVolume(this IRes /// The . public static IResourceBuilder WithDataBindMount(this IResourceBuilder builder, string source, bool isReadOnly = false) { + ArgumentNullException.ThrowIfNull(builder); + ArgumentException.ThrowIfNullOrEmpty(source); + // c.f. https://learn.microsoft.com/sql/linux/sql-server-linux-docker-container-configure?view=sql-server-ver15&pivots=cs1-bash#mount-a-host-directory-as-data-volume foreach (var dir in new string[] { "data", "log", "secrets" }) diff --git a/src/Aspire.Hosting.SqlServer/SqlServerDatabaseResource.cs b/src/Aspire.Hosting.SqlServer/SqlServerDatabaseResource.cs index 74e800aff8..32728f2315 100644 --- a/src/Aspire.Hosting.SqlServer/SqlServerDatabaseResource.cs +++ b/src/Aspire.Hosting.SqlServer/SqlServerDatabaseResource.cs @@ -6,15 +6,12 @@ namespace Aspire.Hosting.ApplicationModel; /// /// A resource that represents a SQL Server database that is a child of a SQL Server container resource. /// -/// The name of the resource. -/// The database name. -/// The parent SQL Server server resource. -public class SqlServerDatabaseResource(string name, string databaseName, SqlServerServerResource parent) : Resource(name), IResourceWithParent, IResourceWithConnectionString +public class SqlServerDatabaseResource : Resource, IResourceWithParent, IResourceWithConnectionString { /// /// Gets the parent SQL Server container resource. /// - public SqlServerServerResource Parent { get; } = parent; + public SqlServerServerResource Parent { get; } /// /// Gets the connection string expression for the SQL Server database. @@ -25,5 +22,18 @@ public class SqlServerDatabaseResource(string name, string databaseName, SqlServ /// /// Gets the database name. /// - public string DatabaseName { get; } = databaseName; + public string DatabaseName { get; } + + /// The name of the resource. + /// The database name. + /// The parent SQL Server server resource. + public SqlServerDatabaseResource(string name, string databaseName, SqlServerServerResource parent) : base(name) + { + ArgumentException.ThrowIfNullOrEmpty(databaseName); + ArgumentNullException.ThrowIfNull(parent); + + DatabaseName = databaseName; + Parent = parent; + + } } diff --git a/tests/Aspire.Hosting.SqlServer.Tests/SqlServerPublicApiTests.cs b/tests/Aspire.Hosting.SqlServer.Tests/SqlServerPublicApiTests.cs new file mode 100644 index 0000000000..88dc29a675 --- /dev/null +++ b/tests/Aspire.Hosting.SqlServer.Tests/SqlServerPublicApiTests.cs @@ -0,0 +1,198 @@ +// 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.ApplicationModel; +using Aspire.Hosting.Utils; +using Xunit; + +namespace Aspire.Hosting.SqlServer.Tests; + +public class SqlServerPublicApiTests +{ + [Fact] + public void AddSqlServerContainerShouldThrowWhenBuilderIsNull() + { + IDistributedApplicationBuilder builder = null!; + const string name = "SqlServer"; + + var action = () => builder.AddSqlServer(name); + + var exception = Assert.Throws(action); + Assert.Equal(nameof(builder), exception.ParamName); + } + + [Fact] + public void AddSqlServerContainerShouldThrowWhenNameIsNull() + { + var builder = DistributedApplication.CreateBuilder([]); + string name = null!; + + var action = () => builder.AddSqlServer(name); + + var exception = Assert.Throws(action); + Assert.Equal(nameof(name), exception.ParamName); + } + + [Fact] + public void AddDatabaseShouldThrowWhenBuilderIsNull() + { + IResourceBuilder builder = null!; + const string name = "SqlServer"; + + var action = () => builder.AddDatabase(name); + + var exception = Assert.Throws(action); + Assert.Equal(nameof(builder), exception.ParamName); + } + + [Fact] + public void AddDatabaseShouldThrowWhenNameIsNull() + { + var builder = DistributedApplication.CreateBuilder([]) + .AddSqlServer("sqlserver"); + string name = null!; + + var action = () => builder.AddDatabase(name); + + var exception = Assert.Throws(action); + Assert.Equal(nameof(name), exception.ParamName); + } + + [Fact] + public void AddDatabaseShouldThrowWhenNameIsEmpty() + { + var builder = DistributedApplication.CreateBuilder([]) + .AddSqlServer("sqlserver"); + string name = ""; + + var action = () => builder.AddDatabase(name); + + var exception = Assert.Throws(action); + Assert.Equal(nameof(name), exception.ParamName); + } + + [Fact] + public void WithDataVolumeShouldThrowWhenBuilderIsNull() + { + IResourceBuilder builder = null!; + + var action = () => builder.WithDataVolume(); + + var exception = Assert.Throws(action); + Assert.Equal(nameof(builder), exception.ParamName); + } + + [Fact] + public void WithDataBindMountShouldThrowWhenBuilderIsNull() + { + IResourceBuilder builder = null!; + const string source = "/sqlserver/data"; + + var action = () => builder.WithDataBindMount(source); + + var exception = Assert.Throws(action); + Assert.Equal(nameof(builder), exception.ParamName); + } + + [Fact] + public void WithDataBindMountShouldThrowWhenSourceIsNull() + { + var builderResource = TestDistributedApplicationBuilder.Create(); + var SqlServer = builderResource.AddSqlServer("SqlServer"); + string source = null!; + + var action = () => SqlServer.WithDataBindMount(source); + + var exception = Assert.Throws(action); + Assert.Equal(nameof(source), exception.ParamName); + } + + [Fact] + public void CtorSqlServerServerResourceShouldThrowWhenNameIsNull() + { + var distributedApplicationBuilder = DistributedApplication.CreateBuilder([]); + string name = null!; + const string key = nameof(key); + var password = ParameterResourceBuilderExtensions.CreateDefaultPasswordParameter(distributedApplicationBuilder, key, special: false); + + var action = () => new SqlServerServerResource(name, password); + + var exception = Assert.Throws(action); + Assert.Equal(nameof(name), exception.ParamName); + } + + [Fact] + public void CtorSqlServerDatabaseResourceShouldThrowWhenNameIsNull() + { + var distributedApplicationBuilder = DistributedApplication.CreateBuilder([]); + + string name = null!; + var databaseName = "db1"; + var password = ParameterResourceBuilderExtensions.CreateDefaultPasswordParameter(distributedApplicationBuilder, "password", special: false); + var parent = new SqlServerServerResource("sqlserver",password); + var action = () => new SqlServerDatabaseResource(name, databaseName, parent); + + var exception = Assert.Throws(action); + Assert.Equal(nameof(name), exception.ParamName); + } + + [Fact] + public void CtorSqlServerDatabaseResourceShouldThrowWhenNameIsEmpty() + { + var distributedApplicationBuilder = DistributedApplication.CreateBuilder([]); + + string name = ""; + var databaseName = "db1"; + var password = ParameterResourceBuilderExtensions.CreateDefaultPasswordParameter(distributedApplicationBuilder, "password", special: false); + var parent = new SqlServerServerResource("sqlserver", password); + var action = () => new SqlServerDatabaseResource(name, databaseName, parent); + + var exception = Assert.Throws(action); + Assert.Equal(nameof(name), exception.ParamName); + } + + [Fact] + public void CtorSqlServerDatabaseResourceShouldThrowWhenDatabaseNameIsNull() + { + var distributedApplicationBuilder = DistributedApplication.CreateBuilder([]); + + string name = "sqlserver"; + string databaseName = null!; + var password = ParameterResourceBuilderExtensions.CreateDefaultPasswordParameter(distributedApplicationBuilder, "password", special: false); + var parent = new SqlServerServerResource("sqlserver", password); + var action = () => new SqlServerDatabaseResource(name, databaseName, parent); + + var exception = Assert.Throws(action); + Assert.Equal(nameof(databaseName), exception.ParamName); + } + + [Fact] + public void CtorSqlServerDatabaseResourceShouldThrowWhenDatabaseNameIsEmpty() + { + var distributedApplicationBuilder = DistributedApplication.CreateBuilder([]); + + string name = "sqlserver"; + string databaseName = null!; + var password = ParameterResourceBuilderExtensions.CreateDefaultPasswordParameter(distributedApplicationBuilder, "password", special: false); + var parent = new SqlServerServerResource("sqlserver", password); + var action = () => new SqlServerDatabaseResource(name, databaseName, parent); + + var exception = Assert.Throws(action); + Assert.Equal(nameof(databaseName), exception.ParamName); + } + + [Fact] + public void CtorSqlServerDatabaseResourceShouldThrowWhenParentIsNull() + { + var distributedApplicationBuilder = DistributedApplication.CreateBuilder([]); + + string name = "sqlserver"; + string databaseName = "db1"; + var password = ParameterResourceBuilderExtensions.CreateDefaultPasswordParameter(distributedApplicationBuilder, "password", special: false); + SqlServerServerResource parent = null!; + var action = () => new SqlServerDatabaseResource(name, databaseName, parent); + + var exception = Assert.Throws(action); + Assert.Equal(nameof(parent), exception.ParamName); + } +}