diff --git a/core/src/main/java/org/testcontainers/utility/DockerImageName.java b/core/src/main/java/org/testcontainers/utility/DockerImageName.java index e3a35855bf8..4be06c12b38 100644 --- a/core/src/main/java/org/testcontainers/utility/DockerImageName.java +++ b/core/src/main/java/org/testcontainers/utility/DockerImageName.java @@ -6,6 +6,7 @@ import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.With; +import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.testcontainers.utility.Versioning.Sha256Versioning; @@ -234,9 +235,16 @@ public DockerImageName asCompatibleSubstituteFor(DockerImageName otherImageName) */ public boolean isCompatibleWith(DockerImageName other) { // Make sure we always compare against a version of the image name containing the LIBRARY_PREFIX - String finalImageName; + if (isImageNameAbsent()) { + return false; + } + + String finalImageName = ""; + if (StringUtils.isNotBlank(this.registry)) { + finalImageName = this.registry + "/"; + } if (this.repository.startsWith(LIBRARY_PREFIX)) { - finalImageName = this.repository; + finalImageName = finalImageName + this.repository; } else { finalImageName = LIBRARY_PREFIX + this.repository; } @@ -249,9 +257,21 @@ public boolean isCompatibleWith(DockerImageName other) { return false; } + if (isImageWithDigest()) { + return true; + } + return this.compatibleSubstituteFor.isCompatibleWith(other); } + private boolean isImageNameAbsent() { + return this.repository.equals(LIBRARY_PREFIX); + } + + private boolean isImageWithDigest() { + return !(this.versioning instanceof Versioning.AnyVersion) && this.versioning.isValid(); + } + /** * Behaves as {@link DockerImageName#isCompatibleWith(DockerImageName)} but throws an exception * rather than returning false if a mismatch is detected. diff --git a/core/src/test/java/org/testcontainers/utility/DockerImageNameCompatibilityTest.java b/core/src/test/java/org/testcontainers/utility/DockerImageNameCompatibilityTest.java index dd17981111f..76eea780f68 100644 --- a/core/src/test/java/org/testcontainers/utility/DockerImageNameCompatibilityTest.java +++ b/core/src/test/java/org/testcontainers/utility/DockerImageNameCompatibilityTest.java @@ -91,12 +91,66 @@ public void testAssertMethodAcceptsCompatible() { subject.assertCompatibleWith(DockerImageName.parse("bar")); } + @Test + public void testAssertMethodAcceptsPathCompatibleDigestSuffix() { + DockerImageName subject = DockerImageName.parse("foo@sha256:301bcb60b8a3ee4ab7e147932723e3abd1cef53516ce5210b39fd9fe5e3602ae"); + subject.assertCompatibleWith(DockerImageName.parse("foo")); + } + + @Test + public void testAssertMethodAcceptsPathInCompatibleDigestSuffix() { + DockerImageName subject = DockerImageName.parse("foo@301bcb60b8a3ee4ab7e147932723e3abd1cef53516ce5210b39fd9fe5e3602ae"); + assertThatThrownBy(() -> subject.assertCompatibleWith(DockerImageName.parse("foo"))) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("Failed to verify that image 'foo@301bcb60b8a3ee4ab7e147932723e3abd1cef53516ce5210b39fd9fe5e3602ae' is a compatible substitute for 'foo'"); + } + + @Test + public void testAssertMethodAcceptsPathCompatibleLibraryPrefixAndDigestSuffix() { + DockerImageName subject = DockerImageName.parse("library/foo@sha256:301bcb60b8a3ee4ab7e147932723e3abd1cef53516ce5210b39fd9fe5e3602ae"); + subject.assertCompatibleWith(DockerImageName.parse("foo")); + } + + @Test + public void testAssertMethodAcceptsPathCompatibleFullLibraryPrefixAndDigestSuffix() { + DockerImageName subject = DockerImageName.parse("foo.registry/library/foo@sha256:301bcb60b8a3ee4ab7e147932723e3abd1cef53516ce5210b39fd9fe5e3602ae"); + subject.assertCompatibleWith(DockerImageName.parse("foo")); + } + + @Test + public void testAssertMethodAcceptsFullLibraryPrefix() { + DockerImageName subject = DockerImageName.parse("foo.registry/library/foo"); + subject.assertCompatibleWith(DockerImageName.parse("foo")); + } + @Test public void testAssertMethodAcceptsCompatibleLibraryPrefix() { DockerImageName subject = DockerImageName.parse("library/foo"); subject.assertCompatibleWith(DockerImageName.parse("foo")); } + @Test + public void testAssertMethodAcceptsCompatibleLibraryPrefixAndLatestSuffix() { + DockerImageName subject = DockerImageName.parse("library/foo:latest"); + subject.assertCompatibleWith(DockerImageName.parse("foo")); + } + + @Test + public void testAssertMethodRejectsIncompatibleWithAbsentImageName() { + DockerImageName subject = DockerImageName.parse("foo.registry/library/"); + assertThatThrownBy(() -> subject.assertCompatibleWith(DockerImageName.parse("foo"))) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("Failed to verify that image 'foo.registry/library/' is a compatible substitute for 'foo'"); + } + + @Test + public void testAssertMethodRejectsIncompatibleWithOnlyRegistryName() { + DockerImageName subject = DockerImageName.parse("foo.registry"); + assertThatThrownBy(() -> subject.assertCompatibleWith(DockerImageName.parse("foo"))) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("Failed to verify that image 'foo.registry' is a compatible substitute for 'foo'"); + } + @Test public void testAssertMethodRejectsIncompatible() { DockerImageName subject = DockerImageName.parse("foo");