github.com/moby/docker@v26.1.3+incompatible/integration/image/list_test.go (about) 1 package image // import "github.com/docker/docker/integration/image" 2 3 import ( 4 "fmt" 5 "strings" 6 "testing" 7 "time" 8 9 containertypes "github.com/docker/docker/api/types/container" 10 "github.com/docker/docker/api/types/filters" 11 "github.com/docker/docker/api/types/image" 12 "github.com/docker/docker/integration/internal/container" 13 "github.com/docker/docker/internal/testutils/specialimage" 14 "github.com/docker/docker/testutil" 15 "github.com/docker/docker/testutil/daemon" 16 "github.com/google/go-cmp/cmp/cmpopts" 17 ocispec "github.com/opencontainers/image-spec/specs-go/v1" 18 "gotest.tools/v3/assert" 19 is "gotest.tools/v3/assert/cmp" 20 "gotest.tools/v3/skip" 21 ) 22 23 // Regression : #38171 24 func TestImagesFilterMultiReference(t *testing.T) { 25 ctx := setupTest(t) 26 27 client := testEnv.APIClient() 28 29 name := strings.ToLower(t.Name()) 30 repoTags := []string{ 31 name + ":v1", 32 name + ":v2", 33 name + ":v3", 34 name + ":v4", 35 } 36 37 for _, repoTag := range repoTags { 38 err := client.ImageTag(ctx, "busybox:latest", repoTag) 39 assert.NilError(t, err) 40 } 41 42 filter := filters.NewArgs() 43 filter.Add("reference", repoTags[0]) 44 filter.Add("reference", repoTags[1]) 45 filter.Add("reference", repoTags[2]) 46 options := image.ListOptions{ 47 Filters: filter, 48 } 49 images, err := client.ImageList(ctx, options) 50 assert.NilError(t, err) 51 52 assert.Assert(t, is.Len(images, 1)) 53 assert.Check(t, is.Len(images[0].RepoTags, 3)) 54 for _, repoTag := range images[0].RepoTags { 55 if repoTag != repoTags[0] && repoTag != repoTags[1] && repoTag != repoTags[2] { 56 t.Errorf("list images doesn't match any repoTag we expected, repoTag: %s", repoTag) 57 } 58 } 59 } 60 61 func TestImagesFilterUntil(t *testing.T) { 62 ctx := setupTest(t) 63 64 client := testEnv.APIClient() 65 66 name := strings.ToLower(t.Name()) 67 ctr := container.Create(ctx, t, client, container.WithName(name)) 68 69 imgs := make([]string, 5) 70 for i := range imgs { 71 if i > 0 { 72 // Make sure each image has a distinct timestamp. 73 time.Sleep(time.Millisecond) 74 } 75 id, err := client.ContainerCommit(ctx, ctr, containertypes.CommitOptions{Reference: fmt.Sprintf("%s:v%d", name, i)}) 76 assert.NilError(t, err) 77 imgs[i] = id.ID 78 } 79 80 olderImage, _, err := client.ImageInspectWithRaw(ctx, imgs[2]) 81 assert.NilError(t, err) 82 olderUntil := olderImage.Created 83 84 laterImage, _, err := client.ImageInspectWithRaw(ctx, imgs[3]) 85 assert.NilError(t, err) 86 laterUntil := laterImage.Created 87 88 filter := filters.NewArgs( 89 filters.Arg("since", imgs[0]), 90 filters.Arg("until", olderUntil), 91 filters.Arg("until", laterUntil), 92 filters.Arg("before", imgs[len(imgs)-1]), 93 ) 94 list, err := client.ImageList(ctx, image.ListOptions{Filters: filter}) 95 assert.NilError(t, err) 96 97 var listedIDs []string 98 for _, i := range list { 99 t.Logf("ImageList: ID=%v RepoTags=%v", i.ID, i.RepoTags) 100 listedIDs = append(listedIDs, i.ID) 101 } 102 assert.DeepEqual(t, listedIDs, imgs[1:2], cmpopts.SortSlices(func(a, b string) bool { return a < b })) 103 } 104 105 func TestImagesFilterBeforeSince(t *testing.T) { 106 ctx := setupTest(t) 107 108 client := testEnv.APIClient() 109 110 name := strings.ToLower(t.Name()) 111 ctr := container.Create(ctx, t, client, container.WithName(name)) 112 113 imgs := make([]string, 5) 114 for i := range imgs { 115 if i > 0 { 116 // Make sure each image has a distinct timestamp. 117 time.Sleep(time.Millisecond) 118 } 119 id, err := client.ContainerCommit(ctx, ctr, containertypes.CommitOptions{Reference: fmt.Sprintf("%s:v%d", name, i)}) 120 assert.NilError(t, err) 121 imgs[i] = id.ID 122 } 123 124 filter := filters.NewArgs( 125 filters.Arg("since", imgs[0]), 126 filters.Arg("before", imgs[len(imgs)-1]), 127 ) 128 list, err := client.ImageList(ctx, image.ListOptions{Filters: filter}) 129 assert.NilError(t, err) 130 131 var listedIDs []string 132 for _, i := range list { 133 t.Logf("ImageList: ID=%v RepoTags=%v", i.ID, i.RepoTags) 134 listedIDs = append(listedIDs, i.ID) 135 } 136 // The ImageList API sorts the list by created timestamp... truncated to 137 // 1-second precision. Since all the images were created within 138 // milliseconds of each other, listedIDs is effectively unordered and 139 // the assertion must therefore be order-independent. 140 assert.DeepEqual(t, listedIDs, imgs[1:len(imgs)-1], cmpopts.SortSlices(func(a, b string) bool { return a < b })) 141 } 142 143 func TestAPIImagesFilters(t *testing.T) { 144 ctx := setupTest(t) 145 client := testEnv.APIClient() 146 147 for _, n := range []string{"utest:tag1", "utest/docker:tag2", "utest:5000/docker:tag3"} { 148 err := client.ImageTag(ctx, "busybox:latest", n) 149 assert.NilError(t, err) 150 } 151 152 testcases := []struct { 153 name string 154 filters []filters.KeyValuePair 155 expectedImages int 156 expectedRepoTags int 157 }{ 158 { 159 name: "repository regex", 160 filters: []filters.KeyValuePair{filters.Arg("reference", "utest*/*")}, 161 expectedImages: 1, 162 expectedRepoTags: 2, 163 }, 164 { 165 name: "image name regex", 166 filters: []filters.KeyValuePair{filters.Arg("reference", "utest*")}, 167 expectedImages: 1, 168 expectedRepoTags: 1, 169 }, 170 { 171 name: "image name without a tag", 172 filters: []filters.KeyValuePair{filters.Arg("reference", "utest")}, 173 expectedImages: 1, 174 expectedRepoTags: 1, 175 }, 176 { 177 name: "registry port regex", 178 filters: []filters.KeyValuePair{filters.Arg("reference", "*5000*/*")}, 179 expectedImages: 1, 180 expectedRepoTags: 1, 181 }, 182 } 183 184 for _, tc := range testcases { 185 tc := tc 186 t.Run(tc.name, func(t *testing.T) { 187 t.Parallel() 188 189 ctx := testutil.StartSpan(ctx, t) 190 images, err := client.ImageList(ctx, image.ListOptions{ 191 Filters: filters.NewArgs(tc.filters...), 192 }) 193 assert.Check(t, err) 194 assert.Assert(t, is.Len(images, tc.expectedImages)) 195 assert.Check(t, is.Len(images[0].RepoTags, tc.expectedRepoTags)) 196 }) 197 } 198 } 199 200 // Verify that the size calculation operates on ChainIDs and not DiffIDs. 201 // This test calls an image list with two images that share one, top layer. 202 func TestAPIImagesListSizeShared(t *testing.T) { 203 skip.If(t, testEnv.DaemonInfo.OSType != "linux") 204 205 ctx := setupTest(t) 206 207 daemon := daemon.New(t) 208 daemon.Start(t) 209 defer daemon.Stop(t) 210 211 client := daemon.NewClientT(t) 212 213 specialimage.Load(ctx, t, client, func(dir string) (*ocispec.Index, error) { 214 return specialimage.MultiLayerCustom(dir, "multilayer:latest", []specialimage.SingleFileLayer{ 215 {Name: "bar", Content: []byte("2")}, 216 {Name: "foo", Content: []byte("1")}, 217 }) 218 }) 219 220 specialimage.Load(ctx, t, client, func(dir string) (*ocispec.Index, error) { 221 return specialimage.MultiLayerCustom(dir, "multilayer2:latest", []specialimage.SingleFileLayer{ 222 {Name: "asdf", Content: []byte("3")}, 223 {Name: "foo", Content: []byte("1")}, 224 }) 225 }) 226 227 _, err := client.ImageList(ctx, image.ListOptions{SharedSize: true}) 228 assert.NilError(t, err) 229 }