github.com/flavio/docker@v0.1.3-0.20170117145210-f63d1a6eec47/integration-cli/docker_utils_test.go (about)

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"io"
     9  	"io/ioutil"
    10  	"net"
    11  	"net/http"
    12  	"net/http/httptest"
    13  	"net/url"
    14  	"os"
    15  	"os/exec"
    16  	"path"
    17  	"path/filepath"
    18  	"strconv"
    19  	"strings"
    20  	"time"
    21  
    22  	"github.com/docker/docker/api/types"
    23  	volumetypes "github.com/docker/docker/api/types/volume"
    24  	"github.com/docker/docker/integration-cli/checker"
    25  	"github.com/docker/docker/integration-cli/daemon"
    26  	"github.com/docker/docker/integration-cli/registry"
    27  	"github.com/docker/docker/integration-cli/request"
    28  	"github.com/docker/docker/opts"
    29  	"github.com/docker/docker/pkg/stringutils"
    30  	icmd "github.com/docker/docker/pkg/testutil/cmd"
    31  	"github.com/go-check/check"
    32  )
    33  
    34  func daemonHost() string {
    35  	daemonURLStr := "unix://" + opts.DefaultUnixSocket
    36  	if daemonHostVar := os.Getenv("DOCKER_HOST"); daemonHostVar != "" {
    37  		daemonURLStr = daemonHostVar
    38  	}
    39  	return daemonURLStr
    40  }
    41  
    42  // FIXME(vdemeester) move this away are remove ignoreNoSuchContainer bool
    43  func deleteContainer(ignoreNoSuchContainer bool, container ...string) error {
    44  	result := icmd.RunCommand(dockerBinary, append([]string{"rm", "-fv"}, container...)...)
    45  	if ignoreNoSuchContainer && result.Error != nil {
    46  		// If the error is "No such container: ..." this means the container doesn't exists anymore,
    47  		// we can safely ignore that one.
    48  		if strings.Contains(result.Stderr(), "No such container") {
    49  			return nil
    50  		}
    51  	}
    52  	return result.Compare(icmd.Success)
    53  }
    54  
    55  func getAllContainers() (string, error) {
    56  	getContainersCmd := exec.Command(dockerBinary, "ps", "-q", "-a")
    57  	out, exitCode, err := runCommandWithOutput(getContainersCmd)
    58  	if exitCode != 0 && err == nil {
    59  		err = fmt.Errorf("failed to get a list of containers: %v\n", out)
    60  	}
    61  
    62  	return out, err
    63  }
    64  
    65  func deleteAllContainers(c *check.C) {
    66  	containers, err := getAllContainers()
    67  	c.Assert(err, checker.IsNil, check.Commentf("containers: %v", containers))
    68  
    69  	if containers != "" {
    70  		err = deleteContainer(true, strings.Split(strings.TrimSpace(containers), "\n")...)
    71  		c.Assert(err, checker.IsNil)
    72  	}
    73  }
    74  
    75  func deleteAllNetworks(c *check.C) {
    76  	networks, err := getAllNetworks()
    77  	c.Assert(err, check.IsNil)
    78  	var errs []string
    79  	for _, n := range networks {
    80  		if n.Name == "bridge" || n.Name == "none" || n.Name == "host" {
    81  			continue
    82  		}
    83  		if testEnv.DaemonPlatform() == "windows" && strings.ToLower(n.Name) == "nat" {
    84  			// nat is a pre-defined network on Windows and cannot be removed
    85  			continue
    86  		}
    87  		status, b, err := request.SockRequest("DELETE", "/networks/"+n.Name, nil, daemonHost())
    88  		if err != nil {
    89  			errs = append(errs, err.Error())
    90  			continue
    91  		}
    92  		if status != http.StatusNoContent {
    93  			errs = append(errs, fmt.Sprintf("error deleting network %s: %s", n.Name, string(b)))
    94  		}
    95  	}
    96  	c.Assert(errs, checker.HasLen, 0, check.Commentf(strings.Join(errs, "\n")))
    97  }
    98  
    99  func getAllNetworks() ([]types.NetworkResource, error) {
   100  	var networks []types.NetworkResource
   101  	_, b, err := request.SockRequest("GET", "/networks", nil, daemonHost())
   102  	if err != nil {
   103  		return nil, err
   104  	}
   105  	if err := json.Unmarshal(b, &networks); err != nil {
   106  		return nil, err
   107  	}
   108  	return networks, nil
   109  }
   110  
   111  func deleteAllPlugins(c *check.C) {
   112  	plugins, err := getAllPlugins()
   113  	c.Assert(err, checker.IsNil)
   114  	var errs []string
   115  	for _, p := range plugins {
   116  		pluginName := p.Name
   117  		status, b, err := request.SockRequest("DELETE", "/plugins/"+pluginName+"?force=1", nil, daemonHost())
   118  		if err != nil {
   119  			errs = append(errs, err.Error())
   120  			continue
   121  		}
   122  		if status != http.StatusOK {
   123  			errs = append(errs, fmt.Sprintf("error deleting plugin %s: %s", p.Name, string(b)))
   124  		}
   125  	}
   126  	c.Assert(errs, checker.HasLen, 0, check.Commentf(strings.Join(errs, "\n")))
   127  }
   128  
   129  func getAllPlugins() (types.PluginsListResponse, error) {
   130  	var plugins types.PluginsListResponse
   131  	_, b, err := request.SockRequest("GET", "/plugins", nil, daemonHost())
   132  	if err != nil {
   133  		return nil, err
   134  	}
   135  	if err := json.Unmarshal(b, &plugins); err != nil {
   136  		return nil, err
   137  	}
   138  	return plugins, nil
   139  }
   140  
   141  func deleteAllVolumes(c *check.C) {
   142  	volumes, err := getAllVolumes()
   143  	c.Assert(err, checker.IsNil)
   144  	var errs []string
   145  	for _, v := range volumes {
   146  		status, b, err := request.SockRequest("DELETE", "/volumes/"+v.Name, nil, daemonHost())
   147  		if err != nil {
   148  			errs = append(errs, err.Error())
   149  			continue
   150  		}
   151  		if status != http.StatusNoContent {
   152  			errs = append(errs, fmt.Sprintf("error deleting volume %s: %s", v.Name, string(b)))
   153  		}
   154  	}
   155  	c.Assert(errs, checker.HasLen, 0, check.Commentf(strings.Join(errs, "\n")))
   156  }
   157  
   158  func getAllVolumes() ([]*types.Volume, error) {
   159  	var volumes volumetypes.VolumesListOKBody
   160  	_, b, err := request.SockRequest("GET", "/volumes", nil, daemonHost())
   161  	if err != nil {
   162  		return nil, err
   163  	}
   164  	if err := json.Unmarshal(b, &volumes); err != nil {
   165  		return nil, err
   166  	}
   167  	return volumes.Volumes, nil
   168  }
   169  
   170  func deleteAllImages(c *check.C) {
   171  	cmd := exec.Command(dockerBinary, "images", "--digests")
   172  	cmd.Env = appendBaseEnv(true)
   173  	out, err := cmd.CombinedOutput()
   174  	c.Assert(err, checker.IsNil)
   175  	lines := strings.Split(string(out), "\n")[1:]
   176  	imgMap := map[string]struct{}{}
   177  	for _, l := range lines {
   178  		if l == "" {
   179  			continue
   180  		}
   181  		fields := strings.Fields(l)
   182  		imgTag := fields[0] + ":" + fields[1]
   183  		if _, ok := protectedImages[imgTag]; !ok {
   184  			if fields[0] == "<none>" || fields[1] == "<none>" {
   185  				if fields[2] != "<none>" {
   186  					imgMap[fields[0]+"@"+fields[2]] = struct{}{}
   187  				} else {
   188  					imgMap[fields[3]] = struct{}{}
   189  				}
   190  				// continue
   191  			} else {
   192  				imgMap[imgTag] = struct{}{}
   193  			}
   194  		}
   195  	}
   196  	if len(imgMap) != 0 {
   197  		imgs := make([]string, 0, len(imgMap))
   198  		for k := range imgMap {
   199  			imgs = append(imgs, k)
   200  		}
   201  		dockerCmd(c, append([]string{"rmi", "-f"}, imgs...)...)
   202  	}
   203  }
   204  
   205  func getPausedContainers() ([]string, error) {
   206  	getPausedContainersCmd := exec.Command(dockerBinary, "ps", "-f", "status=paused", "-q", "-a")
   207  	out, exitCode, err := runCommandWithOutput(getPausedContainersCmd)
   208  	if exitCode != 0 && err == nil {
   209  		err = fmt.Errorf("failed to get a list of paused containers: %v\n", out)
   210  	}
   211  	if err != nil {
   212  		return nil, err
   213  	}
   214  
   215  	return strings.Fields(out), nil
   216  }
   217  
   218  func unpauseContainer(c *check.C, container string) {
   219  	dockerCmd(c, "unpause", container)
   220  }
   221  
   222  func unpauseAllContainers(c *check.C) {
   223  	containers, err := getPausedContainers()
   224  	c.Assert(err, checker.IsNil, check.Commentf("containers: %v", containers))
   225  	for _, value := range containers {
   226  		unpauseContainer(c, value)
   227  	}
   228  }
   229  
   230  func deleteImages(images ...string) error {
   231  	args := []string{dockerBinary, "rmi", "-f"}
   232  	return icmd.RunCmd(icmd.Cmd{Command: append(args, images...)}).Error
   233  }
   234  
   235  func dockerCmdWithError(args ...string) (string, int, error) {
   236  	if err := validateArgs(args...); err != nil {
   237  		return "", 0, err
   238  	}
   239  	result := icmd.RunCommand(dockerBinary, args...)
   240  	if result.Error != nil {
   241  		return result.Combined(), result.ExitCode, result.Compare(icmd.Success)
   242  	}
   243  	return result.Combined(), result.ExitCode, result.Error
   244  }
   245  
   246  func dockerCmdWithStdoutStderr(c *check.C, args ...string) (string, string, int) {
   247  	if err := validateArgs(args...); err != nil {
   248  		c.Fatalf(err.Error())
   249  	}
   250  
   251  	result := icmd.RunCommand(dockerBinary, args...)
   252  	c.Assert(result, icmd.Matches, icmd.Success)
   253  	return result.Stdout(), result.Stderr(), result.ExitCode
   254  }
   255  
   256  func dockerCmd(c *check.C, args ...string) (string, int) {
   257  	if err := validateArgs(args...); err != nil {
   258  		c.Fatalf(err.Error())
   259  	}
   260  	result := icmd.RunCommand(dockerBinary, args...)
   261  	c.Assert(result, icmd.Matches, icmd.Success)
   262  	return result.Combined(), result.ExitCode
   263  }
   264  
   265  func dockerCmdWithResult(args ...string) *icmd.Result {
   266  	return icmd.RunCommand(dockerBinary, args...)
   267  }
   268  
   269  func binaryWithArgs(args ...string) []string {
   270  	return append([]string{dockerBinary}, args...)
   271  }
   272  
   273  // execute a docker command with a timeout
   274  func dockerCmdWithTimeout(timeout time.Duration, args ...string) *icmd.Result {
   275  	if err := validateArgs(args...); err != nil {
   276  		return &icmd.Result{Error: err}
   277  	}
   278  	return icmd.RunCmd(icmd.Cmd{Command: binaryWithArgs(args...), Timeout: timeout})
   279  }
   280  
   281  // execute a docker command in a directory
   282  func dockerCmdInDir(c *check.C, path string, args ...string) (string, int, error) {
   283  	if err := validateArgs(args...); err != nil {
   284  		c.Fatalf(err.Error())
   285  	}
   286  	result := icmd.RunCmd(icmd.Cmd{Command: binaryWithArgs(args...), Dir: path})
   287  	return result.Combined(), result.ExitCode, result.Error
   288  }
   289  
   290  // validateArgs is a checker to ensure tests are not running commands which are
   291  // not supported on platforms. Specifically on Windows this is 'busybox top'.
   292  func validateArgs(args ...string) error {
   293  	if testEnv.DaemonPlatform() != "windows" {
   294  		return nil
   295  	}
   296  	foundBusybox := -1
   297  	for key, value := range args {
   298  		if strings.ToLower(value) == "busybox" {
   299  			foundBusybox = key
   300  		}
   301  		if (foundBusybox != -1) && (key == foundBusybox+1) && (strings.ToLower(value) == "top") {
   302  			return errors.New("cannot use 'busybox top' in tests on Windows. Use runSleepingContainer()")
   303  		}
   304  	}
   305  	return nil
   306  }
   307  
   308  func findContainerIP(c *check.C, id string, network string) string {
   309  	out, _ := dockerCmd(c, "inspect", fmt.Sprintf("--format='{{ .NetworkSettings.Networks.%s.IPAddress }}'", network), id)
   310  	return strings.Trim(out, " \r\n'")
   311  }
   312  
   313  func getContainerCount() (int, error) {
   314  	const containers = "Containers:"
   315  
   316  	cmd := exec.Command(dockerBinary, "info")
   317  	out, _, err := runCommandWithOutput(cmd)
   318  	if err != nil {
   319  		return 0, err
   320  	}
   321  
   322  	lines := strings.Split(out, "\n")
   323  	for _, line := range lines {
   324  		if strings.Contains(line, containers) {
   325  			output := strings.TrimSpace(line)
   326  			output = strings.TrimLeft(output, containers)
   327  			output = strings.Trim(output, " ")
   328  			containerCount, err := strconv.Atoi(output)
   329  			if err != nil {
   330  				return 0, err
   331  			}
   332  			return containerCount, nil
   333  		}
   334  	}
   335  	return 0, fmt.Errorf("couldn't find the Container count in the output")
   336  }
   337  
   338  // FakeContext creates directories that can be used as a build context
   339  type FakeContext struct {
   340  	Dir string
   341  }
   342  
   343  // Add a file at a path, creating directories where necessary
   344  func (f *FakeContext) Add(file, content string) error {
   345  	return f.addFile(file, []byte(content))
   346  }
   347  
   348  func (f *FakeContext) addFile(file string, content []byte) error {
   349  	fp := filepath.Join(f.Dir, filepath.FromSlash(file))
   350  	dirpath := filepath.Dir(fp)
   351  	if dirpath != "." {
   352  		if err := os.MkdirAll(dirpath, 0755); err != nil {
   353  			return err
   354  		}
   355  	}
   356  	return ioutil.WriteFile(fp, content, 0644)
   357  
   358  }
   359  
   360  // Delete a file at a path
   361  func (f *FakeContext) Delete(file string) error {
   362  	fp := filepath.Join(f.Dir, filepath.FromSlash(file))
   363  	return os.RemoveAll(fp)
   364  }
   365  
   366  // Close deletes the context
   367  func (f *FakeContext) Close() error {
   368  	return os.RemoveAll(f.Dir)
   369  }
   370  
   371  func fakeContextFromNewTempDir() (*FakeContext, error) {
   372  	tmp, err := ioutil.TempDir("", "fake-context")
   373  	if err != nil {
   374  		return nil, err
   375  	}
   376  	if err := os.Chmod(tmp, 0755); err != nil {
   377  		return nil, err
   378  	}
   379  	return fakeContextFromDir(tmp), nil
   380  }
   381  
   382  func fakeContextFromDir(dir string) *FakeContext {
   383  	return &FakeContext{dir}
   384  }
   385  
   386  func fakeContextWithFiles(files map[string]string) (*FakeContext, error) {
   387  	ctx, err := fakeContextFromNewTempDir()
   388  	if err != nil {
   389  		return nil, err
   390  	}
   391  	for file, content := range files {
   392  		if err := ctx.Add(file, content); err != nil {
   393  			ctx.Close()
   394  			return nil, err
   395  		}
   396  	}
   397  	return ctx, nil
   398  }
   399  
   400  func fakeContextAddDockerfile(ctx *FakeContext, dockerfile string) error {
   401  	if err := ctx.Add("Dockerfile", dockerfile); err != nil {
   402  		ctx.Close()
   403  		return err
   404  	}
   405  	return nil
   406  }
   407  
   408  func fakeContext(dockerfile string, files map[string]string) (*FakeContext, error) {
   409  	ctx, err := fakeContextWithFiles(files)
   410  	if err != nil {
   411  		return nil, err
   412  	}
   413  	if err := fakeContextAddDockerfile(ctx, dockerfile); err != nil {
   414  		return nil, err
   415  	}
   416  	return ctx, nil
   417  }
   418  
   419  // FakeStorage is a static file server. It might be running locally or remotely
   420  // on test host.
   421  type FakeStorage interface {
   422  	Close() error
   423  	URL() string
   424  	CtxDir() string
   425  }
   426  
   427  func fakeBinaryStorage(archives map[string]*bytes.Buffer) (FakeStorage, error) {
   428  	ctx, err := fakeContextFromNewTempDir()
   429  	if err != nil {
   430  		return nil, err
   431  	}
   432  	for name, content := range archives {
   433  		if err := ctx.addFile(name, content.Bytes()); err != nil {
   434  			return nil, err
   435  		}
   436  	}
   437  	return fakeStorageWithContext(ctx)
   438  }
   439  
   440  // fakeStorage returns either a local or remote (at daemon machine) file server
   441  func fakeStorage(files map[string]string) (FakeStorage, error) {
   442  	ctx, err := fakeContextWithFiles(files)
   443  	if err != nil {
   444  		return nil, err
   445  	}
   446  	return fakeStorageWithContext(ctx)
   447  }
   448  
   449  // fakeStorageWithContext returns either a local or remote (at daemon machine) file server
   450  func fakeStorageWithContext(ctx *FakeContext) (FakeStorage, error) {
   451  	if testEnv.LocalDaemon() {
   452  		return newLocalFakeStorage(ctx)
   453  	}
   454  	return newRemoteFileServer(ctx)
   455  }
   456  
   457  // localFileStorage is a file storage on the running machine
   458  type localFileStorage struct {
   459  	*FakeContext
   460  	*httptest.Server
   461  }
   462  
   463  func (s *localFileStorage) URL() string {
   464  	return s.Server.URL
   465  }
   466  
   467  func (s *localFileStorage) CtxDir() string {
   468  	return s.FakeContext.Dir
   469  }
   470  
   471  func (s *localFileStorage) Close() error {
   472  	defer s.Server.Close()
   473  	return s.FakeContext.Close()
   474  }
   475  
   476  func newLocalFakeStorage(ctx *FakeContext) (*localFileStorage, error) {
   477  	handler := http.FileServer(http.Dir(ctx.Dir))
   478  	server := httptest.NewServer(handler)
   479  	return &localFileStorage{
   480  		FakeContext: ctx,
   481  		Server:      server,
   482  	}, nil
   483  }
   484  
   485  // remoteFileServer is a containerized static file server started on the remote
   486  // testing machine to be used in URL-accepting docker build functionality.
   487  type remoteFileServer struct {
   488  	host      string // hostname/port web server is listening to on docker host e.g. 0.0.0.0:43712
   489  	container string
   490  	image     string
   491  	ctx       *FakeContext
   492  }
   493  
   494  func (f *remoteFileServer) URL() string {
   495  	u := url.URL{
   496  		Scheme: "http",
   497  		Host:   f.host}
   498  	return u.String()
   499  }
   500  
   501  func (f *remoteFileServer) CtxDir() string {
   502  	return f.ctx.Dir
   503  }
   504  
   505  func (f *remoteFileServer) Close() error {
   506  	defer func() {
   507  		if f.ctx != nil {
   508  			f.ctx.Close()
   509  		}
   510  		if f.image != "" {
   511  			deleteImages(f.image)
   512  		}
   513  	}()
   514  	if f.container == "" {
   515  		return nil
   516  	}
   517  	return deleteContainer(false, f.container)
   518  }
   519  
   520  func newRemoteFileServer(ctx *FakeContext) (*remoteFileServer, error) {
   521  	var (
   522  		image     = fmt.Sprintf("fileserver-img-%s", strings.ToLower(stringutils.GenerateRandomAlphaOnlyString(10)))
   523  		container = fmt.Sprintf("fileserver-cnt-%s", strings.ToLower(stringutils.GenerateRandomAlphaOnlyString(10)))
   524  	)
   525  
   526  	if err := ensureHTTPServerImage(); err != nil {
   527  		return nil, err
   528  	}
   529  
   530  	// Build the image
   531  	if err := fakeContextAddDockerfile(ctx, `FROM httpserver
   532  COPY . /static`); err != nil {
   533  		return nil, fmt.Errorf("Cannot add Dockerfile to context: %v", err)
   534  	}
   535  	if _, err := buildImageFromContext(image, ctx, false); err != nil {
   536  		return nil, fmt.Errorf("failed building file storage container image: %v", err)
   537  	}
   538  
   539  	// Start the container
   540  	runCmd := exec.Command(dockerBinary, "run", "-d", "-P", "--name", container, image)
   541  	if out, ec, err := runCommandWithOutput(runCmd); err != nil {
   542  		return nil, fmt.Errorf("failed to start file storage container. ec=%v\nout=%s\nerr=%v", ec, out, err)
   543  	}
   544  
   545  	// Find out the system assigned port
   546  	out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "port", container, "80/tcp"))
   547  	if err != nil {
   548  		return nil, fmt.Errorf("failed to find container port: err=%v\nout=%s", err, out)
   549  	}
   550  
   551  	fileserverHostPort := strings.Trim(out, "\n")
   552  	_, port, err := net.SplitHostPort(fileserverHostPort)
   553  	if err != nil {
   554  		return nil, fmt.Errorf("unable to parse file server host:port: %v", err)
   555  	}
   556  
   557  	dockerHostURL, err := url.Parse(daemonHost())
   558  	if err != nil {
   559  		return nil, fmt.Errorf("unable to parse daemon host URL: %v", err)
   560  	}
   561  
   562  	host, _, err := net.SplitHostPort(dockerHostURL.Host)
   563  	if err != nil {
   564  		return nil, fmt.Errorf("unable to parse docker daemon host:port: %v", err)
   565  	}
   566  
   567  	return &remoteFileServer{
   568  		container: container,
   569  		image:     image,
   570  		host:      fmt.Sprintf("%s:%s", host, port),
   571  		ctx:       ctx}, nil
   572  }
   573  
   574  func inspectFieldAndUnmarshall(c *check.C, name, field string, output interface{}) {
   575  	str := inspectFieldJSON(c, name, field)
   576  	err := json.Unmarshal([]byte(str), output)
   577  	if c != nil {
   578  		c.Assert(err, check.IsNil, check.Commentf("failed to unmarshal: %v", err))
   579  	}
   580  }
   581  
   582  func inspectFilter(name, filter string) (string, error) {
   583  	format := fmt.Sprintf("{{%s}}", filter)
   584  	result := icmd.RunCommand(dockerBinary, "inspect", "-f", format, name)
   585  	if result.Error != nil || result.ExitCode != 0 {
   586  		return "", fmt.Errorf("failed to inspect %s: %s", name, result.Combined())
   587  	}
   588  	return strings.TrimSpace(result.Combined()), nil
   589  }
   590  
   591  func inspectFieldWithError(name, field string) (string, error) {
   592  	return inspectFilter(name, fmt.Sprintf(".%s", field))
   593  }
   594  
   595  func inspectField(c *check.C, name, field string) string {
   596  	out, err := inspectFilter(name, fmt.Sprintf(".%s", field))
   597  	if c != nil {
   598  		c.Assert(err, check.IsNil)
   599  	}
   600  	return out
   601  }
   602  
   603  func inspectFieldJSON(c *check.C, name, field string) string {
   604  	out, err := inspectFilter(name, fmt.Sprintf("json .%s", field))
   605  	if c != nil {
   606  		c.Assert(err, check.IsNil)
   607  	}
   608  	return out
   609  }
   610  
   611  func inspectFieldMap(c *check.C, name, path, field string) string {
   612  	out, err := inspectFilter(name, fmt.Sprintf("index .%s %q", path, field))
   613  	if c != nil {
   614  		c.Assert(err, check.IsNil)
   615  	}
   616  	return out
   617  }
   618  
   619  func inspectMountSourceField(name, destination string) (string, error) {
   620  	m, err := inspectMountPoint(name, destination)
   621  	if err != nil {
   622  		return "", err
   623  	}
   624  	return m.Source, nil
   625  }
   626  
   627  func inspectMountPoint(name, destination string) (types.MountPoint, error) {
   628  	out, err := inspectFilter(name, "json .Mounts")
   629  	if err != nil {
   630  		return types.MountPoint{}, err
   631  	}
   632  
   633  	return inspectMountPointJSON(out, destination)
   634  }
   635  
   636  var errMountNotFound = errors.New("mount point not found")
   637  
   638  func inspectMountPointJSON(j, destination string) (types.MountPoint, error) {
   639  	var mp []types.MountPoint
   640  	if err := json.Unmarshal([]byte(j), &mp); err != nil {
   641  		return types.MountPoint{}, err
   642  	}
   643  
   644  	var m *types.MountPoint
   645  	for _, c := range mp {
   646  		if c.Destination == destination {
   647  			m = &c
   648  			break
   649  		}
   650  	}
   651  
   652  	if m == nil {
   653  		return types.MountPoint{}, errMountNotFound
   654  	}
   655  
   656  	return *m, nil
   657  }
   658  
   659  func inspectImage(name, filter string) (string, error) {
   660  	args := []string{"inspect", "--type", "image"}
   661  	if filter != "" {
   662  		format := fmt.Sprintf("{{%s}}", filter)
   663  		args = append(args, "-f", format)
   664  	}
   665  	args = append(args, name)
   666  	inspectCmd := exec.Command(dockerBinary, args...)
   667  	out, exitCode, err := runCommandWithOutput(inspectCmd)
   668  	if err != nil || exitCode != 0 {
   669  		return "", fmt.Errorf("failed to inspect %s: %s", name, out)
   670  	}
   671  	return strings.TrimSpace(out), nil
   672  }
   673  
   674  func getIDByName(name string) (string, error) {
   675  	return inspectFieldWithError(name, "Id")
   676  }
   677  
   678  // Deprecated
   679  func buildImageCmd(name, dockerfile string, useCache bool, buildFlags ...string) *exec.Cmd {
   680  	return daemon.BuildImageCmdWithHost(dockerBinary, name, dockerfile, "", useCache, buildFlags...)
   681  }
   682  
   683  // Deprecated
   684  func buildImageWithOut(name, dockerfile string, useCache bool, buildFlags ...string) (string, string, error) {
   685  	buildCmd := buildImageCmd(name, dockerfile, useCache, buildFlags...)
   686  	out, exitCode, err := runCommandWithOutput(buildCmd)
   687  	if err != nil || exitCode != 0 {
   688  		return "", out, fmt.Errorf("failed to build the image: %s", out)
   689  	}
   690  	id, err := getIDByName(name)
   691  	if err != nil {
   692  		return "", out, err
   693  	}
   694  	return id, out, nil
   695  }
   696  
   697  // Deprecated
   698  func buildImageWithStdoutStderr(name, dockerfile string, useCache bool, buildFlags ...string) (string, string, string, error) {
   699  	buildCmd := buildImageCmd(name, dockerfile, useCache, buildFlags...)
   700  	result := icmd.RunCmd(transformCmd(buildCmd))
   701  	err := result.Error
   702  	exitCode := result.ExitCode
   703  	if err != nil || exitCode != 0 {
   704  		return "", result.Stdout(), result.Stderr(), fmt.Errorf("failed to build the image: %s", result.Combined())
   705  	}
   706  	id, err := getIDByName(name)
   707  	if err != nil {
   708  		return "", result.Stdout(), result.Stderr(), err
   709  	}
   710  	return id, result.Stdout(), result.Stderr(), nil
   711  }
   712  
   713  func buildImageSuccessfully(c *check.C, name string, cmdOperators ...func(*icmd.Cmd) func()) {
   714  	buildImageNew(name, cmdOperators...).Assert(c, icmd.Success)
   715  }
   716  
   717  // FIXME(vdemeester) rename this buildImage once deprecated buildImage is no more
   718  func buildImageNew(name string, cmdOperators ...func(*icmd.Cmd) func()) *icmd.Result {
   719  	cmd := icmd.Command(dockerBinary, "build", "-t", name)
   720  	for _, op := range cmdOperators {
   721  		deferFn := op(&cmd)
   722  		if deferFn != nil {
   723  			defer deferFn()
   724  		}
   725  	}
   726  	return icmd.RunCmd(cmd)
   727  }
   728  
   729  func withBuildContextPath(path string) func(*icmd.Cmd) func() {
   730  	return func(cmd *icmd.Cmd) func() {
   731  		cmd.Command = append(cmd.Command, path)
   732  		return nil
   733  	}
   734  }
   735  
   736  func withBuildContext(c *check.C, contextOperators ...func(*FakeContext) error) func(*icmd.Cmd) func() {
   737  	ctx, err := fakeContextFromNewTempDir()
   738  	if err != nil {
   739  		c.Fatalf("error creating build context : %v", err)
   740  	}
   741  	for _, op := range contextOperators {
   742  		if err := op(ctx); err != nil {
   743  			c.Fatal(err)
   744  		}
   745  	}
   746  	return func(cmd *icmd.Cmd) func() {
   747  		cmd.Dir = ctx.Dir
   748  		cmd.Command = append(cmd.Command, ".")
   749  		return closeBuildContext(c, ctx)
   750  	}
   751  }
   752  
   753  func withBuildFlags(flags ...string) func(*icmd.Cmd) func() {
   754  	return func(cmd *icmd.Cmd) func() {
   755  		cmd.Command = append(cmd.Command, flags...)
   756  		return nil
   757  	}
   758  }
   759  
   760  func withoutCache(cmd *icmd.Cmd) func() {
   761  	cmd.Command = append(cmd.Command, "--no-cache")
   762  	return nil
   763  }
   764  
   765  func withFile(name, content string) func(*FakeContext) error {
   766  	return func(ctx *FakeContext) error {
   767  		return ctx.Add(name, content)
   768  	}
   769  }
   770  
   771  func closeBuildContext(c *check.C, ctx *FakeContext) func() {
   772  	return func() {
   773  		if err := ctx.Close(); err != nil {
   774  			c.Fatal(err)
   775  		}
   776  	}
   777  }
   778  
   779  func withDockerfile(dockerfile string) func(*icmd.Cmd) func() {
   780  	return func(cmd *icmd.Cmd) func() {
   781  		cmd.Command = append(cmd.Command, "-")
   782  		cmd.Stdin = strings.NewReader(dockerfile)
   783  		return nil
   784  	}
   785  }
   786  
   787  func trustedBuild(cmd *icmd.Cmd) func() {
   788  	trustedCmd(cmd)
   789  	return nil
   790  }
   791  
   792  func withEnvironmentVariales(envs ...string) func(cmd *icmd.Cmd) func() {
   793  	return func(cmd *icmd.Cmd) func() {
   794  		cmd.Env = envs
   795  		return nil
   796  	}
   797  }
   798  
   799  // Deprecated
   800  func buildImage(name, dockerfile string, useCache bool, buildFlags ...string) (string, error) {
   801  	id, _, err := buildImageWithOut(name, dockerfile, useCache, buildFlags...)
   802  	return id, err
   803  }
   804  
   805  // Deprecated
   806  func buildImageFromContext(name string, ctx *FakeContext, useCache bool, buildFlags ...string) (string, error) {
   807  	id, _, err := buildImageFromContextWithOut(name, ctx, useCache, buildFlags...)
   808  	if err != nil {
   809  		return "", err
   810  	}
   811  	return id, nil
   812  }
   813  
   814  // Deprecated
   815  func buildImageFromContextWithOut(name string, ctx *FakeContext, useCache bool, buildFlags ...string) (string, string, error) {
   816  	args := []string{"build", "-t", name}
   817  	if !useCache {
   818  		args = append(args, "--no-cache")
   819  	}
   820  	args = append(args, buildFlags...)
   821  	args = append(args, ".")
   822  	result := icmd.RunCmd(icmd.Cmd{
   823  		Command: append([]string{dockerBinary}, args...),
   824  		Dir:     ctx.Dir,
   825  	})
   826  	out := result.Combined()
   827  	if result.Error != nil || result.ExitCode != 0 {
   828  		return "", "", fmt.Errorf("failed to build the image: %s", out)
   829  	}
   830  	id, err := getIDByName(name)
   831  	if err != nil {
   832  		return "", "", err
   833  	}
   834  	return id, out, nil
   835  }
   836  
   837  // Deprecated
   838  func buildImageFromContextWithStdoutStderr(name string, ctx *FakeContext, useCache bool, buildFlags ...string) (string, string, string, error) {
   839  	args := []string{"build", "-t", name}
   840  	if !useCache {
   841  		args = append(args, "--no-cache")
   842  	}
   843  	args = append(args, buildFlags...)
   844  	args = append(args, ".")
   845  
   846  	result := icmd.RunCmd(icmd.Cmd{
   847  		Command: append([]string{dockerBinary}, args...),
   848  		Dir:     ctx.Dir,
   849  	})
   850  	exitCode := result.ExitCode
   851  	err := result.Error
   852  	if err != nil || exitCode != 0 {
   853  		return "", result.Stdout(), result.Stderr(), fmt.Errorf("failed to build the image: %s", result.Combined())
   854  	}
   855  	id, err := getIDByName(name)
   856  	if err != nil {
   857  		return "", result.Stdout(), result.Stderr(), err
   858  	}
   859  	return id, result.Stdout(), result.Stderr(), nil
   860  }
   861  
   862  // Deprecated
   863  func buildImageFromGitWithStdoutStderr(name string, ctx *fakeGit, useCache bool, buildFlags ...string) (string, string, string, error) {
   864  	args := []string{"build", "-t", name}
   865  	if !useCache {
   866  		args = append(args, "--no-cache")
   867  	}
   868  	args = append(args, buildFlags...)
   869  	args = append(args, ctx.RepoURL)
   870  	result := icmd.RunCmd(icmd.Cmd{
   871  		Command: append([]string{dockerBinary}, args...),
   872  	})
   873  	exitCode := result.ExitCode
   874  	err := result.Error
   875  	if err != nil || exitCode != 0 {
   876  		return "", result.Stdout(), result.Stderr(), fmt.Errorf("failed to build the image: %s", result.Combined())
   877  	}
   878  	id, err := getIDByName(name)
   879  	if err != nil {
   880  		return "", result.Stdout(), result.Stderr(), err
   881  	}
   882  	return id, result.Stdout(), result.Stderr(), nil
   883  }
   884  
   885  // Deprecated
   886  func buildImageFromPath(name, path string, useCache bool, buildFlags ...string) (string, error) {
   887  	args := []string{"build", "-t", name}
   888  	if !useCache {
   889  		args = append(args, "--no-cache")
   890  	}
   891  	args = append(args, buildFlags...)
   892  	args = append(args, path)
   893  	buildCmd := exec.Command(dockerBinary, args...)
   894  	out, exitCode, err := runCommandWithOutput(buildCmd)
   895  	if err != nil || exitCode != 0 {
   896  		return "", fmt.Errorf("failed to build the image: %s", out)
   897  	}
   898  	return getIDByName(name)
   899  }
   900  
   901  type gitServer interface {
   902  	URL() string
   903  	Close() error
   904  }
   905  
   906  type localGitServer struct {
   907  	*httptest.Server
   908  }
   909  
   910  func (r *localGitServer) Close() error {
   911  	r.Server.Close()
   912  	return nil
   913  }
   914  
   915  func (r *localGitServer) URL() string {
   916  	return r.Server.URL
   917  }
   918  
   919  type fakeGit struct {
   920  	root    string
   921  	server  gitServer
   922  	RepoURL string
   923  }
   924  
   925  func (g *fakeGit) Close() {
   926  	g.server.Close()
   927  	os.RemoveAll(g.root)
   928  }
   929  
   930  func newFakeGit(name string, files map[string]string, enforceLocalServer bool) (*fakeGit, error) {
   931  	ctx, err := fakeContextWithFiles(files)
   932  	if err != nil {
   933  		return nil, err
   934  	}
   935  	defer ctx.Close()
   936  	curdir, err := os.Getwd()
   937  	if err != nil {
   938  		return nil, err
   939  	}
   940  	defer os.Chdir(curdir)
   941  
   942  	if output, err := exec.Command("git", "init", ctx.Dir).CombinedOutput(); err != nil {
   943  		return nil, fmt.Errorf("error trying to init repo: %s (%s)", err, output)
   944  	}
   945  	err = os.Chdir(ctx.Dir)
   946  	if err != nil {
   947  		return nil, err
   948  	}
   949  	if output, err := exec.Command("git", "config", "user.name", "Fake User").CombinedOutput(); err != nil {
   950  		return nil, fmt.Errorf("error trying to set 'user.name': %s (%s)", err, output)
   951  	}
   952  	if output, err := exec.Command("git", "config", "user.email", "fake.user@example.com").CombinedOutput(); err != nil {
   953  		return nil, fmt.Errorf("error trying to set 'user.email': %s (%s)", err, output)
   954  	}
   955  	if output, err := exec.Command("git", "add", "*").CombinedOutput(); err != nil {
   956  		return nil, fmt.Errorf("error trying to add files to repo: %s (%s)", err, output)
   957  	}
   958  	if output, err := exec.Command("git", "commit", "-a", "-m", "Initial commit").CombinedOutput(); err != nil {
   959  		return nil, fmt.Errorf("error trying to commit to repo: %s (%s)", err, output)
   960  	}
   961  
   962  	root, err := ioutil.TempDir("", "docker-test-git-repo")
   963  	if err != nil {
   964  		return nil, err
   965  	}
   966  	repoPath := filepath.Join(root, name+".git")
   967  	if output, err := exec.Command("git", "clone", "--bare", ctx.Dir, repoPath).CombinedOutput(); err != nil {
   968  		os.RemoveAll(root)
   969  		return nil, fmt.Errorf("error trying to clone --bare: %s (%s)", err, output)
   970  	}
   971  	err = os.Chdir(repoPath)
   972  	if err != nil {
   973  		os.RemoveAll(root)
   974  		return nil, err
   975  	}
   976  	if output, err := exec.Command("git", "update-server-info").CombinedOutput(); err != nil {
   977  		os.RemoveAll(root)
   978  		return nil, fmt.Errorf("error trying to git update-server-info: %s (%s)", err, output)
   979  	}
   980  	err = os.Chdir(curdir)
   981  	if err != nil {
   982  		os.RemoveAll(root)
   983  		return nil, err
   984  	}
   985  
   986  	var server gitServer
   987  	if !enforceLocalServer {
   988  		// use fakeStorage server, which might be local or remote (at test daemon)
   989  		server, err = fakeStorageWithContext(fakeContextFromDir(root))
   990  		if err != nil {
   991  			return nil, fmt.Errorf("cannot start fake storage: %v", err)
   992  		}
   993  	} else {
   994  		// always start a local http server on CLI test machine
   995  		httpServer := httptest.NewServer(http.FileServer(http.Dir(root)))
   996  		server = &localGitServer{httpServer}
   997  	}
   998  	return &fakeGit{
   999  		root:    root,
  1000  		server:  server,
  1001  		RepoURL: fmt.Sprintf("%s/%s.git", server.URL(), name),
  1002  	}, nil
  1003  }
  1004  
  1005  // Write `content` to the file at path `dst`, creating it if necessary,
  1006  // as well as any missing directories.
  1007  // The file is truncated if it already exists.
  1008  // Fail the test when error occurs.
  1009  func writeFile(dst, content string, c *check.C) {
  1010  	// Create subdirectories if necessary
  1011  	c.Assert(os.MkdirAll(path.Dir(dst), 0700), check.IsNil)
  1012  	f, err := os.OpenFile(dst, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0700)
  1013  	c.Assert(err, check.IsNil)
  1014  	defer f.Close()
  1015  	// Write content (truncate if it exists)
  1016  	_, err = io.Copy(f, strings.NewReader(content))
  1017  	c.Assert(err, check.IsNil)
  1018  }
  1019  
  1020  // Return the contents of file at path `src`.
  1021  // Fail the test when error occurs.
  1022  func readFile(src string, c *check.C) (content string) {
  1023  	data, err := ioutil.ReadFile(src)
  1024  	c.Assert(err, check.IsNil)
  1025  
  1026  	return string(data)
  1027  }
  1028  
  1029  func containerStorageFile(containerID, basename string) string {
  1030  	return filepath.Join(testEnv.ContainerStoragePath(), containerID, basename)
  1031  }
  1032  
  1033  // docker commands that use this function must be run with the '-d' switch.
  1034  func runCommandAndReadContainerFile(filename string, cmd *exec.Cmd) ([]byte, error) {
  1035  	out, _, err := runCommandWithOutput(cmd)
  1036  	if err != nil {
  1037  		return nil, fmt.Errorf("%v: %q", err, out)
  1038  	}
  1039  
  1040  	contID := strings.TrimSpace(out)
  1041  
  1042  	if err := waitRun(contID); err != nil {
  1043  		return nil, fmt.Errorf("%v: %q", contID, err)
  1044  	}
  1045  
  1046  	return readContainerFile(contID, filename)
  1047  }
  1048  
  1049  func readContainerFile(containerID, filename string) ([]byte, error) {
  1050  	f, err := os.Open(containerStorageFile(containerID, filename))
  1051  	if err != nil {
  1052  		return nil, err
  1053  	}
  1054  	defer f.Close()
  1055  
  1056  	content, err := ioutil.ReadAll(f)
  1057  	if err != nil {
  1058  		return nil, err
  1059  	}
  1060  
  1061  	return content, nil
  1062  }
  1063  
  1064  func readContainerFileWithExec(containerID, filename string) ([]byte, error) {
  1065  	out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "exec", containerID, "cat", filename))
  1066  	return []byte(out), err
  1067  }
  1068  
  1069  // daemonTime provides the current time on the daemon host
  1070  func daemonTime(c *check.C) time.Time {
  1071  	if testEnv.LocalDaemon() {
  1072  		return time.Now()
  1073  	}
  1074  
  1075  	status, body, err := request.SockRequest("GET", "/info", nil, daemonHost())
  1076  	c.Assert(err, check.IsNil)
  1077  	c.Assert(status, check.Equals, http.StatusOK)
  1078  
  1079  	type infoJSON struct {
  1080  		SystemTime string
  1081  	}
  1082  	var info infoJSON
  1083  	err = json.Unmarshal(body, &info)
  1084  	c.Assert(err, check.IsNil, check.Commentf("unable to unmarshal GET /info response"))
  1085  
  1086  	dt, err := time.Parse(time.RFC3339Nano, info.SystemTime)
  1087  	c.Assert(err, check.IsNil, check.Commentf("invalid time format in GET /info response"))
  1088  	return dt
  1089  }
  1090  
  1091  // daemonUnixTime returns the current time on the daemon host with nanoseconds precision.
  1092  // It return the time formatted how the client sends timestamps to the server.
  1093  func daemonUnixTime(c *check.C) string {
  1094  	return parseEventTime(daemonTime(c))
  1095  }
  1096  
  1097  func parseEventTime(t time.Time) string {
  1098  	return fmt.Sprintf("%d.%09d", t.Unix(), int64(t.Nanosecond()))
  1099  }
  1100  
  1101  func setupRegistry(c *check.C, schema1 bool, auth, tokenURL string) *registry.V2 {
  1102  	reg, err := registry.NewV2(schema1, auth, tokenURL, privateRegistryURL)
  1103  	c.Assert(err, check.IsNil)
  1104  
  1105  	// Wait for registry to be ready to serve requests.
  1106  	for i := 0; i != 50; i++ {
  1107  		if err = reg.Ping(); err == nil {
  1108  			break
  1109  		}
  1110  		time.Sleep(100 * time.Millisecond)
  1111  	}
  1112  
  1113  	c.Assert(err, check.IsNil, check.Commentf("Timeout waiting for test registry to become available: %v", err))
  1114  	return reg
  1115  }
  1116  
  1117  func setupNotary(c *check.C) *testNotary {
  1118  	ts, err := newTestNotary(c)
  1119  	c.Assert(err, check.IsNil)
  1120  
  1121  	return ts
  1122  }
  1123  
  1124  // appendBaseEnv appends the minimum set of environment variables to exec the
  1125  // docker cli binary for testing with correct configuration to the given env
  1126  // list.
  1127  func appendBaseEnv(isTLS bool, env ...string) []string {
  1128  	preserveList := []string{
  1129  		// preserve remote test host
  1130  		"DOCKER_HOST",
  1131  
  1132  		// windows: requires preserving SystemRoot, otherwise dial tcp fails
  1133  		// with "GetAddrInfoW: A non-recoverable error occurred during a database lookup."
  1134  		"SystemRoot",
  1135  
  1136  		// testing help text requires the $PATH to dockerd is set
  1137  		"PATH",
  1138  	}
  1139  	if isTLS {
  1140  		preserveList = append(preserveList, "DOCKER_TLS_VERIFY", "DOCKER_CERT_PATH")
  1141  	}
  1142  
  1143  	for _, key := range preserveList {
  1144  		if val := os.Getenv(key); val != "" {
  1145  			env = append(env, fmt.Sprintf("%s=%s", key, val))
  1146  		}
  1147  	}
  1148  	return env
  1149  }
  1150  
  1151  func createTmpFile(c *check.C, content string) string {
  1152  	f, err := ioutil.TempFile("", "testfile")
  1153  	c.Assert(err, check.IsNil)
  1154  
  1155  	filename := f.Name()
  1156  
  1157  	err = ioutil.WriteFile(filename, []byte(content), 0644)
  1158  	c.Assert(err, check.IsNil)
  1159  
  1160  	return filename
  1161  }
  1162  
  1163  func waitForContainer(contID string, args ...string) error {
  1164  	args = append([]string{dockerBinary, "run", "--name", contID}, args...)
  1165  	result := icmd.RunCmd(icmd.Cmd{Command: args})
  1166  	if result.Error != nil {
  1167  		return result.Error
  1168  	}
  1169  	return waitRun(contID)
  1170  }
  1171  
  1172  // waitRestart will wait for the specified container to restart once
  1173  func waitRestart(contID string, duration time.Duration) error {
  1174  	return waitInspect(contID, "{{.RestartCount}}", "1", duration)
  1175  }
  1176  
  1177  // waitRun will wait for the specified container to be running, maximum 5 seconds.
  1178  func waitRun(contID string) error {
  1179  	return waitInspect(contID, "{{.State.Running}}", "true", 5*time.Second)
  1180  }
  1181  
  1182  // waitExited will wait for the specified container to state exit, subject
  1183  // to a maximum time limit in seconds supplied by the caller
  1184  func waitExited(contID string, duration time.Duration) error {
  1185  	return waitInspect(contID, "{{.State.Status}}", "exited", duration)
  1186  }
  1187  
  1188  // waitInspect will wait for the specified container to have the specified string
  1189  // in the inspect output. It will wait until the specified timeout (in seconds)
  1190  // is reached.
  1191  func waitInspect(name, expr, expected string, timeout time.Duration) error {
  1192  	return waitInspectWithArgs(name, expr, expected, timeout)
  1193  }
  1194  
  1195  func waitInspectWithArgs(name, expr, expected string, timeout time.Duration, arg ...string) error {
  1196  	return daemon.WaitInspectWithArgs(dockerBinary, name, expr, expected, timeout, arg...)
  1197  }
  1198  
  1199  func getInspectBody(c *check.C, version, id string) []byte {
  1200  	endpoint := fmt.Sprintf("/%s/containers/%s/json", version, id)
  1201  	status, body, err := request.SockRequest("GET", endpoint, nil, daemonHost())
  1202  	c.Assert(err, check.IsNil)
  1203  	c.Assert(status, check.Equals, http.StatusOK)
  1204  	return body
  1205  }
  1206  
  1207  // Run a long running idle task in a background container using the
  1208  // system-specific default image and command.
  1209  func runSleepingContainer(c *check.C, extraArgs ...string) (string, int) {
  1210  	return runSleepingContainerInImage(c, defaultSleepImage, extraArgs...)
  1211  }
  1212  
  1213  // Run a long running idle task in a background container using the specified
  1214  // image and the system-specific command.
  1215  func runSleepingContainerInImage(c *check.C, image string, extraArgs ...string) (string, int) {
  1216  	args := []string{"run", "-d"}
  1217  	args = append(args, extraArgs...)
  1218  	args = append(args, image)
  1219  	args = append(args, sleepCommandForDaemonPlatform()...)
  1220  	return dockerCmd(c, args...)
  1221  }
  1222  
  1223  // minimalBaseImage returns the name of the minimal base image for the current
  1224  // daemon platform.
  1225  func minimalBaseImage() string {
  1226  	return testEnv.MinimalBaseImage()
  1227  }
  1228  
  1229  func getGoroutineNumber() (int, error) {
  1230  	i := struct {
  1231  		NGoroutines int
  1232  	}{}
  1233  	status, b, err := request.SockRequest("GET", "/info", nil, daemonHost())
  1234  	if err != nil {
  1235  		return 0, err
  1236  	}
  1237  	if status != http.StatusOK {
  1238  		return 0, fmt.Errorf("http status code: %d", status)
  1239  	}
  1240  	if err := json.Unmarshal(b, &i); err != nil {
  1241  		return 0, err
  1242  	}
  1243  	return i.NGoroutines, nil
  1244  }
  1245  
  1246  func waitForGoroutines(expected int) error {
  1247  	t := time.After(30 * time.Second)
  1248  	for {
  1249  		select {
  1250  		case <-t:
  1251  			n, err := getGoroutineNumber()
  1252  			if err != nil {
  1253  				return err
  1254  			}
  1255  			if n > expected {
  1256  				return fmt.Errorf("leaked goroutines: expected less than or equal to %d, got: %d", expected, n)
  1257  			}
  1258  		default:
  1259  			n, err := getGoroutineNumber()
  1260  			if err != nil {
  1261  				return err
  1262  			}
  1263  			if n <= expected {
  1264  				return nil
  1265  			}
  1266  			time.Sleep(200 * time.Millisecond)
  1267  		}
  1268  	}
  1269  }
  1270  
  1271  // getErrorMessage returns the error message from an error API response
  1272  func getErrorMessage(c *check.C, body []byte) string {
  1273  	var resp types.ErrorResponse
  1274  	c.Assert(json.Unmarshal(body, &resp), check.IsNil)
  1275  	return strings.TrimSpace(resp.Message)
  1276  }
  1277  
  1278  func waitAndAssert(c *check.C, timeout time.Duration, f checkF, checker check.Checker, args ...interface{}) {
  1279  	after := time.After(timeout)
  1280  	for {
  1281  		v, comment := f(c)
  1282  		assert, _ := checker.Check(append([]interface{}{v}, args...), checker.Info().Params)
  1283  		select {
  1284  		case <-after:
  1285  			assert = true
  1286  		default:
  1287  		}
  1288  		if assert {
  1289  			if comment != nil {
  1290  				args = append(args, comment)
  1291  			}
  1292  			c.Assert(v, checker, args...)
  1293  			return
  1294  		}
  1295  		time.Sleep(100 * time.Millisecond)
  1296  	}
  1297  }
  1298  
  1299  type checkF func(*check.C) (interface{}, check.CommentInterface)
  1300  type reducer func(...interface{}) interface{}
  1301  
  1302  func reducedCheck(r reducer, funcs ...checkF) checkF {
  1303  	return func(c *check.C) (interface{}, check.CommentInterface) {
  1304  		var values []interface{}
  1305  		var comments []string
  1306  		for _, f := range funcs {
  1307  			v, comment := f(c)
  1308  			values = append(values, v)
  1309  			if comment != nil {
  1310  				comments = append(comments, comment.CheckCommentString())
  1311  			}
  1312  		}
  1313  		return r(values...), check.Commentf("%v", strings.Join(comments, ", "))
  1314  	}
  1315  }
  1316  
  1317  func sumAsIntegers(vals ...interface{}) interface{} {
  1318  	var s int
  1319  	for _, v := range vals {
  1320  		s += v.(int)
  1321  	}
  1322  	return s
  1323  }