github.com/kubri/kubri@v0.5.1-0.20240317001612-bda2aaef967e/internal/emulator/container.go (about)

     1  package emulator
     2  
     3  import (
     4  	"archive/tar"
     5  	"bytes"
     6  	"context"
     7  	"strings"
     8  	"testing"
     9  	"unicode"
    10  
    11  	"github.com/docker/docker/api/types/container"
    12  	"github.com/docker/docker/pkg/stdcopy"
    13  	"github.com/testcontainers/testcontainers-go"
    14  	"github.com/testcontainers/testcontainers-go/exec"
    15  )
    16  
    17  type Container struct{ testcontainers.Container }
    18  
    19  func (c *Container) Exec(t *testing.T, script string) string {
    20  	t.Helper()
    21  
    22  	var buf bytes.Buffer
    23  	opt := exec.ProcessOptionFunc(func(opts *exec.ProcessOptions) {
    24  		if opts.Reader != nil {
    25  			_, _ = stdcopy.StdCopy(&buf, &buf, opts.Reader)
    26  		}
    27  	})
    28  
    29  	code, _, err := c.Container.Exec(context.Background(), []string{"sh", "-c", script}, opt)
    30  	if err != nil {
    31  		t.Fatal(err)
    32  	}
    33  
    34  	s := strings.NewReplacer("\r\n", "\n", "\r", "\n").Replace(buf.String())
    35  	t.Logf("%s\n%s", script, s)
    36  
    37  	if code != 0 {
    38  		t.FailNow()
    39  	}
    40  
    41  	return strings.TrimRightFunc(s, unicode.IsSpace)
    42  }
    43  
    44  func Image(t *testing.T, name string) Container {
    45  	t.Helper()
    46  	return runContainer(t, testcontainers.ContainerRequest{
    47  		Image:              name,
    48  		HostConfigModifier: func(hc *container.HostConfig) { hc.NetworkMode = "host" },
    49  		Entrypoint:         []string{"tail", "-f", "/dev/null"},
    50  	})
    51  }
    52  
    53  func Build(t *testing.T, dockerfile string) Container {
    54  	t.Helper()
    55  
    56  	var buf bytes.Buffer
    57  	tw := tar.NewWriter(&buf)
    58  	hdr := &tar.Header{
    59  		Name: "Dockerfile",
    60  		Mode: 0o600,
    61  		Size: int64(len(dockerfile)),
    62  	}
    63  	if err := tw.WriteHeader(hdr); err != nil {
    64  		t.Fatal(err)
    65  	}
    66  	if _, err := tw.Write([]byte(dockerfile)); err != nil {
    67  		t.Fatal(err)
    68  	}
    69  	if err := tw.Close(); err != nil {
    70  		t.Fatal(err)
    71  	}
    72  
    73  	return runContainer(t, testcontainers.ContainerRequest{
    74  		FromDockerfile:     testcontainers.FromDockerfile{ContextArchive: &buf},
    75  		HostConfigModifier: func(hc *container.HostConfig) { hc.NetworkMode = "host" },
    76  	})
    77  }
    78  
    79  func runContainer(t *testing.T, cr testcontainers.ContainerRequest) Container {
    80  	t.Helper()
    81  	ctx := context.Background()
    82  	c, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
    83  		ContainerRequest: cr,
    84  		Started:          true,
    85  		Logger:           nopLogger{},
    86  	})
    87  	if err != nil {
    88  		t.Fatal(err)
    89  	}
    90  	t.Cleanup(func() { _ = c.Terminate(ctx) })
    91  	return Container{c}
    92  }
    93  
    94  type nopLogger struct{}
    95  
    96  func (nopLogger) Printf(string, ...any) {}
    97  func (nopLogger) Print(...any)          {}