|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using Aspire.Cli.Utils.EnvironmentChecker;
namespace Aspire.Cli.Tests.Utils;
public class ContainerRuntimeCheckTests
{
[Fact]
public void ParseVersionFromJsonOutput_WithDockerJsonOutput_ReturnsBothVersions()
{
// Real Docker version -f json output with both client and server
var input = """{"Client":{"Platform":{"Name":"Docker Engine - Community"},"Version":"28.0.4","ApiVersion":"1.48","DefaultAPIVersion":"1.48","GitCommit":"b8034c0","GoVersion":"go1.23.7","Os":"linux","Arch":"amd64","BuildTime":"Tue Mar 25 15:07:16 2025","Context":"default"},"Server":{"Platform":{"Name":"Docker Engine - Community"},"Components":[{"Name":"Engine","Version":"28.0.4"}],"Version":"28.0.4","ApiVersion":"1.48"}}""";
var (clientVersion, serverVersion, context) = ContainerRuntimeCheck.ParseVersionFromJsonOutput(input);
Assert.NotNull(clientVersion);
Assert.Equal(new Version(28, 0, 4), clientVersion);
Assert.NotNull(serverVersion);
Assert.Equal(new Version(28, 0, 4), serverVersion);
Assert.Equal("default", context);
}
[Fact]
public void ParseVersionFromJsonOutput_WithDockerDesktopMacJsonOutput_ReturnsBothVersionsAndContext()
{
// Docker Desktop on macOS JSON output
var input = """{"Client":{"Version":"28.5.1","ApiVersion":"1.51","DefaultAPIVersion":"1.51","GitCommit":"e180ab8","GoVersion":"go1.24.8","Os":"darwin","Arch":"arm64","BuildTime":"Wed Oct 8 12:16:17 2025","Context":"desktop-linux"},"Server":{"Platform":{"Name":"Docker Desktop 4.49.0 (208700)"},"Components":[{"Name":"Engine","Version":"28.5.1"}],"Version":"28.5.1","ApiVersion":"1.51","MinAPIVersion":"1.24","GitCommit":"f8215cc","GoVersion":"go1.24.8","Os":"linux","Arch":"arm64","KernelVersion":"6.10.14-linuxkit","BuildTime":"2025-10-08T12:18:25.000000000+00:00"}}""";
var (clientVersion, serverVersion, context) = ContainerRuntimeCheck.ParseVersionFromJsonOutput(input);
Assert.NotNull(clientVersion);
Assert.Equal(new Version(28, 5, 1), clientVersion);
Assert.NotNull(serverVersion);
Assert.Equal(new Version(28, 5, 1), serverVersion);
Assert.Equal("desktop-linux", context);
}
[Fact]
public void ParseVersionFromJsonOutput_WithDockerEngineJsonOutput_ReturnsBothVersionsAndContext()
{
// Docker Engine (Linux) JSON output
var input = """{"Client":{"Platform":{"Name":"Docker Engine - Community"},"Version":"29.1.3","ApiVersion":"1.52","DefaultAPIVersion":"1.52","GitCommit":"f52814d","GoVersion":"go1.25.5","Os":"linux","Arch":"amd64","BuildTime":"Fri Dec 12 14:49:37 2025","Context":"default"},"Server":{"Platform":{"Name":"Docker Engine - Community"},"Version":"29.1.3","ApiVersion":"1.52","MinAPIVersion":"1.44","Os":"linux","Arch":"amd64","Components":[{"Name":"Engine","Version":"29.1.3"}],"GitCommit":"fbf3ed2","GoVersion":"go1.25.5","KernelVersion":"5.15.0-113-generic","BuildTime":"2025-12-12T14:49:37.000000000+00:00"}}""";
var (clientVersion, serverVersion, context) = ContainerRuntimeCheck.ParseVersionFromJsonOutput(input);
Assert.NotNull(clientVersion);
Assert.Equal(new Version(29, 1, 3), clientVersion);
Assert.NotNull(serverVersion);
Assert.Equal(new Version(29, 1, 3), serverVersion);
Assert.Equal("default", context);
}
[Fact]
public void ParseVersionFromJsonOutput_WithPodmanJsonOutput_ReturnsClientVersionOnly()
{
// Real Podman version -f json output (no Server section)
var input = """{"Client":{"APIVersion":"4.9.3","Version":"4.9.3","GoVersion":"go1.22.2","GitCommit":"","BuiltTime":"Thu Jan 1 00:00:00 1970","Built":0,"OsArch":"linux/amd64","Os":"linux"}}""";
var (clientVersion, serverVersion, context) = ContainerRuntimeCheck.ParseVersionFromJsonOutput(input);
Assert.NotNull(clientVersion);
Assert.Equal(new Version(4, 9, 3), clientVersion);
Assert.Null(serverVersion);
Assert.Null(context);
}
[Fact]
public void ParseVersionFromJsonOutput_WithDockerDesktopWindowsJsonOutput_ServerNull_ReturnsClientAndContext()
{
// Docker Desktop on Windows may have Server:null if daemon is not running
var input = """{"Client":{"Version":"29.1.3","ApiVersion":"1.52","DefaultAPIVersion":"1.52","GitCommit":"f52814d","GoVersion":"go1.25.5","Os":"windows","Arch":"amd64","BuildTime":"Fri Dec 12 14:51:52 2025","Context":"desktop-linux"},"Server":null}""";
var (clientVersion, serverVersion, context) = ContainerRuntimeCheck.ParseVersionFromJsonOutput(input);
Assert.NotNull(clientVersion);
Assert.Equal(new Version(29, 1, 3), clientVersion);
Assert.Null(serverVersion);
Assert.Equal("desktop-linux", context);
}
[Fact]
public void ParseVersionFromJsonOutput_WithOldDockerVersion_ReturnsClientVersion()
{
var input = """{"Client":{"Version":"19.03.15","ApiVersion":"1.40"},"Server":null}""";
var (clientVersion, serverVersion, context) = ContainerRuntimeCheck.ParseVersionFromJsonOutput(input);
Assert.NotNull(clientVersion);
Assert.Equal(new Version(19, 3, 15), clientVersion);
Assert.Null(serverVersion);
Assert.Null(context);
}
[Fact]
public void ParseVersionFromJsonOutput_WithTwoPartVersion_ReturnsVersion()
{
var input = """{"Client":{"Version":"20.10","ApiVersion":"1.41"}}""";
var (clientVersion, serverVersion, context) = ContainerRuntimeCheck.ParseVersionFromJsonOutput(input);
Assert.NotNull(clientVersion);
Assert.Equal(new Version(20, 10), clientVersion);
Assert.Null(serverVersion);
Assert.Null(context);
}
[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData(" ")]
[InlineData("not json")]
[InlineData("{}")]
[InlineData("""{"Client":{}}""")]
public void ParseVersionFromJsonOutput_WithInvalidInput_ReturnsNullVersions(string? input)
{
var (clientVersion, serverVersion, context) = ContainerRuntimeCheck.ParseVersionFromJsonOutput(input!);
Assert.Null(clientVersion);
Assert.Null(serverVersion);
Assert.Null(context);
}
[Fact]
public void ParseVersionFromJsonOutput_WithOnlyServerVersion_ReturnsServerVersionOnly()
{
// Edge case: only server version present (unusual but possible)
var input = """{"Server":{"Version":"1.0.0"}}""";
var (clientVersion, serverVersion, context) = ContainerRuntimeCheck.ParseVersionFromJsonOutput(input);
Assert.Null(clientVersion);
Assert.NotNull(serverVersion);
Assert.Equal(new Version(1, 0, 0), serverVersion);
Assert.Null(context);
}
[Fact]
public void ParseVersionFromJsonOutput_WithInvalidVersionString_ReturnsNull()
{
var input = """{"Client":{"Version":"not-a-version"}}""";
var (clientVersion, serverVersion, context) = ContainerRuntimeCheck.ParseVersionFromJsonOutput(input);
Assert.Null(clientVersion);
Assert.Null(serverVersion);
Assert.Null(context);
}
[Fact]
public void ParseVersionFromJsonOutput_WithMalformedJson_ReturnsNull()
{
var input = "{\"Client\":{\"Version\":\"28.0.4\""; // Missing closing braces
var (clientVersion, serverVersion, context) = ContainerRuntimeCheck.ParseVersionFromJsonOutput(input);
Assert.Null(clientVersion);
Assert.Null(serverVersion);
Assert.Null(context);
}
[Fact]
public void ParseVersionFromJsonOutput_WithMismatchedClientServerVersions_ReturnsBothVersions()
{
// Hypothetical case where client and server versions differ
var input = """{"Client":{"Version":"28.0.4"},"Server":{"Version":"27.5.1"}}""";
var (clientVersion, serverVersion, context) = ContainerRuntimeCheck.ParseVersionFromJsonOutput(input);
Assert.NotNull(clientVersion);
Assert.Equal(new Version(28, 0, 4), clientVersion);
Assert.NotNull(serverVersion);
Assert.Equal(new Version(27, 5, 1), serverVersion);
Assert.Null(context);
}
[Theory]
[InlineData("Docker version 20.10.17, build 100c701", "20.10.17")]
[InlineData("Docker version 27.5.1, build 9f9e405", "27.5.1")]
[InlineData("Docker version 24.0.5, build ced0996", "24.0.5")]
[InlineData("podman version 4.3.1", "4.3.1")]
[InlineData("podman version 5.0.0", "5.0.0")]
[InlineData("podman version 3.4.4", "3.4.4")]
[InlineData("Docker version 19.03.15, build 99e3ed8919", "19.03.15")]
[InlineData("Docker version 20.10, build abc123", "20.10")]
public void ParseVersionFromOutput_WithValidVersionString_ReturnsCorrectVersion(string input, string expectedVersion)
{
var result = ContainerRuntimeCheck.ParseVersionFromOutput(input);
Assert.NotNull(result);
Assert.Equal(Version.Parse(expectedVersion), result);
}
[Theory]
[InlineData("")]
[InlineData(" ")]
[InlineData("Docker is not installed")]
[InlineData("Command not found")]
[InlineData("random text without version info")]
public void ParseVersionFromOutput_WithInvalidInput_ReturnsNull(string input)
{
var result = ContainerRuntimeCheck.ParseVersionFromOutput(input);
Assert.Null(result);
}
[Fact]
public void ParseVersionFromOutput_WithNullInput_ReturnsNull()
{
var result = ContainerRuntimeCheck.ParseVersionFromOutput(null!);
Assert.Null(result);
}
[Fact]
public void ParseVersionFromOutput_WithDockerDesktopOutput_ReturnsVersion()
{
// Docker Desktop on Windows/Mac may have additional output
var input = """
Docker version 27.5.1, build 9f9e405
""";
var result = ContainerRuntimeCheck.ParseVersionFromOutput(input);
Assert.NotNull(result);
Assert.Equal(new Version(27, 5, 1), result);
}
[Fact]
public void ParseVersionFromOutput_WithPodmanVerboseOutput_ReturnsVersion()
{
// Podman may have additional output on some systems
var input = """
podman version 4.3.1
API Version: 4.3.1
""";
var result = ContainerRuntimeCheck.ParseVersionFromOutput(input);
Assert.NotNull(result);
Assert.Equal(new Version(4, 3, 1), result);
}
[Fact]
public void ParseVersionFromOutput_WithCaseInsensitiveVersion_ReturnsVersion()
{
// Test case insensitivity
var inputs = new[]
{
"Docker VERSION 27.5.1, build abc",
"docker Version 27.5.1",
"PODMAN VERSION 4.3.1",
};
foreach (var input in inputs)
{
var result = ContainerRuntimeCheck.ParseVersionFromOutput(input);
Assert.NotNull(result);
}
}
}
|