(refactor): exec tests

This commit is contained in:
Maksym Sadovnychyy 2024-08-18 15:16:42 +02:00
parent b68d8c1bca
commit 4bb2edcd77
6 changed files with 327 additions and 28 deletions

View File

@ -8,7 +8,7 @@
<!-- NuGet package metadata -->
<PackageId>PodmanClient.DotNet</PackageId>
<Version>1.0.2</Version>
<Version>1.0.3</Version>
<Authors>Maksym Sadovnychyy</Authors>
<Company>MAKS-IT</Company>
<Product>PodmanClient</Product>

View File

@ -0,0 +1,54 @@
using ICSharpCode.SharpZipLib.Tar;
namespace MaksIT.PodmanClientDotNet.Tests.Archives
{
public static class Tar
{
public static void CreateTarFromDirectory(string sourceDirectory, Stream outputStream)
{
using (var tarOutputStream = new TarOutputStream(outputStream))
{
tarOutputStream.IsStreamOwner = false;
AddDirectoryFilesToTar(tarOutputStream, sourceDirectory, true);
}
}
static void AddDirectoryFilesToTar(TarOutputStream tarOutputStream, string sourceDirectory, bool recursive, string baseDirectory = null)
{
// If baseDirectory is null, set it to the sourceDirectory to start with
if (baseDirectory == null)
{
baseDirectory = sourceDirectory;
}
var directoryInfo = new DirectoryInfo(sourceDirectory);
foreach (var fileInfo in directoryInfo.GetFiles())
{
// Calculate the relative path for the file within the base directory
string relativePath = Path.GetRelativePath(baseDirectory, fileInfo.FullName);
// Create tar entry with the relative path
var entry = TarEntry.CreateEntryFromFile(fileInfo.FullName);
entry.Name = relativePath.Replace(Path.DirectorySeparatorChar, '/'); // Use Unix-style path separators
tarOutputStream.PutNextEntry(entry);
using (var fileStream = fileInfo.OpenRead())
{
fileStream.CopyTo(tarOutputStream);
}
tarOutputStream.CloseEntry();
}
if (recursive)
{
foreach (var subDirectory in directoryInfo.GetDirectories())
{
// Recurse into subdirectories, passing the base directory
AddDirectoryFilesToTar(tarOutputStream, subDirectory.FullName, true, baseDirectory);
}
}
}
}
}

View File

