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  }