github.com/buildpacks/pack@v0.33.3-0.20240516162812-884dd1837311/internal/commands/inspect_image_test.go (about) 1 package commands_test 2 3 import ( 4 "bytes" 5 "errors" 6 "testing" 7 8 "github.com/buildpacks/lifecycle/platform/files" 9 "github.com/golang/mock/gomock" 10 "github.com/heroku/color" 11 "github.com/sclevine/spec" 12 "github.com/sclevine/spec/report" 13 14 "github.com/buildpacks/pack/internal/commands" 15 "github.com/buildpacks/pack/internal/commands/fakes" 16 "github.com/buildpacks/pack/internal/commands/testmocks" 17 "github.com/buildpacks/pack/internal/config" 18 "github.com/buildpacks/pack/internal/inspectimage" 19 "github.com/buildpacks/pack/pkg/client" 20 "github.com/buildpacks/pack/pkg/logging" 21 h "github.com/buildpacks/pack/testhelpers" 22 ) 23 24 var ( 25 expectedLocalImageDisplay = "Sample output for local image" 26 expectedRemoteImageDisplay = "Sample output for remote image" 27 28 expectedSharedInfo = inspectimage.GeneralInfo{ 29 Name: "some/image", 30 } 31 32 expectedLocalImageInfo = &client.ImageInfo{ 33 StackID: "local.image.stack", 34 Buildpacks: nil, 35 Base: files.RunImageForRebase{}, 36 BOM: nil, 37 Stack: files.Stack{}, 38 Processes: client.ProcessDetails{}, 39 } 40 41 expectedRemoteImageInfo = &client.ImageInfo{ 42 StackID: "remote.image.stack", 43 Buildpacks: nil, 44 Base: files.RunImageForRebase{}, 45 BOM: nil, 46 Stack: files.Stack{}, 47 Processes: client.ProcessDetails{}, 48 } 49 50 expectedLocalImageWithExtensionInfo = &client.ImageInfo{ 51 StackID: "local.image.stack", 52 Buildpacks: nil, 53 Extensions: nil, 54 Base: files.RunImageForRebase{}, 55 BOM: nil, 56 Stack: files.Stack{}, 57 Processes: client.ProcessDetails{}, 58 } 59 60 expectedRemoteImageWithExtensionInfo = &client.ImageInfo{ 61 StackID: "remote.image.stack", 62 Buildpacks: nil, 63 Extensions: nil, 64 Base: files.RunImageForRebase{}, 65 BOM: nil, 66 Stack: files.Stack{}, 67 Processes: client.ProcessDetails{}, 68 } 69 ) 70 71 func TestInspectImageCommand(t *testing.T) { 72 color.Disable(true) 73 defer color.Disable(false) 74 spec.Run(t, "Commands", testInspectImageCommand, spec.Parallel(), spec.Report(report.Terminal{})) 75 } 76 77 func testInspectImageCommand(t *testing.T, when spec.G, it spec.S) { 78 var ( 79 logger logging.Logger 80 outBuf bytes.Buffer 81 mockController *gomock.Controller 82 mockClient *testmocks.MockPackClient 83 cfg config.Config 84 ) 85 86 it.Before(func() { 87 cfg = config.Config{} 88 mockController = gomock.NewController(t) 89 mockClient = testmocks.NewMockPackClient(mockController) 90 logger = logging.NewLogWithWriters(&outBuf, &outBuf) 91 }) 92 93 it.After(func() { 94 mockController.Finish() 95 }) 96 when("#InspectImage", func() { 97 var ( 98 assert = h.NewAssertionManager(t) 99 ) 100 it("passes output of local and remote builders to correct writer", func() { 101 inspectImageWriter := newDefaultInspectImageWriter() 102 inspectImageWriterFactory := newImageWriterFactory(inspectImageWriter) 103 104 mockClient.EXPECT().InspectImage("some/image", true).Return(expectedLocalImageInfo, nil) 105 mockClient.EXPECT().InspectImage("some/image", false).Return(expectedRemoteImageInfo, nil) 106 command := commands.InspectImage(logger, inspectImageWriterFactory, cfg, mockClient) 107 command.SetArgs([]string{"some/image"}) 108 err := command.Execute() 109 assert.Nil(err) 110 111 assert.Equal(inspectImageWriter.ReceivedInfoForLocal, expectedLocalImageInfo) 112 assert.Equal(inspectImageWriter.ReceivedInfoForRemote, expectedRemoteImageInfo) 113 assert.Equal(inspectImageWriter.RecievedGeneralInfo, expectedSharedInfo) 114 assert.Equal(inspectImageWriter.ReceivedErrorForLocal, nil) 115 assert.Equal(inspectImageWriter.ReceivedErrorForRemote, nil) 116 assert.Equal(inspectImageWriterFactory.ReceivedForKind, "human-readable") 117 118 assert.ContainsF(outBuf.String(), "LOCAL:\n%s", expectedLocalImageDisplay) 119 assert.ContainsF(outBuf.String(), "REMOTE:\n%s", expectedRemoteImageDisplay) 120 }) 121 122 it("passes output of local and remote builders to correct writer for extension", func() { 123 inspectImageWriter := newDefaultInspectImageWriter() 124 inspectImageWriterFactory := newImageWriterFactory(inspectImageWriter) 125 126 mockClient.EXPECT().InspectImage("some/image", true).Return(expectedLocalImageWithExtensionInfo, nil) 127 mockClient.EXPECT().InspectImage("some/image", false).Return(expectedRemoteImageWithExtensionInfo, nil) 128 command := commands.InspectImage(logger, inspectImageWriterFactory, cfg, mockClient) 129 command.SetArgs([]string{"some/image"}) 130 err := command.Execute() 131 assert.Nil(err) 132 133 assert.Equal(inspectImageWriter.ReceivedInfoForLocal, expectedLocalImageWithExtensionInfo) 134 assert.Equal(inspectImageWriter.ReceivedInfoForRemote, expectedRemoteImageWithExtensionInfo) 135 assert.Equal(inspectImageWriter.RecievedGeneralInfo, expectedSharedInfo) 136 assert.Equal(inspectImageWriter.ReceivedErrorForLocal, nil) 137 assert.Equal(inspectImageWriter.ReceivedErrorForRemote, nil) 138 assert.Equal(inspectImageWriterFactory.ReceivedForKind, "human-readable") 139 140 assert.ContainsF(outBuf.String(), "LOCAL:\n%s", expectedLocalImageDisplay) 141 assert.ContainsF(outBuf.String(), "REMOTE:\n%s", expectedRemoteImageDisplay) 142 }) 143 144 it("passes configured run image mirrors to the writer", func() { 145 cfg = config.Config{ 146 RunImages: []config.RunImage{{ 147 Image: "image-name", 148 Mirrors: []string{"first-mirror", "second-mirror2"}, 149 }, 150 { 151 Image: "image-name2", 152 Mirrors: []string{"other-mirror"}, 153 }, 154 }, 155 TrustedBuilders: nil, 156 Registries: nil, 157 } 158 159 inspectImageWriter := newDefaultInspectImageWriter() 160 inspectImageWriterFactory := newImageWriterFactory(inspectImageWriter) 161 162 mockClient.EXPECT().InspectImage("some/image", true).Return(expectedLocalImageInfo, nil) 163 mockClient.EXPECT().InspectImage("some/image", false).Return(expectedRemoteImageInfo, nil) 164 165 command := commands.InspectImage(logger, inspectImageWriterFactory, cfg, mockClient) 166 command.SetArgs([]string{"some/image"}) 167 err := command.Execute() 168 assert.Nil(err) 169 170 assert.Equal(inspectImageWriter.RecievedGeneralInfo.RunImageMirrors, cfg.RunImages) 171 }) 172 173 it("passes configured run image mirrors to the writer", func() { 174 cfg = config.Config{ 175 RunImages: []config.RunImage{{ 176 Image: "image-name", 177 Mirrors: []string{"first-mirror", "second-mirror2"}, 178 }, 179 { 180 Image: "image-name2", 181 Mirrors: []string{"other-mirror"}, 182 }, 183 }, 184 TrustedBuilders: nil, 185 Registries: nil, 186 } 187 188 inspectImageWriter := newDefaultInspectImageWriter() 189 inspectImageWriterFactory := newImageWriterFactory(inspectImageWriter) 190 191 mockClient.EXPECT().InspectImage("some/image", true).Return(expectedLocalImageWithExtensionInfo, nil) 192 mockClient.EXPECT().InspectImage("some/image", false).Return(expectedRemoteImageWithExtensionInfo, nil) 193 194 command := commands.InspectImage(logger, inspectImageWriterFactory, cfg, mockClient) 195 command.SetArgs([]string{"some/image"}) 196 err := command.Execute() 197 assert.Nil(err) 198 199 assert.Equal(inspectImageWriter.RecievedGeneralInfo.RunImageMirrors, cfg.RunImages) 200 }) 201 202 when("error cases", func() { 203 when("client returns an error when inspecting", func() { 204 it("passes errors to the Writer", func() { 205 inspectImageWriter := newDefaultInspectImageWriter() 206 inspectImageWriterFactory := newImageWriterFactory(inspectImageWriter) 207 208 localErr := errors.New("local inspection error") 209 mockClient.EXPECT().InspectImage("some/image", true).Return(nil, localErr) 210 211 remoteErr := errors.New("remote inspection error") 212 mockClient.EXPECT().InspectImage("some/image", false).Return(nil, remoteErr) 213 214 command := commands.InspectImage(logger, inspectImageWriterFactory, cfg, mockClient) 215 command.SetArgs([]string{"some/image"}) 216 err := command.Execute() 217 assert.Nil(err) 218 219 assert.ErrorWithMessage(inspectImageWriter.ReceivedErrorForLocal, "local inspection error") 220 assert.ErrorWithMessage(inspectImageWriter.ReceivedErrorForRemote, "remote inspection error") 221 }) 222 }) 223 224 when("writerFactory fails to create a writer", func() { 225 it("returns the error", func() { 226 writerFactoryErr := errors.New("unable to create writer factory") 227 228 erroniousInspectImageWriterFactory := &fakes.FakeInspectImageWriterFactory{ 229 ReturnForWriter: nil, 230 ErrorForWriter: writerFactoryErr, 231 } 232 233 command := commands.InspectImage(logger, erroniousInspectImageWriterFactory, cfg, mockClient) 234 command.SetArgs([]string{"some/image"}) 235 err := command.Execute() 236 assert.ErrorWithMessage(err, "unable to create writer factory") 237 }) 238 }) 239 when("Print returns fails", func() { 240 it("returns the error", func() { 241 printError := errors.New("unable to print") 242 inspectImageWriter := &fakes.FakeInspectImageWriter{ 243 ErrorForPrint: printError, 244 } 245 inspectImageWriterFactory := newImageWriterFactory(inspectImageWriter) 246 247 mockClient.EXPECT().InspectImage("some/image", true).Return(expectedLocalImageInfo, nil) 248 mockClient.EXPECT().InspectImage("some/image", false).Return(expectedRemoteImageInfo, nil) 249 250 command := commands.InspectImage(logger, inspectImageWriterFactory, cfg, mockClient) 251 command.SetArgs([]string{"some/image"}) 252 err := command.Execute() 253 assert.ErrorWithMessage(err, "unable to print") 254 }) 255 }) 256 257 when("Print returns fails for extension", func() { 258 it("returns the error", func() { 259 printError := errors.New("unable to print") 260 inspectImageWriter := &fakes.FakeInspectImageWriter{ 261 ErrorForPrint: printError, 262 } 263 inspectImageWriterFactory := newImageWriterFactory(inspectImageWriter) 264 265 mockClient.EXPECT().InspectImage("some/image", true).Return(expectedLocalImageWithExtensionInfo, nil) 266 mockClient.EXPECT().InspectImage("some/image", false).Return(expectedRemoteImageWithExtensionInfo, nil) 267 268 command := commands.InspectImage(logger, inspectImageWriterFactory, cfg, mockClient) 269 command.SetArgs([]string{"some/image"}) 270 err := command.Execute() 271 assert.ErrorWithMessage(err, "unable to print") 272 }) 273 }) 274 }) 275 }) 276 } 277 278 func newDefaultInspectImageWriter() *fakes.FakeInspectImageWriter { 279 return &fakes.FakeInspectImageWriter{ 280 PrintForLocal: expectedLocalImageDisplay, 281 PrintForRemote: expectedRemoteImageDisplay, 282 } 283 } 284 285 func newImageWriterFactory(writer *fakes.FakeInspectImageWriter) *fakes.FakeInspectImageWriterFactory { 286 return &fakes.FakeInspectImageWriterFactory{ 287 ReturnForWriter: writer, 288 } 289 }