@ -1,6 +1,6 @@
using Microsoft.Extensions.Logging;
using Xunit;
using System.Threading.Tasks;
using MaksIT.PodmanClientDotNet.Tests.Archives;
namespace MaksIT.PodmanClientDotNet.Tests {
public class PodmanClientContainersTests {
@ -15,11 +15,11 @@ namespace MaksIT.PodmanClientDotNet.Tests {
_client = new PodmanClient(logger, "http://wks0002.corp.maks-it.com:8080", 60);
}
#region Success
#region Success Cases
[Fact]
public async Task PodmanClient_ContainerLifecycle_Success() {
// Arrange
string containerName = "test-container";
string containerName = $"podman-client-test-{Guid.NewGuid()}";
string image = "alpine:latest";
// Act & Assert
@ -30,8 +30,42 @@ namespace MaksIT.PodmanClientDotNet.Tests {
await ForceDeleteContainerAsync(containerId);
}
[Fact]
public async Task CopyFilesToContainer_Success() {
// Arrange
string containerName = $"podman-client-test-{Guid.NewGuid()}";
string image = "alpine:latest";
string pathInContainer = "/podman-test-copy";
// Create temporary folder with random files
string tempFolderPath = CreateTemporaryFolderWithFiles();
try {
// Act
await PullImageAsync(image);
var containerId = await CreateContainerAsync(containerName, image);
await StartContainerAsync(containerId);
// Archive the folder and copy to container
using (var tarStream = CreateTarStream(tempFolderPath)) {
await CopyToContainerAsync(containerId, tarStream, pathInContainer);
}
// Stop and delete the container
await StopContainerAsync(containerId);
await ForceDeleteContainerAsync(containerId);
}
finally {
// Cleanup: Delete temporary folder
if (Directory.Exists(tempFolderPath)) {
Directory.Delete(tempFolderPath, true);
}
}
}
#endregion
#region Helper Methods
private async Task PullImageAsync(string image) {
// Implement the logic to pull the image
var exception = await Record.ExceptionAsync(() => _client.PullImageAsync(image));
Assert.Null(exception); // Expect no exceptions if the pull was successful
}
@ -63,42 +97,51 @@ namespace MaksIT.PodmanClientDotNet.Tests {
var exception = await Record.ExceptionAsync(() => _client.ForceDeleteContainerAsync(containerId));
Assert.Null(exception); // Expect no exceptions if the container was deleted successfully
}
private async Task CopyToContainerAsync(string containerId, Stream tarStream, string path) {
var exception = await Record.ExceptionAsync(() => _client.ExtractArchiveToContainerAsync(containerId, tarStream, path));
Assert.Null(exception); // Expect no exceptions if the copy was successful
}
private string CreateTemporaryFolderWithFiles() {
string tempFolder = Path.Combine(Path.GetTempPath(), $"podman-test-{Guid.NewGuid()}");
Directory.CreateDirectory(tempFolder);
// Create some random files
for (int i = 0; i < 5; i++) {
File.WriteAllText(Path.Combine(tempFolder, $"test-file-{i}.txt"), $"This is test file {i}");
}
return tempFolder;
}
private Stream CreateTarStream(string folderPath) {
var memoryStream = new MemoryStream();
Tar.CreateTarFromDirectory(folderPath, memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin); // Reset the stream position for reading
return memoryStream;
}
#endregion
#region Fail
#region Fail Cases
[Fact]
public async Task StartContainerAsync_Should_HandleErrors() {
// Arrange
string invalidContainerId = "invalid-container-id";
// Act
var exception = await Record.ExceptionAsync(() => _client.StartContainerAsync(invalidContainerId));
// Assert
Assert.NotNull(exception); // Expect an exception due to invalid container ID
}
[Fact]
public async Task StopContainerAsync_Should_HandleErrors() {
// Arrange
string invalidContainerId = "invalid-container-id";
// Act
var exception = await Record.ExceptionAsync(() => _client.StopContainerAsync(invalidContainerId));
// Assert
Assert.NotNull(exception); // Expect an exception due to invalid container ID
}
[Fact]
public async Task ForceDeleteContainerAsync_Should_HandleErrors() {
// Arrange
string invalidContainerId = "invalid-container-id";
// Act
var exception = await Record.ExceptionAsync(() => _client.ForceDeleteContainerAsync(invalidContainerId));
// Assert
Assert.NotNull(exception); // Expect an exception due to invalid container ID
}
#endregion

View File

@ -16,6 +16,7 @@
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageReference Include="SharpZipLib" Version="1.4.2" />
<PackageReference Include="xunit" Version="2.9.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<PrivateAssets>all</PrivateAssets>

View File

@ -0,0 +1,193 @@
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Xunit;
namespace MaksIT.PodmanClientDotNet.Tests {
public class PodmanClientExecTests {
private readonly PodmanClient _client;
public PodmanClientExecTests() {
var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
var logger = loggerFactory.CreateLogger<PodmanClient>();
_client = new PodmanClient(logger, "http://wks0002.corp.maks-it.com:8080", 60);
}
#region Success Cases
[Fact]
public async Task Full_ContainerLifecycle_With_Exec_Should_Succeed() {
// Arrange
string containerName = $"podman-client-test-{Guid.NewGuid()}";
string image = "alpine:latest";
// Act & Assert
// 1. Pull the image
await PullImageAsync(image);
// 2. Create the container with sleep infinity command
var containerId = await CreateContainerAsync(containerName, image);
// 3. Start the container
await StartContainerAsync(containerId);
// 4. Execute a command in the container to install a package (e.g., "apk add curl")
var execId = await CreateExecAsync(containerName, new[] { "apk", "add", "--no-cache", "curl" });
await StartExecAsync(execId);
// 5. Stop the container
await StopContainerAsync(containerId);
// 6. Delete the container
await ForceDeleteContainerAsync(containerId);
}
#endregion
#region Helper Methods
private async Task PullImageAsync(string image) {
var exception = await Record.ExceptionAsync(() => _client.PullImageAsync(image));
Assert.Null(exception); // Expect no exceptions if the pull was successful
}
private async Task<string> CreateContainerAsync(string containerName, string image) {
var createResponse = await _client.CreateContainerAsync(
name: containerName,
image: image,
command: new List<string> {
"sh", "-c",
"sleep infinity"
});
Assert.NotNull(createResponse);
Assert.False(string.IsNullOrEmpty(createResponse.Id)); // Ensure a valid container ID is returned
return createResponse.Id;
}
private async Task StartContainerAsync(string containerId) {
var exception = await Record.ExceptionAsync(() => _client.StartContainerAsync(containerId));
Assert.Null(exception); // Expect no exceptions if the container was started successfully
}
private async Task<string> CreateExecAsync(string containerName, string[] cmd) {
var execResponse = await _client.CreateExecAsync(containerName, cmd);
Assert.NotNull(execResponse);
Assert.False(string.IsNullOrEmpty(execResponse.Id)); // Ensure a valid exec ID is returned
return execResponse.Id;
}
private async Task StartExecAsync(string execId) {
var exception = await Record.ExceptionAsync(() => _client.StartExecAsync(execId));
Assert.Null(exception); // Expect no exceptions if the exec command was started successfully
}
private async Task StopContainerAsync(string containerId) {
var exception = await Record.ExceptionAsync(() => _client.StopContainerAsync(containerId));
Assert.Null(exception); // Expect no exceptions if the container was stopped successfully
}
private async Task ForceDeleteContainerAsync(string containerId) {
var exception = await Record.ExceptionAsync(() => _client.ForceDeleteContainerAsync(containerId));
Assert.Null(exception); // Expect no exceptions if the container was deleted successfully
}
#endregion
#region Fail Cases
[Fact]
public async Task PullImageAsync_Should_HandleErrors() {
// Arrange
string invalidImageReference = "invalidimage:latest"; // Intentionally wrong image
// Act
var exception = await Record.ExceptionAsync(() => _client.PullImageAsync(invalidImageReference));
// Assert
Assert.NotNull(exception);
Assert.IsType<HttpRequestException>(exception); // Ensure it's the expected type
}
[Fact]
public async Task CreateContainerAsync_Should_HandleErrors() {
// Arrange
string invalidImage = "invalidimage:latest"; // Intentionally wrong image
string containerName = "test-container";
// Act
var exception = await Record.ExceptionAsync(() => _client.CreateContainerAsync(containerName, invalidImage, new List<string> { "sh", "-c", "sleep infinity" }));
// Assert
Assert.NotNull(exception);
Assert.IsType<HttpRequestException>(exception); // Ensure it's the expected type
}
[Fact]
public async Task StartContainerAsync_Should_HandleErrors() {
// Arrange
string invalidContainerId = "invalid-container-id"; // Intentionally wrong container ID
// Act
var exception = await Record.ExceptionAsync(() => _client.StartContainerAsync(invalidContainerId));
// Assert
Assert.NotNull(exception);
Assert.IsType<HttpRequestException>(exception); // Ensure it's the expected type
}
[Fact]
public async Task CreateExecAsync_Should_HandleErrors() {
// Arrange
string containerName = "invalid-container"; // Intentionally wrong container name
var cmd = new[] { "apk", "add", "--no-cache", "curl" };
// Act
var exception = await Record.ExceptionAsync(() => _client.CreateExecAsync(containerName, cmd));
// Assert
Assert.NotNull(exception);
Assert.IsType<HttpRequestException>(exception); // Ensure it's the expected type
}
[Fact]
public async Task StartExecAsync_Should_HandleErrors() {
// Arrange
string invalidExecId = "invalid-exec-id"; // Intentionally wrong exec ID
// Act
var exception = await Record.ExceptionAsync(() => _client.StartExecAsync(invalidExecId));
// Assert
Assert.NotNull(exception);
Assert.IsType<HttpRequestException>(exception); // Ensure it's the expected type
}
[Fact]
public async Task StopContainerAsync_Should_HandleErrors() {
// Arrange
string invalidContainerId = "invalid-container-id"; // Intentionally wrong container ID
// Act
var exception = await Record.ExceptionAsync(() => _client.StopContainerAsync(invalidContainerId));
// Assert
Assert.NotNull(exception);
Assert.IsType<HttpRequestException>(exception); // Ensure it's the expected type
}
[Fact]
public async Task ForceDeleteContainerAsync_Should_HandleErrors() {
// Arrange
string invalidContainerId = "invalid-container-id"; // Intentionally wrong container ID
// Act
var exception = await Record.ExceptionAsync(() => _client.ForceDeleteContainerAsync(invalidContainerId));
// Assert
Assert.NotNull(exception);
Assert.IsType<HttpRequestException>(exception); // Ensure it's the expected type
}
#endregion
}
}

View File

@ -15,6 +15,8 @@ public class PodmanClientImagesTests {
_client = new PodmanClient(logger, "http://wks0002.corp.maks-it.com:8080", 60);
}
#region Success Cases
[Fact]
public async Task PodmanClient_IntegrationTests() {
// Test 1: Pull Image - Success
@ -23,6 +25,9 @@ public class PodmanClientImagesTests {
// Test 2: Tag Image - Success
await TagImageAsync_Should_Succeed();
}
#endregion
#region Helper Methods
private async Task PullImageAsync_Should_Succeed() {
// Arrange
@ -47,7 +52,9 @@ public class PodmanClientImagesTests {
// Assert
Assert.Null(exception); // Expect no exceptions if the tagging was successful
}
#endregion
#region Fail Cases
[Fact]
public async Task PodmanClient_PullImage_Errors() {
@ -76,4 +83,5 @@ public class PodmanClientImagesTests {
Assert.NotNull(exception); // Expect an exception due to nonexistent image
Assert.IsType<HttpRequestException>(exception); // Ensure it's the expected type
}
#endregion
}