ContainerHelpersTests.cs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. namespace Microsoft.NET.Build.Containers.UnitTests;
  4. public class ContainerHelpersTests
  5. {
  6. private const string DefaultRegistry = "docker.io";
  7. [Theory]
  8. // Valid Tests
  9. [InlineData("mcr.microsoft.com", true)]
  10. [InlineData("mcr.microsoft.com:5001", true)] // Registries can have ports
  11. [InlineData("docker.io", true)] // default docker registry is considered valid
  12. // // Invalid tests
  13. [InlineData("mcr.mi-=crosoft.com", false)] // invalid url
  14. [InlineData("mcr.microsoft.com/", false)] // invalid url
  15. public void IsValidRegistry(string registry, bool expectedReturn)
  16. {
  17. Console.WriteLine($"Domain pattern is '{ReferenceParser.AnchoredDomainRegexp.ToString()}'");
  18. Assert.Equal(expectedReturn, ContainerHelpers.IsValidRegistry(registry));
  19. }
  20. [Theory]
  21. [InlineData("mcr.microsoft.com/dotnet/runtime:6.0", true, "mcr.microsoft.com", "dotnet/runtime", "6.0", true)]
  22. [InlineData("mcr.microsoft.com/dotnet/runtime", true, "mcr.microsoft.com", "dotnet/runtime", null, true)]
  23. [InlineData("mcr.microsoft.com/", false, null, null, null, false)] // no image = nothing resolves
  24. // Ports tag along
  25. [InlineData("mcr.microsoft.com:54/dotnet/runtime", true, "mcr.microsoft.com:54", "dotnet/runtime", null, true)]
  26. // Even if nonsensical
  27. [InlineData("mcr.microsoft.com:0/dotnet/runtime", true, "mcr.microsoft.com:0", "dotnet/runtime", null, true)]
  28. // We don't allow hosts with missing ports when a port is anticipated
  29. [InlineData("mcr.microsoft.com:/dotnet/runtime", false, null, null, null, false)]
  30. // Use default registry when no registry specified.
  31. [InlineData("ubuntu:jammy", true, DefaultRegistry, "library/ubuntu", "jammy", false)]
  32. [InlineData("ubuntu/runtime:jammy", true, DefaultRegistry, "ubuntu/runtime", "jammy", false)]
  33. // Alias 'docker.io' to Docker registry.
  34. [InlineData("docker.io/ubuntu:jammy", true, DefaultRegistry, "library/ubuntu", "jammy", true)]
  35. [InlineData("docker.io/ubuntu/runtime:jammy", true, DefaultRegistry, "ubuntu/runtime", "jammy", true)]
  36. // 'localhost' registry.
  37. [InlineData("localhost/ubuntu:jammy", true, "localhost", "ubuntu", "jammy", true)]
  38. public void TryParseFullyQualifiedContainerName(string fullyQualifiedName, bool expectedReturn, string? expectedRegistry, string? expectedImage, string? expectedTag, bool expectedIsRegistrySpecified)
  39. {
  40. Assert.Equal(expectedReturn, ContainerHelpers.TryParseFullyQualifiedContainerName(fullyQualifiedName, out string? containerReg, out string? containerName, out string? containerTag, out string? containerDigest, out bool isRegistrySpecified));
  41. Assert.Equal(expectedRegistry, containerReg);
  42. Assert.Equal(expectedImage, containerName);
  43. Assert.Equal(expectedTag, containerTag);
  44. Assert.Equal(expectedIsRegistrySpecified, isRegistrySpecified);
  45. }
  46. [Theory]
  47. [InlineData("dotnet/runtime", true)]
  48. [InlineData("foo/bar", true)]
  49. [InlineData("registry", true)]
  50. [InlineData("-foo/bar", false)]
  51. [InlineData(".foo/bar", false)]
  52. [InlineData("_foo/bar", false)]
  53. [InlineData("foo/bar-", false)]
  54. [InlineData("foo/bar.", false)]
  55. [InlineData("foo/bar_", false)]
  56. [InlineData("--------", false)]
  57. public void IsValidImageName(string imageName, bool expectedReturn)
  58. {
  59. Assert.Equal(expectedReturn, ContainerHelpers.IsValidImageName(imageName));
  60. }
  61. [Theory]
  62. [InlineData("0aa", "0aa", null, null)]
  63. [InlineData("9zz", "9zz", null, null)]
  64. [InlineData("aa0", "aa0", null, null)]
  65. [InlineData("zz9", "zz9", null, null)]
  66. [InlineData("runtime", "runtime", null, null)]
  67. [InlineData("dotnet_runtime", "dotnet_runtime", null, null)]
  68. [InlineData("dotnet-runtime", "dotnet-runtime", null, null)]
  69. [InlineData("dotnet/runtime", "dotnet/runtime", null, null)]
  70. [InlineData("dotnet runtime", "dotnet-runtime", "NormalizedContainerName", null)]
  71. [InlineData("Api", "api", "NormalizedContainerName", null)]
  72. [InlineData("API", "api", "NormalizedContainerName", null)]
  73. [InlineData("$runtime", null, null, "InvalidImageName_NonAlphanumericStartCharacter")]
  74. [InlineData("-%", null, null, "InvalidImageName_NonAlphanumericStartCharacter")]
  75. public void IsValidRepositoryName(string containerRepository, string? expectedNormalized, string? expectedWarning, string? expectedError)
  76. {
  77. var actual = ContainerHelpers.NormalizeRepository(containerRepository);
  78. Assert.Equal(expectedNormalized, actual.normalizedImageName);
  79. Assert.Equal(expectedWarning, actual.normalizationWarning?.Item1);
  80. Assert.Equal(expectedError, actual.normalizationError?.Item1);
  81. }
  82. [Theory]
  83. [InlineData("6.0", true)] // baseline
  84. [InlineData("5.2-asd123", true)] // with commit hash
  85. [InlineData(".6.0", false)] // starts with .
  86. [InlineData("-6.0", false)] // starts with -
  87. [InlineData("---", false)] // malformed
  88. public void IsValidImageTag(string imageTag, bool expectedReturn)
  89. {
  90. Assert.Equal(expectedReturn, ContainerHelpers.IsValidImageTag(imageTag));
  91. }
  92. [Fact]
  93. public void IsValidImageTag_InvalidLength()
  94. {
  95. Assert.False(ContainerHelpers.IsValidImageTag(new string('a', 129)));
  96. }
  97. [Theory]
  98. [InlineData("80/tcp", true, 80, PortType.tcp, null)]
  99. [InlineData("80", true, 80, PortType.tcp, null)]
  100. [InlineData("125/dup", false, 125, PortType.tcp, ContainerHelpers.ParsePortError.InvalidPortType)]
  101. [InlineData("invalidNumber", false, null, null, ContainerHelpers.ParsePortError.InvalidPortNumber)]
  102. [InlineData("welp/unknowntype", false, null, null, (ContainerHelpers.ParsePortError)3)]
  103. [InlineData("a/b/c", false, null, null, ContainerHelpers.ParsePortError.UnknownPortFormat)]
  104. [InlineData("/tcp", false, null, null, ContainerHelpers.ParsePortError.MissingPortNumber)]
  105. public void CanParsePort(string input, bool shouldParse, int? expectedPortNumber, PortType? expectedType, ContainerHelpers.ParsePortError? expectedError)
  106. {
  107. var parseSuccess = ContainerHelpers.TryParsePort(input, out var port, out var errors);
  108. Assert.Equal(shouldParse, parseSuccess);
  109. if (shouldParse)
  110. {
  111. Assert.NotNull(port);
  112. Assert.Equal(port.Value.Number, expectedPortNumber);
  113. Assert.Equal(port.Value.Type, expectedType);
  114. }
  115. else
  116. {
  117. Assert.Null(port);
  118. Assert.NotNull(errors);
  119. Assert.Equal(expectedError, errors);
  120. }
  121. }
  122. [Theory]
  123. [InlineData("FOO", true)]
  124. [InlineData("foo_bar", true)]
  125. [InlineData("foo-bar", false)]
  126. [InlineData("foo.bar", false)]
  127. [InlineData("foo bar", false)]
  128. [InlineData("1_NAME", false)]
  129. [InlineData("ASPNETCORE_URLS", true)]
  130. [InlineData("ASPNETCORE_URLS2", true)]
  131. public void CanRecognizeEnvironmentVariableNames(string envVarName, bool isValid)
  132. {
  133. var success = ContainerHelpers.IsValidEnvironmentVariable(envVarName);
  134. Assert.Equal(isValid, success);
  135. }
  136. }