github.com/titanous/docker@v1.4.1/integration/api_test.go (about)

     1  package docker
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"encoding/json"
     7  	"fmt"
     8  	"io"
     9  	"io/ioutil"
    10  	"net"
    11  	"net/http"
    12  	"net/http/httptest"
    13  	"strings"
    14  	"testing"
    15  	"time"
    16  
    17  	"github.com/docker/docker/api"
    18  	"github.com/docker/docker/api/server"
    19  	"github.com/docker/docker/engine"
    20  	"github.com/docker/docker/runconfig"
    21  	"github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
    22  )
    23  
    24  func TestSaveImageAndThenLoad(t *testing.T) {
    25  	eng := NewTestEngine(t)
    26  	defer mkDaemonFromEngine(eng, t).Nuke()
    27  
    28  	// save image
    29  	r := httptest.NewRecorder()
    30  	req, err := http.NewRequest("GET", "/images/"+unitTestImageID+"/get", nil)
    31  	if err != nil {
    32  		t.Fatal(err)
    33  	}
    34  	if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
    35  		t.Fatal(err)
    36  	}
    37  	if r.Code != http.StatusOK {
    38  		t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
    39  	}
    40  	tarball := r.Body
    41  
    42  	// delete the image
    43  	r = httptest.NewRecorder()
    44  	req, err = http.NewRequest("DELETE", "/images/"+unitTestImageID, nil)
    45  	if err != nil {
    46  		t.Fatal(err)
    47  	}
    48  	if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
    49  		t.Fatal(err)
    50  	}
    51  	if r.Code != http.StatusOK {
    52  		t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
    53  	}
    54  
    55  	// make sure there is no image
    56  	r = httptest.NewRecorder()
    57  	req, err = http.NewRequest("GET", "/images/"+unitTestImageID+"/get", nil)
    58  	if err != nil {
    59  		t.Fatal(err)
    60  	}
    61  	if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
    62  		t.Fatal(err)
    63  	}
    64  	if r.Code != http.StatusNotFound {
    65  		t.Fatalf("%d NotFound expected, received %d\n", http.StatusNotFound, r.Code)
    66  	}
    67  
    68  	// load the image
    69  	r = httptest.NewRecorder()
    70  	req, err = http.NewRequest("POST", "/images/load", tarball)
    71  	if err != nil {
    72  		t.Fatal(err)
    73  	}
    74  	if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
    75  		t.Fatal(err)
    76  	}
    77  	if r.Code != http.StatusOK {
    78  		t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
    79  	}
    80  
    81  	// finally make sure the image is there
    82  	r = httptest.NewRecorder()
    83  	req, err = http.NewRequest("GET", "/images/"+unitTestImageID+"/get", nil)
    84  	if err != nil {
    85  		t.Fatal(err)
    86  	}
    87  	if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
    88  		t.Fatal(err)
    89  	}
    90  	if r.Code != http.StatusOK {
    91  		t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
    92  	}
    93  }
    94  
    95  func TestGetContainersTop(t *testing.T) {
    96  	eng := NewTestEngine(t)
    97  	defer mkDaemonFromEngine(eng, t).Nuke()
    98  
    99  	containerID := createTestContainer(eng,
   100  		&runconfig.Config{
   101  			Image:     unitTestImageID,
   102  			Cmd:       []string{"/bin/sh", "-c", "cat"},
   103  			OpenStdin: true,
   104  		},
   105  		t,
   106  	)
   107  	defer func() {
   108  		// Make sure the process dies before destroying daemon
   109  		containerKill(eng, containerID, t)
   110  		containerWait(eng, containerID, t)
   111  	}()
   112  
   113  	startContainer(eng, containerID, t)
   114  
   115  	setTimeout(t, "Waiting for the container to be started timed out", 10*time.Second, func() {
   116  		for {
   117  			if containerRunning(eng, containerID, t) {
   118  				break
   119  			}
   120  			time.Sleep(10 * time.Millisecond)
   121  		}
   122  	})
   123  
   124  	if !containerRunning(eng, containerID, t) {
   125  		t.Fatalf("Container should be running")
   126  	}
   127  
   128  	// Make sure sh spawn up cat
   129  	setTimeout(t, "read/write assertion timed out", 2*time.Second, func() {
   130  		in, out := containerAttach(eng, containerID, t)
   131  		if err := assertPipe("hello\n", "hello", out, in, 150); err != nil {
   132  			t.Fatal(err)
   133  		}
   134  	})
   135  
   136  	r := httptest.NewRecorder()
   137  	req, err := http.NewRequest("GET", "/containers/"+containerID+"/top?ps_args=aux", nil)
   138  	if err != nil {
   139  		t.Fatal(err)
   140  	}
   141  	if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
   142  		t.Fatal(err)
   143  	}
   144  	assertHttpNotError(r, t)
   145  	var procs engine.Env
   146  	if err := procs.Decode(r.Body); err != nil {
   147  		t.Fatal(err)
   148  	}
   149  
   150  	if len(procs.GetList("Titles")) != 11 {
   151  		t.Fatalf("Expected 11 titles, found %d.", len(procs.GetList("Titles")))
   152  	}
   153  	if procs.GetList("Titles")[0] != "USER" || procs.GetList("Titles")[10] != "COMMAND" {
   154  		t.Fatalf("Expected Titles[0] to be USER and Titles[10] to be COMMAND, found %s and %s.", procs.GetList("Titles")[0], procs.GetList("Titles")[10])
   155  	}
   156  	processes := [][]string{}
   157  	if err := procs.GetJson("Processes", &processes); err != nil {
   158  		t.Fatal(err)
   159  	}
   160  	if len(processes) != 2 {
   161  		t.Fatalf("Expected 2 processes, found %d.", len(processes))
   162  	}
   163  	if processes[0][10] != "/bin/sh -c cat" {
   164  		t.Fatalf("Expected `/bin/sh -c cat`, found %s.", processes[0][10])
   165  	}
   166  	if processes[1][10] != "/bin/sh -c cat" {
   167  		t.Fatalf("Expected `/bin/sh -c cat`, found %s.", processes[1][10])
   168  	}
   169  }
   170  
   171  func TestPostCommit(t *testing.T) {
   172  	eng := NewTestEngine(t)
   173  	defer mkDaemonFromEngine(eng, t).Nuke()
   174  
   175  	// Create a container and remove a file
   176  	containerID := createTestContainer(eng,
   177  		&runconfig.Config{
   178  			Image: unitTestImageID,
   179  			Cmd:   []string{"touch", "/test"},
   180  		},
   181  		t,
   182  	)
   183  
   184  	containerRun(eng, containerID, t)
   185  
   186  	req, err := http.NewRequest("POST", "/commit?repo=testrepo&testtag=tag&container="+containerID, bytes.NewReader([]byte{}))
   187  	if err != nil {
   188  		t.Fatal(err)
   189  	}
   190  
   191  	r := httptest.NewRecorder()
   192  	if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
   193  		t.Fatal(err)
   194  	}
   195  	assertHttpNotError(r, t)
   196  	if r.Code != http.StatusCreated {
   197  		t.Fatalf("%d Created expected, received %d\n", http.StatusCreated, r.Code)
   198  	}
   199  
   200  	var env engine.Env
   201  	if err := env.Decode(r.Body); err != nil {
   202  		t.Fatal(err)
   203  	}
   204  	if err := eng.Job("image_inspect", env.Get("Id")).Run(); err != nil {
   205  		t.Fatalf("The image has not been committed")
   206  	}
   207  }
   208  
   209  func TestPostContainersCreate(t *testing.T) {
   210  	eng := NewTestEngine(t)
   211  	defer mkDaemonFromEngine(eng, t).Nuke()
   212  
   213  	configJSON, err := json.Marshal(&runconfig.Config{
   214  		Image:  unitTestImageID,
   215  		Memory: 33554432,
   216  		Cmd:    []string{"touch", "/test"},
   217  	})
   218  	if err != nil {
   219  		t.Fatal(err)
   220  	}
   221  
   222  	req, err := http.NewRequest("POST", "/containers/create", bytes.NewReader(configJSON))
   223  	if err != nil {
   224  		t.Fatal(err)
   225  	}
   226  
   227  	req.Header.Set("Content-Type", "application/json")
   228  
   229  	r := httptest.NewRecorder()
   230  	if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
   231  		t.Fatal(err)
   232  	}
   233  	assertHttpNotError(r, t)
   234  	if r.Code != http.StatusCreated {
   235  		t.Fatalf("%d Created expected, received %d\n", http.StatusCreated, r.Code)
   236  	}
   237  
   238  	var apiRun engine.Env
   239  	if err := apiRun.Decode(r.Body); err != nil {
   240  		t.Fatal(err)
   241  	}
   242  	containerID := apiRun.Get("Id")
   243  
   244  	containerAssertExists(eng, containerID, t)
   245  	containerRun(eng, containerID, t)
   246  
   247  	if !containerFileExists(eng, containerID, "test", t) {
   248  		t.Fatal("Test file was not created")
   249  	}
   250  }
   251  
   252  func TestPostJsonVerify(t *testing.T) {
   253  	eng := NewTestEngine(t)
   254  	defer mkDaemonFromEngine(eng, t).Nuke()
   255  
   256  	configJSON, err := json.Marshal(&runconfig.Config{
   257  		Image:  unitTestImageID,
   258  		Memory: 33554432,
   259  		Cmd:    []string{"touch", "/test"},
   260  	})
   261  	if err != nil {
   262  		t.Fatal(err)
   263  	}
   264  
   265  	req, err := http.NewRequest("POST", "/containers/create", bytes.NewReader(configJSON))
   266  	if err != nil {
   267  		t.Fatal(err)
   268  	}
   269  
   270  	r := httptest.NewRecorder()
   271  
   272  	if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
   273  		t.Fatal(err)
   274  	}
   275  
   276  	// Don't add Content-Type header
   277  	// req.Header.Set("Content-Type", "application/json")
   278  
   279  	err = server.ServeRequest(eng, api.APIVERSION, r, req)
   280  	if r.Code != http.StatusInternalServerError || !strings.Contains(((*r.Body).String()), "application/json") {
   281  		t.Fatal("Create should have failed due to no Content-Type header - got:", r)
   282  	}
   283  
   284  	// Now add header but with wrong type and retest
   285  	req.Header.Set("Content-Type", "application/xml")
   286  
   287  	if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
   288  		t.Fatal(err)
   289  	}
   290  	if r.Code != http.StatusInternalServerError || !strings.Contains(((*r.Body).String()), "application/json") {
   291  		t.Fatal("Create should have failed due to wrong Content-Type header - got:", r)
   292  	}
   293  }
   294  
   295  // Issue 7941 - test to make sure a "null" in JSON is just ignored.
   296  // W/o this fix a null in JSON would be parsed into a string var as "null"
   297  func TestPostCreateNull(t *testing.T) {
   298  	eng := NewTestEngine(t)
   299  	daemon := mkDaemonFromEngine(eng, t)
   300  	defer daemon.Nuke()
   301  
   302  	configStr := fmt.Sprintf(`{
   303  		"Hostname":"",
   304  		"Domainname":"",
   305  		"Memory":0,
   306  		"MemorySwap":0,
   307  		"CpuShares":0,
   308  		"Cpuset":null,
   309  		"AttachStdin":true,
   310  		"AttachStdout":true,
   311  		"AttachStderr":true,
   312  		"PortSpecs":null,
   313  		"ExposedPorts":{},
   314  		"Tty":true,
   315  		"OpenStdin":true,
   316  		"StdinOnce":true,
   317  		"Env":[],
   318  		"Cmd":"ls",
   319  		"Image":"%s",
   320  		"Volumes":{},
   321  		"WorkingDir":"",
   322  		"Entrypoint":null,
   323  		"NetworkDisabled":false,
   324  		"OnBuild":null}`, unitTestImageID)
   325  
   326  	req, err := http.NewRequest("POST", "/containers/create", strings.NewReader(configStr))
   327  	if err != nil {
   328  		t.Fatal(err)
   329  	}
   330  
   331  	req.Header.Set("Content-Type", "application/json")
   332  
   333  	r := httptest.NewRecorder()
   334  	if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
   335  		t.Fatal(err)
   336  	}
   337  	assertHttpNotError(r, t)
   338  	if r.Code != http.StatusCreated {
   339  		t.Fatalf("%d Created expected, received %d\n", http.StatusCreated, r.Code)
   340  	}
   341  
   342  	var apiRun engine.Env
   343  	if err := apiRun.Decode(r.Body); err != nil {
   344  		t.Fatal(err)
   345  	}
   346  	containerID := apiRun.Get("Id")
   347  
   348  	containerAssertExists(eng, containerID, t)
   349  
   350  	c := daemon.Get(containerID)
   351  	if c.Config.Cpuset != "" {
   352  		t.Fatalf("Cpuset should have been empty - instead its:" + c.Config.Cpuset)
   353  	}
   354  }
   355  
   356  func TestPostContainersKill(t *testing.T) {
   357  	eng := NewTestEngine(t)
   358  	defer mkDaemonFromEngine(eng, t).Nuke()
   359  
   360  	containerID := createTestContainer(eng,
   361  		&runconfig.Config{
   362  			Image:     unitTestImageID,
   363  			Cmd:       []string{"/bin/cat"},
   364  			OpenStdin: true,
   365  		},
   366  		t,
   367  	)
   368  
   369  	startContainer(eng, containerID, t)
   370  
   371  	// Give some time to the process to start
   372  	containerWaitTimeout(eng, containerID, t)
   373  
   374  	if !containerRunning(eng, containerID, t) {
   375  		t.Errorf("Container should be running")
   376  	}
   377  
   378  	r := httptest.NewRecorder()
   379  	req, err := http.NewRequest("POST", "/containers/"+containerID+"/kill", bytes.NewReader([]byte{}))
   380  	if err != nil {
   381  		t.Fatal(err)
   382  	}
   383  	if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
   384  		t.Fatal(err)
   385  	}
   386  	assertHttpNotError(r, t)
   387  	if r.Code != http.StatusNoContent {
   388  		t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
   389  	}
   390  	if containerRunning(eng, containerID, t) {
   391  		t.Fatalf("The container hasn't been killed")
   392  	}
   393  }
   394  
   395  func TestPostContainersRestart(t *testing.T) {
   396  	eng := NewTestEngine(t)
   397  	defer mkDaemonFromEngine(eng, t).Nuke()
   398  
   399  	containerID := createTestContainer(eng,
   400  		&runconfig.Config{
   401  			Image:     unitTestImageID,
   402  			Cmd:       []string{"/bin/top"},
   403  			OpenStdin: true,
   404  		},
   405  		t,
   406  	)
   407  
   408  	startContainer(eng, containerID, t)
   409  
   410  	// Give some time to the process to start
   411  	containerWaitTimeout(eng, containerID, t)
   412  
   413  	if !containerRunning(eng, containerID, t) {
   414  		t.Errorf("Container should be running")
   415  	}
   416  
   417  	req, err := http.NewRequest("POST", "/containers/"+containerID+"/restart?t=1", bytes.NewReader([]byte{}))
   418  	if err != nil {
   419  		t.Fatal(err)
   420  	}
   421  	r := httptest.NewRecorder()
   422  	if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
   423  		t.Fatal(err)
   424  	}
   425  	assertHttpNotError(r, t)
   426  	if r.Code != http.StatusNoContent {
   427  		t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
   428  	}
   429  
   430  	// Give some time to the process to restart
   431  	containerWaitTimeout(eng, containerID, t)
   432  
   433  	if !containerRunning(eng, containerID, t) {
   434  		t.Fatalf("Container should be running")
   435  	}
   436  
   437  	containerKill(eng, containerID, t)
   438  }
   439  
   440  func TestPostContainersStart(t *testing.T) {
   441  	eng := NewTestEngine(t)
   442  	defer mkDaemonFromEngine(eng, t).Nuke()
   443  
   444  	containerID := createTestContainer(
   445  		eng,
   446  		&runconfig.Config{
   447  			Image:     unitTestImageID,
   448  			Cmd:       []string{"/bin/cat"},
   449  			OpenStdin: true,
   450  		},
   451  		t,
   452  	)
   453  
   454  	hostConfigJSON, err := json.Marshal(&runconfig.HostConfig{})
   455  
   456  	req, err := http.NewRequest("POST", "/containers/"+containerID+"/start", bytes.NewReader(hostConfigJSON))
   457  	if err != nil {
   458  		t.Fatal(err)
   459  	}
   460  
   461  	req.Header.Set("Content-Type", "application/json")
   462  
   463  	r := httptest.NewRecorder()
   464  	if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
   465  		t.Fatal(err)
   466  	}
   467  	assertHttpNotError(r, t)
   468  	if r.Code != http.StatusNoContent {
   469  		t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
   470  	}
   471  
   472  	containerAssertExists(eng, containerID, t)
   473  
   474  	req, err = http.NewRequest("POST", "/containers/"+containerID+"/start", bytes.NewReader(hostConfigJSON))
   475  	if err != nil {
   476  		t.Fatal(err)
   477  	}
   478  
   479  	req.Header.Set("Content-Type", "application/json")
   480  
   481  	r = httptest.NewRecorder()
   482  	if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
   483  		t.Fatal(err)
   484  	}
   485  
   486  	// Starting an already started container should return a 304
   487  	assertHttpNotError(r, t)
   488  	if r.Code != http.StatusNotModified {
   489  		t.Fatalf("%d NOT MODIFIER expected, received %d\n", http.StatusNotModified, r.Code)
   490  	}
   491  	containerAssertExists(eng, containerID, t)
   492  	containerKill(eng, containerID, t)
   493  }
   494  
   495  func TestPostContainersStop(t *testing.T) {
   496  	eng := NewTestEngine(t)
   497  	defer mkDaemonFromEngine(eng, t).Nuke()
   498  
   499  	containerID := createTestContainer(eng,
   500  		&runconfig.Config{
   501  			Image:     unitTestImageID,
   502  			Cmd:       []string{"/bin/top"},
   503  			OpenStdin: true,
   504  		},
   505  		t,
   506  	)
   507  
   508  	startContainer(eng, containerID, t)
   509  
   510  	// Give some time to the process to start
   511  	containerWaitTimeout(eng, containerID, t)
   512  
   513  	if !containerRunning(eng, containerID, t) {
   514  		t.Errorf("Container should be running")
   515  	}
   516  
   517  	// Note: as it is a POST request, it requires a body.
   518  	req, err := http.NewRequest("POST", "/containers/"+containerID+"/stop?t=1", bytes.NewReader([]byte{}))
   519  	if err != nil {
   520  		t.Fatal(err)
   521  	}
   522  	r := httptest.NewRecorder()
   523  	if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
   524  		t.Fatal(err)
   525  	}
   526  	assertHttpNotError(r, t)
   527  	if r.Code != http.StatusNoContent {
   528  		t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
   529  	}
   530  	if containerRunning(eng, containerID, t) {
   531  		t.Fatalf("The container hasn't been stopped")
   532  	}
   533  
   534  	req, err = http.NewRequest("POST", "/containers/"+containerID+"/stop?t=1", bytes.NewReader([]byte{}))
   535  	if err != nil {
   536  		t.Fatal(err)
   537  	}
   538  
   539  	r = httptest.NewRecorder()
   540  	if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
   541  		t.Fatal(err)
   542  	}
   543  
   544  	// Stopping an already stopper container should return a 304
   545  	assertHttpNotError(r, t)
   546  	if r.Code != http.StatusNotModified {
   547  		t.Fatalf("%d NOT MODIFIER expected, received %d\n", http.StatusNotModified, r.Code)
   548  	}
   549  }
   550  
   551  func TestPostContainersWait(t *testing.T) {
   552  	eng := NewTestEngine(t)
   553  	defer mkDaemonFromEngine(eng, t).Nuke()
   554  
   555  	containerID := createTestContainer(eng,
   556  		&runconfig.Config{
   557  			Image:     unitTestImageID,
   558  			Cmd:       []string{"/bin/sleep", "1"},
   559  			OpenStdin: true,
   560  		},
   561  		t,
   562  	)
   563  	startContainer(eng, containerID, t)
   564  
   565  	setTimeout(t, "Wait timed out", 3*time.Second, func() {
   566  		r := httptest.NewRecorder()
   567  		req, err := http.NewRequest("POST", "/containers/"+containerID+"/wait", bytes.NewReader([]byte{}))
   568  		if err != nil {
   569  			t.Fatal(err)
   570  		}
   571  		if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
   572  			t.Fatal(err)
   573  		}
   574  		assertHttpNotError(r, t)
   575  		var apiWait engine.Env
   576  		if err := apiWait.Decode(r.Body); err != nil {
   577  			t.Fatal(err)
   578  		}
   579  		if apiWait.GetInt("StatusCode") != 0 {
   580  			t.Fatalf("Non zero exit code for sleep: %d\n", apiWait.GetInt("StatusCode"))
   581  		}
   582  	})
   583  
   584  	if containerRunning(eng, containerID, t) {
   585  		t.Fatalf("The container should be stopped after wait")
   586  	}
   587  }
   588  
   589  func TestPostContainersAttach(t *testing.T) {
   590  	eng := NewTestEngine(t)
   591  	defer mkDaemonFromEngine(eng, t).Nuke()
   592  
   593  	containerID := createTestContainer(eng,
   594  		&runconfig.Config{
   595  			Image:     unitTestImageID,
   596  			Cmd:       []string{"/bin/cat"},
   597  			OpenStdin: true,
   598  		},
   599  		t,
   600  	)
   601  	// Start the process
   602  	startContainer(eng, containerID, t)
   603  
   604  	stdin, stdinPipe := io.Pipe()
   605  	stdout, stdoutPipe := io.Pipe()
   606  
   607  	// Try to avoid the timeout in destroy. Best effort, don't check error
   608  	defer func() {
   609  		closeWrap(stdin, stdinPipe, stdout, stdoutPipe)
   610  		containerKill(eng, containerID, t)
   611  	}()
   612  
   613  	// Attach to it
   614  	c1 := make(chan struct{})
   615  	go func() {
   616  		defer close(c1)
   617  
   618  		r := &hijackTester{
   619  			ResponseRecorder: httptest.NewRecorder(),
   620  			in:               stdin,
   621  			out:              stdoutPipe,
   622  		}
   623  
   624  		req, err := http.NewRequest("POST", "/containers/"+containerID+"/attach?stream=1&stdin=1&stdout=1&stderr=1", bytes.NewReader([]byte{}))
   625  		if err != nil {
   626  			t.Fatal(err)
   627  		}
   628  
   629  		if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
   630  			t.Fatal(err)
   631  		}
   632  		assertHttpNotError(r.ResponseRecorder, t)
   633  	}()
   634  
   635  	// Acknowledge hijack
   636  	setTimeout(t, "hijack acknowledge timed out", 2*time.Second, func() {
   637  		stdout.Read([]byte{})
   638  		stdout.Read(make([]byte, 4096))
   639  	})
   640  
   641  	setTimeout(t, "read/write assertion timed out", 2*time.Second, func() {
   642  		if err := assertPipe("hello\n", string([]byte{1, 0, 0, 0, 0, 0, 0, 6})+"hello", stdout, stdinPipe, 150); err != nil {
   643  			t.Fatal(err)
   644  		}
   645  	})
   646  
   647  	// Close pipes (client disconnects)
   648  	if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
   649  		t.Fatal(err)
   650  	}
   651  
   652  	// Wait for attach to finish, the client disconnected, therefore, Attach finished his job
   653  	setTimeout(t, "Waiting for CmdAttach timed out", 10*time.Second, func() {
   654  		<-c1
   655  	})
   656  
   657  	// We closed stdin, expect /bin/cat to still be running
   658  	// Wait a little bit to make sure container.monitor() did his thing
   659  	containerWaitTimeout(eng, containerID, t)
   660  
   661  	// Try to avoid the timeout in destroy. Best effort, don't check error
   662  	cStdin, _ := containerAttach(eng, containerID, t)
   663  	cStdin.Close()
   664  	containerWait(eng, containerID, t)
   665  }
   666  
   667  func TestPostContainersAttachStderr(t *testing.T) {
   668  	eng := NewTestEngine(t)
   669  	defer mkDaemonFromEngine(eng, t).Nuke()
   670  
   671  	containerID := createTestContainer(eng,
   672  		&runconfig.Config{
   673  			Image:     unitTestImageID,
   674  			Cmd:       []string{"/bin/sh", "-c", "/bin/cat >&2"},
   675  			OpenStdin: true,
   676  		},
   677  		t,
   678  	)
   679  	// Start the process
   680  	startContainer(eng, containerID, t)
   681  
   682  	stdin, stdinPipe := io.Pipe()
   683  	stdout, stdoutPipe := io.Pipe()
   684  
   685  	// Try to avoid the timeout in destroy. Best effort, don't check error
   686  	defer func() {
   687  		closeWrap(stdin, stdinPipe, stdout, stdoutPipe)
   688  		containerKill(eng, containerID, t)
   689  	}()
   690  
   691  	// Attach to it
   692  	c1 := make(chan struct{})
   693  	go func() {
   694  		defer close(c1)
   695  
   696  		r := &hijackTester{
   697  			ResponseRecorder: httptest.NewRecorder(),
   698  			in:               stdin,
   699  			out:              stdoutPipe,
   700  		}
   701  
   702  		req, err := http.NewRequest("POST", "/containers/"+containerID+"/attach?stream=1&stdin=1&stdout=1&stderr=1", bytes.NewReader([]byte{}))
   703  		if err != nil {
   704  			t.Fatal(err)
   705  		}
   706  
   707  		if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
   708  			t.Fatal(err)
   709  		}
   710  		assertHttpNotError(r.ResponseRecorder, t)
   711  	}()
   712  
   713  	// Acknowledge hijack
   714  	setTimeout(t, "hijack acknowledge timed out", 2*time.Second, func() {
   715  		stdout.Read([]byte{})
   716  		stdout.Read(make([]byte, 4096))
   717  	})
   718  
   719  	setTimeout(t, "read/write assertion timed out", 2*time.Second, func() {
   720  		if err := assertPipe("hello\n", string([]byte{2, 0, 0, 0, 0, 0, 0, 6})+"hello", stdout, stdinPipe, 150); err != nil {
   721  			t.Fatal(err)
   722  		}
   723  	})
   724  
   725  	// Close pipes (client disconnects)
   726  	if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
   727  		t.Fatal(err)
   728  	}
   729  
   730  	// Wait for attach to finish, the client disconnected, therefore, Attach finished his job
   731  	setTimeout(t, "Waiting for CmdAttach timed out", 10*time.Second, func() {
   732  		<-c1
   733  	})
   734  
   735  	// We closed stdin, expect /bin/cat to still be running
   736  	// Wait a little bit to make sure container.monitor() did his thing
   737  	containerWaitTimeout(eng, containerID, t)
   738  
   739  	// Try to avoid the timeout in destroy. Best effort, don't check error
   740  	cStdin, _ := containerAttach(eng, containerID, t)
   741  	cStdin.Close()
   742  	containerWait(eng, containerID, t)
   743  }
   744  
   745  func TestOptionsRoute(t *testing.T) {
   746  	eng := NewTestEngine(t)
   747  	defer mkDaemonFromEngine(eng, t).Nuke()
   748  
   749  	r := httptest.NewRecorder()
   750  	req, err := http.NewRequest("OPTIONS", "/", nil)
   751  	if err != nil {
   752  		t.Fatal(err)
   753  	}
   754  	if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
   755  		t.Fatal(err)
   756  	}
   757  	assertHttpNotError(r, t)
   758  	if r.Code != http.StatusOK {
   759  		t.Errorf("Expected response for OPTIONS request to be \"200\", %v found.", r.Code)
   760  	}
   761  }
   762  
   763  func TestGetEnabledCors(t *testing.T) {
   764  	eng := NewTestEngine(t)
   765  	defer mkDaemonFromEngine(eng, t).Nuke()
   766  
   767  	r := httptest.NewRecorder()
   768  
   769  	req, err := http.NewRequest("GET", "/version", nil)
   770  	if err != nil {
   771  		t.Fatal(err)
   772  	}
   773  	if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
   774  		t.Fatal(err)
   775  	}
   776  	assertHttpNotError(r, t)
   777  	if r.Code != http.StatusOK {
   778  		t.Errorf("Expected response for OPTIONS request to be \"200\", %v found.", r.Code)
   779  	}
   780  
   781  	allowOrigin := r.Header().Get("Access-Control-Allow-Origin")
   782  	allowHeaders := r.Header().Get("Access-Control-Allow-Headers")
   783  	allowMethods := r.Header().Get("Access-Control-Allow-Methods")
   784  
   785  	if allowOrigin != "*" {
   786  		t.Errorf("Expected header Access-Control-Allow-Origin to be \"*\", %s found.", allowOrigin)
   787  	}
   788  	if allowHeaders != "Origin, X-Requested-With, Content-Type, Accept, X-Registry-Auth" {
   789  		t.Errorf("Expected header Access-Control-Allow-Headers to be \"Origin, X-Requested-With, Content-Type, Accept, X-Registry-Auth\", %s found.", allowHeaders)
   790  	}
   791  	if allowMethods != "GET, POST, DELETE, PUT, OPTIONS" {
   792  		t.Errorf("Expected hearder Access-Control-Allow-Methods to be \"GET, POST, DELETE, PUT, OPTIONS\", %s found.", allowMethods)
   793  	}
   794  }
   795  
   796  func TestDeleteImages(t *testing.T) {
   797  	eng := NewTestEngine(t)
   798  	//we expect errors, so we disable stderr
   799  	eng.Stderr = ioutil.Discard
   800  	defer mkDaemonFromEngine(eng, t).Nuke()
   801  
   802  	initialImages := getImages(eng, t, true, "")
   803  
   804  	if err := eng.Job("tag", unitTestImageName, "test", "test").Run(); err != nil {
   805  		t.Fatal(err)
   806  	}
   807  
   808  	images := getImages(eng, t, true, "")
   809  
   810  	if len(images.Data[0].GetList("RepoTags")) != len(initialImages.Data[0].GetList("RepoTags"))+1 {
   811  		t.Errorf("Expected %d images, %d found", len(initialImages.Data[0].GetList("RepoTags"))+1, len(images.Data[0].GetList("RepoTags")))
   812  	}
   813  
   814  	req, err := http.NewRequest("DELETE", "/images/"+unitTestImageID, nil)
   815  	if err != nil {
   816  		t.Fatal(err)
   817  	}
   818  
   819  	r := httptest.NewRecorder()
   820  	if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
   821  		t.Fatal(err)
   822  	}
   823  	if r.Code != http.StatusConflict {
   824  		t.Fatalf("Expected http status 409-conflict, got %v", r.Code)
   825  	}
   826  
   827  	req2, err := http.NewRequest("DELETE", "/images/test:test", nil)
   828  	if err != nil {
   829  		t.Fatal(err)
   830  	}
   831  
   832  	r2 := httptest.NewRecorder()
   833  	if err := server.ServeRequest(eng, api.APIVERSION, r2, req2); err != nil {
   834  		t.Fatal(err)
   835  	}
   836  	assertHttpNotError(r2, t)
   837  	if r2.Code != http.StatusOK {
   838  		t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
   839  	}
   840  
   841  	outs := engine.NewTable("Created", 0)
   842  	if _, err := outs.ReadListFrom(r2.Body.Bytes()); err != nil {
   843  		t.Fatal(err)
   844  	}
   845  	if len(outs.Data) != 1 {
   846  		t.Fatalf("Expected %d event (untagged), got %d", 1, len(outs.Data))
   847  	}
   848  	images = getImages(eng, t, false, "")
   849  
   850  	if images.Len() != initialImages.Len() {
   851  		t.Errorf("Expected %d image, %d found", initialImages.Len(), images.Len())
   852  	}
   853  }
   854  
   855  func TestPostContainersCopy(t *testing.T) {
   856  	eng := NewTestEngine(t)
   857  	defer mkDaemonFromEngine(eng, t).Nuke()
   858  
   859  	// Create a container and remove a file
   860  	containerID := createTestContainer(eng,
   861  		&runconfig.Config{
   862  			Image: unitTestImageID,
   863  			Cmd:   []string{"touch", "/test.txt"},
   864  		},
   865  		t,
   866  	)
   867  	containerRun(eng, containerID, t)
   868  
   869  	r := httptest.NewRecorder()
   870  
   871  	var copyData engine.Env
   872  	copyData.Set("Resource", "/test.txt")
   873  	copyData.Set("HostPath", ".")
   874  
   875  	jsonData := bytes.NewBuffer(nil)
   876  	if err := copyData.Encode(jsonData); err != nil {
   877  		t.Fatal(err)
   878  	}
   879  
   880  	req, err := http.NewRequest("POST", "/containers/"+containerID+"/copy", jsonData)
   881  	if err != nil {
   882  		t.Fatal(err)
   883  	}
   884  	req.Header.Add("Content-Type", "application/json")
   885  	if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
   886  		t.Fatal(err)
   887  	}
   888  	assertHttpNotError(r, t)
   889  
   890  	if r.Code != http.StatusOK {
   891  		t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
   892  	}
   893  
   894  	found := false
   895  	for tarReader := tar.NewReader(r.Body); ; {
   896  		h, err := tarReader.Next()
   897  		if err != nil {
   898  			if err == io.EOF {
   899  				break
   900  			}
   901  			t.Fatal(err)
   902  		}
   903  		if h.Name == "test.txt" {
   904  			found = true
   905  			break
   906  		}
   907  	}
   908  	if !found {
   909  		t.Fatalf("The created test file has not been found in the copied output")
   910  	}
   911  }
   912  
   913  func TestPostContainersCopyWhenContainerNotFound(t *testing.T) {
   914  	eng := NewTestEngine(t)
   915  	defer mkDaemonFromEngine(eng, t).Nuke()
   916  
   917  	r := httptest.NewRecorder()
   918  
   919  	var copyData engine.Env
   920  	copyData.Set("Resource", "/test.txt")
   921  	copyData.Set("HostPath", ".")
   922  
   923  	jsonData := bytes.NewBuffer(nil)
   924  	if err := copyData.Encode(jsonData); err != nil {
   925  		t.Fatal(err)
   926  	}
   927  
   928  	req, err := http.NewRequest("POST", "/containers/id_not_found/copy", jsonData)
   929  	if err != nil {
   930  		t.Fatal(err)
   931  	}
   932  	req.Header.Add("Content-Type", "application/json")
   933  	if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
   934  		t.Fatal(err)
   935  	}
   936  	if r.Code != http.StatusNotFound {
   937  		t.Fatalf("404 expected for id_not_found Container, received %v", r.Code)
   938  	}
   939  }
   940  
   941  // Regression test for https://github.com/docker/docker/issues/6231
   942  func TestConstainersStartChunkedEncodingHostConfig(t *testing.T) {
   943  	eng := NewTestEngine(t)
   944  	defer mkDaemonFromEngine(eng, t).Nuke()
   945  
   946  	r := httptest.NewRecorder()
   947  
   948  	var testData engine.Env
   949  	testData.Set("Image", "docker-test-image")
   950  	testData.SetAuto("Volumes", map[string]struct{}{"/foo": {}})
   951  	testData.Set("Cmd", "true")
   952  	jsonData := bytes.NewBuffer(nil)
   953  	if err := testData.Encode(jsonData); err != nil {
   954  		t.Fatal(err)
   955  	}
   956  
   957  	req, err := http.NewRequest("POST", "/containers/create?name=chunk_test", jsonData)
   958  	if err != nil {
   959  		t.Fatal(err)
   960  	}
   961  
   962  	req.Header.Add("Content-Type", "application/json")
   963  	if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
   964  		t.Fatal(err)
   965  	}
   966  	assertHttpNotError(r, t)
   967  
   968  	var testData2 engine.Env
   969  	testData2.SetAuto("Binds", []string{"/tmp:/foo"})
   970  	jsonData = bytes.NewBuffer(nil)
   971  	if err := testData2.Encode(jsonData); err != nil {
   972  		t.Fatal(err)
   973  	}
   974  
   975  	req, err = http.NewRequest("POST", "/containers/chunk_test/start", jsonData)
   976  	if err != nil {
   977  		t.Fatal(err)
   978  	}
   979  
   980  	req.Header.Add("Content-Type", "application/json")
   981  	// This is a cheat to make the http request do chunked encoding
   982  	// Otherwise (just setting the Content-Encoding to chunked) net/http will overwrite
   983  	// http://golang.org/src/pkg/net/http/request.go?s=11980:12172
   984  	req.ContentLength = -1
   985  	if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
   986  		t.Fatal(err)
   987  	}
   988  	assertHttpNotError(r, t)
   989  
   990  	type config struct {
   991  		HostConfig struct {
   992  			Binds []string
   993  		}
   994  	}
   995  
   996  	req, err = http.NewRequest("GET", "/containers/chunk_test/json", nil)
   997  	if err != nil {
   998  		t.Fatal(err)
   999  	}
  1000  
  1001  	r2 := httptest.NewRecorder()
  1002  	req.Header.Add("Content-Type", "application/json")
  1003  	if err := server.ServeRequest(eng, api.APIVERSION, r2, req); err != nil {
  1004  		t.Fatal(err)
  1005  	}
  1006  	assertHttpNotError(r, t)
  1007  
  1008  	c := config{}
  1009  
  1010  	json.Unmarshal(r2.Body.Bytes(), &c)
  1011  
  1012  	if len(c.HostConfig.Binds) == 0 {
  1013  		t.Fatal("Chunked Encoding not handled")
  1014  	}
  1015  
  1016  	if c.HostConfig.Binds[0] != "/tmp:/foo" {
  1017  		t.Fatal("Chunked encoding not properly handled, execpted binds to be /tmp:/foo, got:", c.HostConfig.Binds[0])
  1018  	}
  1019  }
  1020  
  1021  // Mocked types for tests
  1022  type NopConn struct {
  1023  	io.ReadCloser
  1024  	io.Writer
  1025  }
  1026  
  1027  func (c *NopConn) LocalAddr() net.Addr                { return nil }
  1028  func (c *NopConn) RemoteAddr() net.Addr               { return nil }
  1029  func (c *NopConn) SetDeadline(t time.Time) error      { return nil }
  1030  func (c *NopConn) SetReadDeadline(t time.Time) error  { return nil }
  1031  func (c *NopConn) SetWriteDeadline(t time.Time) error { return nil }
  1032  
  1033  type hijackTester struct {
  1034  	*httptest.ResponseRecorder
  1035  	in  io.ReadCloser
  1036  	out io.Writer
  1037  }
  1038  
  1039  func (t *hijackTester) Hijack() (net.Conn, *bufio.ReadWriter, error) {
  1040  	bufrw := bufio.NewReadWriter(bufio.NewReader(t.in), bufio.NewWriter(t.out))
  1041  	conn := &NopConn{
  1042  		ReadCloser: t.in,
  1043  		Writer:     t.out,
  1044  	}
  1045  	return conn, bufrw, nil
  1046  }