github.com/buildpacks/pack@v0.33.3-0.20240516162812-884dd1837311/pkg/cache/volume_cache_test.go (about) 1 package cache_test 2 3 import ( 4 "context" 5 "strings" 6 "testing" 7 8 "github.com/buildpacks/pack/pkg/cache" 9 10 "github.com/docker/docker/api/types/filters" 11 "github.com/docker/docker/api/types/volume" 12 "github.com/docker/docker/client" 13 "github.com/docker/docker/daemon/names" 14 "github.com/google/go-containerregistry/pkg/name" 15 "github.com/heroku/color" 16 "github.com/sclevine/spec" 17 "github.com/sclevine/spec/report" 18 19 h "github.com/buildpacks/pack/testhelpers" 20 ) 21 22 func TestVolumeCache(t *testing.T) { 23 h.RequireDocker(t) 24 color.Disable(true) 25 defer color.Disable(false) 26 27 spec.Run(t, "VolumeCache", testCache, spec.Parallel(), spec.Report(report.Terminal{})) 28 } 29 30 func testCache(t *testing.T, when spec.G, it spec.S) { 31 var dockerClient client.CommonAPIClient 32 33 it.Before(func() { 34 var err error 35 dockerClient, err = client.NewClientWithOpts(client.FromEnv, client.WithVersion("1.38")) 36 h.AssertNil(t, err) 37 }) 38 when("#NewVolumeCache", func() { 39 when("volume cache name is empty", func() { 40 it("adds suffix to calculated name", func() { 41 ref, err := name.ParseReference("my/repo", name.WeakValidation) 42 h.AssertNil(t, err) 43 subject := cache.NewVolumeCache(ref, cache.CacheInfo{}, "some-suffix", dockerClient) 44 if !strings.HasSuffix(subject.Name(), ".some-suffix") { 45 t.Fatalf("Calculated volume name '%s' should end with '.some-suffix'", subject.Name()) 46 } 47 }) 48 49 it("reusing the same cache for the same repo name", func() { 50 ref, err := name.ParseReference("my/repo", name.WeakValidation) 51 h.AssertNil(t, err) 52 53 subject := cache.NewVolumeCache(ref, cache.CacheInfo{}, "some-suffix", dockerClient) 54 expected := cache.NewVolumeCache(ref, cache.CacheInfo{}, "some-suffix", dockerClient) 55 if subject.Name() != expected.Name() { 56 t.Fatalf("The same repo name should result in the same volume") 57 } 58 }) 59 60 it("supplies different volumes for different tags", func() { 61 ref, err := name.ParseReference("my/repo:other-tag", name.WeakValidation) 62 h.AssertNil(t, err) 63 64 subject := cache.NewVolumeCache(ref, cache.CacheInfo{}, "some-suffix", dockerClient) 65 66 ref, err = name.ParseReference("my/repo", name.WeakValidation) 67 h.AssertNil(t, err) 68 notExpected := cache.NewVolumeCache(ref, cache.CacheInfo{}, "some-suffix", dockerClient) 69 if subject.Name() == notExpected.Name() { 70 t.Fatalf("Different image tags should result in different volumes") 71 } 72 }) 73 74 it("supplies different volumes for different registries", func() { 75 ref, err := name.ParseReference("registry.com/my/repo:other-tag", name.WeakValidation) 76 h.AssertNil(t, err) 77 78 subject := cache.NewVolumeCache(ref, cache.CacheInfo{}, "some-suffix", dockerClient) 79 80 ref, err = name.ParseReference("my/repo", name.WeakValidation) 81 h.AssertNil(t, err) 82 notExpected := cache.NewVolumeCache(ref, cache.CacheInfo{}, "some-suffix", dockerClient) 83 if subject.Name() == notExpected.Name() { 84 t.Fatalf("Different image registries should result in different volumes") 85 } 86 }) 87 88 it("resolves implied tag", func() { 89 ref, err := name.ParseReference("my/repo:latest", name.WeakValidation) 90 h.AssertNil(t, err) 91 92 subject := cache.NewVolumeCache(ref, cache.CacheInfo{}, "some-suffix", dockerClient) 93 94 ref, err = name.ParseReference("my/repo", name.WeakValidation) 95 h.AssertNil(t, err) 96 expected := cache.NewVolumeCache(ref, cache.CacheInfo{}, "some-suffix", dockerClient) 97 h.AssertEq(t, subject.Name(), expected.Name()) 98 }) 99 100 it("resolves implied registry", func() { 101 ref, err := name.ParseReference("index.docker.io/my/repo", name.WeakValidation) 102 h.AssertNil(t, err) 103 104 subject := cache.NewVolumeCache(ref, cache.CacheInfo{}, "some-suffix", dockerClient) 105 106 ref, err = name.ParseReference("my/repo", name.WeakValidation) 107 h.AssertNil(t, err) 108 expected := cache.NewVolumeCache(ref, cache.CacheInfo{}, "some-suffix", dockerClient) 109 h.AssertEq(t, subject.Name(), expected.Name()) 110 }) 111 112 it("includes human readable information", func() { 113 ref, err := name.ParseReference("myregistryhost:5000/fedora/httpd:version1.0", name.WeakValidation) 114 h.AssertNil(t, err) 115 116 subject := cache.NewVolumeCache(ref, cache.CacheInfo{}, "some-suffix", dockerClient) 117 118 h.AssertContains(t, subject.Name(), "fedora_httpd_version1.0") 119 h.AssertTrue(t, names.RestrictedNamePattern.MatchString(subject.Name())) 120 }) 121 }) 122 123 when("volume cache name is not empty", func() { 124 volumeName := "test-volume-name" 125 cacheInfo := cache.CacheInfo{ 126 Format: cache.CacheVolume, 127 Source: volumeName, 128 } 129 130 it("named volume created without suffix", func() { 131 ref, err := name.ParseReference("my/repo", name.WeakValidation) 132 h.AssertNil(t, err) 133 134 subject := cache.NewVolumeCache(ref, cacheInfo, "some-suffix", dockerClient) 135 136 if volumeName != subject.Name() { 137 t.Fatalf("Volume name '%s' should be same as the name specified '%s'", subject.Name(), volumeName) 138 } 139 }) 140 141 it("reusing the same cache for the same repo name", func() { 142 ref, err := name.ParseReference("my/repo", name.WeakValidation) 143 h.AssertNil(t, err) 144 145 subject := cache.NewVolumeCache(ref, cacheInfo, "some-suffix", dockerClient) 146 147 expected := cache.NewVolumeCache(ref, cacheInfo, "some-suffix", dockerClient) 148 if subject.Name() != expected.Name() { 149 t.Fatalf("The same repo name should result in the same volume") 150 } 151 }) 152 153 it("supplies different volumes for different registries", func() { 154 ref, err := name.ParseReference("registry.com/my/repo:other-tag", name.WeakValidation) 155 h.AssertNil(t, err) 156 157 subject := cache.NewVolumeCache(ref, cache.CacheInfo{}, "some-suffix", dockerClient) 158 159 ref, err = name.ParseReference("my/repo", name.WeakValidation) 160 h.AssertNil(t, err) 161 notExpected := cache.NewVolumeCache(ref, cache.CacheInfo{}, "some-suffix", dockerClient) 162 if subject.Name() == notExpected.Name() { 163 t.Fatalf("Different image registries should result in different volumes") 164 } 165 }) 166 167 it("resolves implied tag", func() { 168 ref, err := name.ParseReference("my/repo:latest", name.WeakValidation) 169 h.AssertNil(t, err) 170 171 subject := cache.NewVolumeCache(ref, cache.CacheInfo{}, "some-suffix", dockerClient) 172 173 ref, err = name.ParseReference("my/repo", name.WeakValidation) 174 h.AssertNil(t, err) 175 expected := cache.NewVolumeCache(ref, cache.CacheInfo{}, "some-suffix", dockerClient) 176 h.AssertEq(t, subject.Name(), expected.Name()) 177 }) 178 179 it("resolves implied registry", func() { 180 ref, err := name.ParseReference("index.docker.io/my/repo", name.WeakValidation) 181 h.AssertNil(t, err) 182 183 subject := cache.NewVolumeCache(ref, cache.CacheInfo{}, "some-suffix", dockerClient) 184 185 ref, err = name.ParseReference("my/repo", name.WeakValidation) 186 h.AssertNil(t, err) 187 expected := cache.NewVolumeCache(ref, cache.CacheInfo{}, "some-suffix", dockerClient) 188 h.AssertEq(t, subject.Name(), expected.Name()) 189 }) 190 191 it("includes human readable information", func() { 192 ref, err := name.ParseReference("myregistryhost:5000/fedora/httpd:version1.0", name.WeakValidation) 193 h.AssertNil(t, err) 194 195 subject := cache.NewVolumeCache(ref, cache.CacheInfo{}, "some-suffix", dockerClient) 196 197 h.AssertContains(t, subject.Name(), "fedora_httpd_version1.0") 198 h.AssertTrue(t, names.RestrictedNamePattern.MatchString(subject.Name())) 199 }) 200 }) 201 }) 202 203 when("#Clear", func() { 204 var ( 205 volumeName string 206 dockerClient client.CommonAPIClient 207 subject *cache.VolumeCache 208 ctx context.Context 209 ) 210 211 it.Before(func() { 212 var err error 213 dockerClient, err = client.NewClientWithOpts(client.FromEnv, client.WithVersion("1.38")) 214 h.AssertNil(t, err) 215 ctx = context.TODO() 216 217 ref, err := name.ParseReference(h.RandString(10), name.WeakValidation) 218 h.AssertNil(t, err) 219 220 subject = cache.NewVolumeCache(ref, cache.CacheInfo{}, "some-suffix", dockerClient) 221 volumeName = subject.Name() 222 }) 223 224 when("there is a cache volume", func() { 225 it.Before(func() { 226 dockerClient.VolumeCreate(context.TODO(), volume.CreateOptions{ 227 Name: volumeName, 228 }) 229 }) 230 231 it("removes the volume", func() { 232 err := subject.Clear(ctx) 233 h.AssertNil(t, err) 234 235 volumes, err := dockerClient.VolumeList(context.TODO(), volume.ListOptions{ 236 Filters: filters.NewArgs(filters.KeyValuePair{ 237 Key: "name", 238 Value: volumeName, 239 }), 240 }) 241 h.AssertNil(t, err) 242 h.AssertEq(t, len(volumes.Volumes), 0) 243 }) 244 }) 245 246 when("there is no cache volume", func() { 247 it("does not fail", func() { 248 err := subject.Clear(ctx) 249 h.AssertNil(t, err) 250 }) 251 }) 252 }) 253 254 when("#Type", func() { 255 it("returns the cache type", func() { 256 ref, err := name.ParseReference("my/repo", name.WeakValidation) 257 h.AssertNil(t, err) 258 subject := cache.NewVolumeCache(ref, cache.CacheInfo{}, "some-suffix", dockerClient) 259 expected := cache.Volume 260 h.AssertEq(t, subject.Type(), expected) 261 }) 262 }) 263 }