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