sing-box/test/docker_test.go

123 lines
3.4 KiB
Go
Raw Normal View History

2022-07-08 16:01:23 +00:00
package main
import (
"context"
2022-08-01 04:23:34 +00:00
"os"
2022-08-08 00:56:04 +00:00
"path/filepath"
2022-07-08 16:01:23 +00:00
"testing"
2022-07-10 11:17:44 +00:00
"time"
2022-07-08 16:01:23 +00:00
2022-08-01 04:23:34 +00:00
"github.com/sagernet/sing/common/debug"
2022-07-08 16:01:23 +00:00
F "github.com/sagernet/sing/common/format"
2022-08-10 12:19:16 +00:00
"github.com/sagernet/sing/common/rw"
2022-07-08 16:01:23 +00:00
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
2022-08-01 04:23:34 +00:00
"github.com/docker/docker/pkg/stdcopy"
2022-07-08 16:01:23 +00:00
"github.com/docker/go-connections/nat"
"github.com/stretchr/testify/require"
)
type DockerOptions struct {
Image string
EntryPoint string
Ports []uint16
Cmd []string
Env []string
2022-08-08 00:56:04 +00:00
Bind map[string]string
2022-07-18 10:50:19 +00:00
Stdin []byte
2022-08-16 15:37:51 +00:00
Cap []string
2022-07-08 16:01:23 +00:00
}
func startDockerContainer(t *testing.T, options DockerOptions) {
dockerClient, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
require.NoError(t, err)
defer dockerClient.Close()
2022-07-18 10:50:19 +00:00
writeStdin := len(options.Stdin) > 0
2022-07-08 16:01:23 +00:00
var containerOptions container.Config
2022-07-18 10:50:19 +00:00
if writeStdin {
containerOptions.OpenStdin = true
containerOptions.StdinOnce = true
}
2022-07-08 16:01:23 +00:00
containerOptions.Image = options.Image
2022-07-18 10:50:19 +00:00
if options.EntryPoint != "" {
containerOptions.Entrypoint = []string{options.EntryPoint}
}
2022-07-08 16:01:23 +00:00
containerOptions.Cmd = options.Cmd
containerOptions.Env = options.Env
containerOptions.ExposedPorts = make(nat.PortSet)
var hostOptions container.HostConfig
2023-07-11 06:03:55 +00:00
hostOptions.NetworkMode = "host"
2022-08-16 15:37:51 +00:00
hostOptions.CapAdd = options.Cap
2022-07-08 16:01:23 +00:00
hostOptions.PortBindings = make(nat.PortMap)
for _, port := range options.Ports {
containerOptions.ExposedPorts[nat.Port(F.ToString(port, "/tcp"))] = struct{}{}
containerOptions.ExposedPorts[nat.Port(F.ToString(port, "/udp"))] = struct{}{}
hostOptions.PortBindings[nat.Port(F.ToString(port, "/tcp"))] = []nat.PortBinding{
{HostPort: F.ToString(port), HostIP: "0.0.0.0"},
}
hostOptions.PortBindings[nat.Port(F.ToString(port, "/udp"))] = []nat.PortBinding{
{HostPort: F.ToString(port), HostIP: "0.0.0.0"},
}
}
2022-08-08 00:56:04 +00:00
if len(options.Bind) > 0 {
hostOptions.Binds = []string{}
for path, internalPath := range options.Bind {
2022-08-10 12:19:16 +00:00
if !rw.FileExists(path) {
path = filepath.Join("config", path)
}
2022-08-08 00:56:04 +00:00
path, _ = filepath.Abs(path)
hostOptions.Binds = append(hostOptions.Binds, path+":"+internalPath)
}
}
2022-07-08 16:01:23 +00:00
dockerContainer, err := dockerClient.ContainerCreate(context.Background(), &containerOptions, &hostOptions, nil, nil, "")
require.NoError(t, err)
t.Cleanup(func() {
cleanContainer(dockerContainer.ID)
})
2022-07-18 10:50:19 +00:00
2022-07-08 16:01:23 +00:00
require.NoError(t, dockerClient.ContainerStart(context.Background(), dockerContainer.ID, types.ContainerStartOptions{}))
2022-07-18 10:50:19 +00:00
if writeStdin {
stdinAttach, err := dockerClient.ContainerAttach(context.Background(), dockerContainer.ID, types.ContainerAttachOptions{
Stdin: writeStdin,
Stream: true,
})
require.NoError(t, err)
_, err = stdinAttach.Conn.Write(options.Stdin)
require.NoError(t, err)
stdinAttach.Close()
}
2022-08-01 04:23:34 +00:00
if debug.Enabled {
attach, err := dockerClient.ContainerAttach(context.Background(), dockerContainer.ID, types.ContainerAttachOptions{
Stdout: true,
Stderr: true,
Logs: true,
Stream: true,
})
require.NoError(t, err)
go func() {
stdcopy.StdCopy(os.Stderr, os.Stderr, attach.Reader)
}()
}
2022-07-10 06:22:28 +00:00
time.Sleep(time.Second)
2022-07-08 16:01:23 +00:00
}
func cleanContainer(id string) error {
dockerClient, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
return err
}
defer dockerClient.Close()
return dockerClient.ContainerRemove(context.Background(), id, types.ContainerRemoveOptions{Force: true})
}