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