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