diff options
author | Sam Whited <sam@samwhited.com> | 2019-08-29 15:52:40 -0500 |
---|---|---|
committer | Sam Whited <sam@samwhited.com> | 2019-09-11 07:47:23 -0500 |
commit | b37c214e3c8c4ff5450bd5fc1225d53827d240e7 (patch) | |
tree | 5687180effbed0fef2b57743bbf210fd7fd71af2 /internal | |
parent | cd9e4ec24002fcf3238c1f1e8629e08966c2b7fb (diff) |
testutil: make testing packages public
This was done with something along the lines of:
```
mv internal/test testutil
pushd testutil/; grep -IRl "package test" | xargs -I '{}' sed -i -e 's|package test|package testutil|g' {}; popd
mv internal/testutil/*.go testutil/ && rm -rf internal/
grep -IRl "github.com\/docker\/docker\/internal\/test" | xargs -I '{}' sed -i -e 's|github.com/docker/docker/internal/test|github.com/docker/docker/test|g' {}
goimports .
```
I also modified the basic plugin path in testutil/fixtures/plugin.
Signed-off-by: Sam Whited <sam@samwhited.com>
Diffstat (limited to 'internal')
33 files changed, 0 insertions, 4069 deletions
diff --git a/internal/test/daemon/config.go b/internal/test/daemon/config.go deleted file mode 100644 index ce99222b37..0000000000 --- a/internal/test/daemon/config.go +++ /dev/null @@ -1,82 +0,0 @@ -package daemon - -import ( - "context" - - "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/swarm" - "github.com/docker/docker/internal/test" - "gotest.tools/assert" -) - -// ConfigConstructor defines a swarm config constructor -type ConfigConstructor func(*swarm.Config) - -// CreateConfig creates a config given the specified spec -func (d *Daemon) CreateConfig(t assert.TestingT, configSpec swarm.ConfigSpec) string { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - cli := d.NewClientT(t) - defer cli.Close() - - scr, err := cli.ConfigCreate(context.Background(), configSpec) - assert.NilError(t, err) - return scr.ID -} - -// ListConfigs returns the list of the current swarm configs -func (d *Daemon) ListConfigs(t assert.TestingT) []swarm.Config { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - cli := d.NewClientT(t) - defer cli.Close() - - configs, err := cli.ConfigList(context.Background(), types.ConfigListOptions{}) - assert.NilError(t, err) - return configs -} - -// GetConfig returns a swarm config identified by the specified id -func (d *Daemon) GetConfig(t assert.TestingT, id string) *swarm.Config { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - cli := d.NewClientT(t) - defer cli.Close() - - config, _, err := cli.ConfigInspectWithRaw(context.Background(), id) - assert.NilError(t, err) - return &config -} - -// DeleteConfig removes the swarm config identified by the specified id -func (d *Daemon) DeleteConfig(t assert.TestingT, id string) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - cli := d.NewClientT(t) - defer cli.Close() - - err := cli.ConfigRemove(context.Background(), id) - assert.NilError(t, err) -} - -// UpdateConfig updates the swarm config identified by the specified id -// Currently, only label update is supported. -func (d *Daemon) UpdateConfig(t assert.TestingT, id string, f ...ConfigConstructor) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - cli := d.NewClientT(t) - defer cli.Close() - - config := d.GetConfig(t, id) - for _, fn := range f { - fn(config) - } - - err := cli.ConfigUpdate(context.Background(), config.ID, config.Version, config.Spec) - assert.NilError(t, err) -} diff --git a/internal/test/daemon/container.go b/internal/test/daemon/container.go deleted file mode 100644 index 3aa69e195c..0000000000 --- a/internal/test/daemon/container.go +++ /dev/null @@ -1,40 +0,0 @@ -package daemon - -import ( - "context" - - "github.com/docker/docker/api/types" - "github.com/docker/docker/internal/test" - "gotest.tools/assert" -) - -// ActiveContainers returns the list of ids of the currently running containers -func (d *Daemon) ActiveContainers(t assert.TestingT) []string { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - cli := d.NewClientT(t) - defer cli.Close() - - containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{}) - assert.NilError(t, err) - - ids := make([]string, len(containers)) - for i, c := range containers { - ids[i] = c.ID - } - return ids -} - -// FindContainerIP returns the ip of the specified container -func (d *Daemon) FindContainerIP(t assert.TestingT, id string) string { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - cli := d.NewClientT(t) - defer cli.Close() - - i, err := cli.ContainerInspect(context.Background(), id) - assert.NilError(t, err) - return i.NetworkSettings.IPAddress -} diff --git a/internal/test/daemon/daemon.go b/internal/test/daemon/daemon.go deleted file mode 100644 index b3ea876ccc..0000000000 --- a/internal/test/daemon/daemon.go +++ /dev/null @@ -1,738 +0,0 @@ -package daemon // import "github.com/docker/docker/internal/test/daemon" - -import ( - "context" - "encoding/json" - "fmt" - "io/ioutil" - "net/http" - "os" - "os/exec" - "path/filepath" - "strconv" - "strings" - "time" - - "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/events" - "github.com/docker/docker/client" - "github.com/docker/docker/daemon/images" - "github.com/docker/docker/internal/test" - "github.com/docker/docker/internal/test/request" - "github.com/docker/docker/opts" - "github.com/docker/docker/pkg/ioutils" - "github.com/docker/docker/pkg/stringid" - "github.com/docker/go-connections/sockets" - "github.com/docker/go-connections/tlsconfig" - "github.com/pkg/errors" - "gotest.tools/assert" -) - -type testingT interface { - assert.TestingT - logT - Fatalf(string, ...interface{}) -} - -type namer interface { - Name() string -} -type testNamer interface { - TestName() string -} - -type logT interface { - Logf(string, ...interface{}) -} - -const defaultDockerdBinary = "dockerd" -const containerdSocket = "/var/run/docker/containerd/containerd.sock" - -var errDaemonNotStarted = errors.New("daemon not started") - -// SockRoot holds the path of the default docker integration daemon socket -var SockRoot = filepath.Join(os.TempDir(), "docker-integration") - -type clientConfig struct { - transport *http.Transport - scheme string - addr string -} - -// Daemon represents a Docker daemon for the testing framework -type Daemon struct { - GlobalFlags []string - Root string - Folder string - Wait chan error - UseDefaultHost bool - UseDefaultTLSHost bool - - id string - logFile *os.File - cmd *exec.Cmd - storageDriver string - userlandProxy bool - defaultCgroupNamespaceMode string - execRoot string - experimental bool - init bool - dockerdBinary string - log logT - imageService *images.ImageService - - // swarm related field - swarmListenAddr string - SwarmPort int // FIXME(vdemeester) should probably not be exported - DefaultAddrPool []string - SubnetSize uint32 - DataPathPort uint32 - // cached information - CachedInfo types.Info -} - -// New returns a Daemon instance to be used for testing. -// This will create a directory such as d123456789 in the folder specified by $DOCKER_INTEGRATION_DAEMON_DEST or $DEST. -// The daemon will not automatically start. -func New(t testingT, ops ...func(*Daemon)) *Daemon { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - dest := os.Getenv("DOCKER_INTEGRATION_DAEMON_DEST") - if dest == "" { - dest = os.Getenv("DEST") - } - switch v := t.(type) { - case namer: - dest = filepath.Join(dest, v.Name()) - case testNamer: - dest = filepath.Join(dest, v.TestName()) - } - t.Logf("Creating a new daemon at: %s", dest) - assert.Check(t, dest != "", "Please set the DOCKER_INTEGRATION_DAEMON_DEST or the DEST environment variable") - - storageDriver := os.Getenv("DOCKER_GRAPHDRIVER") - - assert.NilError(t, os.MkdirAll(SockRoot, 0700), "could not create daemon socket root") - - id := fmt.Sprintf("d%s", stringid.TruncateID(stringid.GenerateRandomID())) - dir := filepath.Join(dest, id) - daemonFolder, err := filepath.Abs(dir) - assert.NilError(t, err, "Could not make %q an absolute path", dir) - daemonRoot := filepath.Join(daemonFolder, "root") - - assert.NilError(t, os.MkdirAll(daemonRoot, 0755), "Could not create daemon root %q", dir) - - userlandProxy := true - if env := os.Getenv("DOCKER_USERLANDPROXY"); env != "" { - if val, err := strconv.ParseBool(env); err != nil { - userlandProxy = val - } - } - d := &Daemon{ - id: id, - Folder: daemonFolder, - Root: daemonRoot, - storageDriver: storageDriver, - userlandProxy: userlandProxy, - // dxr stands for docker-execroot (shortened for avoiding unix(7) path length limitation) - execRoot: filepath.Join(os.TempDir(), "dxr", id), - dockerdBinary: defaultDockerdBinary, - swarmListenAddr: defaultSwarmListenAddr, - SwarmPort: DefaultSwarmPort, - log: t, - } - - for _, op := range ops { - op(d) - } - - return d -} - -// ContainersNamespace returns the containerd namespace used for containers. -func (d *Daemon) ContainersNamespace() string { - return d.id -} - -// RootDir returns the root directory of the daemon. -func (d *Daemon) RootDir() string { - return d.Root -} - -// ID returns the generated id of the daemon -func (d *Daemon) ID() string { - return d.id -} - -// StorageDriver returns the configured storage driver of the daemon -func (d *Daemon) StorageDriver() string { - return d.storageDriver -} - -// Sock returns the socket path of the daemon -func (d *Daemon) Sock() string { - return fmt.Sprintf("unix://" + d.sockPath()) -} - -func (d *Daemon) sockPath() string { - return filepath.Join(SockRoot, d.id+".sock") -} - -// LogFileName returns the path the daemon's log file -func (d *Daemon) LogFileName() string { - return d.logFile.Name() -} - -// ReadLogFile returns the content of the daemon log file -func (d *Daemon) ReadLogFile() ([]byte, error) { - return ioutil.ReadFile(d.logFile.Name()) -} - -// NewClientT creates new client based on daemon's socket path -func (d *Daemon) NewClientT(t assert.TestingT, extraOpts ...client.Opt) *client.Client { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - - clientOpts := []client.Opt{ - client.FromEnv, - client.WithHost(d.Sock()), - } - clientOpts = append(clientOpts, extraOpts...) - - c, err := client.NewClientWithOpts(clientOpts...) - assert.NilError(t, err, "cannot create daemon client") - return c -} - -// Cleanup cleans the daemon files : exec root (network namespaces, ...), swarmkit files -func (d *Daemon) Cleanup(t testingT) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - // Cleanup swarmkit wal files if present - cleanupRaftDir(t, d.Root) - cleanupNetworkNamespace(t, d.execRoot) -} - -// Start starts the daemon and return once it is ready to receive requests. -func (d *Daemon) Start(t testingT, args ...string) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - if err := d.StartWithError(args...); err != nil { - t.Fatalf("failed to start daemon with arguments %v : %v", args, err) - } -} - -// StartWithError starts the daemon and return once it is ready to receive requests. -// It returns an error in case it couldn't start. -func (d *Daemon) StartWithError(args ...string) error { - logFile, err := os.OpenFile(filepath.Join(d.Folder, "docker.log"), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600) - if err != nil { - return errors.Wrapf(err, "[%s] Could not create %s/docker.log", d.id, d.Folder) - } - - return d.StartWithLogFile(logFile, args...) -} - -// StartWithLogFile will start the daemon and attach its streams to a given file. -func (d *Daemon) StartWithLogFile(out *os.File, providedArgs ...string) error { - d.handleUserns() - dockerdBinary, err := exec.LookPath(d.dockerdBinary) - if err != nil { - return errors.Wrapf(err, "[%s] could not find docker binary in $PATH", d.id) - } - - args := append(d.GlobalFlags, - "--containerd", containerdSocket, - "--data-root", d.Root, - "--exec-root", d.execRoot, - "--pidfile", fmt.Sprintf("%s/docker.pid", d.Folder), - fmt.Sprintf("--userland-proxy=%t", d.userlandProxy), - "--containerd-namespace", d.id, - "--containerd-plugins-namespace", d.id+"p", - ) - if d.defaultCgroupNamespaceMode != "" { - args = append(args, []string{"--default-cgroupns-mode", d.defaultCgroupNamespaceMode}...) - } - if d.experimental { - args = append(args, "--experimental") - } - if d.init { - args = append(args, "--init") - } - if !(d.UseDefaultHost || d.UseDefaultTLSHost) { - args = append(args, []string{"--host", d.Sock()}...) - } - if root := os.Getenv("DOCKER_REMAP_ROOT"); root != "" { - args = append(args, []string{"--userns-remap", root}...) - } - - // If we don't explicitly set the log-level or debug flag(-D) then - // turn on debug mode - foundLog := false - foundSd := false - for _, a := range providedArgs { - if strings.Contains(a, "--log-level") || strings.Contains(a, "-D") || strings.Contains(a, "--debug") { - foundLog = true - } - if strings.Contains(a, "--storage-driver") { - foundSd = true - } - } - if !foundLog { - args = append(args, "--debug") - } - if d.storageDriver != "" && !foundSd { - args = append(args, "--storage-driver", d.storageDriver) - } - - args = append(args, providedArgs...) - d.cmd = exec.Command(dockerdBinary, args...) - d.cmd.Env = append(os.Environ(), "DOCKER_SERVICE_PREFER_OFFLINE_IMAGE=1") - d.cmd.Stdout = out - d.cmd.Stderr = out - d.logFile = out - - if err := d.cmd.Start(); err != nil { - return errors.Errorf("[%s] could not start daemon container: %v", d.id, err) - } - - wait := make(chan error, 1) - - go func() { - ret := d.cmd.Wait() - d.log.Logf("[%s] exiting daemon", d.id) - // If we send before logging, we might accidentally log _after_ the test is done. - // As of Go 1.12, this incurs a panic instead of silently being dropped. - wait <- ret - close(wait) - }() - - d.Wait = wait - - clientConfig, err := d.getClientConfig() - if err != nil { - return err - } - client := &http.Client{ - Transport: clientConfig.transport, - } - - req, err := http.NewRequest("GET", "/_ping", nil) - if err != nil { - return errors.Wrapf(err, "[%s] could not create new request", d.id) - } - req.URL.Host = clientConfig.addr - req.URL.Scheme = clientConfig.scheme - - ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) - defer cancel() - - // make sure daemon is ready to receive requests - for i := 0; ; i++ { - d.log.Logf("[%s] waiting for daemon to start", d.id) - - select { - case <-ctx.Done(): - return errors.Errorf("[%s] Daemon exited and never started: %s", d.id, ctx.Err()) - case err := <-d.Wait: - return errors.Errorf("[%s] Daemon exited during startup: %v", d.id, err) - default: - rctx, rcancel := context.WithTimeout(context.TODO(), 2*time.Second) - defer rcancel() - - resp, err := client.Do(req.WithContext(rctx)) - if err != nil { - if i > 2 { // don't log the first couple, this ends up just being noise - d.log.Logf("[%s] error pinging daemon on start: %v", d.id, err) - } - - select { - case <-ctx.Done(): - case <-time.After(500 * time.Millisecond): - } - continue - } - - resp.Body.Close() - if resp.StatusCode != http.StatusOK { - d.log.Logf("[%s] received status != 200 OK: %s\n", d.id, resp.Status) - } - d.log.Logf("[%s] daemon started\n", d.id) - d.Root, err = d.queryRootDir() - if err != nil { - return errors.Errorf("[%s] error querying daemon for root directory: %v", d.id, err) - } - return nil - } - } -} - -// StartWithBusybox will first start the daemon with Daemon.Start() -// then save the busybox image from the main daemon and load it into this Daemon instance. -func (d *Daemon) StartWithBusybox(t testingT, arg ...string) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - d.Start(t, arg...) - d.LoadBusybox(t) -} - -// Kill will send a SIGKILL to the daemon -func (d *Daemon) Kill() error { - if d.cmd == nil || d.Wait == nil { - return errDaemonNotStarted - } - - defer func() { - d.logFile.Close() - d.cmd = nil - }() - - if err := d.cmd.Process.Kill(); err != nil { - return err - } - - return os.Remove(fmt.Sprintf("%s/docker.pid", d.Folder)) -} - -// Pid returns the pid of the daemon -func (d *Daemon) Pid() int { - return d.cmd.Process.Pid -} - -// Interrupt stops the daemon by sending it an Interrupt signal -func (d *Daemon) Interrupt() error { - return d.Signal(os.Interrupt) -} - -// Signal sends the specified signal to the daemon if running -func (d *Daemon) Signal(signal os.Signal) error { - if d.cmd == nil || d.Wait == nil { - return errDaemonNotStarted - } - return d.cmd.Process.Signal(signal) -} - -// DumpStackAndQuit sends SIGQUIT to the daemon, which triggers it to dump its -// stack to its log file and exit -// This is used primarily for gathering debug information on test timeout -func (d *Daemon) DumpStackAndQuit() { - if d.cmd == nil || d.cmd.Process == nil { - return - } - SignalDaemonDump(d.cmd.Process.Pid) -} - -// Stop will send a SIGINT every second and wait for the daemon to stop. -// If it times out, a SIGKILL is sent. -// Stop will not delete the daemon directory. If a purged daemon is needed, -// instantiate a new one with NewDaemon. -// If an error occurs while starting the daemon, the test will fail. -func (d *Daemon) Stop(t testingT) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - err := d.StopWithError() - if err != nil { - if err != errDaemonNotStarted { - t.Fatalf("Error while stopping the daemon %s : %v", d.id, err) - } else { - t.Logf("Daemon %s is not started", d.id) - } - } -} - -// StopWithError will send a SIGINT every second and wait for the daemon to stop. -// If it timeouts, a SIGKILL is sent. -// Stop will not delete the daemon directory. If a purged daemon is needed, -// instantiate a new one with NewDaemon. -func (d *Daemon) StopWithError() (err error) { - if d.cmd == nil || d.Wait == nil { - return errDaemonNotStarted - } - defer func() { - if err == nil { - d.log.Logf("[%s] Daemon stopped", d.id) - } else { - d.log.Logf("[%s] Error when stopping daemon: %v", d.id, err) - } - d.logFile.Close() - d.cmd = nil - }() - - i := 1 - ticker := time.NewTicker(time.Second) - defer ticker.Stop() - tick := ticker.C - - d.log.Logf("[%s] Stopping daemon", d.id) - - if err := d.cmd.Process.Signal(os.Interrupt); err != nil { - if strings.Contains(err.Error(), "os: process already finished") { - return errDaemonNotStarted - } - return errors.Errorf("could not send signal: %v", err) - } - -out1: - for { - select { - case err := <-d.Wait: - return err - case <-time.After(20 * time.Second): - // time for stopping jobs and run onShutdown hooks - d.log.Logf("[%s] daemon stop timeout", d.id) - break out1 - } - } - -out2: - for { - select { - case err := <-d.Wait: - return err - case <-tick: - i++ - if i > 5 { - d.log.Logf("tried to interrupt daemon for %d times, now try to kill it", i) - break out2 - } - d.log.Logf("Attempt #%d: daemon is still running with pid %d", i, d.cmd.Process.Pid) - if err := d.cmd.Process.Signal(os.Interrupt); err != nil { - return errors.Errorf("could not send signal: %v", err) - } - } - } - - if err := d.cmd.Process.Kill(); err != nil { - d.log.Logf("Could not kill daemon: %v", err) - return err - } - - d.cmd.Wait() - - return os.Remove(fmt.Sprintf("%s/docker.pid", d.Folder)) -} - -// Restart will restart the daemon by first stopping it and the starting it. -// If an error occurs while starting the daemon, the test will fail. -func (d *Daemon) Restart(t testingT, args ...string) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - d.Stop(t) - d.Start(t, args...) -} - -// RestartWithError will restart the daemon by first stopping it and then starting it. -func (d *Daemon) RestartWithError(arg ...string) error { - if err := d.StopWithError(); err != nil { - return err - } - return d.StartWithError(arg...) -} - -func (d *Daemon) handleUserns() { - // in the case of tests running a user namespace-enabled daemon, we have resolved - // d.Root to be the actual final path of the graph dir after the "uid.gid" of - // remapped root is added--we need to subtract it from the path before calling - // start or else we will continue making subdirectories rather than truly restarting - // with the same location/root: - if root := os.Getenv("DOCKER_REMAP_ROOT"); root != "" { - d.Root = filepath.Dir(d.Root) - } -} - -// ReloadConfig asks the daemon to reload its configuration -func (d *Daemon) ReloadConfig() error { - if d.cmd == nil || d.cmd.Process == nil { - return errors.New("daemon is not running") - } - - errCh := make(chan error) - started := make(chan struct{}) - go func() { - _, body, err := request.Get("/events", request.Host(d.Sock())) - close(started) - if err != nil { - errCh <- err - } - defer body.Close() - dec := json.NewDecoder(body) - for { - var e events.Message - if err := dec.Decode(&e); err != nil { - errCh <- err - return - } - if e.Type != events.DaemonEventType { - continue - } - if e.Action != "reload" { - continue - } - close(errCh) // notify that we are done - return - } - }() - - <-started - if err := signalDaemonReload(d.cmd.Process.Pid); err != nil { - return errors.Errorf("error signaling daemon reload: %v", err) - } - select { - case err := <-errCh: - if err != nil { - return errors.Errorf("error waiting for daemon reload event: %v", err) - } - case <-time.After(30 * time.Second): - return errors.New("timeout waiting for daemon reload event") - } - return nil -} - -// LoadBusybox image into the daemon -func (d *Daemon) LoadBusybox(t assert.TestingT) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - clientHost, err := client.NewClientWithOpts(client.FromEnv) - assert.NilError(t, err, "failed to create client") - defer clientHost.Close() - - ctx := context.Background() - reader, err := clientHost.ImageSave(ctx, []string{"busybox:latest"}) - assert.NilError(t, err, "failed to download busybox") - defer reader.Close() - - c := d.NewClientT(t) - defer c.Close() - - resp, err := c.ImageLoad(ctx, reader, true) - assert.NilError(t, err, "failed to load busybox") - defer resp.Body.Close() -} - -func (d *Daemon) getClientConfig() (*clientConfig, error) { - var ( - transport *http.Transport - scheme string - addr string - proto string - ) - if d.UseDefaultTLSHost { - option := &tlsconfig.Options{ - CAFile: "fixtures/https/ca.pem", - CertFile: "fixtures/https/client-cert.pem", - KeyFile: "fixtures/https/client-key.pem", - } - tlsConfig, err := tlsconfig.Client(*option) - if err != nil { - return nil, err - } - transport = &http.Transport{ - TLSClientConfig: tlsConfig, - } - addr = fmt.Sprintf("%s:%d", opts.DefaultHTTPHost, opts.DefaultTLSHTTPPort) - scheme = "https" - proto = "tcp" - } else if d.UseDefaultHost { - addr = opts.DefaultUnixSocket - proto = "unix" - scheme = "http" - transport = &http.Transport{} - } else { - addr = d.sockPath() - proto = "unix" - scheme = "http" - transport = &http.Transport{} - } - - if err := sockets.ConfigureTransport(transport, proto, addr); err != nil { - return nil, err - } - transport.DisableKeepAlives = true - if proto == "unix" { - addr = filepath.Base(addr) - } - return &clientConfig{ - transport: transport, - scheme: scheme, - addr: addr, - }, nil -} - -func (d *Daemon) queryRootDir() (string, error) { - // update daemon root by asking /info endpoint (to support user - // namespaced daemon with root remapped uid.gid directory) - clientConfig, err := d.getClientConfig() - if err != nil { - return "", err - } - - c := &http.Client{ - Transport: clientConfig.transport, - } - - req, err := http.NewRequest("GET", "/info", nil) - if err != nil { - return "", err - } - req.Header.Set("Content-Type", "application/json") - req.URL.Host = clientConfig.addr - req.URL.Scheme = clientConfig.scheme - - resp, err := c.Do(req) - if err != nil { - return "", err - } - body := ioutils.NewReadCloserWrapper(resp.Body, func() error { - return resp.Body.Close() - }) - - type Info struct { - DockerRootDir string - } - var b []byte - var i Info - b, err = request.ReadBody(body) - if err == nil && resp.StatusCode == http.StatusOK { - // read the docker root dir - if err = json.Unmarshal(b, &i); err == nil { - return i.DockerRootDir, nil - } - } - return "", err -} - -// Info returns the info struct for this daemon -func (d *Daemon) Info(t assert.TestingT) types.Info { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - c := d.NewClientT(t) - info, err := c.Info(context.Background()) - assert.NilError(t, err) - return info -} - -func cleanupRaftDir(t testingT, rootPath string) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - for _, p := range []string{"wal", "wal-v3-encrypted", "snap-v3-encrypted"} { - dir := filepath.Join(rootPath, "swarm/raft", p) - if err := os.RemoveAll(dir); err != nil { - t.Logf("error removing %v: %v", dir, err) - } - } -} - -// ImageService returns the Daemon's ImageService -func (d *Daemon) ImageService() *images.ImageService { - return d.imageService -} diff --git a/internal/test/daemon/daemon_unix.go b/internal/test/daemon/daemon_unix.go deleted file mode 100644 index 7c2b15c1ad..0000000000 --- a/internal/test/daemon/daemon_unix.go +++ /dev/null @@ -1,50 +0,0 @@ -// +build !windows - -package daemon // import "github.com/docker/docker/internal/test/daemon" - -import ( - "fmt" - "os" - "path/filepath" - "strings" - - "github.com/docker/docker/internal/test" - "golang.org/x/sys/unix" - "gotest.tools/assert" -) - -func cleanupNetworkNamespace(t testingT, execRoot string) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - // Cleanup network namespaces in the exec root of this - // daemon because this exec root is specific to this - // daemon instance and has no chance of getting - // cleaned up when a new daemon is instantiated with a - // new exec root. - netnsPath := filepath.Join(execRoot, "netns") - filepath.Walk(netnsPath, func(path string, info os.FileInfo, err error) error { - if err := unix.Unmount(path, unix.MNT_DETACH); err != nil && err != unix.EINVAL && err != unix.ENOENT { - t.Logf("unmount of %s failed: %v", path, err) - } - os.Remove(path) - return nil - }) -} - -// CgroupNamespace returns the cgroup namespace the daemon is running in -func (d *Daemon) CgroupNamespace(t assert.TestingT) string { - link, err := os.Readlink(fmt.Sprintf("/proc/%d/ns/cgroup", d.Pid())) - assert.NilError(t, err) - - return strings.TrimSpace(link) -} - -// SignalDaemonDump sends a signal to the daemon to write a dump file -func SignalDaemonDump(pid int) { - unix.Kill(pid, unix.SIGQUIT) -} - -func signalDaemonReload(pid int) error { - return unix.Kill(pid, unix.SIGHUP) -} diff --git a/internal/test/daemon/daemon_windows.go b/internal/test/daemon/daemon_windows.go deleted file mode 100644 index a7e987c92f..0000000000 --- a/internal/test/daemon/daemon_windows.go +++ /dev/null @@ -1,32 +0,0 @@ -package daemon // import "github.com/docker/docker/internal/test/daemon" - -import ( - "fmt" - "strconv" - - "golang.org/x/sys/windows" - "gotest.tools/assert" -) - -// SignalDaemonDump sends a signal to the daemon to write a dump file -func SignalDaemonDump(pid int) { - ev, _ := windows.UTF16PtrFromString("Global\\docker-daemon-" + strconv.Itoa(pid)) - h2, err := windows.OpenEvent(0x0002, false, ev) - if h2 == 0 || err != nil { - return - } - windows.PulseEvent(h2) -} - -func signalDaemonReload(pid int) error { - return fmt.Errorf("daemon reload not supported") -} - -func cleanupNetworkNamespace(t testingT, execRoot string) { -} - -// CgroupNamespace returns the cgroup namespace the daemon is running in -func (d *Daemon) CgroupNamespace(t assert.TestingT) string { - assert.Assert(t, false) - return "cgroup namespaces are not supported on Windows" -} diff --git a/internal/test/daemon/node.go b/internal/test/daemon/node.go deleted file mode 100644 index d5f6f15263..0000000000 --- a/internal/test/daemon/node.go +++ /dev/null @@ -1,89 +0,0 @@ -package daemon - -import ( - "context" - "strings" - "time" - - "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/swarm" - "github.com/docker/docker/internal/test" - "gotest.tools/assert" -) - -// NodeConstructor defines a swarm node constructor -type NodeConstructor func(*swarm.Node) - -// GetNode returns a swarm node identified by the specified id -func (d *Daemon) GetNode(t assert.TestingT, id string, errCheck ...func(error) bool) *swarm.Node { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - cli := d.NewClientT(t) - defer cli.Close() - - node, _, err := cli.NodeInspectWithRaw(context.Background(), id) - if err != nil { - for _, f := range errCheck { - if f(err) { - return nil - } - } - } - assert.NilError(t, err, "[%s] (*Daemon).GetNode: NodeInspectWithRaw(%q) failed", d.id, id) - assert.Check(t, node.ID == id) - return &node -} - -// RemoveNode removes the specified node -func (d *Daemon) RemoveNode(t assert.TestingT, id string, force bool) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - cli := d.NewClientT(t) - defer cli.Close() - - options := types.NodeRemoveOptions{ - Force: force, - } - err := cli.NodeRemove(context.Background(), id, options) - assert.NilError(t, err) -} - -// UpdateNode updates a swarm node with the specified node constructor -func (d *Daemon) UpdateNode(t assert.TestingT, id string, f ...NodeConstructor) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - cli := d.NewClientT(t) - defer cli.Close() - - for i := 0; ; i++ { - node := d.GetNode(t, id) - for _, fn := range f { - fn(node) - } - - err := cli.NodeUpdate(context.Background(), node.ID, node.Version, node.Spec) - if i < 10 && err != nil && strings.Contains(err.Error(), "update out of sequence") { - time.Sleep(100 * time.Millisecond) - continue - } - assert.NilError(t, err) - return - } -} - -// ListNodes returns the list of the current swarm nodes -func (d *Daemon) ListNodes(t assert.TestingT) []swarm.Node { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - cli := d.NewClientT(t) - defer cli.Close() - - nodes, err := cli.NodeList(context.Background(), types.NodeListOptions{}) - assert.NilError(t, err) - - return nodes -} diff --git a/internal/test/daemon/ops.go b/internal/test/daemon/ops.go deleted file mode 100644 index 9f869dee0f..0000000000 --- a/internal/test/daemon/ops.go +++ /dev/null @@ -1,79 +0,0 @@ -package daemon - -import "github.com/docker/docker/internal/test/environment" - -// WithDefaultCgroupNamespaceMode sets the default cgroup namespace mode for the daemon -func WithDefaultCgroupNamespaceMode(mode string) func(*Daemon) { - return func(d *Daemon) { - d.defaultCgroupNamespaceMode = mode - } -} - -// WithExperimental sets the daemon in experimental mode -func WithExperimental(d *Daemon) { - d.experimental = true - d.init = true -} - -// WithInit sets the daemon init -func WithInit(d *Daemon) { - d.init = true -} - -// WithDockerdBinary sets the dockerd binary to the specified one -func WithDockerdBinary(dockerdBinary string) func(*Daemon) { - return func(d *Daemon) { - d.dockerdBinary = dockerdBinary - } -} - -// WithSwarmPort sets the swarm port to use for swarm mode -func WithSwarmPort(port int) func(*Daemon) { - return func(d *Daemon) { - d.SwarmPort = port - } -} - -// WithSwarmListenAddr sets the swarm listen addr to use for swarm mode -func WithSwarmListenAddr(listenAddr string) func(*Daemon) { - return func(d *Daemon) { - d.swarmListenAddr = listenAddr - } -} - -// WithSwarmDefaultAddrPool sets the swarm default address pool to use for swarm mode -func WithSwarmDefaultAddrPool(defaultAddrPool []string) func(*Daemon) { - return func(d *Daemon) { - d.DefaultAddrPool = defaultAddrPool - } -} - -// WithSwarmDefaultAddrPoolSubnetSize sets the subnet length mask of swarm default address pool to use for swarm mode -func WithSwarmDefaultAddrPoolSubnetSize(subnetSize uint32) func(*Daemon) { - return func(d *Daemon) { - d.SubnetSize = subnetSize - } -} - -// WithSwarmDataPathPort sets the swarm datapath port to use for swarm mode -func WithSwarmDataPathPort(datapathPort uint32) func(*Daemon) { - return func(d *Daemon) { - d.DataPathPort = datapathPort - } -} - -// WithEnvironment sets options from internal/test/environment.Execution struct -func WithEnvironment(e environment.Execution) func(*Daemon) { - return func(d *Daemon) { - if e.DaemonInfo.ExperimentalBuild { - d.experimental = true - } - } -} - -// WithStorageDriver sets store driver option -func WithStorageDriver(driver string) func(d *Daemon) { - return func(d *Daemon) { - d.storageDriver = driver - } -} diff --git a/internal/test/daemon/ops_unix.go b/internal/test/daemon/ops_unix.go deleted file mode 100644 index 41011e87c5..0000000000 --- a/internal/test/daemon/ops_unix.go +++ /dev/null @@ -1,34 +0,0 @@ -// +build !windows - -package daemon - -import ( - "path/filepath" - "runtime" - - "github.com/docker/docker/daemon/images" - "github.com/docker/docker/layer" - - // register graph drivers - _ "github.com/docker/docker/daemon/graphdriver/register" - "github.com/docker/docker/pkg/idtools" -) - -// WithImageService sets imageService options -func WithImageService(d *Daemon) { - layerStores := make(map[string]layer.Store) - os := runtime.GOOS - layerStores[os], _ = layer.NewStoreFromOptions(layer.StoreOptions{ - Root: d.Root, - MetadataStorePathTemplate: filepath.Join(d.RootDir(), "image", "%s", "layerdb"), - GraphDriver: d.storageDriver, - GraphDriverOptions: nil, - IDMapping: &idtools.IdentityMapping{}, - PluginGetter: nil, - ExperimentalEnabled: false, - OS: os, - }) - d.imageService = images.NewImageService(images.ImageServiceConfig{ - LayerStores: layerStores, - }) -} diff --git a/internal/test/daemon/plugin.go b/internal/test/daemon/plugin.go deleted file mode 100644 index ad66ebbf07..0000000000 --- a/internal/test/daemon/plugin.go +++ /dev/null @@ -1,75 +0,0 @@ -package daemon - -import ( - "context" - - "github.com/docker/docker/api/types" - "github.com/docker/docker/client" - "gotest.tools/assert" - "gotest.tools/poll" -) - -// PluginIsRunning provides a poller to check if the specified plugin is running -func (d *Daemon) PluginIsRunning(t assert.TestingT, name string) func(poll.LogT) poll.Result { - return withClient(t, d, withPluginInspect(name, func(plugin *types.Plugin, t poll.LogT) poll.Result { - if plugin.Enabled { - return poll.Success() - } - return poll.Continue("plugin %q is not enabled", name) - })) -} - -// PluginIsNotRunning provides a poller to check if the specified plugin is not running -func (d *Daemon) PluginIsNotRunning(t assert.TestingT, name string) func(poll.LogT) poll.Result { - return withClient(t, d, withPluginInspect(name, func(plugin *types.Plugin, t poll.LogT) poll.Result { - if !plugin.Enabled { - return poll.Success() - } - return poll.Continue("plugin %q is enabled", name) - })) -} - -// PluginIsNotPresent provides a poller to check if the specified plugin is not present -func (d *Daemon) PluginIsNotPresent(t assert.TestingT, name string) func(poll.LogT) poll.Result { - return withClient(t, d, func(c client.APIClient, t poll.LogT) poll.Result { - _, _, err := c.PluginInspectWithRaw(context.Background(), name) - if client.IsErrNotFound(err) { - return poll.Success() - } - if err != nil { - return poll.Error(err) - } - return poll.Continue("plugin %q exists", name) - }) -} - -// PluginReferenceIs provides a poller to check if the specified plugin has the specified reference -func (d *Daemon) PluginReferenceIs(t assert.TestingT, name, expectedRef string) func(poll.LogT) poll.Result { - return withClient(t, d, withPluginInspect(name, func(plugin *types.Plugin, t poll.LogT) poll.Result { - if plugin.PluginReference == expectedRef { - return poll.Success() - } - return poll.Continue("plugin %q reference is not %q", name, expectedRef) - })) -} - -func withPluginInspect(name string, f func(*types.Plugin, poll.LogT) poll.Result) func(client.APIClient, poll.LogT) poll.Result { - return func(c client.APIClient, t poll.LogT) poll.Result { - plugin, _, err := c.PluginInspectWithRaw(context.Background(), name) - if client.IsErrNotFound(err) { - return poll.Continue("plugin %q not found", name) - } - if err != nil { - return poll.Error(err) - } - return f(plugin, t) - } - -} - -func withClient(t assert.TestingT, d *Daemon, f func(client.APIClient, poll.LogT) poll.Result) func(poll.LogT) poll.Result { - return func(pt poll.LogT) poll.Result { - c := d.NewClientT(t) - return f(c, pt) - } -} diff --git a/internal/test/daemon/secret.go b/internal/test/daemon/secret.go deleted file mode 100644 index f3db7a4260..0000000000 --- a/internal/test/daemon/secret.go +++ /dev/null @@ -1,84 +0,0 @@ -package daemon - -import ( - "context" - - "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/swarm" - "github.com/docker/docker/internal/test" - "gotest.tools/assert" -) - -// SecretConstructor defines a swarm secret constructor -type SecretConstructor func(*swarm.Secret) - -// CreateSecret creates a secret given the specified spec -func (d *Daemon) CreateSecret(t assert.TestingT, secretSpec swarm.SecretSpec) string { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - cli := d.NewClientT(t) - defer cli.Close() - - scr, err := cli.SecretCreate(context.Background(), secretSpec) - assert.NilError(t, err) - - return scr.ID -} - -// ListSecrets returns the list of the current swarm secrets -func (d *Daemon) ListSecrets(t assert.TestingT) []swarm.Secret { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - cli := d.NewClientT(t) - defer cli.Close() - - secrets, err := cli.SecretList(context.Background(), types.SecretListOptions{}) - assert.NilError(t, err) - return secrets -} - -// GetSecret returns a swarm secret identified by the specified id -func (d *Daemon) GetSecret(t assert.TestingT, id string) *swarm.Secret { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - cli := d.NewClientT(t) - defer cli.Close() - - secret, _, err := cli.SecretInspectWithRaw(context.Background(), id) - assert.NilError(t, err) - return &secret -} - -// DeleteSecret removes the swarm secret identified by the specified id -func (d *Daemon) DeleteSecret(t assert.TestingT, id string) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - cli := d.NewClientT(t) - defer cli.Close() - - err := cli.SecretRemove(context.Background(), id) - assert.NilError(t, err) -} - -// UpdateSecret updates the swarm secret identified by the specified id -// Currently, only label update is supported. -func (d *Daemon) UpdateSecret(t assert.TestingT, id string, f ...SecretConstructor) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - cli := d.NewClientT(t) - defer cli.Close() - - secret := d.GetSecret(t, id) - for _, fn := range f { - fn(secret) - } - - err := cli.SecretUpdate(context.Background(), secret.ID, secret.Version, secret.Spec) - - assert.NilError(t, err) -} diff --git a/internal/test/daemon/service.go b/internal/test/daemon/service.go deleted file mode 100644 index a51671639c..0000000000 --- a/internal/test/daemon/service.go +++ /dev/null @@ -1,134 +0,0 @@ -package daemon - -import ( - "context" - "time" - - "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/filters" - "github.com/docker/docker/api/types/swarm" - "github.com/docker/docker/internal/test" - "gotest.tools/assert" -) - -// ServiceConstructor defines a swarm service constructor function -type ServiceConstructor func(*swarm.Service) - -func (d *Daemon) createServiceWithOptions(t assert.TestingT, opts types.ServiceCreateOptions, f ...ServiceConstructor) string { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - var service swarm.Service - for _, fn := range f { - fn(&service) - } - - cli := d.NewClientT(t) - defer cli.Close() - - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) - defer cancel() - - res, err := cli.ServiceCreate(ctx, service.Spec, opts) - assert.NilError(t, err) - return res.ID -} - -// CreateService creates a swarm service given the specified service constructor -func (d *Daemon) CreateService(t assert.TestingT, f ...ServiceConstructor) string { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - return d.createServiceWithOptions(t, types.ServiceCreateOptions{}, f...) -} - -// GetService returns the swarm service corresponding to the specified id -func (d *Daemon) GetService(t assert.TestingT, id string) *swarm.Service { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - cli := d.NewClientT(t) - defer cli.Close() - - service, _, err := cli.ServiceInspectWithRaw(context.Background(), id, types.ServiceInspectOptions{}) - assert.NilError(t, err) - return &service -} - -// GetServiceTasks returns the swarm tasks for the specified service -func (d *Daemon) GetServiceTasks(t assert.TestingT, service string, additionalFilters ...filters.KeyValuePair) []swarm.Task { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - cli := d.NewClientT(t) - defer cli.Close() - - filterArgs := filters.NewArgs() - filterArgs.Add("desired-state", "running") - filterArgs.Add("service", service) - for _, filter := range additionalFilters { - filterArgs.Add(filter.Key, filter.Value) - } - - options := types.TaskListOptions{ - Filters: filterArgs, - } - - tasks, err := cli.TaskList(context.Background(), options) - assert.NilError(t, err) - return tasks -} - -// UpdateService updates a swarm service with the specified service constructor -func (d *Daemon) UpdateService(t assert.TestingT, service *swarm.Service, f ...ServiceConstructor) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - cli := d.NewClientT(t) - defer cli.Close() - - for _, fn := range f { - fn(service) - } - - _, err := cli.ServiceUpdate(context.Background(), service.ID, service.Version, service.Spec, types.ServiceUpdateOptions{}) - assert.NilError(t, err) -} - -// RemoveService removes the specified service -func (d *Daemon) RemoveService(t assert.TestingT, id string) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - cli := d.NewClientT(t) - defer cli.Close() - - err := cli.ServiceRemove(context.Background(), id) - assert.NilError(t, err) -} - -// ListServices returns the list of the current swarm services -func (d *Daemon) ListServices(t assert.TestingT) []swarm.Service { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - cli := d.NewClientT(t) - defer cli.Close() - - services, err := cli.ServiceList(context.Background(), types.ServiceListOptions{}) - assert.NilError(t, err) - return services -} - -// GetTask returns the swarm task identified by the specified id -func (d *Daemon) GetTask(t assert.TestingT, id string) swarm.Task { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - cli := d.NewClientT(t) - defer cli.Close() - - task, _, err := cli.TaskInspectWithRaw(context.Background(), id) - assert.NilError(t, err) - return task -} diff --git a/internal/test/daemon/swarm.go b/internal/test/daemon/swarm.go deleted file mode 100644 index 20300a1f4a..0000000000 --- a/internal/test/daemon/swarm.go +++ /dev/null @@ -1,223 +0,0 @@ -package daemon - -import ( - "context" - "fmt" - - "github.com/docker/docker/api/types/swarm" - "github.com/docker/docker/internal/test" - "github.com/pkg/errors" - "gotest.tools/assert" -) - -const ( - // DefaultSwarmPort is the default port use for swarm in the tests - DefaultSwarmPort = 2477 - defaultSwarmListenAddr = "0.0.0.0" -) - -var ( - startArgs = []string{"--iptables=false", "--swarm-default-advertise-addr=lo"} -) - -// StartNode (re)starts the daemon -func (d *Daemon) StartNode(t testingT) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - d.Start(t, startArgs...) -} - -// StartNodeWithBusybox starts daemon to be used as a swarm node, and loads the busybox image -func (d *Daemon) StartNodeWithBusybox(t testingT) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - d.StartWithBusybox(t, startArgs...) -} - -// RestartNode restarts a daemon to be used as a swarm node -func (d *Daemon) RestartNode(t testingT) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - // avoid networking conflicts - d.Stop(t) - d.Start(t, startArgs...) -} - -// StartAndSwarmInit starts the daemon (with busybox) and init the swarm -func (d *Daemon) StartAndSwarmInit(t testingT) { - d.StartNodeWithBusybox(t) - d.SwarmInit(t, swarm.InitRequest{}) -} - -// StartAndSwarmJoin starts the daemon (with busybox) and join the specified swarm as worker or manager -func (d *Daemon) StartAndSwarmJoin(t testingT, leader *Daemon, manager bool) { - if th, ok := t.(test.HelperT); ok { - th.Helper() - } - d.StartNodeWithBusybox(t) - - tokens := leader.JoinTokens(t) - token := tokens.Worker - if manager { - token = tokens.Manager - } - t.Logf("[%s] joining swarm manager [%s]@%s, swarm listen addr %s", d.id, leader.id, leader.SwarmListenAddr(), d.SwarmListenAddr()) - d.SwarmJoin(t, swarm.JoinRequest{ - RemoteAddrs: []string{leader.SwarmListenAddr()}, - JoinToken: token, - }) -} - -// SpecConstructor defines a swarm spec constructor -type SpecConstructor func(*swarm.Spec) - -// SwarmListenAddr returns the listen-addr used for the daemon -func (d *Daemon) SwarmListenAddr() string { - return fmt.Sprintf("%s:%d", d.swarmListenAddr, d.SwarmPort) -} - -// NodeID returns the swarm mode node ID -func (d *Daemon) NodeID() string { - return d.CachedInfo.Swarm.NodeID -} - -// SwarmInit initializes a new swarm cluster. -func (d *Daemon) SwarmInit(t assert.TestingT, req swarm.InitRequest) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - if req.ListenAddr == "" { - req.ListenAddr = fmt.Sprintf("%s:%d", d.swarmListenAddr, d.SwarmPort) - } - if req.DefaultAddrPool == nil { - req.DefaultAddrPool = d.DefaultAddrPool - req.SubnetSize = d.SubnetSize - } - if d.DataPathPort > 0 { - req.DataPathPort = d.DataPathPort - } - cli := d.NewClientT(t) - defer cli.Close() - _, err := cli.SwarmInit(context.Background(), req) - assert.NilError(t, err, "initializing swarm") - d.CachedInfo = d.Info(t) -} - -// SwarmJoin joins a daemon to an existing cluster. -func (d *Daemon) SwarmJoin(t assert.TestingT, req swarm.JoinRequest) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - if req.ListenAddr == "" { - req.ListenAddr = fmt.Sprintf("%s:%d", d.swarmListenAddr, d.SwarmPort) - } - cli := d.NewClientT(t) - defer cli.Close() - err := cli.SwarmJoin(context.Background(), req) - assert.NilError(t, err, "[%s] joining swarm", d.id) - d.CachedInfo = d.Info(t) -} - -// SwarmLeave forces daemon to leave current cluster. -// -// The passed in TestingT is only used to validate that the client was successfully created -// Some tests rely on error checking the result of the actual unlock, so allow -// the error to be returned. -func (d *Daemon) SwarmLeave(t assert.TestingT, force bool) error { - cli := d.NewClientT(t) - defer cli.Close() - return cli.SwarmLeave(context.Background(), force) -} - -// SwarmInfo returns the swarm information of the daemon -func (d *Daemon) SwarmInfo(t assert.TestingT) swarm.Info { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - cli := d.NewClientT(t) - info, err := cli.Info(context.Background()) - assert.NilError(t, err, "get swarm info") - return info.Swarm -} - -// SwarmUnlock tries to unlock a locked swarm -// -// The passed in TestingT is only used to validate that the client was successfully created -// Some tests rely on error checking the result of the actual unlock, so allow -// the error to be returned. -func (d *Daemon) SwarmUnlock(t assert.TestingT, req swarm.UnlockRequest) error { - cli := d.NewClientT(t) - defer cli.Close() - - err := cli.SwarmUnlock(context.Background(), req) - if err != nil { - err = errors.Wrap(err, "unlocking swarm") - } - return err -} - -// GetSwarm returns the current swarm object -func (d *Daemon) GetSwarm(t assert.TestingT) swarm.Swarm { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - cli := d.NewClientT(t) - defer cli.Close() - - sw, err := cli.SwarmInspect(context.Background()) - assert.NilError(t, err) - return sw -} - -// UpdateSwarm updates the current swarm object with the specified spec constructors -func (d *Daemon) UpdateSwarm(t assert.TestingT, f ...SpecConstructor) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - cli := d.NewClientT(t) - defer cli.Close() - - sw := d.GetSwarm(t) - for _, fn := range f { - fn(&sw.Spec) - } - - err := cli.SwarmUpdate(context.Background(), sw.Version, sw.Spec, swarm.UpdateFlags{}) - assert.NilError(t, err) -} - -// RotateTokens update the swarm to rotate tokens -func (d *Daemon) RotateTokens(t assert.TestingT) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - cli := d.NewClientT(t) - defer cli.Close() - - sw, err := cli.SwarmInspect(context.Background()) - assert.NilError(t, err) - - flags := swarm.UpdateFlags{ - RotateManagerToken: true, - RotateWorkerToken: true, - } - - err = cli.SwarmUpdate(context.Background(), sw.Version, sw.Spec, flags) - assert.NilError(t, err) -} - -// JoinTokens returns the current swarm join tokens -func (d *Daemon) JoinTokens(t assert.TestingT) swarm.JoinTokens { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - cli := d.NewClientT(t) - defer cli.Close() - - sw, err := cli.SwarmInspect(context.Background()) - assert.NilError(t, err) - return sw.JoinTokens -} diff --git a/internal/test/environment/clean.go b/internal/test/environment/clean.go deleted file mode 100644 index ad6ec93e4a..0000000000 --- a/internal/test/environment/clean.go +++ /dev/null @@ -1,207 +0,0 @@ -package environment // import "github.com/docker/docker/internal/test/environment" - -import ( - "context" - "regexp" - "strings" - - "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/filters" - "github.com/docker/docker/client" - "github.com/docker/docker/internal/test" - "gotest.tools/assert" -) - -// Clean the environment, preserving protected objects (images, containers, ...) -// and removing everything else. It's meant to run after any tests so that they don't -// depend on each others. -func (e *Execution) Clean(t assert.TestingT) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - client := e.APIClient() - - platform := e.OSType - if (platform != "windows") || (platform == "windows" && e.DaemonInfo.Isolation == "hyperv") { - unpauseAllContainers(t, client) - } - deleteAllContainers(t, client, e.protectedElements.containers) - deleteAllImages(t, client, e.protectedElements.images) - deleteAllVolumes(t, client, e.protectedElements.volumes) - deleteAllNetworks(t, client, platform, e.protectedElements.networks) - if platform == "linux" { - deleteAllPlugins(t, client, e.protectedElements.plugins) - } -} - -func unpauseAllContainers(t assert.TestingT, client client.ContainerAPIClient) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - ctx := context.Background() - containers := getPausedContainers(ctx, t, client) - if len(containers) > 0 { - for _, container := range containers { - err := client.ContainerUnpause(ctx, container.ID) - assert.Check(t, err, "failed to unpause container %s", container.ID) - } - } -} - -func getPausedContainers(ctx context.Context, t assert.TestingT, client client.ContainerAPIClient) []types.Container { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - filter := filters.NewArgs() - filter.Add("status", "paused") - containers, err := client.ContainerList(ctx, types.ContainerListOptions{ - Filters: filter, - Quiet: true, - All: true, - }) - assert.Check(t, err, "failed to list containers") - return containers -} - -var alreadyExists = regexp.MustCompile(`Error response from daemon: removal of container (\w+) is already in progress`) - -func deleteAllContainers(t assert.TestingT, apiclient client.ContainerAPIClient, protectedContainers map[string]struct{}) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - ctx := context.Background() - containers := getAllContainers(ctx, t, apiclient) - if len(containers) == 0 { - return - } - - for _, container := range containers { - if _, ok := protectedContainers[container.ID]; ok { - continue - } - err := apiclient.ContainerRemove(ctx, container.ID, types.ContainerRemoveOptions{ - Force: true, - RemoveVolumes: true, - }) - if err == nil || client.IsErrNotFound(err) || alreadyExists.MatchString(err.Error()) || isErrNotFoundSwarmClassic(err) { - continue - } - assert.Check(t, err, "failed to remove %s", container.ID) - } -} - -func getAllContainers(ctx context.Context, t assert.TestingT, client client.ContainerAPIClient) []types.Container { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - containers, err := client.ContainerList(ctx, types.ContainerListOptions{ - Quiet: true, - All: true, - }) - assert.Check(t, err, "failed to list containers") - return containers -} - -func deleteAllImages(t assert.TestingT, apiclient client.ImageAPIClient, protectedImages map[string]struct{}) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - images, err := apiclient.ImageList(context.Background(), types.ImageListOptions{}) - assert.Check(t, err, "failed to list images") - - ctx := context.Background() - for _, image := range images { - tags := tagsFromImageSummary(image) - if len(tags) == 0 { - removeImage(ctx, t, apiclient, image.ID) - continue - } - for _, tag := range tags { - if _, ok := protectedImages[tag]; !ok { - removeImage(ctx, t, apiclient, tag) - } - } - } -} - -func removeImage(ctx context.Context, t assert.TestingT, apiclient client.ImageAPIClient, ref string) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - _, err := apiclient.ImageRemove(ctx, ref, types.ImageRemoveOptions{ - Force: true, - }) - if client.IsErrNotFound(err) { - return - } - assert.Check(t, err, "failed to remove image %s", ref) -} - -func deleteAllVolumes(t assert.TestingT, c client.VolumeAPIClient, protectedVolumes map[string]struct{}) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - volumes, err := c.VolumeList(context.Background(), filters.Args{}) - assert.Check(t, err, "failed to list volumes") - - for _, v := range volumes.Volumes { - if _, ok := protectedVolumes[v.Name]; ok { - continue - } - err := c.VolumeRemove(context.Background(), v.Name, true) - // Docker EE may list volumes that no longer exist. - if isErrNotFoundSwarmClassic(err) { - continue - } - assert.Check(t, err, "failed to remove volume %s", v.Name) - } -} - -func deleteAllNetworks(t assert.TestingT, c client.NetworkAPIClient, daemonPlatform string, protectedNetworks map[string]struct{}) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - networks, err := c.NetworkList(context.Background(), types.NetworkListOptions{}) - assert.Check(t, err, "failed to list networks") - - for _, n := range networks { - if n.Name == "bridge" || n.Name == "none" || n.Name == "host" { - continue - } - if _, ok := protectedNetworks[n.ID]; ok { - continue - } - if daemonPlatform == "windows" && strings.ToLower(n.Name) == "nat" { - // nat is a pre-defined network on Windows and cannot be removed - continue - } - err := c.NetworkRemove(context.Background(), n.ID) - assert.Check(t, err, "failed to remove network %s", n.ID) - } -} - -func deleteAllPlugins(t assert.TestingT, c client.PluginAPIClient, protectedPlugins map[string]struct{}) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - plugins, err := c.PluginList(context.Background(), filters.Args{}) - // Docker EE does not allow cluster-wide plugin management. - if client.IsErrNotImplemented(err) { - return - } - assert.Check(t, err, "failed to list plugins") - - for _, p := range plugins { - if _, ok := protectedPlugins[p.Name]; ok { - continue - } - err := c.PluginRemove(context.Background(), p.Name, types.PluginRemoveOptions{Force: true}) - assert.Check(t, err, "failed to remove plugin %s", p.ID) - } -} - -// Swarm classic aggregates node errors and returns a 500 so we need to check -// the error string instead of just IsErrNotFound(). -func isErrNotFoundSwarmClassic(err error) bool { - return err != nil && strings.Contains(strings.ToLower(err.Error()), "no such") -} diff --git a/internal/test/environment/environment.go b/internal/test/environment/environment.go deleted file mode 100644 index 3310590e7c..0000000000 --- a/internal/test/environment/environment.go +++ /dev/null @@ -1,195 +0,0 @@ -package environment // import "github.com/docker/docker/internal/test/environment" - -import ( - "context" - "fmt" - "os" - "path/filepath" - "strings" - - "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/filters" - "github.com/docker/docker/client" - "github.com/docker/docker/internal/test" - "github.com/docker/docker/internal/test/fixtures/load" - "github.com/pkg/errors" - "gotest.tools/assert" -) - -// Execution contains information about the current test execution and daemon -// under test -type Execution struct { - client client.APIClient - DaemonInfo types.Info - OSType string - PlatformDefaults PlatformDefaults - protectedElements protectedElements -} - -// PlatformDefaults are defaults values for the platform of the daemon under test -type PlatformDefaults struct { - BaseImage string - VolumesConfigPath string - ContainerStoragePath string -} - -// New creates a new Execution struct -// This is configured useing the env client (see client.FromEnv) -func New() (*Execution, error) { - c, err := client.NewClientWithOpts(client.FromEnv) - if err != nil { - return nil, errors.Wrapf(err, "failed to create client") - } - return FromClient(c) -} - -// FromClient creates a new Execution environment from the passed in client -func FromClient(c *client.Client) (*Execution, error) { - info, err := c.Info(context.Background()) - if err != nil { - return nil, errors.Wrapf(err, "failed to get info from daemon") - } - - osType := getOSType(info) - - return &Execution{ - client: c, - DaemonInfo: info, - OSType: osType, - PlatformDefaults: getPlatformDefaults(info, osType), - protectedElements: newProtectedElements(), - }, nil -} - -func getOSType(info types.Info) string { - // Docker EE does not set the OSType so allow the user to override this value. - userOsType := os.Getenv("TEST_OSTYPE") - if userOsType != "" { - return userOsType - } - return info.OSType -} - -func getPlatformDefaults(info types.Info, osType string) PlatformDefaults { - volumesPath := filepath.Join(info.DockerRootDir, "volumes") - containersPath := filepath.Join(info.DockerRootDir, "containers") - - switch osType { - case "linux": - return PlatformDefaults{ - BaseImage: "scratch", - VolumesConfigPath: toSlash(volumesPath), - ContainerStoragePath: toSlash(containersPath), - } - case "windows": - baseImage := "microsoft/windowsservercore" - if overrideBaseImage := os.Getenv("WINDOWS_BASE_IMAGE"); overrideBaseImage != "" { - baseImage = overrideBaseImage - if overrideBaseImageTag := os.Getenv("WINDOWS_BASE_IMAGE_TAG"); overrideBaseImageTag != "" { - baseImage = baseImage + ":" + overrideBaseImageTag - } - } - fmt.Println("INFO: Windows Base image is ", baseImage) - return PlatformDefaults{ - BaseImage: baseImage, - VolumesConfigPath: filepath.FromSlash(volumesPath), - ContainerStoragePath: filepath.FromSlash(containersPath), - } - default: - panic(fmt.Sprintf("unknown OSType for daemon: %s", osType)) - } -} - -// Make sure in context of daemon, not the local platform. Note we can't -// use filepath.FromSlash or ToSlash here as they are a no-op on Unix. -func toSlash(path string) string { - return strings.Replace(path, `\`, `/`, -1) -} - -// IsLocalDaemon is true if the daemon under test is on the same -// host as the test process. -// -// Deterministically working out the environment in which CI is running -// to evaluate whether the daemon is local or remote is not possible through -// a build tag. -// -// For example Windows to Linux CI under Jenkins tests the 64-bit -// Windows binary build with the daemon build tag, but calls a remote -// Linux daemon. -// -// We can't just say if Windows then assume the daemon is local as at -// some point, we will be testing the Windows CLI against a Windows daemon. -// -// Similarly, it will be perfectly valid to also run CLI tests from -// a Linux CLI (built with the daemon tag) against a Windows daemon. -func (e *Execution) IsLocalDaemon() bool { - return os.Getenv("DOCKER_REMOTE_DAEMON") == "" -} - -// IsRemoteDaemon is true if the daemon under test is on different host -// as the test process. -func (e *Execution) IsRemoteDaemon() bool { - return !e.IsLocalDaemon() -} - -// DaemonAPIVersion returns the negotiated daemon api version -func (e *Execution) DaemonAPIVersion() string { - version, err := e.APIClient().ServerVersion(context.TODO()) - if err != nil { - return "" - } - return version.APIVersion -} - -// Print the execution details to stdout -// TODO: print everything -func (e *Execution) Print() { - if e.IsLocalDaemon() { - fmt.Println("INFO: Testing against a local daemon") - } else { - fmt.Println("INFO: Testing against a remote daemon") - } -} - -// APIClient returns an APIClient connected to the daemon under test -func (e *Execution) APIClient() client.APIClient { - return e.client -} - -// IsUserNamespace returns whether the user namespace remapping is enabled -func (e *Execution) IsUserNamespace() bool { - root := os.Getenv("DOCKER_REMAP_ROOT") - return root != "" -} - -// HasExistingImage checks whether there is an image with the given reference. -// Note that this is done by filtering and then checking whether there were any -// results -- so ambiguous references might result in false-positives. -func (e *Execution) HasExistingImage(t assert.TestingT, reference string) bool { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - client := e.APIClient() - filter := filters.NewArgs() - filter.Add("dangling", "false") - filter.Add("reference", reference) - imageList, err := client.ImageList(context.Background(), types.ImageListOptions{ - All: true, - Filters: filter, - }) - assert.NilError(t, err, "failed to list images") - - return len(imageList) > 0 -} - -// EnsureFrozenImagesLinux loads frozen test images into the daemon -// if they aren't already loaded -func EnsureFrozenImagesLinux(testEnv *Execution) error { - if testEnv.OSType == "linux" { - err := load.FrozenImagesLinux(testEnv.APIClient(), frozenImages...) - if err != nil { - return errors.Wrap(err, "error loading frozen images") - } - } - return nil -} diff --git a/internal/test/environment/protect.go b/internal/test/environment/protect.go deleted file mode 100644 index a47ea3c2fd..0000000000 --- a/internal/test/environment/protect.go +++ /dev/null @@ -1,254 +0,0 @@ -package environment // import "github.com/docker/docker/internal/test/environment" - -import ( - "context" - - "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/filters" - dclient "github.com/docker/docker/client" - "github.com/docker/docker/internal/test" - "gotest.tools/assert" -) - -var frozenImages = []string{"busybox:latest", "busybox:glibc", "hello-world:frozen", "debian:jessie"} - -type protectedElements struct { - containers map[string]struct{} - images map[string]struct{} - networks map[string]struct{} - plugins map[string]struct{} - volumes map[string]struct{} -} - -func newProtectedElements() protectedElements { - return protectedElements{ - containers: map[string]struct{}{}, - images: map[string]struct{}{}, - networks: map[string]struct{}{}, - plugins: map[string]struct{}{}, - volumes: map[string]struct{}{}, - } -} - -// ProtectAll protects the existing environment (containers, images, networks, -// volumes, and, on Linux, plugins) from being cleaned up at the end of test -// runs -func ProtectAll(t assert.TestingT, testEnv *Execution) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - ProtectContainers(t, testEnv) - ProtectImages(t, testEnv) - ProtectNetworks(t, testEnv) - ProtectVolumes(t, testEnv) - if testEnv.OSType == "linux" { - ProtectPlugins(t, testEnv) - } -} - -// ProtectContainer adds the specified container(s) to be protected in case of -// clean -func (e *Execution) ProtectContainer(t assert.TestingT, containers ...string) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - for _, container := range containers { - e.protectedElements.containers[container] = struct{}{} - } -} - -// ProtectContainers protects existing containers from being cleaned up at the -// end of test runs -func ProtectContainers(t assert.TestingT, testEnv *Execution) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - containers := getExistingContainers(t, testEnv) - testEnv.ProtectContainer(t, containers...) -} - -func getExistingContainers(t assert.TestingT, testEnv *Execution) []string { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - client := testEnv.APIClient() - containerList, err := client.ContainerList(context.Background(), types.ContainerListOptions{ - All: true, - }) - assert.NilError(t, err, "failed to list containers") - - var containers []string - for _, container := range containerList { - containers = append(containers, container.ID) - } - return containers -} - -// ProtectImage adds the specified image(s) to be protected in case of clean -func (e *Execution) ProtectImage(t assert.TestingT, images ...string) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - for _, image := range images { - e.protectedElements.images[image] = struct{}{} - } -} - -// ProtectImages protects existing images and on linux frozen images from being -// cleaned up at the end of test runs -func ProtectImages(t assert.TestingT, testEnv *Execution) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - images := getExistingImages(t, testEnv) - - if testEnv.OSType == "linux" { - images = append(images, frozenImages...) - } - testEnv.ProtectImage(t, images...) -} - -func getExistingImages(t assert.TestingT, testEnv *Execution) []string { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - client := testEnv.APIClient() - filter := filters.NewArgs() - filter.Add("dangling", "false") - imageList, err := client.ImageList(context.Background(), types.ImageListOptions{ - All: true, - Filters: filter, - }) - assert.NilError(t, err, "failed to list images") - - var images []string - for _, image := range imageList { - images = append(images, tagsFromImageSummary(image)...) - } - return images -} - -func tagsFromImageSummary(image types.ImageSummary) []string { - var result []string - for _, tag := range image.RepoTags { - if tag != "<none>:<none>" { - result = append(result, tag) - } - } - for _, digest := range image.RepoDigests { - if digest != "<none>@<none>" { - result = append(result, digest) - } - } - return result -} - -// ProtectNetwork adds the specified network(s) to be protected in case of -// clean -func (e *Execution) ProtectNetwork(t assert.TestingT, networks ...string) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - for _, network := range networks { - e.protectedElements.networks[network] = struct{}{} - } -} - -// ProtectNetworks protects existing networks from being cleaned up at the end -// of test runs -func ProtectNetworks(t assert.TestingT, testEnv *Execution) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - networks := getExistingNetworks(t, testEnv) - testEnv.ProtectNetwork(t, networks...) -} - -func getExistingNetworks(t assert.TestingT, testEnv *Execution) []string { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - client := testEnv.APIClient() - networkList, err := client.NetworkList(context.Background(), types.NetworkListOptions{}) - assert.NilError(t, err, "failed to list networks") - - var networks []string - for _, network := range networkList { - networks = append(networks, network.ID) - } - return networks -} - -// ProtectPlugin adds the specified plugin(s) to be protected in case of clean -func (e *Execution) ProtectPlugin(t assert.TestingT, plugins ...string) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - for _, plugin := range plugins { - e.protectedElements.plugins[plugin] = struct{}{} - } -} - -// ProtectPlugins protects existing plugins from being cleaned up at the end of -// test runs -func ProtectPlugins(t assert.TestingT, testEnv *Execution) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - plugins := getExistingPlugins(t, testEnv) - testEnv.ProtectPlugin(t, plugins...) -} - -func getExistingPlugins(t assert.TestingT, testEnv *Execution) []string { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - client := testEnv.APIClient() - pluginList, err := client.PluginList(context.Background(), filters.Args{}) - // Docker EE does not allow cluster-wide plugin management. - if dclient.IsErrNotImplemented(err) { - return []string{} - } - assert.NilError(t, err, "failed to list plugins") - - var plugins []string - for _, plugin := range pluginList { - plugins = append(plugins, plugin.Name) - } - return plugins -} - -// ProtectVolume adds the specified volume(s) to be protected in case of clean -func (e *Execution) ProtectVolume(t assert.TestingT, volumes ...string) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - for _, volume := range volumes { - e.protectedElements.volumes[volume] = struct{}{} - } -} - -// ProtectVolumes protects existing volumes from being cleaned up at the end of -// test runs -func ProtectVolumes(t assert.TestingT, testEnv *Execution) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - volumes := getExistingVolumes(t, testEnv) - testEnv.ProtectVolume(t, volumes...) -} - -func getExistingVolumes(t assert.TestingT, testEnv *Execution) []string { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - client := testEnv.APIClient() - volumeList, err := client.VolumeList(context.Background(), filters.Args{}) - assert.NilError(t, err, "failed to list volumes") - - var volumes []string - for _, volume := range volumeList.Volumes { - volumes = append(volumes, volume.Name) - } - return volumes -} diff --git a/internal/test/fakecontext/context.go b/internal/test/fakecontext/context.go deleted file mode 100644 index 8b11da207e..0000000000 --- a/internal/test/fakecontext/context.go +++ /dev/null @@ -1,131 +0,0 @@ -package fakecontext // import "github.com/docker/docker/internal/test/fakecontext" - -import ( - "bytes" - "io" - "io/ioutil" - "os" - "path/filepath" - - "github.com/docker/docker/internal/test" - "github.com/docker/docker/pkg/archive" -) - -type testingT interface { - Fatal(args ...interface{}) - Fatalf(string, ...interface{}) -} - -// New creates a fake build context -func New(t testingT, dir string, modifiers ...func(*Fake) error) *Fake { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - fakeContext := &Fake{Dir: dir} - if dir == "" { - if err := newDir(fakeContext); err != nil { - t.Fatal(err) - } - } - - for _, modifier := range modifiers { - if err := modifier(fakeContext); err != nil { - t.Fatal(err) - } - } - - return fakeContext -} - -func newDir(fake *Fake) error { - tmp, err := ioutil.TempDir("", "fake-context") - if err != nil { - return err - } - if err := os.Chmod(tmp, 0755); err != nil { - return err - } - fake.Dir = tmp - return nil -} - -// WithFile adds the specified file (with content) in the build context -func WithFile(name, content string) func(*Fake) error { - return func(ctx *Fake) error { - return ctx.Add(name, content) - } -} - -// WithDockerfile adds the specified content as Dockerfile in the build context -func WithDockerfile(content string) func(*Fake) error { - return WithFile("Dockerfile", content) -} - -// WithFiles adds the specified files in the build context, content is a string -func WithFiles(files map[string]string) func(*Fake) error { - return func(fakeContext *Fake) error { - for file, content := range files { - if err := fakeContext.Add(file, content); err != nil { - return err - } - } - return nil - } -} - -// WithBinaryFiles adds the specified files in the build context, content is binary -func WithBinaryFiles(files map[string]*bytes.Buffer) func(*Fake) error { - return func(fakeContext *Fake) error { - for file, content := range files { - if err := fakeContext.Add(file, content.String()); err != nil { - return err - } - } - return nil - } -} - -// Fake creates directories that can be used as a build context -type Fake struct { - Dir string -} - -// Add a file at a path, creating directories where necessary -func (f *Fake) Add(file, content string) error { - return f.addFile(file, []byte(content)) -} - -func (f *Fake) addFile(file string, content []byte) error { - fp := filepath.Join(f.Dir, filepath.FromSlash(file)) - dirpath := filepath.Dir(fp) - if dirpath != "." { - if err := os.MkdirAll(dirpath, 0755); err != nil { - return err - } - } - return ioutil.WriteFile(fp, content, 0644) - -} - -// Delete a file at a path -func (f *Fake) Delete(file string) error { - fp := filepath.Join(f.Dir, filepath.FromSlash(file)) - return os.RemoveAll(fp) -} - -// Close deletes the context -func (f *Fake) Close() error { - return os.RemoveAll(f.Dir) -} - -// AsTarReader returns a ReadCloser with the contents of Dir as a tar archive. -func (f *Fake) AsTarReader(t testingT) io.ReadCloser { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - reader, err := archive.TarWithOptions(f.Dir, &archive.TarOptions{}) - if err != nil { - t.Fatalf("Failed to create tar from %s: %s", f.Dir, err) - } - return reader -} diff --git a/internal/test/fakegit/fakegit.go b/internal/test/fakegit/fakegit.go deleted file mode 100644 index 30de769743..0000000000 --- a/internal/test/fakegit/fakegit.go +++ /dev/null @@ -1,136 +0,0 @@ -package fakegit // import "github.com/docker/docker/internal/test/fakegit" - -import ( - "fmt" - "io/ioutil" - "net/http" - "net/http/httptest" - "os" - "os/exec" - "path/filepath" - - "github.com/docker/docker/internal/test" - "github.com/docker/docker/internal/test/fakecontext" - "github.com/docker/docker/internal/test/fakestorage" - "gotest.tools/assert" -) - -type testingT interface { - assert.TestingT - logT - skipT - Fatal(args ...interface{}) - Fatalf(string, ...interface{}) -} - -type logT interface { - Logf(string, ...interface{}) -} - -type skipT interface { - Skip(...interface{}) -} - -type gitServer interface { - URL() string - Close() error -} - -type localGitServer struct { - *httptest.Server -} - -func (r *localGitServer) Close() error { - r.Server.Close() - return nil -} - -func (r *localGitServer) URL() string { - return r.Server.URL -} - -// FakeGit is a fake git server -type FakeGit struct { - root string - server gitServer - RepoURL string -} - -// Close closes the server, implements Closer interface -func (g *FakeGit) Close() { - g.server.Close() - os.RemoveAll(g.root) -} - -// New create a fake git server that can be used for git related tests -func New(c testingT, name string, files map[string]string, enforceLocalServer bool) *FakeGit { - if ht, ok := c.(test.HelperT); ok { - ht.Helper() - } - ctx := fakecontext.New(c, "", fakecontext.WithFiles(files)) - defer ctx.Close() - curdir, err := os.Getwd() - if err != nil { - c.Fatal(err) - } - defer os.Chdir(curdir) - - if output, err := exec.Command("git", "init", ctx.Dir).CombinedOutput(); err != nil { - c.Fatalf("error trying to init repo: %s (%s)", err, output) - } - err = os.Chdir(ctx.Dir) - if err != nil { - c.Fatal(err) - } - if output, err := exec.Command("git", "config", "user.name", "Fake User").CombinedOutput(); err != nil { - c.Fatalf("error trying to set 'user.name': %s (%s)", err, output) - } - if output, err := exec.Command("git", "config", "user.email", "fake.user@example.com").CombinedOutput(); err != nil { - c.Fatalf("error trying to set 'user.email': %s (%s)", err, output) - } - if output, err := exec.Command("git", "add", "*").CombinedOutput(); err != nil { - c.Fatalf("error trying to add files to repo: %s (%s)", err, output) - } - if output, err := exec.Command("git", "commit", "-a", "-m", "Initial commit").CombinedOutput(); err != nil { - c.Fatalf("error trying to commit to repo: %s (%s)", err, output) - } - - root, err := ioutil.TempDir("", "docker-test-git-repo") - if err != nil { - c.Fatal(err) - } - repoPath := filepath.Join(root, name+".git") - if output, err := exec.Command("git", "clone", "--bare", ctx.Dir, repoPath).CombinedOutput(); err != nil { - os.RemoveAll(root) - c.Fatalf("error trying to clone --bare: %s (%s)", err, output) - } - err = os.Chdir(repoPath) - if err != nil { - os.RemoveAll(root) - c.Fatal(err) - } - if output, err := exec.Command("git", "update-server-info").CombinedOutput(); err != nil { - os.RemoveAll(root) - c.Fatalf("error trying to git update-server-info: %s (%s)", err, output) - } - err = os.Chdir(curdir) - if err != nil { - os.RemoveAll(root) - c.Fatal(err) - } - - var server gitServer - if !enforceLocalServer { - // use fakeStorage server, which might be local or remote (at test daemon) - server = fakestorage.New(c, root) - } else { - // always start a local http server on CLI test machine - httpServer := httptest.NewServer(http.FileServer(http.Dir(root))) - server = &localGitServer{httpServer} - } - return &FakeGit{ - root: root, - server: server, - RepoURL: fmt.Sprintf("%s/%s.git", server.URL(), name), - } -} diff --git a/internal/test/fakestorage/fixtures.go b/internal/test/fakestorage/fixtures.go deleted file mode 100644 index ad8f763143..0000000000 --- a/internal/test/fakestorage/fixtures.go +++ /dev/null @@ -1,92 +0,0 @@ -package fakestorage // import "github.com/docker/docker/internal/test/fakestorage" - -import ( - "context" - "io" - "io/ioutil" - "os" - "os/exec" - "path/filepath" - "sync" - - "github.com/docker/docker/api/types" - "github.com/docker/docker/internal/test" - "github.com/docker/docker/pkg/archive" - "gotest.tools/assert" -) - -var ensureHTTPServerOnce sync.Once - -func ensureHTTPServerImage(t testingT) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - var doIt bool - ensureHTTPServerOnce.Do(func() { - doIt = true - }) - - if !doIt { - return - } - - defer testEnv.ProtectImage(t, "httpserver:latest") - - tmp, err := ioutil.TempDir("", "docker-http-server-test") - if err != nil { - t.Fatalf("could not build http server: %v", err) - } - defer os.RemoveAll(tmp) - - goos := testEnv.OSType - if goos == "" { - goos = "linux" - } - goarch := os.Getenv("DOCKER_ENGINE_GOARCH") - if goarch == "" { - goarch = "amd64" - } - - cpCmd, lookErr := exec.LookPath("cp") - if lookErr != nil { - t.Fatalf("could not build http server: %v", lookErr) - } - - if _, err = os.Stat("../contrib/httpserver/httpserver"); os.IsNotExist(err) { - goCmd, lookErr := exec.LookPath("go") - if lookErr != nil { - t.Fatalf("could not build http server: %v", lookErr) - } - - cmd := exec.Command(goCmd, "build", "-o", filepath.Join(tmp, "httpserver"), "github.com/docker/docker/contrib/httpserver") - cmd.Env = append(os.Environ(), []string{ - "CGO_ENABLED=0", - "GOOS=" + goos, - "GOARCH=" + goarch, - }...) - var out []byte - if out, err = cmd.CombinedOutput(); err != nil { - t.Fatalf("could not build http server: %s", string(out)) - } - } else { - if out, err := exec.Command(cpCmd, "../contrib/httpserver/httpserver", filepath.Join(tmp, "httpserver")).CombinedOutput(); err != nil { - t.Fatalf("could not copy http server: %v", string(out)) - } - } - - if out, err := exec.Command(cpCmd, "../contrib/httpserver/Dockerfile", filepath.Join(tmp, "Dockerfile")).CombinedOutput(); err != nil { - t.Fatalf("could not build http server: %v", string(out)) - } - - c := testEnv.APIClient() - reader, err := archive.TarWithOptions(tmp, &archive.TarOptions{}) - assert.NilError(t, err) - resp, err := c.ImageBuild(context.Background(), reader, types.ImageBuildOptions{ - Remove: true, - ForceRemove: true, - Tags: []string{"httpserver"}, - }) - assert.NilError(t, err) - _, err = io.Copy(ioutil.Discard, resp.Body) - assert.NilError(t, err) -} diff --git a/internal/test/fakestorage/storage.go b/internal/test/fakestorage/storage.go deleted file mode 100644 index e229fd0813..0000000000 --- a/internal/test/fakestorage/storage.go +++ /dev/null @@ -1,200 +0,0 @@ -package fakestorage // import "github.com/docker/docker/internal/test/fakestorage" - -import ( - "context" - "fmt" - "io" - "io/ioutil" - "net/http" - "net/http/httptest" - "net/url" - "os" - "strings" - - "github.com/docker/docker/api/types" - containertypes "github.com/docker/docker/api/types/container" - "github.com/docker/docker/client" - "github.com/docker/docker/internal/test" - "github.com/docker/docker/internal/test/environment" - "github.com/docker/docker/internal/test/fakecontext" - "github.com/docker/docker/internal/test/request" - "github.com/docker/docker/internal/testutil" - "github.com/docker/go-connections/nat" - "gotest.tools/assert" -) - -var testEnv *environment.Execution - -type testingT interface { - assert.TestingT - logT - skipT - Fatal(args ...interface{}) - Fatalf(string, ...interface{}) -} - -type logT interface { - Logf(string, ...interface{}) -} - -type skipT interface { - Skip(...interface{}) -} - -// Fake is a static file server. It might be running locally or remotely -// on test host. -type Fake interface { - Close() error - URL() string - CtxDir() string -} - -// SetTestEnvironment sets a static test environment -// TODO: decouple this package from environment -func SetTestEnvironment(env *environment.Execution) { - testEnv = env -} - -// New returns a static file server that will be use as build context. -func New(t testingT, dir string, modifiers ...func(*fakecontext.Fake) error) Fake { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - if testEnv == nil { - t.Fatal("fakstorage package requires SetTestEnvironment() to be called before use.") - } - ctx := fakecontext.New(t, dir, modifiers...) - switch { - case testEnv.IsRemoteDaemon() && strings.HasPrefix(request.DaemonHost(), "unix:///"): - t.Skip("e2e run : daemon is remote but docker host points to a unix socket") - case testEnv.IsLocalDaemon(): - return newLocalFakeStorage(ctx) - default: - return newRemoteFileServer(t, ctx, testEnv.APIClient()) - } - return nil -} - -// localFileStorage is a file storage on the running machine -type localFileStorage struct { - *fakecontext.Fake - *httptest.Server -} - -func (s *localFileStorage) URL() string { - return s.Server.URL -} - -func (s *localFileStorage) CtxDir() string { - return s.Fake.Dir -} - -func (s *localFileStorage) Close() error { - defer s.Server.Close() - return s.Fake.Close() -} - -func newLocalFakeStorage(ctx *fakecontext.Fake) *localFileStorage { - handler := http.FileServer(http.Dir(ctx.Dir)) - server := httptest.NewServer(handler) - return &localFileStorage{ - Fake: ctx, - Server: server, - } -} - -// remoteFileServer is a containerized static file server started on the remote -// testing machine to be used in URL-accepting docker build functionality. -type remoteFileServer struct { - host string // hostname/port web server is listening to on docker host e.g. 0.0.0.0:43712 - container string - image string - client client.APIClient - ctx *fakecontext.Fake -} - -func (f *remoteFileServer) URL() string { - u := url.URL{ - Scheme: "http", - Host: f.host} - return u.String() -} - -func (f *remoteFileServer) CtxDir() string { - return f.ctx.Dir -} - -func (f *remoteFileServer) Close() error { - defer func() { - if f.ctx != nil { - f.ctx.Close() - } - if f.image != "" { - if _, err := f.client.ImageRemove(context.Background(), f.image, types.ImageRemoveOptions{ - Force: true, - }); err != nil { - fmt.Fprintf(os.Stderr, "Error closing remote file server : %v\n", err) - } - } - if err := f.client.Close(); err != nil { - fmt.Fprintf(os.Stderr, "Error closing remote file server : %v\n", err) - } - }() - if f.container == "" { - return nil - } - return f.client.ContainerRemove(context.Background(), f.container, types.ContainerRemoveOptions{ - Force: true, - RemoveVolumes: true, - }) -} - -func newRemoteFileServer(t testingT, ctx *fakecontext.Fake, c client.APIClient) *remoteFileServer { - var ( - image = fmt.Sprintf("fileserver-img-%s", strings.ToLower(testutil.GenerateRandomAlphaOnlyString(10))) - container = fmt.Sprintf("fileserver-cnt-%s", strings.ToLower(testutil.GenerateRandomAlphaOnlyString(10))) - ) - - ensureHTTPServerImage(t) - - // Build the image - if err := ctx.Add("Dockerfile", `FROM httpserver -COPY . /static`); err != nil { - t.Fatal(err) - } - resp, err := c.ImageBuild(context.Background(), ctx.AsTarReader(t), types.ImageBuildOptions{ - NoCache: true, - Tags: []string{image}, - }) - assert.NilError(t, err) - _, err = io.Copy(ioutil.Discard, resp.Body) - assert.NilError(t, err) - - // Start the container - b, err := c.ContainerCreate(context.Background(), &containertypes.Config{ - Image: image, - }, &containertypes.HostConfig{}, nil, container) - assert.NilError(t, err) - err = c.ContainerStart(context.Background(), b.ID, types.ContainerStartOptions{}) - assert.NilError(t, err) - - // Find out the system assigned port - i, err := c.ContainerInspect(context.Background(), b.ID) - assert.NilError(t, err) - newP, err := nat.NewPort("tcp", "80") - assert.NilError(t, err) - ports, exists := i.NetworkSettings.Ports[newP] - if !exists || len(ports) != 1 { - t.Fatalf("unable to find port 80/tcp for %s", container) - } - host := ports[0].HostIP - port := ports[0].HostPort - - return &remoteFileServer{ - container: container, - image: image, - host: fmt.Sprintf("%s:%s", host, port), - ctx: ctx, - client: c, - } -} diff --git a/internal/test/fixtures/load/frozen.go b/internal/test/fixtures/load/frozen.go deleted file mode 100644 index 94f3680f95..0000000000 --- a/internal/test/fixtures/load/frozen.go +++ /dev/null @@ -1,196 +0,0 @@ -package load // import "github.com/docker/docker/internal/test/fixtures/load" - -import ( - "bufio" - "bytes" - "context" - "os" - "os/exec" - "path/filepath" - "strings" - "sync" - - "github.com/docker/docker/api/types" - "github.com/docker/docker/client" - "github.com/docker/docker/pkg/jsonmessage" - "github.com/docker/docker/pkg/term" - "github.com/pkg/errors" -) - -const frozenImgDir = "/docker-frozen-images" - -// FrozenImagesLinux loads the frozen image set for the integration suite -// If the images are not available locally it will download them -// TODO: This loads whatever is in the frozen image dir, regardless of what -// images were passed in. If the images need to be downloaded, then it will respect -// the passed in images -func FrozenImagesLinux(client client.APIClient, images ...string) error { - var loadImages []struct{ srcName, destName string } - for _, img := range images { - if !imageExists(client, img) { - srcName := img - // hello-world:latest gets re-tagged as hello-world:frozen - // there are some tests that use hello-world:latest specifically so it pulls - // the image and hello-world:frozen is used for when we just want a super - // small image - if img == "hello-world:frozen" { - srcName = "hello-world:latest" - } - loadImages = append(loadImages, struct{ srcName, destName string }{ - srcName: srcName, - destName: img, - }) - } - } - if len(loadImages) == 0 { - // everything is loaded, we're done - return nil - } - - ctx := context.Background() - fi, err := os.Stat(frozenImgDir) - if err != nil || !fi.IsDir() { - srcImages := make([]string, 0, len(loadImages)) - for _, img := range loadImages { - srcImages = append(srcImages, img.srcName) - } - if err := pullImages(ctx, client, srcImages); err != nil { - return errors.Wrap(err, "error pulling image list") - } - } else { - if err := loadFrozenImages(ctx, client); err != nil { - return err - } - } - - for _, img := range loadImages { - if img.srcName != img.destName { - if err := client.ImageTag(ctx, img.srcName, img.destName); err != nil { - return errors.Wrapf(err, "failed to tag %s as %s", img.srcName, img.destName) - } - if _, err := client.ImageRemove(ctx, img.srcName, types.ImageRemoveOptions{}); err != nil { - return errors.Wrapf(err, "failed to remove %s", img.srcName) - } - } - } - return nil -} - -func imageExists(client client.APIClient, name string) bool { - _, _, err := client.ImageInspectWithRaw(context.Background(), name) - return err == nil -} - -func loadFrozenImages(ctx context.Context, client client.APIClient) error { - tar, err := exec.LookPath("tar") - if err != nil { - return errors.Wrap(err, "could not find tar binary") - } - tarCmd := exec.Command(tar, "-cC", frozenImgDir, ".") - out, err := tarCmd.StdoutPipe() - if err != nil { - return errors.Wrap(err, "error getting stdout pipe for tar command") - } - - errBuf := bytes.NewBuffer(nil) - tarCmd.Stderr = errBuf - tarCmd.Start() - defer tarCmd.Wait() - - resp, err := client.ImageLoad(ctx, out, true) - if err != nil { - return errors.Wrap(err, "failed to load frozen images") - } - defer resp.Body.Close() - fd, isTerminal := term.GetFdInfo(os.Stdout) - return jsonmessage.DisplayJSONMessagesStream(resp.Body, os.Stdout, fd, isTerminal, nil) -} - -func pullImages(ctx context.Context, client client.APIClient, images []string) error { - cwd, err := os.Getwd() - if err != nil { - return errors.Wrap(err, "error getting path to dockerfile") - } - dockerfile := os.Getenv("DOCKERFILE") - if dockerfile == "" { - dockerfile = "Dockerfile" - } - dockerfilePath := filepath.Join(filepath.Dir(filepath.Clean(cwd)), dockerfile) - pullRefs, err := readFrozenImageList(dockerfilePath, images) - if err != nil { - return errors.Wrap(err, "error reading frozen image list") - } - - var wg sync.WaitGroup - chErr := make(chan error, len(images)) - for tag, ref := range pullRefs { - wg.Add(1) - go func(tag, ref string) { - defer wg.Done() - if err := pullTagAndRemove(ctx, client, ref, tag); err != nil { - chErr <- err - return - } - }(tag, ref) - } - wg.Wait() - close(chErr) - return <-chErr -} - -func pullTagAndRemove(ctx context.Context, client client.APIClient, ref string, tag string) error { - resp, err := client.ImagePull(ctx, ref, types.ImagePullOptions{}) - if err != nil { - return errors.Wrapf(err, "failed to pull %s", ref) - } - defer resp.Close() - fd, isTerminal := term.GetFdInfo(os.Stdout) - if err := jsonmessage.DisplayJSONMessagesStream(resp, os.Stdout, fd, isTerminal, nil); err != nil { - return err - } - - if err := client.ImageTag(ctx, ref, tag); err != nil { - return errors.Wrapf(err, "failed to tag %s as %s", ref, tag) - } - _, err = client.ImageRemove(ctx, ref, types.ImageRemoveOptions{}) - return errors.Wrapf(err, "failed to remove %s", ref) - -} - -func readFrozenImageList(dockerfilePath string, images []string) (map[string]string, error) { - f, err := os.Open(dockerfilePath) - if err != nil { - return nil, errors.Wrap(err, "error reading dockerfile") - } - defer f.Close() - ls := make(map[string]string) - - scanner := bufio.NewScanner(f) - for scanner.Scan() { - line := strings.Fields(scanner.Text()) - if len(line) < 3 { - continue - } - if !(line[0] == "RUN" && line[1] == "./contrib/download-frozen-image-v2.sh") { - continue - } - - for scanner.Scan() { - img := strings.TrimSpace(scanner.Text()) - img = strings.TrimSuffix(img, "\\") - img = strings.TrimSpace(img) - split := strings.Split(img, "@") - if len(split) < 2 { - break - } - - for _, i := range images { - if split[0] == i { - ls[i] = img - break - } - } - } - } - return ls, nil -} diff --git a/internal/test/fixtures/plugin/basic/basic.go b/internal/test/fixtures/plugin/basic/basic.go deleted file mode 100644 index 892272826f..0000000000 --- a/internal/test/fixtures/plugin/basic/basic.go +++ /dev/null @@ -1,34 +0,0 @@ -package main - -import ( - "fmt" - "net" - "net/http" - "os" - "path/filepath" -) - -func main() { - p, err := filepath.Abs(filepath.Join("run", "docker", "plugins")) - if err != nil { - panic(err) - } - if err := os.MkdirAll(p, 0755); err != nil { - panic(err) - } - l, err := net.Listen("unix", filepath.Join(p, "basic.sock")) - if err != nil { - panic(err) - } - - mux := http.NewServeMux() - server := http.Server{ - Addr: l.Addr().String(), - Handler: http.NewServeMux(), - } - mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1.1+json") - fmt.Println(w, `{"Implements": ["dummy"]}`) - }) - server.Serve(l) -} diff --git a/internal/test/fixtures/plugin/plugin.go b/internal/test/fixtures/plugin/plugin.go deleted file mode 100644 index 93f5f99fed..0000000000 --- a/internal/test/fixtures/plugin/plugin.go +++ /dev/null @@ -1,216 +0,0 @@ -package plugin // import "github.com/docker/docker/internal/test/fixtures/plugin" - -import ( - "context" - "encoding/json" - "io" - "io/ioutil" - "os" - "os/exec" - "path/filepath" - "time" - - "github.com/docker/docker/api/types" - "github.com/docker/docker/pkg/archive" - "github.com/docker/docker/plugin" - "github.com/docker/docker/registry" - "github.com/pkg/errors" -) - -// CreateOpt is passed used to change the default plugin config before -// creating it -type CreateOpt func(*Config) - -// Config wraps types.PluginConfig to provide some extra state for options -// extra customizations on the plugin details, such as using a custom binary to -// create the plugin with. -type Config struct { - *types.PluginConfig - binPath string -} - -// WithBinary is a CreateOpt to set an custom binary to create the plugin with. -// This binary must be statically compiled. -func WithBinary(bin string) CreateOpt { - return func(cfg *Config) { - cfg.binPath = bin - } -} - -// CreateClient is the interface used for `BuildPlugin` to interact with the -// daemon. -type CreateClient interface { - PluginCreate(context.Context, io.Reader, types.PluginCreateOptions) error -} - -// Create creates a new plugin with the specified name -func Create(ctx context.Context, c CreateClient, name string, opts ...CreateOpt) error { - tmpDir, err := ioutil.TempDir("", "create-test-plugin") - if err != nil { - return err - } - defer os.RemoveAll(tmpDir) - - tar, err := makePluginBundle(tmpDir, opts...) - if err != nil { - return err - } - defer tar.Close() - - ctx, cancel := context.WithTimeout(ctx, 30*time.Second) - defer cancel() - - return c.PluginCreate(ctx, tar, types.PluginCreateOptions{RepoName: name}) -} - -// CreateInRegistry makes a plugin (locally) and pushes it to a registry. -// This does not use a dockerd instance to create or push the plugin. -// If you just want to create a plugin in some daemon, use `Create`. -// -// This can be useful when testing plugins on swarm where you don't really want -// the plugin to exist on any of the daemons (immediately) and there needs to be -// some way to distribute the plugin. -func CreateInRegistry(ctx context.Context, repo string, auth *types.AuthConfig, opts ...CreateOpt) error { - tmpDir, err := ioutil.TempDir("", "create-test-plugin-local") - if err != nil { - return err - } - defer os.RemoveAll(tmpDir) - - inPath := filepath.Join(tmpDir, "plugin") - if err := os.MkdirAll(inPath, 0755); err != nil { - return errors.Wrap(err, "error creating plugin root") - } - - tar, err := makePluginBundle(inPath, opts...) - if err != nil { - return err - } - defer tar.Close() - - dummyExec := func(m *plugin.Manager) (plugin.Executor, error) { - return nil, nil - } - - regService, err := registry.NewService(registry.ServiceOptions{}) - if err != nil { - return err - } - - managerConfig := plugin.ManagerConfig{ - Store: plugin.NewStore(), - RegistryService: regService, - Root: filepath.Join(tmpDir, "root"), - ExecRoot: "/run/docker", // manager init fails if not set - CreateExecutor: dummyExec, - LogPluginEvent: func(id, name, action string) {}, // panics when not set - } - manager, err := plugin.NewManager(managerConfig) - if err != nil { - return errors.Wrap(err, "error creating plugin manager") - } - - ctx, cancel := context.WithTimeout(ctx, 30*time.Second) - defer cancel() - if err := manager.CreateFromContext(ctx, tar, &types.PluginCreateOptions{RepoName: repo}); err != nil { - return err - } - - if auth == nil { - auth = &types.AuthConfig{} - } - err = manager.Push(ctx, repo, nil, auth, ioutil.Discard) - return errors.Wrap(err, "error pushing plugin") -} - -func makePluginBundle(inPath string, opts ...CreateOpt) (io.ReadCloser, error) { - p := &types.PluginConfig{ - Interface: types.PluginConfigInterface{ - Socket: "basic.sock", - Types: []types.PluginInterfaceType{{Capability: "docker.dummy/1.0"}}, - }, - Entrypoint: []string{"/basic"}, - } - cfg := &Config{ - PluginConfig: p, - } - for _, o := range opts { - o(cfg) - } - if cfg.binPath == "" { - binPath, err := ensureBasicPluginBin() - if err != nil { - return nil, err - } - cfg.binPath = binPath - } - - configJSON, err := json.Marshal(p) - if err != nil { - return nil, err - } - if err := ioutil.WriteFile(filepath.Join(inPath, "config.json"), configJSON, 0644); err != nil { - return nil, err - } - if err := os.MkdirAll(filepath.Join(inPath, "rootfs", filepath.Dir(p.Entrypoint[0])), 0755); err != nil { - return nil, errors.Wrap(err, "error creating plugin rootfs dir") - } - - // Ensure the mount target paths exist - for _, m := range p.Mounts { - var stat os.FileInfo - if m.Source != nil { - stat, err = os.Stat(*m.Source) - if err != nil && !os.IsNotExist(err) { - return nil, err - } - } - - if stat == nil || stat.IsDir() { - var mode os.FileMode = 0755 - if stat != nil { - mode = stat.Mode() - } - if err := os.MkdirAll(filepath.Join(inPath, "rootfs", m.Destination), mode); err != nil { - return nil, errors.Wrap(err, "error preparing plugin mount destination path") - } - } else { - if err := os.MkdirAll(filepath.Join(inPath, "rootfs", filepath.Dir(m.Destination)), 0755); err != nil { - return nil, errors.Wrap(err, "error preparing plugin mount destination dir") - } - f, err := os.Create(filepath.Join(inPath, "rootfs", m.Destination)) - if err != nil && !os.IsExist(err) { - return nil, errors.Wrap(err, "error preparing plugin mount destination file") - } - if f != nil { - f.Close() - } - } - } - if err := archive.NewDefaultArchiver().CopyFileWithTar(cfg.binPath, filepath.Join(inPath, "rootfs", p.Entrypoint[0])); err != nil { - return nil, errors.Wrap(err, "error copying plugin binary to rootfs path") - } - tar, err := archive.Tar(inPath, archive.Uncompressed) - return tar, errors.Wrap(err, "error making plugin archive") -} - -func ensureBasicPluginBin() (string, error) { - name := "docker-basic-plugin" - p, err := exec.LookPath(name) - if err == nil { - return p, nil - } - - goBin, err := exec.LookPath("go") - if err != nil { - return "", err - } - installPath := filepath.Join(os.Getenv("GOPATH"), "bin", name) - sourcePath := filepath.Join("github.com", "docker", "docker", "internal", "test", "fixtures", "plugin", "basic") - cmd := exec.Command(goBin, "build", "-o", installPath, sourcePath) - cmd.Env = append(os.Environ(), "CGO_ENABLED=0") - if out, err := cmd.CombinedOutput(); err != nil { - return "", errors.Wrapf(err, "error building basic plugin bin: %s", string(out)) - } - return installPath, nil -} diff --git a/internal/test/helper.go b/internal/test/helper.go deleted file mode 100644 index 1b9fd75090..0000000000 --- a/internal/test/helper.go +++ /dev/null @@ -1,6 +0,0 @@ -package test - -// HelperT is a subset of testing.T that implements the Helper function -type HelperT interface { - Helper() -} diff --git a/internal/test/registry/ops.go b/internal/test/registry/ops.go deleted file mode 100644 index c004f37424..0000000000 --- a/internal/test/registry/ops.go +++ /dev/null @@ -1,26 +0,0 @@ -package registry - -// Schema1 sets the registry to serve v1 api -func Schema1(c *Config) { - c.schema1 = true -} - -// Htpasswd sets the auth method with htpasswd -func Htpasswd(c *Config) { - c.auth = "htpasswd" -} - -// Token sets the auth method to token, with the specified token url -func Token(tokenURL string) func(*Config) { - return func(c *Config) { - c.auth = "token" - c.tokenURL = tokenURL - } -} - -// URL sets the registry url -func URL(registryURL string) func(*Config) { - return func(c *Config) { - c.registryURL = registryURL - } -} diff --git a/internal/test/registry/registry.go b/internal/test/registry/registry.go deleted file mode 100644 index b6128d3ba4..0000000000 --- a/internal/test/registry/registry.go +++ /dev/null @@ -1,255 +0,0 @@ -package registry // import "github.com/docker/docker/internal/test/registry" - -import ( - "fmt" - "io/ioutil" - "net/http" - "os" - "os/exec" - "path/filepath" - "time" - - "github.com/docker/docker/internal/test" - "github.com/opencontainers/go-digest" - "gotest.tools/assert" -) - -const ( - // V2binary is the name of the registry v2 binary - V2binary = "registry-v2" - // V2binarySchema1 is the name of the registry that serve schema1 - V2binarySchema1 = "registry-v2-schema1" - // DefaultURL is the default url that will be used by the registry (if not specified otherwise) - DefaultURL = "127.0.0.1:5000" -) - -type testingT interface { - assert.TestingT - logT - Fatal(...interface{}) - Fatalf(string, ...interface{}) -} - -type logT interface { - Logf(string, ...interface{}) -} - -// V2 represent a registry version 2 -type V2 struct { - cmd *exec.Cmd - registryURL string - dir string - auth string - username string - password string - email string -} - -// Config contains the test registry configuration -type Config struct { - schema1 bool - auth string - tokenURL string - registryURL string -} - -// NewV2 creates a v2 registry server -func NewV2(t testingT, ops ...func(*Config)) *V2 { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - c := &Config{ - registryURL: DefaultURL, - } - for _, op := range ops { - op(c) - } - tmp, err := ioutil.TempDir("", "registry-test-") - assert.NilError(t, err) - template := `version: 0.1 -loglevel: debug -storage: - filesystem: - rootdirectory: %s -http: - addr: %s -%s` - var ( - authTemplate string - username string - password string - email string - ) - switch c.auth { - case "htpasswd": - htpasswdPath := filepath.Join(tmp, "htpasswd") - // generated with: htpasswd -Bbn testuser testpassword - userpasswd := "testuser:$2y$05$sBsSqk0OpSD1uTZkHXc4FeJ0Z70wLQdAX/82UiHuQOKbNbBrzs63m" - username = "testuser" - password = "testpassword" - email = "test@test.org" - err := ioutil.WriteFile(htpasswdPath, []byte(userpasswd), os.FileMode(0644)) - assert.NilError(t, err) - authTemplate = fmt.Sprintf(`auth: - htpasswd: - realm: basic-realm - path: %s -`, htpasswdPath) - case "token": - authTemplate = fmt.Sprintf(`auth: - token: - realm: %s - service: "registry" - issuer: "auth-registry" - rootcertbundle: "fixtures/registry/cert.pem" -`, c.tokenURL) - } - - confPath := filepath.Join(tmp, "config.yaml") - config, err := os.Create(confPath) - assert.NilError(t, err) - defer config.Close() - - if _, err := fmt.Fprintf(config, template, tmp, c.registryURL, authTemplate); err != nil { - // FIXME(vdemeester) use a defer/clean func - os.RemoveAll(tmp) - t.Fatal(err) - } - - binary := V2binary - if c.schema1 { - binary = V2binarySchema1 - } - cmd := exec.Command(binary, confPath) - if err := cmd.Start(); err != nil { - // FIXME(vdemeester) use a defer/clean func - os.RemoveAll(tmp) - t.Fatal(err) - } - return &V2{ - cmd: cmd, - dir: tmp, - auth: c.auth, - username: username, - password: password, - email: email, - registryURL: c.registryURL, - } -} - -// WaitReady waits for the registry to be ready to serve requests (or fail after a while) -func (r *V2) WaitReady(t testingT) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - var err error - for i := 0; i != 50; i++ { - if err = r.Ping(); err == nil { - return - } - time.Sleep(100 * time.Millisecond) - } - t.Fatalf("timeout waiting for test registry to become available: %v", err) -} - -// Ping sends an http request to the current registry, and fail if it doesn't respond correctly -func (r *V2) Ping() error { - // We always ping through HTTP for our test registry. - resp, err := http.Get(fmt.Sprintf("http://%s/v2/", r.registryURL)) - if err != nil { - return err - } - resp.Body.Close() - - fail := resp.StatusCode != http.StatusOK - if r.auth != "" { - // unauthorized is a _good_ status when pinging v2/ and it needs auth - fail = fail && resp.StatusCode != http.StatusUnauthorized - } - if fail { - return fmt.Errorf("registry ping replied with an unexpected status code %d", resp.StatusCode) - } - return nil -} - -// Close kills the registry server -func (r *V2) Close() { - r.cmd.Process.Kill() - r.cmd.Process.Wait() - os.RemoveAll(r.dir) -} - -func (r *V2) getBlobFilename(blobDigest digest.Digest) string { - // Split the digest into its algorithm and hex components. - dgstAlg, dgstHex := blobDigest.Algorithm(), blobDigest.Hex() - - // The path to the target blob data looks something like: - // baseDir + "docker/registry/v2/blobs/sha256/a3/a3ed...46d4/data" - return fmt.Sprintf("%s/docker/registry/v2/blobs/%s/%s/%s/data", r.dir, dgstAlg, dgstHex[:2], dgstHex) -} - -// ReadBlobContents read the file corresponding to the specified digest -func (r *V2) ReadBlobContents(t assert.TestingT, blobDigest digest.Digest) []byte { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - // Load the target manifest blob. - manifestBlob, err := ioutil.ReadFile(r.getBlobFilename(blobDigest)) - assert.NilError(t, err, "unable to read blob") - return manifestBlob -} - -// WriteBlobContents write the file corresponding to the specified digest with the given content -func (r *V2) WriteBlobContents(t assert.TestingT, blobDigest digest.Digest, data []byte) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - err := ioutil.WriteFile(r.getBlobFilename(blobDigest), data, os.FileMode(0644)) - assert.NilError(t, err, "unable to write malicious data blob") -} - -// TempMoveBlobData moves the existing data file aside, so that we can replace it with a -// malicious blob of data for example. -func (r *V2) TempMoveBlobData(t testingT, blobDigest digest.Digest) (undo func()) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - tempFile, err := ioutil.TempFile("", "registry-temp-blob-") - assert.NilError(t, err, "unable to get temporary blob file") - tempFile.Close() - - blobFilename := r.getBlobFilename(blobDigest) - - // Move the existing data file aside, so that we can replace it with a - // another blob of data. - if err := os.Rename(blobFilename, tempFile.Name()); err != nil { - // FIXME(vdemeester) use a defer/clean func - os.Remove(tempFile.Name()) - t.Fatalf("unable to move data blob: %s", err) - } - - return func() { - os.Rename(tempFile.Name(), blobFilename) - os.Remove(tempFile.Name()) - } -} - -// Username returns the configured user name of the server -func (r *V2) Username() string { - return r.username -} - -// Password returns the configured password of the server -func (r *V2) Password() string { - return r.password -} - -// Email returns the configured email of the server -func (r *V2) Email() string { - return r.email -} - -// Path returns the path where the registry write data -func (r *V2) Path() string { - return filepath.Join(r.dir, "docker", "registry", "v2") -} diff --git a/internal/test/registry/registry_mock.go b/internal/test/registry/registry_mock.go deleted file mode 100644 index d139401a62..0000000000 --- a/internal/test/registry/registry_mock.go +++ /dev/null @@ -1,71 +0,0 @@ -package registry // import "github.com/docker/docker/internal/test/registry" - -import ( - "net/http" - "net/http/httptest" - "regexp" - "strings" - "sync" - - "github.com/docker/docker/internal/test" -) - -type handlerFunc func(w http.ResponseWriter, r *http.Request) - -// Mock represent a registry mock -type Mock struct { - server *httptest.Server - hostport string - handlers map[string]handlerFunc - mu sync.Mutex -} - -// RegisterHandler register the specified handler for the registry mock -func (tr *Mock) RegisterHandler(path string, h handlerFunc) { - tr.mu.Lock() - defer tr.mu.Unlock() - tr.handlers[path] = h -} - -// NewMock creates a registry mock -func NewMock(t testingT) (*Mock, error) { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - testReg := &Mock{handlers: make(map[string]handlerFunc)} - - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - url := r.URL.String() - - var matched bool - var err error - for re, function := range testReg.handlers { - matched, err = regexp.MatchString(re, url) - if err != nil { - t.Fatal("Error with handler regexp") - } - if matched { - function(w, r) - break - } - } - - if !matched { - t.Fatalf("Unable to match %s with regexp", url) - } - })) - - testReg.server = ts - testReg.hostport = strings.Replace(ts.URL, "http://", "", 1) - return testReg, nil -} - -// URL returns the url of the registry -func (tr *Mock) URL() string { - return tr.hostport -} - -// Close closes mock and releases resources -func (tr *Mock) Close() { - tr.server.Close() -} diff --git a/internal/test/request/npipe.go b/internal/test/request/npipe.go deleted file mode 100644 index e6ab03945e..0000000000 --- a/internal/test/request/npipe.go +++ /dev/null @@ -1,12 +0,0 @@ -// +build !windows - -package request - -import ( - "net" - "time" -) - -func npipeDial(path string, timeout time.Duration) (net.Conn, error) { - panic("npipe protocol only supported on Windows") -} diff --git a/internal/test/request/npipe_windows.go b/internal/test/request/npipe_windows.go deleted file mode 100644 index a268aac922..0000000000 --- a/internal/test/request/npipe_windows.go +++ /dev/null @@ -1,12 +0,0 @@ -package request - -import ( - "net" - "time" - - "github.com/Microsoft/go-winio" -) - -func npipeDial(path string, timeout time.Duration) (net.Conn, error) { - return winio.DialPipe(path, &timeout) -} diff --git a/internal/test/request/ops.go b/internal/test/request/ops.go deleted file mode 100644 index c85308c476..0000000000 --- a/internal/test/request/ops.go +++ /dev/null @@ -1,78 +0,0 @@ -package request - -import ( - "bytes" - "encoding/json" - "io" - "io/ioutil" - "net/http" - "strings" -) - -// Options defines request options, like request modifiers and which host to target -type Options struct { - host string - requestModifiers []func(*http.Request) error -} - -// Host creates a modifier that sets the specified host as the request URL host -func Host(host string) func(*Options) { - return func(o *Options) { - o.host = host - } -} - -// With adds a request modifier to the options -func With(f func(*http.Request) error) func(*Options) { - return func(o *Options) { - o.requestModifiers = append(o.requestModifiers, f) - } -} - -// Method creates a modifier that sets the specified string as the request method -func Method(method string) func(*Options) { - return With(func(req *http.Request) error { - req.Method = method - return nil - }) -} - -// RawString sets the specified string as body for the request -func RawString(content string) func(*Options) { - return RawContent(ioutil.NopCloser(strings.NewReader(content))) -} - -// RawContent sets the specified reader as body for the request -func RawContent(reader io.ReadCloser) func(*Options) { - return With(func(req *http.Request) error { - req.Body = reader - return nil - }) -} - -// ContentType sets the specified Content-Type request header -func ContentType(contentType string) func(*Options) { - return With(func(req *http.Request) error { - req.Header.Set("Content-Type", contentType) - return nil - }) -} - -// JSON sets the Content-Type request header to json -func JSON(o *Options) { - ContentType("application/json")(o) -} - -// JSONBody creates a modifier that encodes the specified data to a JSON string and set it as request body. It also sets -// the Content-Type header of the request. -func JSONBody(data interface{}) func(*Options) { - return With(func(req *http.Request) error { - jsonData := bytes.NewBuffer(nil) - if err := json.NewEncoder(jsonData).Encode(data); err != nil { - return err - } - req.Body = ioutil.NopCloser(jsonData) - req.Header.Set("Content-Type", "application/json") - return nil - }) -} diff --git a/internal/test/request/request.go b/internal/test/request/request.go deleted file mode 100644 index 6bf70c7437..0000000000 --- a/internal/test/request/request.go +++ /dev/null @@ -1,223 +0,0 @@ -package request // import "github.com/docker/docker/internal/test/request" - -import ( - "context" - "crypto/tls" - "fmt" - "io" - "io/ioutil" - "net" - "net/http" - "net/url" - "os" - "path/filepath" - "time" - - "github.com/docker/docker/client" - "github.com/docker/docker/internal/test" - "github.com/docker/docker/internal/test/environment" - "github.com/docker/docker/opts" - "github.com/docker/docker/pkg/ioutils" - "github.com/docker/go-connections/sockets" - "github.com/docker/go-connections/tlsconfig" - "github.com/pkg/errors" - "gotest.tools/assert" -) - -// NewAPIClient returns a docker API client configured from environment variables -func NewAPIClient(t assert.TestingT, ops ...client.Opt) client.APIClient { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - ops = append([]client.Opt{client.FromEnv}, ops...) - clt, err := client.NewClientWithOpts(ops...) - assert.NilError(t, err) - return clt -} - -// DaemonTime provides the current time on the daemon host -func DaemonTime(ctx context.Context, t assert.TestingT, client client.APIClient, testEnv *environment.Execution) time.Time { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - if testEnv.IsLocalDaemon() { - return time.Now() - } - - info, err := client.Info(ctx) - assert.NilError(t, err) - - dt, err := time.Parse(time.RFC3339Nano, info.SystemTime) - assert.NilError(t, err, "invalid time format in GET /info response") - return dt -} - -// DaemonUnixTime returns the current time on the daemon host with nanoseconds precision. -// It return the time formatted how the client sends timestamps to the server. -func DaemonUnixTime(ctx context.Context, t assert.TestingT, client client.APIClient, testEnv *environment.Execution) string { - if ht, ok := t.(test.HelperT); ok { - ht.Helper() - } - dt := DaemonTime(ctx, t, client, testEnv) - return fmt.Sprintf("%d.%09d", dt.Unix(), int64(dt.Nanosecond())) -} - -// Post creates and execute a POST request on the specified host and endpoint, with the specified request modifiers -func Post(endpoint string, modifiers ...func(*Options)) (*http.Response, io.ReadCloser, error) { - return Do(endpoint, append(modifiers, Method(http.MethodPost))...) -} - -// Delete creates and execute a DELETE request on the specified host and endpoint, with the specified request modifiers -func Delete(endpoint string, modifiers ...func(*Options)) (*http.Response, io.ReadCloser, error) { - return Do(endpoint, append(modifiers, Method(http.MethodDelete))...) -} - -// Get creates and execute a GET request on the specified host and endpoint, with the specified request modifiers -func Get(endpoint string, modifiers ...func(*Options)) (*http.Response, io.ReadCloser, error) { - return Do(endpoint, modifiers...) -} - -// Head creates and execute a HEAD request on the specified host and endpoint, with the specified request modifiers -func Head(endpoint string, modifiers ...func(*Options)) (*http.Response, io.ReadCloser, error) { - return Do(endpoint, append(modifiers, Method(http.MethodHead))...) -} - -// Do creates and execute a request on the specified endpoint, with the specified request modifiers -func Do(endpoint string, modifiers ...func(*Options)) (*http.Response, io.ReadCloser, error) { - opts := &Options{ - host: DaemonHost(), - } - for _, mod := range modifiers { - mod(opts) - } - req, err := newRequest(endpoint, opts) - if err != nil { - return nil, nil, err - } - client, err := newHTTPClient(opts.host) - if err != nil { - return nil, nil, err - } - resp, err := client.Do(req) - var body io.ReadCloser - if resp != nil { - body = ioutils.NewReadCloserWrapper(resp.Body, func() error { - defer resp.Body.Close() - return nil - }) - } - return resp, body, err -} - -// ReadBody read the specified ReadCloser content and returns it -func ReadBody(b io.ReadCloser) ([]byte, error) { - defer b.Close() - return ioutil.ReadAll(b) -} - -// newRequest creates a new http Request to the specified host and endpoint, with the specified request modifiers -func newRequest(endpoint string, opts *Options) (*http.Request, error) { - hostURL, err := client.ParseHostURL(opts.host) - if err != nil { - return nil, errors.Wrapf(err, "failed parsing url %q", opts.host) - } - req, err := http.NewRequest("GET", endpoint, nil) - if err != nil { - return nil, errors.Wrap(err, "failed to create request") - } - - if os.Getenv("DOCKER_TLS_VERIFY") != "" { - req.URL.Scheme = "https" - } else { - req.URL.Scheme = "http" - } - req.URL.Host = hostURL.Host - - for _, config := range opts.requestModifiers { - if err := config(req); err != nil { - return nil, err - } - } - - return req, nil -} - -// newHTTPClient creates an http client for the specific host -// TODO: Share more code with client.defaultHTTPClient -func newHTTPClient(host string) (*http.Client, error) { - // FIXME(vdemeester) 10*time.Second timeout of SockRequest… ? - hostURL, err := client.ParseHostURL(host) - if err != nil { - return nil, err - } - transport := new(http.Transport) - if hostURL.Scheme == "tcp" && os.Getenv("DOCKER_TLS_VERIFY") != "" { - // Setup the socket TLS configuration. - tlsConfig, err := getTLSConfig() - if err != nil { - return nil, err - } - transport = &http.Transport{TLSClientConfig: tlsConfig} - } - transport.DisableKeepAlives = true - err = sockets.ConfigureTransport(transport, hostURL.Scheme, hostURL.Host) - return &http.Client{Transport: transport}, err -} - -func getTLSConfig() (*tls.Config, error) { - dockerCertPath := os.Getenv("DOCKER_CERT_PATH") - - if dockerCertPath == "" { - return nil, errors.New("DOCKER_TLS_VERIFY specified, but no DOCKER_CERT_PATH environment variable") - } - - option := &tlsconfig.Options{ - CAFile: filepath.Join(dockerCertPath, "ca.pem"), - CertFile: filepath.Join(dockerCertPath, "cert.pem"), - KeyFile: filepath.Join(dockerCertPath, "key.pem"), - } - tlsConfig, err := tlsconfig.Client(*option) - if err != nil { - return nil, err - } - - return tlsConfig, nil -} - -// DaemonHost return the daemon host string for this test execution -func DaemonHost() string { - daemonURLStr := "unix://" + opts.DefaultUnixSocket - if daemonHostVar := os.Getenv("DOCKER_HOST"); daemonHostVar != "" { - daemonURLStr = daemonHostVar - } - return daemonURLStr -} - -// SockConn opens a connection on the specified socket -func SockConn(timeout time.Duration, daemon string) (net.Conn, error) { - daemonURL, err := url.Parse(daemon) - if err != nil { - return nil, errors.Wrapf(err, "could not parse url %q", daemon) - } - - var c net.Conn - switch daemonURL.Scheme { - case "npipe": - return npipeDial(daemonURL.Path, timeout) - case "unix": - return net.DialTimeout(daemonURL.Scheme, daemonURL.Path, timeout) - case "tcp": - if os.Getenv("DOCKER_TLS_VERIFY") != "" { - // Setup the socket TLS configuration. - tlsConfig, err := getTLSConfig() - if err != nil { - return nil, err - } - dialer := &net.Dialer{Timeout: timeout} - return tls.DialWithDialer(dialer, daemonURL.Scheme, daemonURL.Host, tlsConfig) - } - return net.DialTimeout(daemonURL.Scheme, daemonURL.Host, timeout) - default: - return c, errors.Errorf("unknown scheme %v (%s)", daemonURL.Scheme, daemon) - } -} diff --git a/internal/testutil/helpers.go b/internal/testutil/helpers.go deleted file mode 100644 index 38cd1693f5..0000000000 --- a/internal/testutil/helpers.go +++ /dev/null @@ -1,17 +0,0 @@ -package testutil // import "github.com/docker/docker/internal/testutil" - -import ( - "io" -) - -// DevZero acts like /dev/zero but in an OS-independent fashion. -var DevZero io.Reader = devZero{} - -type devZero struct{} - -func (d devZero) Read(p []byte) (n int, err error) { - for i := range p { - p[i] = 0 - } - return len(p), nil -} diff --git a/internal/testutil/stringutils.go b/internal/testutil/stringutils.go deleted file mode 100644 index 574aeb51f2..0000000000 --- a/internal/testutil/stringutils.go +++ /dev/null @@ -1,14 +0,0 @@ -package testutil // import "github.com/docker/docker/internal/testutil" - -import "math/rand" - -// GenerateRandomAlphaOnlyString generates an alphabetical random string with length n. -func GenerateRandomAlphaOnlyString(n int) string { - // make a really long string - letters := []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") - b := make([]byte, n) - for i := range b { - b[i] = letters[rand.Intn(len(letters))] - } - return string(b) -} diff --git a/internal/testutil/stringutils_test.go b/internal/testutil/stringutils_test.go deleted file mode 100644 index 753aac966d..0000000000 --- a/internal/testutil/stringutils_test.go +++ /dev/null @@ -1,34 +0,0 @@ -package testutil // import "github.com/docker/docker/internal/testutil" - -import ( - "testing" - - "gotest.tools/assert" - is "gotest.tools/assert/cmp" -) - -func testLengthHelper(generator func(int) string, t *testing.T) { - expectedLength := 20 - s := generator(expectedLength) - assert.Check(t, is.Equal(expectedLength, len(s))) -} - -func testUniquenessHelper(generator func(int) string, t *testing.T) { - repeats := 25 - set := make(map[string]struct{}, repeats) - for i := 0; i < repeats; i = i + 1 { - str := generator(64) - assert.Check(t, is.Equal(64, len(str))) - _, ok := set[str] - assert.Check(t, !ok, "Random number is repeated") - set[str] = struct{}{} - } -} - -func TestGenerateRandomAlphaOnlyStringLength(t *testing.T) { - testLengthHelper(GenerateRandomAlphaOnlyString, t) -} - -func TestGenerateRandomAlphaOnlyStringUniqueness(t *testing.T) { - testUniquenessHelper(GenerateRandomAlphaOnlyString, t) -} |