2022-05-24 01:08:53 +08:00
|
|
|
//go:build !freebsd
|
|
|
|
|
|
|
|
|
|
package testutil
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"fmt"
|
2022-05-28 00:24:31 +08:00
|
|
|
"strings"
|
2022-05-24 01:08:53 +08:00
|
|
|
|
|
|
|
|
"github.com/docker/go-connections/nat"
|
|
|
|
|
"github.com/testcontainers/testcontainers-go"
|
|
|
|
|
"github.com/testcontainers/testcontainers-go/wait"
|
|
|
|
|
)
|
|
|
|
|
|
2022-06-01 21:42:46 +08:00
|
|
|
type TestLogConsumer struct {
|
|
|
|
|
Msgs []string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (g *TestLogConsumer) Accept(l testcontainers.Log) {
|
|
|
|
|
g.Msgs = append(g.Msgs, string(l.Content))
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-24 01:08:53 +08:00
|
|
|
type Container struct {
|
2022-05-28 00:24:31 +08:00
|
|
|
BindMounts map[string]string
|
2022-05-24 23:28:40 +08:00
|
|
|
Entrypoint []string
|
2022-05-24 01:08:53 +08:00
|
|
|
Env map[string]string
|
|
|
|
|
ExposedPorts []string
|
2022-05-28 00:24:31 +08:00
|
|
|
Image string
|
|
|
|
|
Name string
|
|
|
|
|
Networks []string
|
2022-05-24 01:08:53 +08:00
|
|
|
WaitingFor wait.Strategy
|
|
|
|
|
|
|
|
|
|
Address string
|
2022-05-28 00:24:31 +08:00
|
|
|
Ports map[string]string
|
2022-06-01 21:42:46 +08:00
|
|
|
Logs TestLogConsumer
|
2022-05-24 01:08:53 +08:00
|
|
|
|
|
|
|
|
container testcontainers.Container
|
|
|
|
|
ctx context.Context
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (c *Container) Start() error {
|
|
|
|
|
c.ctx = context.Background()
|
|
|
|
|
|
2022-07-30 02:13:55 +08:00
|
|
|
var containerMounts []testcontainers.ContainerMount
|
|
|
|
|
|
|
|
|
|
for k, v := range c.BindMounts {
|
|
|
|
|
containerMounts = append(containerMounts, testcontainers.BindMount(v, testcontainers.ContainerMountTarget(k)))
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-24 01:08:53 +08:00
|
|
|
req := testcontainers.GenericContainerRequest{
|
|
|
|
|
ContainerRequest: testcontainers.ContainerRequest{
|
2022-07-30 02:13:55 +08:00
|
|
|
Mounts: testcontainers.Mounts(containerMounts...),
|
2022-05-24 23:28:40 +08:00
|
|
|
Entrypoint: c.Entrypoint,
|
2022-05-28 00:24:31 +08:00
|
|
|
Env: c.Env,
|
|
|
|
|
ExposedPorts: c.ExposedPorts,
|
|
|
|
|
Image: c.Image,
|
|
|
|
|
Name: c.Name,
|
|
|
|
|
Networks: c.Networks,
|
2022-05-25 00:31:49 +08:00
|
|
|
WaitingFor: c.WaitingFor,
|
2022-05-24 01:08:53 +08:00
|
|
|
},
|
|
|
|
|
Started: true,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
container, err := testcontainers.GenericContainer(c.ctx, req)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return fmt.Errorf("container failed to start: %s", err)
|
|
|
|
|
}
|
|
|
|
|
c.container = container
|
|
|
|
|
|
2022-06-01 21:42:46 +08:00
|
|
|
c.Logs = TestLogConsumer{
|
|
|
|
|
Msgs: []string{},
|
|
|
|
|
}
|
|
|
|
|
c.container.FollowOutput(&c.Logs)
|
|
|
|
|
err = c.container.StartLogProducer(c.ctx)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return fmt.Errorf("log producer failed: %s", err)
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-28 00:24:31 +08:00
|
|
|
c.Address = "localhost"
|
|
|
|
|
|
|
|
|
|
err = c.LookupMappedPorts()
|
2022-05-24 01:08:53 +08:00
|
|
|
if err != nil {
|
2022-05-28 00:24:31 +08:00
|
|
|
_ = c.Terminate()
|
|
|
|
|
return fmt.Errorf("port lookup failed: %s", err)
|
2022-05-24 01:08:53 +08:00
|
|
|
}
|
|
|
|
|
|
2022-05-28 00:24:31 +08:00
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// create a lookup table of exposed ports to mapped ports
|
|
|
|
|
func (c *Container) LookupMappedPorts() error {
|
|
|
|
|
if len(c.ExposedPorts) == 0 {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(c.Ports) == 0 {
|
|
|
|
|
c.Ports = make(map[string]string)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, port := range c.ExposedPorts {
|
|
|
|
|
// strip off leading host port: 80:8080 -> 8080
|
|
|
|
|
if strings.Contains(port, ":") {
|
|
|
|
|
port = strings.Split(port, ":")[1]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// strip off the transport: 80/tcp -> 80
|
|
|
|
|
if strings.Contains(port, "/") {
|
|
|
|
|
port = strings.Split(port, "/")[0]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p, err := c.container.MappedPort(c.ctx, nat.Port(port))
|
2022-05-24 01:08:53 +08:00
|
|
|
if err != nil {
|
2022-05-28 00:24:31 +08:00
|
|
|
return fmt.Errorf("failed to find '%s' - %s", port, err)
|
2022-05-24 01:08:53 +08:00
|
|
|
}
|
2022-05-28 00:24:31 +08:00
|
|
|
fmt.Printf("mapped container port '%s' to host port '%s'\n", port, p.Port())
|
|
|
|
|
c.Ports[port] = p.Port()
|
2022-05-24 01:08:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-04 00:29:08 +08:00
|
|
|
func (c *Container) Exec(cmds []string) (int, error) {
|
|
|
|
|
return c.container.Exec(c.ctx, cmds)
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-01 21:42:46 +08:00
|
|
|
func (c *Container) PrintLogs() {
|
|
|
|
|
fmt.Println("--- Container Logs Start ---")
|
|
|
|
|
for _, msg := range c.Logs.Msgs {
|
|
|
|
|
fmt.Print(msg)
|
|
|
|
|
}
|
|
|
|
|
fmt.Println("--- Container Logs End ---")
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-24 01:08:53 +08:00
|
|
|
func (c *Container) Terminate() error {
|
2022-06-04 00:29:08 +08:00
|
|
|
err := c.container.StopLogProducer()
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Println(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = c.container.Terminate(c.ctx)
|
2022-05-24 01:08:53 +08:00
|
|
|
if err != nil {
|
2022-06-01 21:42:46 +08:00
|
|
|
fmt.Printf("failed to terminate the container: %s", err)
|
2022-05-24 01:08:53 +08:00
|
|
|
}
|
|
|
|
|
|
2022-06-01 21:42:46 +08:00
|
|
|
c.PrintLogs()
|
|
|
|
|
|
2022-06-04 00:29:08 +08:00
|
|
|
return nil
|
2022-05-24 01:08:53 +08:00
|
|
|
}
|