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

     1  // +build !test_no_exec
     2  
     3  package main
     4  
     5  import (
     6  	"bytes"
     7  	"encoding/json"
     8  	"fmt"
     9  	"net/http"
    10  	"strings"
    11  	"time"
    12  
    13  	"github.com/docker/docker/integration-cli/checker"
    14  	"github.com/docker/docker/integration-cli/request"
    15  	"github.com/docker/docker/pkg/testutil"
    16  	"github.com/go-check/check"
    17  )
    18  
    19  // Regression test for #9414
    20  func (s *DockerSuite) TestExecAPICreateNoCmd(c *check.C) {
    21  	name := "exec_test"
    22  	dockerCmd(c, "run", "-d", "-t", "--name", name, "busybox", "/bin/sh")
    23  
    24  	status, body, err := request.SockRequest("POST", fmt.Sprintf("/containers/%s/exec", name), map[string]interface{}{"Cmd": nil}, daemonHost())
    25  	c.Assert(err, checker.IsNil)
    26  	c.Assert(status, checker.Equals, http.StatusInternalServerError)
    27  
    28  	comment := check.Commentf("Expected message when creating exec command with no Cmd specified")
    29  	c.Assert(getErrorMessage(c, body), checker.Contains, "No exec command specified", comment)
    30  }
    31  
    32  func (s *DockerSuite) TestExecAPICreateNoValidContentType(c *check.C) {
    33  	name := "exec_test"
    34  	dockerCmd(c, "run", "-d", "-t", "--name", name, "busybox", "/bin/sh")
    35  
    36  	jsonData := bytes.NewBuffer(nil)
    37  	if err := json.NewEncoder(jsonData).Encode(map[string]interface{}{"Cmd": nil}); err != nil {
    38  		c.Fatalf("Can not encode data to json %s", err)
    39  	}
    40  
    41  	res, body, err := request.SockRequestRaw("POST", fmt.Sprintf("/containers/%s/exec", name), jsonData, "text/plain", daemonHost())
    42  	c.Assert(err, checker.IsNil)
    43  	c.Assert(res.StatusCode, checker.Equals, http.StatusInternalServerError)
    44  
    45  	b, err := testutil.ReadBody(body)
    46  	c.Assert(err, checker.IsNil)
    47  
    48  	comment := check.Commentf("Expected message when creating exec command with invalid Content-Type specified")
    49  	c.Assert(getErrorMessage(c, b), checker.Contains, "Content-Type specified", comment)
    50  }
    51  
    52  func (s *DockerSuite) TestExecAPICreateContainerPaused(c *check.C) {
    53  	// Not relevant on Windows as Windows containers cannot be paused
    54  	testRequires(c, DaemonIsLinux)
    55  	name := "exec_create_test"
    56  	dockerCmd(c, "run", "-d", "-t", "--name", name, "busybox", "/bin/sh")
    57  
    58  	dockerCmd(c, "pause", name)
    59  	status, body, err := request.SockRequest("POST", fmt.Sprintf("/containers/%s/exec", name), map[string]interface{}{"Cmd": []string{"true"}}, daemonHost())
    60  	c.Assert(err, checker.IsNil)
    61  	c.Assert(status, checker.Equals, http.StatusConflict)
    62  
    63  	comment := check.Commentf("Expected message when creating exec command with Container %s is paused", name)
    64  	c.Assert(getErrorMessage(c, body), checker.Contains, "Container "+name+" is paused, unpause the container before exec", comment)
    65  }
    66  
    67  func (s *DockerSuite) TestExecAPIStart(c *check.C) {
    68  	testRequires(c, DaemonIsLinux) // Uses pause/unpause but bits may be salvagable to Windows to Windows CI
    69  	dockerCmd(c, "run", "-d", "--name", "test", "busybox", "top")
    70  
    71  	id := createExec(c, "test")
    72  	startExec(c, id, http.StatusOK)
    73  
    74  	var execJSON struct{ PID int }
    75  	inspectExec(c, id, &execJSON)
    76  	c.Assert(execJSON.PID, checker.GreaterThan, 1)
    77  
    78  	id = createExec(c, "test")
    79  	dockerCmd(c, "stop", "test")
    80  
    81  	startExec(c, id, http.StatusNotFound)
    82  
    83  	dockerCmd(c, "start", "test")
    84  	startExec(c, id, http.StatusNotFound)
    85  
    86  	// make sure exec is created before pausing
    87  	id = createExec(c, "test")
    88  	dockerCmd(c, "pause", "test")
    89  	startExec(c, id, http.StatusConflict)
    90  	dockerCmd(c, "unpause", "test")
    91  	startExec(c, id, http.StatusOK)
    92  }
    93  
    94  func (s *DockerSuite) TestExecAPIStartEnsureHeaders(c *check.C) {
    95  	testRequires(c, DaemonIsLinux)
    96  	dockerCmd(c, "run", "-d", "--name", "test", "busybox", "top")
    97  
    98  	id := createExec(c, "test")
    99  	resp, _, err := request.SockRequestRaw("POST", fmt.Sprintf("/exec/%s/start", id), strings.NewReader(`{"Detach": true}`), "application/json", daemonHost())
   100  	c.Assert(err, checker.IsNil)
   101  	c.Assert(resp.Header.Get("Server"), checker.Not(checker.Equals), "")
   102  }
   103  
   104  func (s *DockerSuite) TestExecAPIStartBackwardsCompatible(c *check.C) {
   105  	testRequires(c, DaemonIsLinux) // Windows only supports 1.25 or later
   106  	runSleepingContainer(c, "-d", "--name", "test")
   107  	id := createExec(c, "test")
   108  
   109  	resp, body, err := request.SockRequestRaw("POST", fmt.Sprintf("/v1.20/exec/%s/start", id), strings.NewReader(`{"Detach": true}`), "text/plain", daemonHost())
   110  	c.Assert(err, checker.IsNil)
   111  
   112  	b, err := testutil.ReadBody(body)
   113  	comment := check.Commentf("response body: %s", b)
   114  	c.Assert(err, checker.IsNil, comment)
   115  	c.Assert(resp.StatusCode, checker.Equals, http.StatusOK, comment)
   116  }
   117  
   118  // #19362
   119  func (s *DockerSuite) TestExecAPIStartMultipleTimesError(c *check.C) {
   120  	runSleepingContainer(c, "-d", "--name", "test")
   121  	execID := createExec(c, "test")
   122  	startExec(c, execID, http.StatusOK)
   123  
   124  	timeout := time.After(60 * time.Second)
   125  	var execJSON struct{ Running bool }
   126  	for {
   127  		select {
   128  		case <-timeout:
   129  			c.Fatal("timeout waiting for exec to start")
   130  		default:
   131  		}
   132  
   133  		inspectExec(c, execID, &execJSON)
   134  		if !execJSON.Running {
   135  			break
   136  		}
   137  	}
   138  
   139  	startExec(c, execID, http.StatusConflict)
   140  }
   141  
   142  // #20638
   143  func (s *DockerSuite) TestExecAPIStartWithDetach(c *check.C) {
   144  	name := "foo"
   145  	runSleepingContainer(c, "-d", "-t", "--name", name)
   146  	data := map[string]interface{}{
   147  		"cmd":         []string{"true"},
   148  		"AttachStdin": true,
   149  	}
   150  	_, b, err := request.SockRequest("POST", fmt.Sprintf("/containers/%s/exec", name), data, daemonHost())
   151  	c.Assert(err, checker.IsNil, check.Commentf(string(b)))
   152  
   153  	createResp := struct {
   154  		ID string `json:"Id"`
   155  	}{}
   156  	c.Assert(json.Unmarshal(b, &createResp), checker.IsNil, check.Commentf(string(b)))
   157  
   158  	_, body, err := request.SockRequestRaw("POST", fmt.Sprintf("/exec/%s/start", createResp.ID), strings.NewReader(`{"Detach": true}`), "application/json", daemonHost())
   159  	c.Assert(err, checker.IsNil)
   160  
   161  	b, err = testutil.ReadBody(body)
   162  	comment := check.Commentf("response body: %s", b)
   163  	c.Assert(err, checker.IsNil, comment)
   164  
   165  	resp, _, err := request.SockRequestRaw("GET", "/_ping", nil, "", daemonHost())
   166  	c.Assert(err, checker.IsNil)
   167  	if resp.StatusCode != http.StatusOK {
   168  		c.Fatal("daemon is down, it should alive")
   169  	}
   170  }
   171  
   172  func createExec(c *check.C, name string) string {
   173  	_, b, err := request.SockRequest("POST", fmt.Sprintf("/containers/%s/exec", name), map[string]interface{}{"Cmd": []string{"true"}}, daemonHost())
   174  	c.Assert(err, checker.IsNil, check.Commentf(string(b)))
   175  
   176  	createResp := struct {
   177  		ID string `json:"Id"`
   178  	}{}
   179  	c.Assert(json.Unmarshal(b, &createResp), checker.IsNil, check.Commentf(string(b)))
   180  	return createResp.ID
   181  }
   182  
   183  func startExec(c *check.C, id string, code int) {
   184  	resp, body, err := request.SockRequestRaw("POST", fmt.Sprintf("/exec/%s/start", id), strings.NewReader(`{"Detach": true}`), "application/json", daemonHost())
   185  	c.Assert(err, checker.IsNil)
   186  
   187  	b, err := testutil.ReadBody(body)
   188  	comment := check.Commentf("response body: %s", b)
   189  	c.Assert(err, checker.IsNil, comment)
   190  	c.Assert(resp.StatusCode, checker.Equals, code, comment)
   191  }
   192  
   193  func inspectExec(c *check.C, id string, out interface{}) {
   194  	resp, body, err := request.SockRequestRaw("GET", fmt.Sprintf("/exec/%s/json", id), nil, "", daemonHost())
   195  	c.Assert(err, checker.IsNil)
   196  	defer body.Close()
   197  	c.Assert(resp.StatusCode, checker.Equals, http.StatusOK)
   198  	err = json.NewDecoder(body).Decode(out)
   199  	c.Assert(err, checker.IsNil)
   200  }