Fix ListImages test flaky Before/Since filter ordering (#40468)

* Fix ListImages test flaky Before/Since filter ordering The test hardcoded the assumption that debian:latest was created before python:3.12-alpine, but Docker image Created timestamps come from when the image was built in the registry, not when it was pulled or saved. The arm64 test data tars have debian (Mar 16) newer than python (Mar 3), causing the since filter to not return python. Fix by dynamically determining which image is older/newer based on actual Created timestamps, making the test robust against independently updated test data tars. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * format * Address PR feedback: assert Created timestamps are populated and distinct Adds explicit VERIFY checks that debianCreated/pythonCreated are > 0 and not equal before using them to choose the since/before boundary, preventing silent fallthrough or ambiguous Docker filter behavior when both images share a Created timestamp. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Ben Hillis committed May 11, 2026 at 12:47 UTC b51a8d9d0c67ad4972847fccf95e73e43cddd71d
1 file changed +38 -13
test/windows/WSLCTests.cpp
+38 -13
@@ -898,69 +898,94 @@ class WSLCTests
898
899 LogInfo("Test: Before/Since filters");
900 {
901 - // Get all images to find their IDs
901 + // Get all images to find their IDs and creation times
902 wil::unique_cotaskmem_array_ptr<WSLCImageInformation> allImages;
903 VERIFY_SUCCEEDED(m_defaultSession->ListImages(nullptr, allImages.addressof(), allImages.size_address<ULONG>()));
904
905 std::string debianId, pythonId;
906 + LONGLONG debianCreated = 0, pythonCreated = 0;
907 for (const auto& image : allImages)
908 {
909 std::string imageName = image.Image;
910 if (imageName == "debian:latest")
911 {
912 debianId = image.Hash;
913 + debianCreated = image.Created;
914 }
915 else if (imageName == "python:3.12-alpine")
916 {
917 pythonId = image.Hash;
918 + pythonCreated = image.Created;
919 }
920 }
921
922 VERIFY_IS_FALSE(debianId.empty());
923 VERIFY_IS_FALSE(pythonId.empty());
924
922 - // Test 'since' filter - images created after debian
925 + // Both Created timestamps must be populated and distinct so that the since/before
926 + // boundaries are unambiguous. Equal timestamps would make Docker's filter behavior
927 + // ambiguous and could reintroduce flakiness.
928 + VERIFY_IS_GREATER_THAN(debianCreated, 0LL);
929 + VERIFY_IS_GREATER_THAN(pythonCreated, 0LL);
930 + VERIFY_ARE_NOT_EQUAL(debianCreated, pythonCreated);
931 +
932 + // Determine which image is older/newer based on actual creation timestamps.
933 + // Image creation times come from the registry and can change independently.
934 + const bool debianIsOlder = debianCreated < pythonCreated;
935 + const auto& olderId = debianIsOlder ? debianId : pythonId;
936 + const auto& newerId = debianIsOlder ? pythonId : debianId;
937 + const auto* olderName = debianIsOlder ? "debian:latest" : "python:3.12-alpine";
938 + const auto* newerName = debianIsOlder ? "python:3.12-alpine" : "debian:latest";
939 +
940 + LogInfo(
941 + "Older image: %hs (Created: %lld), Newer image: %hs (Created: %lld)",
942 + olderName,
943 + debianIsOlder ? debianCreated : pythonCreated,
944 + newerName,
945 + debianIsOlder ? pythonCreated : debianCreated);
946 +
947 + // Test 'since' filter - images created after the older image
948 {
949 WSLCListImageOptions options{};
950 options.Flags = WSLCListImagesFlagsNone;
926 - options.Since = debianId.c_str();
951 + options.Since = olderId.c_str();
952
953 wil::unique_cotaskmem_array_ptr<WSLCImageInformation> images;
954 VERIFY_SUCCEEDED(m_defaultSession->ListImages(&options, images.addressof(), images.size_address<ULONG>()));
955 VERIFY_IS_TRUE(images.size() > 0);
956
932 - bool foundPython = false;
957 + bool foundNewer = false;
958 for (const auto& image : images)
959 {
960 LogInfo("Image: %hs, Hash: %hs, Created: %lld", image.Image, image.Hash, image.Created);
936 - if (std::string{image.Image} == "python:3.12-alpine")
961 + if (std::string{image.Image} == newerName)
962 {
938 - foundPython = true;
963 + foundNewer = true;
964 }
965 }
966
942 - VERIFY_IS_TRUE(foundPython);
967 + VERIFY_IS_TRUE(foundNewer);
968 }
969
945 - // Test 'before' filter - images created before python
970 + // Test 'before' filter - images created before the newer image
971 {
972 WSLCListImageOptions options{};
973 options.Flags = WSLCListImagesFlagsNone;
949 - options.Before = pythonId.c_str();
974 + options.Before = newerId.c_str();
975 wil::unique_cotaskmem_array_ptr<WSLCImageInformation> images;
976 VERIFY_SUCCEEDED(m_defaultSession->ListImages(&options, images.addressof(), images.size_address<ULONG>()));
977 VERIFY_IS_TRUE(images.size() > 0);
978
954 - bool foundDebian = false;
979 + bool foundOlder = false;
980 for (const auto& image : images)
981 {
957 - if (std::string{image.Image} == "debian:latest")
982 + if (std::string{image.Image} == olderName)
983 {
959 - foundDebian = true;
984 + foundOlder = true;
985 }
986 }
987
963 - VERIFY_IS_TRUE(foundDebian);
988 + VERIFY_IS_TRUE(foundOlder);
989 }
990 }
991