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 }