github.com/clcy1243/docker@v1.6.0-rc3/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 }