github.com/buildpacks/pack@v0.33.3-0.20240516162812-884dd1837311/pkg/client/manifest_annotate_test.go (about) 1 package client 2 3 import ( 4 "bytes" 5 "context" 6 "os" 7 "testing" 8 9 "github.com/buildpacks/imgutil" 10 "github.com/golang/mock/gomock" 11 "github.com/google/go-containerregistry/pkg/authn" 12 "github.com/google/go-containerregistry/pkg/name" 13 "github.com/heroku/color" 14 "github.com/pkg/errors" 15 "github.com/sclevine/spec" 16 "github.com/sclevine/spec/report" 17 18 ifakes "github.com/buildpacks/pack/internal/fakes" 19 "github.com/buildpacks/pack/pkg/logging" 20 "github.com/buildpacks/pack/pkg/testmocks" 21 h "github.com/buildpacks/pack/testhelpers" 22 ) 23 24 const invalidDigest = "sha256:d4707523ce6e12afdbe9a3be5ad69027150a834870ca0933baf7516dd1fe0f56" 25 26 func TestAnnotateManifest(t *testing.T) { 27 color.Disable(true) 28 defer color.Disable(false) 29 spec.Run(t, "build", testAnnotateManifest, spec.Sequential(), spec.Report(report.Terminal{})) 30 } 31 32 func testAnnotateManifest(t *testing.T, when spec.G, it spec.S) { 33 var ( 34 mockController *gomock.Controller 35 mockIndexFactory *testmocks.MockIndexFactory 36 fakeImageFetcher *ifakes.FakeImageFetcher 37 out bytes.Buffer 38 logger logging.Logger 39 subject *Client 40 err error 41 tmpDir string 42 ) 43 44 it.Before(func() { 45 fakeImageFetcher = ifakes.NewFakeImageFetcher() 46 logger = logging.NewLogWithWriters(&out, &out, logging.WithVerbose()) 47 mockController = gomock.NewController(t) 48 mockIndexFactory = testmocks.NewMockIndexFactory(mockController) 49 50 tmpDir, err = os.MkdirTemp("", "annotate-manifest-test") 51 h.AssertNil(t, err) 52 os.Setenv("XDG_RUNTIME_DIR", tmpDir) 53 54 subject, err = NewClient( 55 WithLogger(logger), 56 WithFetcher(fakeImageFetcher), 57 WithIndexFactory(mockIndexFactory), 58 WithExperimental(true), 59 WithKeychain(authn.DefaultKeychain), 60 ) 61 h.AssertSameInstance(t, mockIndexFactory, subject.indexFactory) 62 h.AssertNil(t, err) 63 }) 64 it.After(func() { 65 mockController.Finish() 66 os.RemoveAll(tmpDir) 67 }) 68 69 when("#AnnotateManifest", func() { 70 var ( 71 digest name.Digest 72 idx imgutil.ImageIndex 73 indexRepoName string 74 ) 75 when("index doesn't exist", func() { 76 it.Before(func() { 77 indexRepoName = h.NewRandomIndexRepoName() 78 mockIndexFactory.EXPECT().LoadIndex(gomock.Any(), gomock.Any()).Return(nil, errors.New("index not found locally")) 79 }) 80 81 it("should return an error", func() { 82 err = subject.AnnotateManifest( 83 context.TODO(), 84 ManifestAnnotateOptions{ 85 IndexRepoName: indexRepoName, 86 RepoName: "pack/image", 87 }, 88 ) 89 h.AssertEq(t, err.Error(), "index not found locally") 90 }) 91 }) 92 93 when("index exists", func() { 94 when("no errors on save", func() { 95 when("OS is given", func() { 96 it.Before(func() { 97 indexRepoName = h.NewRandomIndexRepoName() 98 idx, digest = h.RandomCNBIndexAndDigest(t, indexRepoName, 1, 2) 99 mockIndexFactory.EXPECT().LoadIndex(gomock.Eq(indexRepoName), gomock.Any()).Return(idx, nil) 100 fakeImage := h.NewFakeWithRandomUnderlyingV1Image(t, "pack/image", digest) 101 fakeImageFetcher.RemoteImages[digest.Name()] = fakeImage 102 }) 103 104 it("should set OS for given image", func() { 105 err = subject.AnnotateManifest( 106 context.TODO(), 107 ManifestAnnotateOptions{ 108 IndexRepoName: indexRepoName, 109 RepoName: digest.Name(), 110 OS: "some-os", 111 }, 112 ) 113 h.AssertNil(t, err) 114 115 os, err := idx.OS(digest) 116 h.AssertNil(t, err) 117 h.AssertEq(t, os, "some-os") 118 }) 119 }) 120 when("Arch is given", func() { 121 it.Before(func() { 122 indexRepoName = h.NewRandomIndexRepoName() 123 idx, digest = h.RandomCNBIndexAndDigest(t, indexRepoName, 1, 2) 124 mockIndexFactory.EXPECT().LoadIndex(gomock.Eq(indexRepoName), gomock.Any()).Return(idx, nil) 125 fakeImage := h.NewFakeWithRandomUnderlyingV1Image(t, "pack/image", digest) 126 fakeImageFetcher.RemoteImages[digest.Name()] = fakeImage 127 }) 128 129 it("should set Arch for given image", func() { 130 err = subject.AnnotateManifest( 131 context.TODO(), 132 ManifestAnnotateOptions{ 133 IndexRepoName: indexRepoName, 134 RepoName: digest.Name(), 135 OSArch: "some-arch", 136 }, 137 ) 138 h.AssertNil(t, err) 139 140 arch, err := idx.Architecture(digest) 141 h.AssertNil(t, err) 142 h.AssertEq(t, arch, "some-arch") 143 }) 144 }) 145 when("OS Variant is given", func() { 146 it.Before(func() { 147 indexRepoName = h.NewRandomIndexRepoName() 148 idx, digest = h.RandomCNBIndexAndDigest(t, indexRepoName, 1, 2) 149 mockIndexFactory.EXPECT().LoadIndex(gomock.Eq(indexRepoName), gomock.Any()).Return(idx, nil) 150 fakeImage := h.NewFakeWithRandomUnderlyingV1Image(t, "pack/image", digest) 151 fakeImageFetcher.RemoteImages[digest.Name()] = fakeImage 152 }) 153 154 it("should set Variant for given image", func() { 155 err = subject.AnnotateManifest( 156 context.TODO(), 157 ManifestAnnotateOptions{ 158 IndexRepoName: indexRepoName, 159 RepoName: digest.Name(), 160 OSVariant: "some-variant", 161 }, 162 ) 163 h.AssertNil(t, err) 164 165 variant, err := idx.Variant(digest) 166 h.AssertNil(t, err) 167 h.AssertEq(t, variant, "some-variant") 168 }) 169 }) 170 when("Annotations are given", func() { 171 it.Before(func() { 172 indexRepoName = h.NewRandomIndexRepoName() 173 idx, digest = h.RandomCNBIndexAndDigest(t, indexRepoName, 1, 2) 174 mockIndexFactory.EXPECT().LoadIndex(gomock.Eq(indexRepoName), gomock.Any()).Return(idx, nil) 175 fakeImage := h.NewFakeWithRandomUnderlyingV1Image(t, "pack/image", digest) 176 fakeImageFetcher.RemoteImages[digest.Name()] = fakeImage 177 }) 178 179 it("should set Annotations for given image", func() { 180 err = subject.AnnotateManifest( 181 context.TODO(), 182 ManifestAnnotateOptions{ 183 IndexRepoName: indexRepoName, 184 RepoName: digest.Name(), 185 Annotations: map[string]string{"some-key": "some-value"}, 186 }, 187 ) 188 h.AssertNil(t, err) 189 190 annos, err := idx.Annotations(digest) 191 h.AssertNil(t, err) 192 h.AssertEq(t, annos, map[string]string{"some-key": "some-value"}) 193 }) 194 195 it("should save the annotated index", func() { 196 var ( 197 fakeOS = "some-os" 198 fakeArch = "some-arch" 199 fakeVariant = "some-variant" 200 fakeAnnotations = map[string]string{"some-key": "some-value"} 201 ) 202 203 err = subject.AnnotateManifest( 204 context.TODO(), 205 ManifestAnnotateOptions{ 206 IndexRepoName: indexRepoName, 207 RepoName: digest.Name(), 208 OS: fakeOS, 209 OSArch: fakeArch, 210 OSVariant: fakeVariant, 211 Annotations: fakeAnnotations, 212 }, 213 ) 214 h.AssertNil(t, err) 215 216 err = idx.SaveDir() 217 h.AssertNil(t, err) 218 219 os, err := idx.OS(digest) 220 h.AssertNil(t, err) 221 h.AssertEq(t, os, fakeOS) 222 223 arch, err := idx.Architecture(digest) 224 h.AssertNil(t, err) 225 h.AssertEq(t, arch, fakeArch) 226 227 variant, err := idx.Variant(digest) 228 h.AssertNil(t, err) 229 h.AssertEq(t, variant, fakeVariant) 230 231 annos, err := idx.Annotations(digest) 232 h.AssertNil(t, err) 233 h.AssertEq(t, annos, fakeAnnotations) 234 }) 235 }) 236 }) 237 }) 238 239 when("image does not exist with given digest", func() { 240 var nonExistentDigest string 241 242 it.Before(func() { 243 indexRepoName = h.NewRandomIndexRepoName() 244 idx = h.RandomCNBIndex(t, indexRepoName, 1, 2) 245 nonExistentDigest = "busybox@" + invalidDigest 246 mockIndexFactory.EXPECT().LoadIndex(gomock.Eq(indexRepoName), gomock.Any()).Return(idx, nil) 247 }) 248 249 it("errors for Arch", func() { 250 err = subject.AnnotateManifest( 251 context.TODO(), 252 ManifestAnnotateOptions{ 253 IndexRepoName: indexRepoName, 254 RepoName: nonExistentDigest, 255 OSArch: "some-arch", 256 }, 257 ) 258 h.AssertNotNil(t, err) 259 }) 260 it("errors for Variant", func() { 261 err = subject.AnnotateManifest( 262 context.TODO(), 263 ManifestAnnotateOptions{ 264 IndexRepoName: indexRepoName, 265 RepoName: nonExistentDigest, 266 OSVariant: "some-variant", 267 }, 268 ) 269 h.AssertNotNil(t, err) 270 }) 271 it("errors for Annotations", func() { 272 err = subject.AnnotateManifest( 273 context.TODO(), 274 ManifestAnnotateOptions{ 275 IndexRepoName: indexRepoName, 276 RepoName: nonExistentDigest, 277 Annotations: map[string]string{"some-key": "some-value"}, 278 }, 279 ) 280 h.AssertNotNil(t, err) 281 }) 282 }) 283 }) 284 }