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) {}