6f3e12b3b4
Replace Console.WriteLine calls with ILogger usage across all CLI commands. Serilog is configured via DI with clean message-only output suitable for CLI tooling. Log levels map to --quiet (Warning), default (Information), and --verbose (Debug) flags. - Add Serilog packages and configure in Program.cs - Convert all 7 command files to use ILoggerFactory from DI - Add BeginScope with context properties (Command, ConfigPath, etc.) - Create logging_style.md documenting patterns and best practices - Update tests with TestLoggingHelper for Serilog test configuration
664 lines
24 KiB
C#
664 lines
24 KiB
C#
using System.CommandLine;
|
|
using JdeScoping.ConfigManager.Cli.Commands;
|
|
using JdeScoping.ConfigManager.Core.Models;
|
|
using JdeScoping.ConfigManager.Core.Services;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
|
namespace JdeScoping.ConfigManager.Cli.Tests.Commands;
|
|
|
|
[Collection("Console Tests")]
|
|
public class ConnectionCommandsTests
|
|
{
|
|
private readonly IServiceProvider _serviceProvider;
|
|
private readonly IConfigFileService _configFileService;
|
|
private readonly IAutoDiscoveryService _autoDiscoveryService;
|
|
private readonly Option<string?> _configPathOption;
|
|
private readonly Option<bool> _verboseOption;
|
|
private readonly Option<bool> _quietOption;
|
|
|
|
public ConnectionCommandsTests()
|
|
{
|
|
_configFileService = Substitute.For<IConfigFileService>();
|
|
_autoDiscoveryService = Substitute.For<IAutoDiscoveryService>();
|
|
|
|
var services = new ServiceCollection();
|
|
services.AddSingleton(_configFileService);
|
|
services.AddSingleton(_autoDiscoveryService);
|
|
services.AddTestLogging();
|
|
_serviceProvider = services.BuildServiceProvider();
|
|
|
|
_configPathOption = new Option<string?>(["--config-path", "-c"]);
|
|
_verboseOption = new Option<bool>(["--verbose", "-v"]);
|
|
_quietOption = new Option<bool>(["--quiet", "-q"]);
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateListCommand_ReturnsCommand()
|
|
{
|
|
// Act
|
|
var command = ConnectionCommands.CreateListCommand(
|
|
_serviceProvider, _configPathOption, _verboseOption, _quietOption);
|
|
|
|
// Assert
|
|
command.ShouldNotBeNull();
|
|
command.Name.ShouldBe("list");
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateShowCommand_ReturnsCommandWithNameArgument()
|
|
{
|
|
// Act
|
|
var command = ConnectionCommands.CreateShowCommand(
|
|
_serviceProvider, _configPathOption, _verboseOption, _quietOption);
|
|
|
|
// Assert
|
|
command.ShouldNotBeNull();
|
|
command.Name.ShouldBe("show");
|
|
command.Arguments.ShouldContain(a => a.Name == "name");
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateAddCommand_ReturnsCommandWithOptions()
|
|
{
|
|
// Act
|
|
var command = ConnectionCommands.CreateAddCommand(
|
|
_serviceProvider, _configPathOption, _verboseOption, _quietOption);
|
|
|
|
// Assert
|
|
command.ShouldNotBeNull();
|
|
command.Name.ShouldBe("add");
|
|
command.Arguments.ShouldContain(a => a.Name == "name");
|
|
command.Options.ShouldContain(o => o.Name == "provider");
|
|
command.Options.ShouldContain(o => o.Name == "server");
|
|
command.Options.ShouldContain(o => o.Name == "database");
|
|
command.Options.ShouldContain(o => o.Name == "user");
|
|
command.Options.ShouldContain(o => o.Name == "password");
|
|
command.Options.ShouldContain(o => o.Name == "port");
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateRemoveCommand_ReturnsCommandWithNameArgument()
|
|
{
|
|
// Act
|
|
var command = ConnectionCommands.CreateRemoveCommand(
|
|
_serviceProvider, _configPathOption, _verboseOption, _quietOption);
|
|
|
|
// Assert
|
|
command.ShouldNotBeNull();
|
|
command.Name.ShouldBe("remove");
|
|
command.Arguments.ShouldContain(a => a.Name == "name");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ListCommand_WithNoConfigFolder_ReturnsError()
|
|
{
|
|
// Arrange
|
|
_autoDiscoveryService.FindConfigFolderAsync(Arg.Any<CancellationToken>())
|
|
.Returns(Task.FromResult<string?>(null));
|
|
|
|
var command = ConnectionCommands.CreateListCommand(
|
|
_serviceProvider, _configPathOption, _verboseOption, _quietOption);
|
|
var rootCommand = new RootCommand { command };
|
|
rootCommand.AddGlobalOption(_configPathOption);
|
|
rootCommand.AddGlobalOption(_verboseOption);
|
|
rootCommand.AddGlobalOption(_quietOption);
|
|
|
|
// Act
|
|
var exitCode = await rootCommand.InvokeAsync(["list"]);
|
|
|
|
// Assert - command completes without throwing
|
|
command.ShouldNotBeNull();
|
|
}
|
|
|
|
[Fact]
|
|
public void ListCommand_HasCorrectDescription()
|
|
{
|
|
// Arrange & Act
|
|
var command = ConnectionCommands.CreateListCommand(
|
|
_serviceProvider, _configPathOption, _verboseOption, _quietOption);
|
|
|
|
// Assert
|
|
command.Description.ShouldBe("List all connection names and providers");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ShowCommand_WithValidConnection_ShowsDetailsWithMaskedPassword()
|
|
{
|
|
// Arrange
|
|
var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
|
Directory.CreateDirectory(tempDir);
|
|
var appSettingsPath = Path.Combine(tempDir, "appsettings.json");
|
|
File.WriteAllText(appSettingsPath, "{}");
|
|
|
|
try
|
|
{
|
|
_autoDiscoveryService.FindConfigFolderAsync(Arg.Any<CancellationToken>())
|
|
.Returns(Task.FromResult<string?>(tempDir));
|
|
|
|
var config = new ConfigModel
|
|
{
|
|
ConnectionStrings = new ConnectionStringsSection
|
|
{
|
|
Entries =
|
|
[
|
|
new ConnectionStringEntry
|
|
{
|
|
Name = "TestConnection",
|
|
Provider = ConnectionProvider.SqlServer,
|
|
Server = "localhost",
|
|
Database = "TestDb",
|
|
UserId = "sa",
|
|
Password = "SuperSecretPassword123!"
|
|
}
|
|
]
|
|
}
|
|
};
|
|
|
|
_configFileService.LoadAppSettingsAsync(appSettingsPath, Arg.Any<CancellationToken>())
|
|
.Returns(Task.FromResult(config));
|
|
|
|
var command = ConnectionCommands.CreateShowCommand(
|
|
_serviceProvider, _configPathOption, _verboseOption, _quietOption);
|
|
var rootCommand = new RootCommand { command };
|
|
rootCommand.AddGlobalOption(_configPathOption);
|
|
rootCommand.AddGlobalOption(_verboseOption);
|
|
rootCommand.AddGlobalOption(_quietOption);
|
|
|
|
// Capture console output
|
|
var originalOut = Console.Out;
|
|
using var writer = new StringWriter();
|
|
Console.SetOut(writer);
|
|
|
|
try
|
|
{
|
|
// Act
|
|
await rootCommand.InvokeAsync(["show", "TestConnection"]);
|
|
|
|
// Assert
|
|
var output = writer.ToString();
|
|
output.ShouldContain("TestConnection");
|
|
output.ShouldContain("SqlServer");
|
|
output.ShouldContain("localhost");
|
|
output.ShouldContain("TestDb");
|
|
output.ShouldContain("********"); // Password should be masked
|
|
output.ShouldNotContain("SuperSecretPassword123!"); // Actual password should not appear
|
|
}
|
|
finally
|
|
{
|
|
Console.SetOut(originalOut);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
Directory.Delete(tempDir, true);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ShowCommand_WithNonExistentConnection_ReturnsError()
|
|
{
|
|
// Arrange
|
|
var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
|
Directory.CreateDirectory(tempDir);
|
|
var appSettingsPath = Path.Combine(tempDir, "appsettings.json");
|
|
File.WriteAllText(appSettingsPath, "{}");
|
|
|
|
try
|
|
{
|
|
_autoDiscoveryService.FindConfigFolderAsync(Arg.Any<CancellationToken>())
|
|
.Returns(Task.FromResult<string?>(tempDir));
|
|
|
|
var config = new ConfigModel();
|
|
|
|
_configFileService.LoadAppSettingsAsync(appSettingsPath, Arg.Any<CancellationToken>())
|
|
.Returns(Task.FromResult(config));
|
|
|
|
var command = ConnectionCommands.CreateShowCommand(
|
|
_serviceProvider, _configPathOption, _verboseOption, _quietOption);
|
|
var rootCommand = new RootCommand { command };
|
|
rootCommand.AddGlobalOption(_configPathOption);
|
|
rootCommand.AddGlobalOption(_verboseOption);
|
|
rootCommand.AddGlobalOption(_quietOption);
|
|
|
|
// Capture console output (Serilog writes all output to stdout)
|
|
var originalOut = Console.Out;
|
|
using var writer = new StringWriter();
|
|
Console.SetOut(writer);
|
|
|
|
try
|
|
{
|
|
// Act
|
|
await rootCommand.InvokeAsync(["show", "NonExistent"]);
|
|
|
|
// Assert
|
|
var output = writer.ToString();
|
|
output.ShouldContain("not found");
|
|
}
|
|
finally
|
|
{
|
|
Console.SetOut(originalOut);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
Directory.Delete(tempDir, true);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public async Task AddCommand_WithNewConnection_AddsConnection()
|
|
{
|
|
// Arrange
|
|
var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
|
Directory.CreateDirectory(tempDir);
|
|
var appSettingsPath = Path.Combine(tempDir, "appsettings.json");
|
|
File.WriteAllText(appSettingsPath, "{}");
|
|
|
|
try
|
|
{
|
|
_autoDiscoveryService.FindConfigFolderAsync(Arg.Any<CancellationToken>())
|
|
.Returns(Task.FromResult<string?>(tempDir));
|
|
|
|
var config = new ConfigModel();
|
|
|
|
_configFileService.LoadAppSettingsAsync(appSettingsPath, Arg.Any<CancellationToken>())
|
|
.Returns(Task.FromResult(config));
|
|
|
|
var command = ConnectionCommands.CreateAddCommand(
|
|
_serviceProvider, _configPathOption, _verboseOption, _quietOption);
|
|
var rootCommand = new RootCommand { command };
|
|
rootCommand.AddGlobalOption(_configPathOption);
|
|
rootCommand.AddGlobalOption(_verboseOption);
|
|
rootCommand.AddGlobalOption(_quietOption);
|
|
|
|
// Capture console output
|
|
var originalOut = Console.Out;
|
|
using var writer = new StringWriter();
|
|
Console.SetOut(writer);
|
|
|
|
try
|
|
{
|
|
// Act
|
|
await rootCommand.InvokeAsync(["add", "NewConnection", "--server", "localhost", "--database", "TestDb"]);
|
|
|
|
// Assert
|
|
var output = writer.ToString();
|
|
output.ShouldContain("added successfully");
|
|
await _configFileService.Received(1).SaveAppSettingsAsync(appSettingsPath, Arg.Any<ConfigModel>(), Arg.Any<CancellationToken>());
|
|
}
|
|
finally
|
|
{
|
|
Console.SetOut(originalOut);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
Directory.Delete(tempDir, true);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public async Task AddCommand_WithExistingConnection_ReturnsError()
|
|
{
|
|
// Arrange
|
|
var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
|
Directory.CreateDirectory(tempDir);
|
|
var appSettingsPath = Path.Combine(tempDir, "appsettings.json");
|
|
File.WriteAllText(appSettingsPath, "{}");
|
|
|
|
try
|
|
{
|
|
_autoDiscoveryService.FindConfigFolderAsync(Arg.Any<CancellationToken>())
|
|
.Returns(Task.FromResult<string?>(tempDir));
|
|
|
|
var config = new ConfigModel
|
|
{
|
|
ConnectionStrings = new ConnectionStringsSection
|
|
{
|
|
Entries =
|
|
[
|
|
new ConnectionStringEntry { Name = "ExistingConnection" }
|
|
]
|
|
}
|
|
};
|
|
|
|
_configFileService.LoadAppSettingsAsync(appSettingsPath, Arg.Any<CancellationToken>())
|
|
.Returns(Task.FromResult(config));
|
|
|
|
var command = ConnectionCommands.CreateAddCommand(
|
|
_serviceProvider, _configPathOption, _verboseOption, _quietOption);
|
|
var rootCommand = new RootCommand { command };
|
|
rootCommand.AddGlobalOption(_configPathOption);
|
|
rootCommand.AddGlobalOption(_verboseOption);
|
|
rootCommand.AddGlobalOption(_quietOption);
|
|
|
|
// Capture console output (Serilog writes all output to stdout)
|
|
var originalOut = Console.Out;
|
|
using var writer = new StringWriter();
|
|
Console.SetOut(writer);
|
|
|
|
try
|
|
{
|
|
// Act
|
|
await rootCommand.InvokeAsync(["add", "ExistingConnection", "--server", "localhost"]);
|
|
|
|
// Assert
|
|
var output = writer.ToString();
|
|
output.ShouldContain("already exists");
|
|
}
|
|
finally
|
|
{
|
|
Console.SetOut(originalOut);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
Directory.Delete(tempDir, true);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void RemoveCommand_HasCorrectDescription()
|
|
{
|
|
// Arrange & Act
|
|
var command = ConnectionCommands.CreateRemoveCommand(
|
|
_serviceProvider, _configPathOption, _verboseOption, _quietOption);
|
|
|
|
// Assert
|
|
command.Description.ShouldBe("Remove a connection");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task RemoveCommand_WithNonExistentConnection_ReturnsError()
|
|
{
|
|
// Arrange
|
|
var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
|
Directory.CreateDirectory(tempDir);
|
|
var appSettingsPath = Path.Combine(tempDir, "appsettings.json");
|
|
File.WriteAllText(appSettingsPath, "{}");
|
|
|
|
try
|
|
{
|
|
_autoDiscoveryService.FindConfigFolderAsync(Arg.Any<CancellationToken>())
|
|
.Returns(Task.FromResult<string?>(tempDir));
|
|
|
|
var config = new ConfigModel();
|
|
|
|
_configFileService.LoadAppSettingsAsync(appSettingsPath, Arg.Any<CancellationToken>())
|
|
.Returns(Task.FromResult(config));
|
|
|
|
var command = ConnectionCommands.CreateRemoveCommand(
|
|
_serviceProvider, _configPathOption, _verboseOption, _quietOption);
|
|
var rootCommand = new RootCommand { command };
|
|
rootCommand.AddGlobalOption(_configPathOption);
|
|
rootCommand.AddGlobalOption(_verboseOption);
|
|
rootCommand.AddGlobalOption(_quietOption);
|
|
|
|
// Capture console output (Serilog writes all output to stdout)
|
|
var originalOut = Console.Out;
|
|
using var writer = new StringWriter();
|
|
Console.SetOut(writer);
|
|
|
|
try
|
|
{
|
|
// Act
|
|
await rootCommand.InvokeAsync(["remove", "NonExistent"]);
|
|
|
|
// Assert
|
|
var output = writer.ToString();
|
|
output.ShouldContain("not found");
|
|
}
|
|
finally
|
|
{
|
|
Console.SetOut(originalOut);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
Directory.Delete(tempDir, true);
|
|
}
|
|
}
|
|
|
|
// ===== Connection Update Command Tests =====
|
|
|
|
[Fact]
|
|
public void CreateUpdateCommand_ReturnsCommandWithOptions()
|
|
{
|
|
// Act
|
|
var command = ConnectionCommands.CreateUpdateCommand(
|
|
_serviceProvider, _configPathOption, _verboseOption, _quietOption);
|
|
|
|
// Assert
|
|
command.ShouldNotBeNull();
|
|
command.Name.ShouldBe("update");
|
|
command.Arguments.ShouldContain(a => a.Name == "name");
|
|
command.Options.ShouldContain(o => o.Name == "provider");
|
|
command.Options.ShouldContain(o => o.Name == "server");
|
|
command.Options.ShouldContain(o => o.Name == "database");
|
|
command.Options.ShouldContain(o => o.Name == "user");
|
|
command.Options.ShouldContain(o => o.Name == "password");
|
|
command.Options.ShouldContain(o => o.Name == "port");
|
|
command.Options.ShouldContain(o => o.Name == "service-name");
|
|
command.Options.ShouldContain(o => o.Name == "raw");
|
|
}
|
|
|
|
[Fact]
|
|
public void UpdateCommand_HasCorrectDescription()
|
|
{
|
|
// Arrange & Act
|
|
var command = ConnectionCommands.CreateUpdateCommand(
|
|
_serviceProvider, _configPathOption, _verboseOption, _quietOption);
|
|
|
|
// Assert
|
|
command.Description.ShouldBe("Update an existing connection");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task UpdateCommand_WithNonExistentConnection_ReturnsError()
|
|
{
|
|
// Arrange
|
|
var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
|
Directory.CreateDirectory(tempDir);
|
|
var appSettingsPath = Path.Combine(tempDir, "appsettings.json");
|
|
File.WriteAllText(appSettingsPath, "{}");
|
|
|
|
try
|
|
{
|
|
_autoDiscoveryService.FindConfigFolderAsync(Arg.Any<CancellationToken>())
|
|
.Returns(Task.FromResult<string?>(tempDir));
|
|
|
|
var config = new ConfigModel();
|
|
|
|
_configFileService.LoadAppSettingsAsync(appSettingsPath, Arg.Any<CancellationToken>())
|
|
.Returns(Task.FromResult(config));
|
|
|
|
var command = ConnectionCommands.CreateUpdateCommand(
|
|
_serviceProvider, _configPathOption, _verboseOption, _quietOption);
|
|
var rootCommand = new RootCommand { command };
|
|
rootCommand.AddGlobalOption(_configPathOption);
|
|
rootCommand.AddGlobalOption(_verboseOption);
|
|
rootCommand.AddGlobalOption(_quietOption);
|
|
|
|
// Capture console output (Serilog writes all output to stdout)
|
|
var originalOut = Console.Out;
|
|
using var writer = new StringWriter();
|
|
Console.SetOut(writer);
|
|
|
|
try
|
|
{
|
|
// Act
|
|
await rootCommand.InvokeAsync(["update", "NonExistent", "--server", "newhost"]);
|
|
|
|
// Assert
|
|
var output = writer.ToString();
|
|
output.ShouldContain("not found");
|
|
}
|
|
finally
|
|
{
|
|
Console.SetOut(originalOut);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
Directory.Delete(tempDir, true);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void UpdateCommand_AllOptionsExist()
|
|
{
|
|
// Arrange & Act
|
|
var command = ConnectionCommands.CreateUpdateCommand(
|
|
_serviceProvider, _configPathOption, _verboseOption, _quietOption);
|
|
|
|
// Assert - Verify all options exist
|
|
command.Options.ShouldContain(o => o.Name == "provider");
|
|
command.Options.ShouldContain(o => o.Name == "server");
|
|
command.Options.ShouldContain(o => o.Name == "database");
|
|
command.Options.ShouldContain(o => o.Name == "user");
|
|
command.Options.ShouldContain(o => o.Name == "password");
|
|
command.Options.ShouldContain(o => o.Name == "port");
|
|
command.Options.ShouldContain(o => o.Name == "service-name");
|
|
command.Options.ShouldContain(o => o.Name == "raw");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task UpdateCommand_WithValidChange_UpdatesAndSaves()
|
|
{
|
|
// Arrange
|
|
var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
|
Directory.CreateDirectory(tempDir);
|
|
var appSettingsPath = Path.Combine(tempDir, "appsettings.json");
|
|
File.WriteAllText(appSettingsPath, "{}");
|
|
|
|
try
|
|
{
|
|
_autoDiscoveryService.FindConfigFolderAsync(Arg.Any<CancellationToken>())
|
|
.Returns(Task.FromResult<string?>(tempDir));
|
|
|
|
var config = new ConfigModel
|
|
{
|
|
ConnectionStrings = new ConnectionStringsSection
|
|
{
|
|
Entries =
|
|
[
|
|
new ConnectionStringEntry
|
|
{
|
|
Name = "TestConnection",
|
|
Provider = ConnectionProvider.SqlServer,
|
|
Server = "localhost",
|
|
Database = "OldDb"
|
|
}
|
|
]
|
|
}
|
|
};
|
|
|
|
_configFileService.LoadAppSettingsAsync(appSettingsPath, Arg.Any<CancellationToken>())
|
|
.Returns(Task.FromResult(config));
|
|
|
|
var command = ConnectionCommands.CreateUpdateCommand(
|
|
_serviceProvider, _configPathOption, _verboseOption, _quietOption);
|
|
var rootCommand = new RootCommand { command };
|
|
rootCommand.AddGlobalOption(_configPathOption);
|
|
rootCommand.AddGlobalOption(_verboseOption);
|
|
rootCommand.AddGlobalOption(_quietOption);
|
|
|
|
// Capture console output
|
|
var originalOut = Console.Out;
|
|
using var writer = new StringWriter();
|
|
Console.SetOut(writer);
|
|
|
|
try
|
|
{
|
|
// Act
|
|
await rootCommand.InvokeAsync(["update", "TestConnection", "--database", "NewDb"]);
|
|
|
|
// Assert
|
|
var output = writer.ToString();
|
|
output.ShouldContain("updated successfully");
|
|
await _configFileService.Received(1).SaveAppSettingsAsync(appSettingsPath, Arg.Any<ConfigModel>(), Arg.Any<CancellationToken>());
|
|
}
|
|
finally
|
|
{
|
|
Console.SetOut(originalOut);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
Directory.Delete(tempDir, true);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public async Task UpdateCommand_WithMultipleChanges_UpdatesAllProperties()
|
|
{
|
|
// Arrange
|
|
var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
|
Directory.CreateDirectory(tempDir);
|
|
var appSettingsPath = Path.Combine(tempDir, "appsettings.json");
|
|
File.WriteAllText(appSettingsPath, "{}");
|
|
|
|
try
|
|
{
|
|
_autoDiscoveryService.FindConfigFolderAsync(Arg.Any<CancellationToken>())
|
|
.Returns(Task.FromResult<string?>(tempDir));
|
|
|
|
var config = new ConfigModel
|
|
{
|
|
ConnectionStrings = new ConnectionStringsSection
|
|
{
|
|
Entries =
|
|
[
|
|
new ConnectionStringEntry
|
|
{
|
|
Name = "TestConnection",
|
|
Provider = ConnectionProvider.SqlServer,
|
|
Server = "localhost",
|
|
Database = "OldDb",
|
|
UserId = "olduser"
|
|
}
|
|
]
|
|
}
|
|
};
|
|
|
|
_configFileService.LoadAppSettingsAsync(appSettingsPath, Arg.Any<CancellationToken>())
|
|
.Returns(Task.FromResult(config));
|
|
|
|
var command = ConnectionCommands.CreateUpdateCommand(
|
|
_serviceProvider, _configPathOption, _verboseOption, _quietOption);
|
|
var rootCommand = new RootCommand { command };
|
|
rootCommand.AddGlobalOption(_configPathOption);
|
|
rootCommand.AddGlobalOption(_verboseOption);
|
|
rootCommand.AddGlobalOption(_quietOption);
|
|
|
|
// Capture console output
|
|
var originalOut = Console.Out;
|
|
using var writer = new StringWriter();
|
|
Console.SetOut(writer);
|
|
|
|
try
|
|
{
|
|
// Act
|
|
await rootCommand.InvokeAsync(["update", "TestConnection", "--server", "newhost", "--database", "NewDb", "--user", "newuser"]);
|
|
|
|
// Assert
|
|
var output = writer.ToString();
|
|
output.ShouldContain("updated successfully");
|
|
|
|
// Verify the config was updated
|
|
config.ConnectionStrings.Entries[0].Server.ShouldBe("newhost");
|
|
config.ConnectionStrings.Entries[0].Database.ShouldBe("NewDb");
|
|
config.ConnectionStrings.Entries[0].UserId.ShouldBe("newuser");
|
|
}
|
|
finally
|
|
{
|
|
Console.SetOut(originalOut);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
Directory.Delete(tempDir, true);
|
|
}
|
|
}
|
|
}
|