Latest Tag Static Validation Tests (#5852)

This commit is contained in:
Ella Hathaway 2024-09-06 11:41:21 -07:00 коммит произвёл Logan Bussell
Родитель 3d5dc2f970
Коммит d5d1e30181
4 изменённых файлов: 177 добавлений и 1 удалений

Просмотреть файл

@ -13,9 +13,9 @@ namespace Microsoft.DotNet.Docker.Tests
{
private const string VariableGroupName = "variable";
private const string VariablePattern = $"\\$\\((?<{VariableGroupName}>[\\w:\\-.|]+)\\)";
private static Lazy<JObject> Manifest { get; } = new Lazy<JObject>(() => LoadManifest("manifest.json"));
private static Lazy<JObject> ManifestVersions { get; } = new Lazy<JObject>(() => LoadManifest("manifest.versions.json"));
public static Lazy<JObject> Manifest { get; } = new Lazy<JObject>(() => LoadManifest("manifest.json"));
public static string SourceRepoRoot { get; } = Environment.GetEnvironmentVariable("SOURCE_REPO_ROOT") ?? string.Empty;
public static bool IsHttpVerificationDisabled { get; } =
Environment.GetEnvironmentVariable("DISABLE_HTTP_VERIFICATION") != null;

Просмотреть файл

@ -0,0 +1,34 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
namespace Microsoft.DotNet.Docker.Tests
{
// Simplified version of the ImageBuilder manifest model
// See https://github.com/dotnet/docker-tools/tree/main/src/Microsoft.DotNet.ImageBuilder/src/Models/Manifest
public class Manifest
{
public List<Repo> Repos { get; set; } = new List<Repo>();
}
public class Repo
{
public string Name { get; set; } = string.Empty;
public List<Image> Images { get; set; } = new List<Image>();
}
public class Image
{
public Dictionary<string, object> SharedTags { get; set; } = new Dictionary<string, object>();
public string ProductVersion { get; set; } = string.Empty;
public List<Platform> Platforms { get; set; } = new List<Platform>();
}
public class Platform
{
public string Dockerfile { get; set; } = string.Empty;
public Dictionary<string, object> Tags { get; set; } = new Dictionary<string, object>();
}
}

Просмотреть файл

@ -0,0 +1,41 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using System.Linq;
using System.Text.RegularExpressions;
#nullable enable
namespace Microsoft.DotNet.Docker.Tests
{
public static class ManifestHelper
{
public static Manifest GetManifest() =>
JsonConvert.DeserializeObject<Manifest>(Config.Manifest.Value.ToString()) ??
throw new Exception("Failed to deserialize manifest");
public static string GetResolvedProductVersion(Image image) =>
GetVariableValue(image.ProductVersion);
public static List<string> GetResolvedSharedTags(Image image) =>
image.SharedTags.Keys.Select(GetVariableValue).ToList();
public static List<string> GetResolvedTags(Platform platform) =>
platform.Tags.Keys.Select(GetVariableValue).ToList();
private static string GetVariableValue(string input)
{
string variablePattern = @"\$\((?<variable>.+)\)";
foreach (Match match in Regex.Matches(input, variablePattern))
{
string variableName = Config.GetVariableValue(match.Groups["variable"].Value);
input = input.Replace(match.Value, variableName);
}
return input;
}
}
}

Просмотреть файл

@ -0,0 +1,101 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis;
using Xunit;
#nullable enable
namespace Microsoft.DotNet.Docker.Tests
{
[Trait("Category", "pre-build")]
public class StaticTagTests
{
private const string LatestTagValue = "latest";
public static IEnumerable<object[]> GetRepoObjects() =>
ManifestHelper.GetManifest().Repos.Select(repo => new object[] { repo }).ToArray();
[Theory]
[MemberData(nameof(GetRepoObjects))]
private void LatestTag_OnePerRepo(Repo repo)
{
IEnumerable<Image> latestTagImages = repo.Images
.Where(image => ManifestHelper.GetResolvedSharedTags(image).Contains(LatestTagValue));
Assert.Single(latestTagImages);
}
[Theory]
[MemberData(nameof(GetRepoObjects))]
private void LatestTag_IsNotPlatformSpecific(Repo repo)
{
foreach (Image image in repo.Images)
{
IEnumerable<Platform> latestTagPlatforms = image.Platforms
.Where(platform => ManifestHelper.GetResolvedTags(platform).Contains(LatestTagValue));
Assert.Empty(latestTagPlatforms);
}
}
[Theory]
[MemberData(nameof(GetRepoObjects))]
private void LatestTag_OnCorrectMajorVersion(Repo repo)
{
Image latestImage = repo.Images
.Where(image => ManifestHelper.GetResolvedSharedTags(image).Contains(LatestTagValue))
.First();
int expectedMajorVersion = GetExpectedMajorVersion(repo);
int actualMajorVersion = GetMajorVersion(ManifestHelper.GetResolvedProductVersion(latestImage));
Assert.Equal(expectedMajorVersion, actualMajorVersion);
}
private static int GetExpectedMajorVersion(Repo repo)
{
List<string> productVersions = repo.Images
.Select(ManifestHelper.GetResolvedProductVersion)
.Distinct()
.ToList();
Assert.NotEmpty(productVersions);
if (productVersions.Count == 1)
{
// Use the first product version if there is only one
return GetMajorVersion(productVersions[0]);
}
if (Config.IsNightlyRepo)
{
// Use the latest major version on the nightly branch
List<int> majorVersions = productVersions
.Select(GetMajorVersion)
.Distinct()
.ToList();
return majorVersions.Max();
}
// Use the latest GA major version on the main branch
// Assumes that non-GA versions have a hyphen in them
// e.g. non GA: 5.0.0-preview.1, GA: 5.0.0
List<int> gaVersions = productVersions
.Where(version => !version.Contains('-'))
.Select(GetMajorVersion)
.Distinct()
.ToList();
return gaVersions.Max();
}
private static int GetMajorVersion(string version) =>
int.Parse(version.Split('.')[0]);
}
}