github.com/buildpacks/pack@v0.33.3-0.20240516162812-884dd1837311/acceptance/managers/image_manager.go (about)

     1  //go:build acceptance
     2  // +build acceptance
     3  
     4  package managers
     5  
     6  import (
     7  	"bytes"
     8  	"context"
     9  	"fmt"
    10  	"testing"
    11  	"time"
    12  
    13  	dockertypes "github.com/docker/docker/api/types"
    14  	"github.com/docker/docker/api/types/container"
    15  	"github.com/docker/docker/client"
    16  	"github.com/docker/go-connections/nat"
    17  
    18  	h "github.com/buildpacks/pack/testhelpers"
    19  )
    20  
    21  var DefaultDuration = 10 * time.Second
    22  
    23  type ImageManager struct {
    24  	testObject *testing.T
    25  	assert     h.AssertionManager
    26  	dockerCli  client.CommonAPIClient
    27  }
    28  
    29  func NewImageManager(t *testing.T, dockerCli client.CommonAPIClient) ImageManager {
    30  	return ImageManager{
    31  		testObject: t,
    32  		assert:     h.NewAssertionManager(t),
    33  		dockerCli:  dockerCli,
    34  	}
    35  }
    36  
    37  func (im ImageManager) CleanupImages(imageNames ...string) {
    38  	im.testObject.Helper()
    39  	err := h.DockerRmi(im.dockerCli, imageNames...)
    40  	if err != nil {
    41  		im.testObject.Logf("%s: Failed to remove image from %s", err, imageNames)
    42  	}
    43  }
    44  
    45  func (im ImageManager) InspectLocal(image string) (dockertypes.ImageInspect, error) {
    46  	im.testObject.Helper()
    47  	inspect, _, err := im.dockerCli.ImageInspectWithRaw(context.Background(), image)
    48  	return inspect, err
    49  }
    50  
    51  func (im ImageManager) GetImageID(image string) string {
    52  	im.testObject.Helper()
    53  	inspect, err := im.InspectLocal(image)
    54  	im.assert.Nil(err)
    55  	return inspect.ID
    56  }
    57  
    58  func (im ImageManager) HostOS() string {
    59  	im.testObject.Helper()
    60  	daemonInfo, err := im.dockerCli.Info(context.Background())
    61  	im.assert.Nil(err)
    62  	return daemonInfo.OSType
    63  }
    64  
    65  func (im ImageManager) TagImage(image, ref string) {
    66  	im.testObject.Helper()
    67  	err := im.dockerCli.ImageTag(context.Background(), image, ref)
    68  	im.assert.Nil(err)
    69  }
    70  
    71  func (im ImageManager) PullImage(image, registryAuth string) {
    72  	im.testObject.Helper()
    73  	err := h.PullImageWithAuth(im.dockerCli, image, registryAuth)
    74  	im.assert.Nil(err)
    75  }
    76  
    77  func (im ImageManager) ExposePortOnImage(image, containerName string) TestContainer {
    78  	im.testObject.Helper()
    79  	ctx := context.Background()
    80  
    81  	ctr, err := im.dockerCli.ContainerCreate(ctx, &container.Config{
    82  		Image:        image,
    83  		ExposedPorts: map[nat.Port]struct{}{"8080/tcp": {}},
    84  		Healthcheck:  nil,
    85  	}, &container.HostConfig{
    86  		PortBindings: nat.PortMap{
    87  			"8080/tcp": []nat.PortBinding{{}},
    88  		},
    89  		AutoRemove: true,
    90  	}, nil, nil, containerName)
    91  	im.assert.Nil(err)
    92  
    93  	err = im.dockerCli.ContainerStart(ctx, ctr.ID, container.StartOptions{})
    94  	im.assert.Nil(err)
    95  	return TestContainer{
    96  		testObject: im.testObject,
    97  		dockerCli:  im.dockerCli,
    98  		assert:     im.assert,
    99  		name:       containerName,
   100  		id:         ctr.ID,
   101  	}
   102  }
   103  
   104  func (im ImageManager) CreateContainer(name string) TestContainer {
   105  	im.testObject.Helper()
   106  	containerName := "test-" + h.RandString(10)
   107  	ctr, err := im.dockerCli.ContainerCreate(context.Background(), &container.Config{
   108  		Image: name,
   109  	}, nil, nil, nil, containerName)
   110  	im.assert.Nil(err)
   111  
   112  	return TestContainer{
   113  		testObject: im.testObject,
   114  		dockerCli:  im.dockerCli,
   115  		assert:     im.assert,
   116  		name:       containerName,
   117  		id:         ctr.ID,
   118  	}
   119  }
   120  
   121  type TestContainer struct {
   122  	testObject *testing.T
   123  	dockerCli  client.CommonAPIClient
   124  	assert     h.AssertionManager
   125  	name       string
   126  	id         string
   127  }
   128  
   129  func (t TestContainer) RunWithOutput() string {
   130  	t.testObject.Helper()
   131  	var b bytes.Buffer
   132  	err := h.RunContainer(context.Background(), t.dockerCli, t.id, &b, &b)
   133  	t.assert.Nil(err)
   134  	return b.String()
   135  }
   136  
   137  func (t TestContainer) Cleanup() {
   138  	t.testObject.Helper()
   139  	t.dockerCli.ContainerKill(context.Background(), t.name, "SIGKILL")
   140  	t.dockerCli.ContainerRemove(context.Background(), t.name, container.RemoveOptions{Force: true})
   141  }
   142  
   143  func (t TestContainer) WaitForResponse(duration time.Duration) string {
   144  	t.testObject.Helper()
   145  	ticker := time.NewTicker(500 * time.Millisecond)
   146  	defer ticker.Stop()
   147  	timer := time.NewTimer(duration)
   148  	defer timer.Stop()
   149  
   150  	appURI := fmt.Sprintf("http://%s", h.RegistryHost(h.DockerHostname(t.testObject), t.hostPort()))
   151  	for {
   152  		select {
   153  		case <-ticker.C:
   154  			resp, err := h.HTTPGetE(appURI, map[string]string{})
   155  			if err != nil {
   156  				break
   157  			}
   158  			return resp
   159  		case <-timer.C:
   160  			t.testObject.Fatalf("timeout waiting for response: %v", duration)
   161  		}
   162  	}
   163  }
   164  
   165  func (t TestContainer) hostPort() string {
   166  	t.testObject.Helper()
   167  	i, err := t.dockerCli.ContainerInspect(context.Background(), t.name)
   168  	t.assert.Nil(err)
   169  	for _, port := range i.NetworkSettings.Ports {
   170  		for _, binding := range port {
   171  			return binding.HostPort
   172  		}
   173  	}
   174  
   175  	t.testObject.Fatalf("Failed to fetch host port for %s: no ports exposed", t.name)
   176  	return ""
   177  }