api_test.go
60ddcaa1
 package docker
 
 import (
5bec9275
 	"archive/tar"
310fec48
 	"bufio"
b2b59ddb
 	"bytes"
60ddcaa1
 	"encoding/json"
 	"github.com/dotcloud/docker/auth"
e7077320
 	"github.com/dotcloud/docker/utils"
310fec48
 	"io"
 	"net"
b2b59ddb
 	"net/http"
 	"net/http/httptest"
2a303dab
 	"os"
 	"path"
60ddcaa1
 	"testing"
2a303dab
 	"time"
60ddcaa1
 )
 
49e65683
 func TestPostAuth(t *testing.T) {
b2b59ddb
 	runtime, err := newTestRuntime()
60ddcaa1
 	if err != nil {
 		t.Fatal(err)
 	}
b2b59ddb
 	defer nuke(runtime)
60ddcaa1
 
95dd6d31
 	srv := &Server{
b76d6120
 		runtime: runtime,
95dd6d31
 	}
60ddcaa1
 
b2b59ddb
 	r := httptest.NewRecorder()
60ddcaa1
 
b2b59ddb
 	authConfig := &auth.AuthConfig{
 		Username: "utest",
 		Password: "utest",
 		Email:    "utest@yopmail.com",
60ddcaa1
 	}
 
fd224ee5
 	authConfigJSON, err := json.Marshal(authConfig)
60ddcaa1
 	if err != nil {
 		t.Fatal(err)
 	}
b2b59ddb
 
fd224ee5
 	req, err := http.NewRequest("POST", "/auth", bytes.NewReader(authConfigJSON))
60ddcaa1
 	if err != nil {
 		t.Fatal(err)
 	}
 
fd224ee5
 	if err := postAuth(srv, APIVERSION, r, req, nil); err != nil {
60ddcaa1
 		t.Fatal(err)
 	}
10e19e4b
 
53a8229c
 	if r.Code != http.StatusOK && r.Code != 0 {
 		t.Fatalf("%d OK or 0 expected, received %d\n", http.StatusOK, r.Code)
60ddcaa1
 	}
24816a8b
 }
60ddcaa1
 
24816a8b
 func TestGetVersion(t *testing.T) {
 	runtime, err := newTestRuntime()
60ddcaa1
 	if err != nil {
 		t.Fatal(err)
 	}
24816a8b
 	defer nuke(runtime)
60ddcaa1
 
24816a8b
 	srv := &Server{runtime: runtime}
 
b9944683
 	r := httptest.NewRecorder()
 
fd224ee5
 	if err := getVersion(srv, APIVERSION, r, nil, nil); err != nil {
60ddcaa1
 		t.Fatal(err)
 	}
 
fd224ee5
 	v := &APIVersion{}
b9944683
 	if err = json.Unmarshal(r.Body.Bytes(), v); err != nil {
60ddcaa1
 		t.Fatal(err)
 	}
24816a8b
 	if v.Version != VERSION {
 		t.Errorf("Excepted version %s, %s found", VERSION, v.Version)
60ddcaa1
 	}
 }
 
24816a8b
 func TestGetInfo(t *testing.T) {
b2b59ddb
 	runtime, err := newTestRuntime()
60ddcaa1
 	if err != nil {
 		t.Fatal(err)
 	}
b2b59ddb
 	defer nuke(runtime)
60ddcaa1
 
b2b59ddb
 	srv := &Server{runtime: runtime}
60ddcaa1
 
b9944683
 	r := httptest.NewRecorder()
 
fd224ee5
 	if err := getInfo(srv, APIVERSION, r, nil, nil); err != nil {
60ddcaa1
 		t.Fatal(err)
 	}
b9944683
 
fd224ee5
 	infos := &APIInfo{}
b9944683
 	err = json.Unmarshal(r.Body.Bytes(), infos)
60ddcaa1
 	if err != nil {
 		t.Fatal(err)
 	}
8243f251
 	if infos.Images != 1 {
 		t.Errorf("Excepted images: %d, %d found", 1, infos.Images)
60ddcaa1
 	}
 }
 
fd224ee5
 func TestGetImagesJSON(t *testing.T) {
7e8b413b
 	runtime, err := newTestRuntime()
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer nuke(runtime)
60ddcaa1
 
7e8b413b
 	srv := &Server{runtime: runtime}
60ddcaa1
 
1990c49a
 	// all=0
 	req, err := http.NewRequest("GET", "/images/json?all=0", nil)
7e8b413b
 	if err != nil {
 		t.Fatal(err)
 	}
 
b9944683
 	r := httptest.NewRecorder()
 
fd224ee5
 	if err := getImagesJSON(srv, APIVERSION, r, req, nil); err != nil {
7e8b413b
 		t.Fatal(err)
 	}
 
fd224ee5
 	images := []APIImages{}
b9944683
 	if err := json.Unmarshal(r.Body.Bytes(), &images); err != nil {
7e8b413b
 		t.Fatal(err)
 	}
60ddcaa1
 
7e8b413b
 	if len(images) != 1 {
 		t.Errorf("Excepted 1 image, %d found", len(images))
 	}
 
5bec9275
 	if images[0].Repository != unitTestImageName {
 		t.Errorf("Excepted image %s, %s found", unitTestImageName, images[0].Repository)
7e8b413b
 	}
53a8229c
 
b9944683
 	r2 := httptest.NewRecorder()
 
1990c49a
 	// all=1
0c544357
 	req2, err := http.NewRequest("GET", "/images/json?all=true", nil)
53a8229c
 	if err != nil {
 		t.Fatal(err)
 	}
 
fd224ee5
 	if err := getImagesJSON(srv, APIVERSION, r2, req2, nil); err != nil {
53a8229c
 		t.Fatal(err)
 	}
 
fd224ee5
 	images2 := []APIImages{}
b9944683
 	if err := json.Unmarshal(r2.Body.Bytes(), &images2); err != nil {
53a8229c
 		t.Fatal(err)
 	}
 
 	if len(images2) != 1 {
 		t.Errorf("Excepted 1 image, %d found", len(images2))
 	}
 
fd224ee5
 	if images2[0].ID != GetTestImage(runtime).ID {
 		t.Errorf("Retrieved image Id differs, expected %s, received %s", GetTestImage(runtime).ID, images2[0].ID)
53a8229c
 	}
 
b9944683
 	r3 := httptest.NewRecorder()
 
53a8229c
 	// filter=a
 	req3, err := http.NewRequest("GET", "/images/json?filter=a", nil)
 	if err != nil {
 		t.Fatal(err)
 	}
 
fd224ee5
 	if err := getImagesJSON(srv, APIVERSION, r3, req3, nil); err != nil {
53a8229c
 		t.Fatal(err)
 	}
 
fd224ee5
 	images3 := []APIImages{}
b9944683
 	if err := json.Unmarshal(r3.Body.Bytes(), &images3); err != nil {
53a8229c
 		t.Fatal(err)
 	}
 
 	if len(images3) != 0 {
 		t.Errorf("Excepted 1 image, %d found", len(images3))
 	}
0c544357
 
 	r4 := httptest.NewRecorder()
 
 	// all=foobar
 	req4, err := http.NewRequest("GET", "/images/json?all=foobar", nil)
 	if err != nil {
 		t.Fatal(err)
 	}
 
fd224ee5
 	err = getImagesJSON(srv, APIVERSION, r4, req4, nil)
0c544357
 	if err == nil {
 		t.Fatalf("Error expected, received none")
 	}
 
 	httpError(r4, err)
 	if r4.Code != http.StatusBadRequest {
 		t.Fatalf("%d Bad Request expected, received %d\n", http.StatusBadRequest, r4.Code)
 	}
7e8b413b
 }
 
24816a8b
 func TestGetImagesViz(t *testing.T) {
53a8229c
 	runtime, err := newTestRuntime()
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer nuke(runtime)
 
 	srv := &Server{runtime: runtime}
 
 	r := httptest.NewRecorder()
fd224ee5
 	if err := getImagesViz(srv, APIVERSION, r, nil, nil); err != nil {
53a8229c
 		t.Fatal(err)
 	}
 
 	if r.Code != http.StatusOK {
 		t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
 	}
 
 	reader := bufio.NewReader(r.Body)
 	line, err := reader.ReadString('\n')
 	if err != nil {
 		t.Fatal(err)
 	}
 	if line != "digraph docker {\n" {
 		t.Errorf("Excepted digraph docker {\n, %s found", line)
 	}
24816a8b
 }
 
 func TestGetImagesSearch(t *testing.T) {
7e8b413b
 	runtime, err := newTestRuntime()
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer nuke(runtime)
 
e7077320
 	srv := &Server{
b76d6120
 		runtime: runtime,
e7077320
 	}
7e8b413b
 
b9944683
 	r := httptest.NewRecorder()
 
24816a8b
 	req, err := http.NewRequest("GET", "/images/search?term=redis", nil)
7e8b413b
 	if err != nil {
 		t.Fatal(err)
 	}
24816a8b
 
fd224ee5
 	if err := getImagesSearch(srv, APIVERSION, r, req, nil); err != nil {
7e8b413b
 		t.Fatal(err)
 	}
24816a8b
 
fd224ee5
 	results := []APISearch{}
b9944683
 	if err := json.Unmarshal(r.Body.Bytes(), &results); err != nil {
24816a8b
 		t.Fatal(err)
 	}
 	if len(results) < 2 {
 		t.Errorf("Excepted at least 2 lines, %d found", len(results))
7e8b413b
 	}
 }
60ddcaa1
 
24816a8b
 func TestGetImagesHistory(t *testing.T) {
ede0793d
 	runtime, err := newTestRuntime()
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer nuke(runtime)
 
 	srv := &Server{runtime: runtime}
 
b9944683
 	r := httptest.NewRecorder()
 
fd224ee5
 	if err := getImagesHistory(srv, APIVERSION, r, nil, map[string]string{"name": unitTestImageName}); err != nil {
ede0793d
 		t.Fatal(err)
 	}
 
fd224ee5
 	history := []APIHistory{}
b9944683
 	if err := json.Unmarshal(r.Body.Bytes(), &history); err != nil {
ede0793d
 		t.Fatal(err)
 	}
 	if len(history) != 1 {
 		t.Errorf("Excepted 1 line, %d found", len(history))
 	}
 }
 
24816a8b
 func TestGetImagesByName(t *testing.T) {
ede0793d
 	runtime, err := newTestRuntime()
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer nuke(runtime)
 
 	srv := &Server{runtime: runtime}
 
b9944683
 	r := httptest.NewRecorder()
fd224ee5
 	if err := getImagesByName(srv, APIVERSION, r, nil, map[string]string{"name": unitTestImageName}); err != nil {
ede0793d
 		t.Fatal(err)
 	}
 
24816a8b
 	img := &Image{}
b9944683
 	if err := json.Unmarshal(r.Body.Bytes(), img); err != nil {
ede0793d
 		t.Fatal(err)
 	}
fd224ee5
 	if img.ID != GetTestImage(runtime).ID || img.Comment != "Imported from http://get.docker.io/images/busybox" {
24816a8b
 		t.Errorf("Error inspecting image")
 	}
 }
ede0793d
 
fd224ee5
 func TestGetContainersJSON(t *testing.T) {
24816a8b
 	runtime, err := newTestRuntime()
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer nuke(runtime)
ede0793d
 
24816a8b
 	srv := &Server{runtime: runtime}
 
 	container, err := NewBuilder(runtime).Create(&Config{
fd224ee5
 		Image: GetTestImage(runtime).ID,
24816a8b
 		Cmd:   []string{"echo", "test"},
 	})
ede0793d
 	if err != nil {
 		t.Fatal(err)
 	}
24816a8b
 	defer runtime.Destroy(container)
 
4f944392
 	req, err := http.NewRequest("GET", "/containers/json?all=1", nil)
24816a8b
 	if err != nil {
 		t.Fatal(err)
 	}
 
b9944683
 	r := httptest.NewRecorder()
fd224ee5
 	if err := getContainersJSON(srv, APIVERSION, r, req, nil); err != nil {
24816a8b
 		t.Fatal(err)
 	}
fd224ee5
 	containers := []APIContainers{}
b9944683
 	if err := json.Unmarshal(r.Body.Bytes(), &containers); err != nil {
24816a8b
 		t.Fatal(err)
 	}
 	if len(containers) != 1 {
 		t.Fatalf("Excepted %d container, %d found", 1, len(containers))
 	}
fd224ee5
 	if containers[0].ID != container.ID {
 		t.Fatalf("Container ID mismatch. Expected: %s, received: %s\n", container.ID, containers[0].ID)
ede0793d
 	}
 }
 
24816a8b
 func TestGetContainersExport(t *testing.T) {
53a8229c
 	runtime, err := newTestRuntime()
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer nuke(runtime)
 
 	srv := &Server{runtime: runtime}
 
 	builder := NewBuilder(runtime)
 
 	// Create a container and remove a file
 	container, err := builder.Create(
 		&Config{
fd224ee5
 			Image: GetTestImage(runtime).ID,
5bec9275
 			Cmd:   []string{"touch", "/test"},
53a8229c
 		},
 	)
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer runtime.Destroy(container)
 
 	if err := container.Run(); err != nil {
 		t.Fatal(err)
 	}
 
 	r := httptest.NewRecorder()
fd224ee5
 	if err = getContainersExport(srv, APIVERSION, r, nil, map[string]string{"name": container.ID}); err != nil {
53a8229c
 		t.Fatal(err)
 	}
 
 	if r.Code != http.StatusOK {
 		t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
 	}
 
5bec9275
 	found := false
 	for tarReader := tar.NewReader(r.Body); ; {
 		h, err := tarReader.Next()
 		if err != nil {
 			if err == io.EOF {
 				break
 			}
 			t.Fatal(err)
 		}
 		if h.Name == "./test" {
 			found = true
 			break
 		}
 	}
 	if !found {
 		t.Fatalf("The created test file has not been found in the exported image")
53a8229c
 	}
24816a8b
 }
 
310fec48
 func TestGetContainersChanges(t *testing.T) {
 	runtime, err := newTestRuntime()
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer nuke(runtime)
 
 	srv := &Server{runtime: runtime}
24816a8b
 
310fec48
 	builder := NewBuilder(runtime)
24816a8b
 
310fec48
 	// Create a container and remove a file
 	container, err := builder.Create(
 		&Config{
fd224ee5
 			Image: GetTestImage(runtime).ID,
310fec48
 			Cmd:   []string{"/bin/rm", "/etc/passwd"},
 		},
 	)
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer runtime.Destroy(container)
24816a8b
 
310fec48
 	if err := container.Run(); err != nil {
 		t.Fatal(err)
 	}
 
b9944683
 	r := httptest.NewRecorder()
fd224ee5
 	if err := getContainersChanges(srv, APIVERSION, r, nil, map[string]string{"name": container.ID}); err != nil {
310fec48
 		t.Fatal(err)
 	}
 	changes := []Change{}
b9944683
 	if err := json.Unmarshal(r.Body.Bytes(), &changes); err != nil {
310fec48
 		t.Fatal(err)
 	}
 
 	// Check the changelog
 	success := false
 	for _, elem := range changes {
 		if elem.Path == "/etc/passwd" && elem.Kind == 2 {
 			success = true
 		}
 	}
 	if !success {
 		t.Fatalf("/etc/passwd as been removed but is not present in the diff")
 	}
 }
24816a8b
 
483c9425
 func TestGetContainersByName(t *testing.T) {
53a8229c
 	runtime, err := newTestRuntime()
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer nuke(runtime)
 
 	srv := &Server{runtime: runtime}
 
 	builder := NewBuilder(runtime)
 
 	// Create a container and remove a file
 	container, err := builder.Create(
 		&Config{
fd224ee5
 			Image: GetTestImage(runtime).ID,
5bec9275
 			Cmd:   []string{"echo", "test"},
53a8229c
 		},
 	)
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer runtime.Destroy(container)
 
b9944683
 	r := httptest.NewRecorder()
fd224ee5
 	if err := getContainersByName(srv, APIVERSION, r, nil, map[string]string{"name": container.ID}); err != nil {
53a8229c
 		t.Fatal(err)
 	}
5bec9275
 	outContainer := &Container{}
b9944683
 	if err := json.Unmarshal(r.Body.Bytes(), outContainer); err != nil {
53a8229c
 		t.Fatal(err)
 	}
fd224ee5
 	if outContainer.ID != container.ID {
 		t.Fatalf("Wrong containers retrieved. Expected %s, recieved %s", container.ID, outContainer.ID)
5bec9275
 	}
24816a8b
 }
 
 func TestPostCommit(t *testing.T) {
53a8229c
 	runtime, err := newTestRuntime()
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer nuke(runtime)
 
 	srv := &Server{runtime: runtime}
 
 	builder := NewBuilder(runtime)
 
 	// Create a container and remove a file
 	container, err := builder.Create(
 		&Config{
fd224ee5
 			Image: GetTestImage(runtime).ID,
5bec9275
 			Cmd:   []string{"touch", "/test"},
53a8229c
 		},
 	)
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer runtime.Destroy(container)
 
 	if err := container.Run(); err != nil {
 		t.Fatal(err)
 	}
 
fd224ee5
 	req, err := http.NewRequest("POST", "/commit?repo=testrepo&testtag=tag&container="+container.ID, bytes.NewReader([]byte{}))
53a8229c
 	if err != nil {
 		t.Fatal(err)
 	}
 
b9944683
 	r := httptest.NewRecorder()
fd224ee5
 	if err := postCommit(srv, APIVERSION, r, req, nil); err != nil {
53a8229c
 		t.Fatal(err)
 	}
 	if r.Code != http.StatusCreated {
 		t.Fatalf("%d Created expected, received %d\n", http.StatusCreated, r.Code)
 	}
5bec9275
 
fd224ee5
 	apiID := &APIID{}
 	if err := json.Unmarshal(r.Body.Bytes(), apiID); err != nil {
5bec9275
 		t.Fatal(err)
 	}
fd224ee5
 	if _, err := runtime.graph.Get(apiID.ID); err != nil {
5bec9275
 		t.Fatalf("The image has not been commited")
 	}
24816a8b
 }
 
 func TestPostImagesCreate(t *testing.T) {
5bec9275
 	// FIXME: Use the staging in order to perform tests
 
 	// runtime, err := newTestRuntime()
 	// if err != nil {
 	// 	t.Fatal(err)
 	// }
 	// defer nuke(runtime)
 
 	// srv := &Server{runtime: runtime}
 
 	// stdin, stdinPipe := io.Pipe()
 	// stdout, stdoutPipe := io.Pipe()
 
 	// c1 := make(chan struct{})
 	// go func() {
 	// 	defer close(c1)
 
 	// 	r := &hijackTester{
 	// 		ResponseRecorder: httptest.NewRecorder(),
 	// 		in:               stdin,
 	// 		out:              stdoutPipe,
 	// 	}
 
 	// 	req, err := http.NewRequest("POST", "/images/create?fromImage="+unitTestImageName, bytes.NewReader([]byte{}))
 	// 	if err != nil {
 	// 		t.Fatal(err)
 	// 	}
 
 	// 	body, err := postImagesCreate(srv, r, req, nil)
 	// 	if err != nil {
 	// 		t.Fatal(err)
 	// 	}
 	// 	if body != nil {
 	// 		t.Fatalf("No body expected, received: %s\n", body)
 	// 	}
 	// }()
 
 	// // Acknowledge hijack
 	// setTimeout(t, "hijack acknowledge timed out", 2*time.Second, func() {
 	// 	stdout.Read([]byte{})
 	// 	stdout.Read(make([]byte, 4096))
 	// })
 
 	// setTimeout(t, "Waiting for imagesCreate output", 5*time.Second, func() {
 	// 	reader := bufio.NewReader(stdout)
 	// 	line, err := reader.ReadString('\n')
 	// 	if err != nil {
 	// 		t.Fatal(err)
 	// 	}
 	// 	if !strings.HasPrefix(line, "Pulling repository d from") {
 	// 		t.Fatalf("Expected Pulling repository docker-ut from..., found %s", line)
 	// 	}
 	// })
 
 	// // Close pipes (client disconnects)
 	// if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
 	// 	t.Fatal(err)
 	// }
 
 	// // Wait for imagesCreate to finish, the client disconnected, therefore, Create finished his job
 	// setTimeout(t, "Waiting for imagesCreate timed out", 10*time.Second, func() {
 	// 	<-c1
 	// })
24816a8b
 }
 
3703a654
 func TestPostImagesInsert(t *testing.T) {
 	// runtime, err := newTestRuntime()
 	// if err != nil {
 	// 	t.Fatal(err)
 	// }
 	// defer nuke(runtime)
 
 	// srv := &Server{runtime: runtime}
 
 	// stdin, stdinPipe := io.Pipe()
 	// stdout, stdoutPipe := io.Pipe()
 
 	// // Attach to it
 	// c1 := make(chan struct{})
 	// go func() {
 	// 	defer close(c1)
 	// 	r := &hijackTester{
 	// 		ResponseRecorder: httptest.NewRecorder(),
 	// 		in:               stdin,
 	// 		out:              stdoutPipe,
 	// 	}
 
 	// 	req, err := http.NewRequest("POST", "/images/"+unitTestImageName+"/insert?path=%2Ftest&url=https%3A%2F%2Fraw.github.com%2Fdotcloud%2Fdocker%2Fmaster%2FREADME.md", bytes.NewReader([]byte{}))
 	// 	if err != nil {
 	// 		t.Fatal(err)
 	// 	}
 	// 	if err := postContainersCreate(srv, r, req, nil); err != nil {
 	// 		t.Fatal(err)
 	// 	}
 	// }()
 
 	// // Acknowledge hijack
 	// setTimeout(t, "hijack acknowledge timed out", 5*time.Second, func() {
 	// 	stdout.Read([]byte{})
 	// 	stdout.Read(make([]byte, 4096))
 	// })
 
 	// id := ""
 	// setTimeout(t, "Waiting for imagesInsert output", 10*time.Second, func() {
 	// 	for {
 	// 		reader := bufio.NewReader(stdout)
 	// 		id, err = reader.ReadString('\n')
 	// 		if err != nil {
 	// 			t.Fatal(err)
 	// 		}
 	// 	}
 	// })
 
 	// // Close pipes (client disconnects)
 	// if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
 	// 	t.Fatal(err)
 	// }
 
 	// // Wait for attach to finish, the client disconnected, therefore, Attach finished his job
 	// setTimeout(t, "Waiting for CmdAttach timed out", 2*time.Second, func() {
 	// 	<-c1
 	// })
 
 	// img, err := srv.runtime.repositories.LookupImage(id)
 	// if err != nil {
 	// 	t.Fatalf("New image %s expected but not found", id)
 	// }
 
 	// layer, err := img.layer()
 	// if err != nil {
 	// 	t.Fatal(err)
 	// }
 
 	// if _, err := os.Stat(path.Join(layer, "test")); err != nil {
 	// 	t.Fatalf("The test file has not been found")
 	// }
 
fd224ee5
 	// if err := srv.runtime.graph.Delete(img.ID); err != nil {
3703a654
 	// 	t.Fatal(err)
 	// }
 }
24816a8b
 
 func TestPostImagesPush(t *testing.T) {
5bec9275
 	//FIXME: Use staging in order to perform tests
 	// runtime, err := newTestRuntime()
 	// if err != nil {
 	// 	t.Fatal(err)
 	// }
 	// defer nuke(runtime)
 
 	// srv := &Server{runtime: runtime}
 
 	// stdin, stdinPipe := io.Pipe()
 	// stdout, stdoutPipe := io.Pipe()
 
 	// c1 := make(chan struct{})
 	// go func() {
 	// 	r := &hijackTester{
 	// 		ResponseRecorder: httptest.NewRecorder(),
 	// 		in:               stdin,
 	// 		out:              stdoutPipe,
 	// 	}
 
 	// 	req, err := http.NewRequest("POST", "/images/docker-ut/push", bytes.NewReader([]byte{}))
 	// 	if err != nil {
 	// 		t.Fatal(err)
 	// 	}
 
 	// 	body, err := postImagesPush(srv, r, req, map[string]string{"name": "docker-ut"})
 	// 	close(c1)
 	// 	if err != nil {
 	// 		t.Fatal(err)
 	// 	}
 	// 	if body != nil {
 	// 		t.Fatalf("No body expected, received: %s\n", body)
 	// 	}
 	// }()
 
 	// // Acknowledge hijack
 	// setTimeout(t, "hijack acknowledge timed out", 2*time.Second, func() {
 	// 	stdout.Read([]byte{})
 	// 	stdout.Read(make([]byte, 4096))
 	// })
 
 	// setTimeout(t, "Waiting for imagesCreate output", 5*time.Second, func() {
 	// 	reader := bufio.NewReader(stdout)
 	// 	line, err := reader.ReadString('\n')
 	// 	if err != nil {
 	// 		t.Fatal(err)
 	// 	}
 	// 	if !strings.HasPrefix(line, "Processing checksum") {
 	// 		t.Fatalf("Processing checksum..., found %s", line)
 	// 	}
 	// })
 
 	// // Close pipes (client disconnects)
 	// if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
 	// 	t.Fatal(err)
 	// }
 
 	// // Wait for imagesPush to finish, the client disconnected, therefore, Push finished his job
 	// setTimeout(t, "Waiting for imagesPush timed out", 10*time.Second, func() {
 	// 	<-c1
 	// })
24816a8b
 }
 
 func TestPostImagesTag(t *testing.T) {
5bec9275
 	// FIXME: Use staging in order to perform tests
 
 	// runtime, err := newTestRuntime()
 	// if err != nil {
 	// 	t.Fatal(err)
 	// }
 	// defer nuke(runtime)
 
 	// srv := &Server{runtime: runtime}
 
 	// r := httptest.NewRecorder()
 
 	// req, err := http.NewRequest("POST", "/images/docker-ut/tag?repo=testrepo&tag=testtag", bytes.NewReader([]byte{}))
 	// if err != nil {
 	// 	t.Fatal(err)
 	// }
 
 	// body, err := postImagesTag(srv, r, req, map[string]string{"name": "docker-ut"})
 	// if err != nil {
 	// 	t.Fatal(err)
 	// }
 
 	// if body != nil {
 	// 	t.Fatalf("No body expected, received: %s\n", body)
 	// }
 	// if r.Code != http.StatusCreated {
 	// 	t.Fatalf("%d Created expected, received %d\n", http.StatusCreated, r.Code)
 	// }
24816a8b
 }
 
2a303dab
 func TestPostContainersCreate(t *testing.T) {
3115c5a2
 	runtime, err := newTestRuntime()
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer nuke(runtime)
b2b59ddb
 
3115c5a2
 	srv := &Server{runtime: runtime}
b2b59ddb
 
fd224ee5
 	configJSON, err := json.Marshal(&Config{
 		Image:  GetTestImage(runtime).ID,
2a303dab
 		Memory: 33554432,
 		Cmd:    []string{"touch", "/test"},
 	})
3115c5a2
 	if err != nil {
 		t.Fatal(err)
 	}
b2b59ddb
 
fd224ee5
 	req, err := http.NewRequest("POST", "/containers/create", bytes.NewReader(configJSON))
3115c5a2
 	if err != nil {
 		t.Fatal(err)
 	}
b2b59ddb
 
b9944683
 	r := httptest.NewRecorder()
fd224ee5
 	if err := postContainersCreate(srv, APIVERSION, r, req, nil); err != nil {
3115c5a2
 		t.Fatal(err)
 	}
2a303dab
 	if r.Code != http.StatusCreated {
 		t.Fatalf("%d Created expected, received %d\n", http.StatusCreated, r.Code)
 	}
b2b59ddb
 
fd224ee5
 	apiRun := &APIRun{}
b9944683
 	if err := json.Unmarshal(r.Body.Bytes(), apiRun); err != nil {
3115c5a2
 		t.Fatal(err)
 	}
b2b59ddb
 
fd224ee5
 	container := srv.runtime.Get(apiRun.ID)
2a303dab
 	if container == nil {
 		t.Fatalf("Container not created")
3115c5a2
 	}
 
2a303dab
 	if err := container.Run(); err != nil {
 		t.Fatal(err)
 	}
 
 	if _, err := os.Stat(path.Join(container.rwPath(), "test")); err != nil {
 		if os.IsNotExist(err) {
2e69e172
 			utils.Debugf("Err: %s", err)
2a303dab
 			t.Fatalf("The test file has not been created")
 		}
 		t.Fatal(err)
3115c5a2
 	}
 }
 
24816a8b
 func TestPostContainersKill(t *testing.T) {
2a303dab
 	runtime, err := newTestRuntime()
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer nuke(runtime)
3115c5a2
 
2a303dab
 	srv := &Server{runtime: runtime}
3115c5a2
 
24816a8b
 	container, err := NewBuilder(runtime).Create(
 		&Config{
fd224ee5
 			Image:     GetTestImage(runtime).ID,
24816a8b
 			Cmd:       []string{"/bin/cat"},
 			OpenStdin: true,
 		},
 	)
3115c5a2
 	if err != nil {
 		t.Fatal(err)
 	}
2a303dab
 	defer runtime.Destroy(container)
3115c5a2
 
24816a8b
 	if err := container.Start(); err != nil {
3115c5a2
 		t.Fatal(err)
 	}
 
24816a8b
 	// Give some time to the process to start
 	container.WaitTimeout(500 * time.Millisecond)
 
 	if !container.State.Running {
 		t.Errorf("Container should be running")
2a303dab
 	}
24816a8b
 
 	r := httptest.NewRecorder()
fd224ee5
 	if err := postContainersKill(srv, APIVERSION, r, nil, map[string]string{"name": container.ID}); err != nil {
3115c5a2
 		t.Fatal(err)
 	}
24816a8b
 	if r.Code != http.StatusNoContent {
 		t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
 	}
 	if container.State.Running {
 		t.Fatalf("The container hasn't been killed")
3115c5a2
 	}
 }
 
24816a8b
 func TestPostContainersRestart(t *testing.T) {
2a303dab
 	runtime, err := newTestRuntime()
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer nuke(runtime)
3115c5a2
 
2a303dab
 	srv := &Server{runtime: runtime}
3115c5a2
 
2a303dab
 	container, err := NewBuilder(runtime).Create(
 		&Config{
fd224ee5
 			Image:     GetTestImage(runtime).ID,
2a303dab
 			Cmd:       []string{"/bin/cat"},
 			OpenStdin: true,
 		},
 	)
3115c5a2
 	if err != nil {
 		t.Fatal(err)
 	}
2a303dab
 	defer runtime.Destroy(container)
 
24816a8b
 	if err := container.Start(); err != nil {
 		t.Fatal(err)
 	}
 
 	// Give some time to the process to start
 	container.WaitTimeout(500 * time.Millisecond)
 
 	if !container.State.Running {
 		t.Errorf("Container should be running")
 	}
 
fd224ee5
 	req, err := http.NewRequest("POST", "/containers/"+container.ID+"/restart?t=1", bytes.NewReader([]byte{}))
24816a8b
 	if err != nil {
 		t.Fatal(err)
 	}
b9944683
 	r := httptest.NewRecorder()
fd224ee5
 	if err := postContainersRestart(srv, APIVERSION, r, req, map[string]string{"name": container.ID}); err != nil {
3115c5a2
 		t.Fatal(err)
 	}
 	if r.Code != http.StatusNoContent {
 		t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
 	}
2a303dab
 
24816a8b
 	// Give some time to the process to restart
2a303dab
 	container.WaitTimeout(500 * time.Millisecond)
 
 	if !container.State.Running {
24816a8b
 		t.Fatalf("Container should be running")
2a303dab
 	}
 
 	if err := container.Kill(); err != nil {
 		t.Fatal(err)
 	}
3115c5a2
 }
 
24816a8b
 func TestPostContainersStart(t *testing.T) {
 	runtime, err := newTestRuntime()
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer nuke(runtime)
3115c5a2
 
24816a8b
 	srv := &Server{runtime: runtime}
3115c5a2
 
24816a8b
 	container, err := NewBuilder(runtime).Create(
 		&Config{
fd224ee5
 			Image:     GetTestImage(runtime).ID,
24816a8b
 			Cmd:       []string{"/bin/cat"},
 			OpenStdin: true,
 		},
 	)
3115c5a2
 	if err != nil {
 		t.Fatal(err)
 	}
24816a8b
 	defer runtime.Destroy(container)
3115c5a2
 
24816a8b
 	r := httptest.NewRecorder()
fd224ee5
 	if err := postContainersStart(srv, APIVERSION, r, nil, map[string]string{"name": container.ID}); err != nil {
3115c5a2
 		t.Fatal(err)
 	}
 	if r.Code != http.StatusNoContent {
 		t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
 	}
24816a8b
 
 	// Give some time to the process to start
 	container.WaitTimeout(500 * time.Millisecond)
 
 	if !container.State.Running {
 		t.Errorf("Container should be running")
 	}
 
b9944683
 	r = httptest.NewRecorder()
fd224ee5
 	if err = postContainersStart(srv, APIVERSION, r, nil, map[string]string{"name": container.ID}); err == nil {
24816a8b
 		t.Fatalf("A running containter should be able to be started")
 	}
 
 	if err := container.Kill(); err != nil {
 		t.Fatal(err)
 	}
3115c5a2
 }
 
2a303dab
 func TestPostContainersStop(t *testing.T) {
 	runtime, err := newTestRuntime()
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer nuke(runtime)
3115c5a2
 
2a303dab
 	srv := &Server{runtime: runtime}
3115c5a2
 
2a303dab
 	container, err := NewBuilder(runtime).Create(
 		&Config{
fd224ee5
 			Image:     GetTestImage(runtime).ID,
2a303dab
 			Cmd:       []string{"/bin/cat"},
 			OpenStdin: true,
 		},
 	)
3115c5a2
 	if err != nil {
 		t.Fatal(err)
 	}
2a303dab
 	defer runtime.Destroy(container)
3115c5a2
 
2a303dab
 	if err := container.Start(); err != nil {
3115c5a2
 		t.Fatal(err)
 	}
 
2a303dab
 	// Give some time to the process to start
 	container.WaitTimeout(500 * time.Millisecond)
 
 	if !container.State.Running {
 		t.Errorf("Container should be running")
 	}
 
 	// Note: as it is a POST request, it requires a body.
fd224ee5
 	req, err := http.NewRequest("POST", "/containers/"+container.ID+"/stop?t=1", bytes.NewReader([]byte{}))
2a303dab
 	if err != nil {
 		t.Fatal(err)
 	}
b9944683
 	r := httptest.NewRecorder()
fd224ee5
 	if err := postContainersStop(srv, APIVERSION, r, req, map[string]string{"name": container.ID}); err != nil {
2a303dab
 		t.Fatal(err)
 	}
3115c5a2
 	if r.Code != http.StatusNoContent {
 		t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
 	}
2a303dab
 	if container.State.Running {
 		t.Fatalf("The container hasn't been stopped")
 	}
3115c5a2
 }
 
24816a8b
 func TestPostContainersWait(t *testing.T) {
 	runtime, err := newTestRuntime()
3115c5a2
 	if err != nil {
 		t.Fatal(err)
 	}
24816a8b
 	defer nuke(runtime)
3115c5a2
 
24816a8b
 	srv := &Server{runtime: runtime}
3115c5a2
 
24816a8b
 	container, err := NewBuilder(runtime).Create(
 		&Config{
fd224ee5
 			Image:     GetTestImage(runtime).ID,
24816a8b
 			Cmd:       []string{"/bin/sleep", "1"},
 			OpenStdin: true,
 		},
 	)
3115c5a2
 	if err != nil {
 		t.Fatal(err)
 	}
24816a8b
 	defer runtime.Destroy(container)
3115c5a2
 
24816a8b
 	if err := container.Start(); err != nil {
3115c5a2
 		t.Fatal(err)
 	}
 
24816a8b
 	setTimeout(t, "Wait timed out", 3*time.Second, func() {
b9944683
 		r := httptest.NewRecorder()
fd224ee5
 		if err := postContainersWait(srv, APIVERSION, r, nil, map[string]string{"name": container.ID}); err != nil {
24816a8b
 			t.Fatal(err)
 		}
fd224ee5
 		apiWait := &APIWait{}
b9944683
 		if err := json.Unmarshal(r.Body.Bytes(), apiWait); err != nil {
24816a8b
 			t.Fatal(err)
 		}
 		if apiWait.StatusCode != 0 {
 			t.Fatalf("Non zero exit code for sleep: %d\n", apiWait.StatusCode)
 		}
 	})
3115c5a2
 
24816a8b
 	if container.State.Running {
 		t.Fatalf("The container should be stopped after wait")
3115c5a2
 	}
 }
 
24816a8b
 func TestPostContainersAttach(t *testing.T) {
15ae314c
 	runtime, err := newTestRuntime()
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer nuke(runtime)
 
 	srv := &Server{runtime: runtime}
 
 	container, err := NewBuilder(runtime).Create(
 		&Config{
fd224ee5
 			Image:     GetTestImage(runtime).ID,
15ae314c
 			Cmd:       []string{"/bin/cat"},
 			OpenStdin: true,
 		},
 	)
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer runtime.Destroy(container)
 
 	// Start the process
 	if err := container.Start(); err != nil {
 		t.Fatal(err)
 	}
 
 	stdin, stdinPipe := io.Pipe()
 	stdout, stdoutPipe := io.Pipe()
 
 	// Attach to it
 	c1 := make(chan struct{})
 	go func() {
b9944683
 		defer close(c1)
15ae314c
 
 		r := &hijackTester{
 			ResponseRecorder: httptest.NewRecorder(),
 			in:               stdin,
 			out:              stdoutPipe,
 		}
 
fd224ee5
 		req, err := http.NewRequest("POST", "/containers/"+container.ID+"/attach?stream=1&stdin=1&stdout=1&stderr=1", bytes.NewReader([]byte{}))
15ae314c
 		if err != nil {
 			t.Fatal(err)
 		}
 
fd224ee5
 		if err := postContainersAttach(srv, APIVERSION, r, req, map[string]string{"name": container.ID}); err != nil {
15ae314c
 			t.Fatal(err)
 		}
 	}()
 
 	// Acknowledge hijack
 	setTimeout(t, "hijack acknowledge timed out", 2*time.Second, func() {
 		stdout.Read([]byte{})
 		stdout.Read(make([]byte, 4096))
 	})
 
 	setTimeout(t, "read/write assertion timed out", 2*time.Second, func() {
 		if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil {
 			t.Fatal(err)
 		}
 	})
 
 	// Close pipes (client disconnects)
 	if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
 		t.Fatal(err)
 	}
 
 	// Wait for attach to finish, the client disconnected, therefore, Attach finished his job
 	setTimeout(t, "Waiting for CmdAttach timed out", 2*time.Second, func() {
 		<-c1
 	})
 
 	// We closed stdin, expect /bin/cat to still be running
 	// Wait a little bit to make sure container.monitor() did his thing
 	err = container.WaitTimeout(500 * time.Millisecond)
 	if err == nil || !container.State.Running {
 		t.Fatalf("/bin/cat is not running after closing stdin")
 	}
 
 	// Try to avoid the timeoout in destroy. Best effort, don't check error
 	cStdin, _ := container.StdinPipe()
 	cStdin.Close()
 	container.Wait()
24816a8b
 }
 
5bec9275
 // FIXME: Test deleting running container
2a303dab
 // FIXME: Test deleting container with volume
 // FIXME: Test deleting volume in use by other container
 func TestDeleteContainers(t *testing.T) {
 	runtime, err := newTestRuntime()
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer nuke(runtime)
3115c5a2
 
2a303dab
 	srv := &Server{runtime: runtime}
3115c5a2
 
2a303dab
 	container, err := NewBuilder(runtime).Create(&Config{
fd224ee5
 		Image: GetTestImage(runtime).ID,
2a303dab
 		Cmd:   []string{"touch", "/test"},
 	})
3115c5a2
 	if err != nil {
 		t.Fatal(err)
 	}
2a303dab
 	defer runtime.Destroy(container)
 
 	if err := container.Run(); err != nil {
 		t.Fatal(err)
 	}
 
fd224ee5
 	req, err := http.NewRequest("DELETE", "/containers/"+container.ID, nil)
3115c5a2
 	if err != nil {
 		t.Fatal(err)
 	}
b9944683
 	r := httptest.NewRecorder()
fd224ee5
 	if err := deleteContainers(srv, APIVERSION, r, req, map[string]string{"name": container.ID}); err != nil {
2a303dab
 		t.Fatal(err)
 	}
3115c5a2
 	if r.Code != http.StatusNoContent {
 		t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
 	}
2a303dab
 
fd224ee5
 	if c := runtime.Get(container.ID); c != nil {
2a303dab
 		t.Fatalf("The container as not been deleted")
 	}
 
 	if _, err := os.Stat(path.Join(container.rwPath(), "test")); err == nil {
 		t.Fatalf("The test file has not been deleted")
 	}
3115c5a2
 }
 
0a28628c
 func TestOptionsRoute(t *testing.T) {
 	runtime, err := newTestRuntime()
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer nuke(runtime)
 
 	srv := &Server{runtime: runtime, enableCors: true}
 
 	r := httptest.NewRecorder()
 	router, err := createRouter(srv, false)
 	if err != nil {
 		t.Fatal(err)
 	}
 
 	req, err := http.NewRequest("OPTIONS", "/", nil)
 	if err != nil {
 		t.Fatal(err)
 	}
 
 	router.ServeHTTP(r, req)
ac599d65
 	if r.Code != http.StatusOK {
0a28628c
 		t.Errorf("Expected response for OPTIONS request to be \"200\", %v found.", r.Code)
 	}
 }
 
6d5bdff3
 func TestGetEnabledCors(t *testing.T) {
 	runtime, err := newTestRuntime()
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer nuke(runtime)
 
 	srv := &Server{runtime: runtime, enableCors: true}
 
 	r := httptest.NewRecorder()
 
0a28628c
 	router, err := createRouter(srv, false)
 	if err != nil {
6d5bdff3
 		t.Fatal(err)
 	}
 
0a28628c
 	req, err := http.NewRequest("GET", "/version", nil)
 	if err != nil {
 		t.Fatal(err)
 	}
 
 	router.ServeHTTP(r, req)
ac599d65
 	if r.Code != http.StatusOK {
0a28628c
 		t.Errorf("Expected response for OPTIONS request to be \"200\", %v found.", r.Code)
 	}
 
6d5bdff3
 	allowOrigin := r.Header().Get("Access-Control-Allow-Origin")
 	allowHeaders := r.Header().Get("Access-Control-Allow-Headers")
0a28628c
 	allowMethods := r.Header().Get("Access-Control-Allow-Methods")
6d5bdff3
 
 	if allowOrigin != "*" {
 		t.Errorf("Expected header Access-Control-Allow-Origin to be \"*\", %s found.", allowOrigin)
 	}
 	if allowHeaders != "Origin, X-Requested-With, Content-Type, Accept" {
 		t.Errorf("Expected header Access-Control-Allow-Headers to be \"Origin, X-Requested-With, Content-Type, Accept\", %s found.", allowHeaders)
 	}
0a28628c
 	if allowMethods != "GET, POST, DELETE, PUT, OPTIONS" {
 		t.Errorf("Expected hearder Access-Control-Allow-Methods to be \"GET, POST, DELETE, PUT, OPTIONS\", %s found.", allowMethods)
 	}
6d5bdff3
 }
 
24816a8b
 func TestDeleteImages(t *testing.T) {
c80448c4
 	runtime, err := newTestRuntime()
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer nuke(runtime)
 
 	srv := &Server{runtime: runtime}
 
 	if err := srv.runtime.repositories.Set("test", "test", unitTestImageName, true); err != nil {
 		t.Fatal(err)
 	}
 
 	images, err := srv.Images(false, "")
 	if err != nil {
 		t.Fatal(err)
 	}
 
 	if len(images) != 2 {
 		t.Errorf("Excepted 2 images, %d found", len(images))
 	}
 
67b20f2c
 	req, err := http.NewRequest("DELETE", "/images/test:test", nil)
 	if err != nil {
 		t.Fatal(err)
 	}
 
c80448c4
 	r := httptest.NewRecorder()
66d9a733
 	if err := deleteImages(srv, APIVERSION, r, req, map[string]string{"name": "test:test"}); err != nil {
c80448c4
 		t.Fatal(err)
 	}
9060b5c2
 	if r.Code != http.StatusOK {
 		t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
c80448c4
 	}
 
66d9a733
 	var outs []APIRmi
9060b5c2
 	if err := json.Unmarshal(r.Body.Bytes(), &outs); err != nil {
 		t.Fatal(err)
 	}
 	if len(outs) != 1 {
 		t.Fatalf("Expected %d event (untagged), got %d", 1, len(outs))
 	}
c80448c4
 	images, err = srv.Images(false, "")
 	if err != nil {
 		t.Fatal(err)
 	}
 
 	if len(images) != 1 {
 		t.Errorf("Excepted 1 image, %d found", len(images))
 	}
 
 	/*	if c := runtime.Get(container.Id); c != nil {
 			t.Fatalf("The container as not been deleted")
 		}
 
 		if _, err := os.Stat(path.Join(container.rwPath(), "test")); err == nil {
 			t.Fatalf("The test file has not been deleted")
 		} */
15ae314c
 }
 
 // Mocked types for tests
 type NopConn struct {
 	io.ReadCloser
 	io.Writer
 }
 
 func (c *NopConn) LocalAddr() net.Addr                { return nil }
 func (c *NopConn) RemoteAddr() net.Addr               { return nil }
 func (c *NopConn) SetDeadline(t time.Time) error      { return nil }
 func (c *NopConn) SetReadDeadline(t time.Time) error  { return nil }
 func (c *NopConn) SetWriteDeadline(t time.Time) error { return nil }
 
 type hijackTester struct {
 	*httptest.ResponseRecorder
 	in  io.ReadCloser
 	out io.Writer
 }
 
 func (t *hijackTester) Hijack() (net.Conn, *bufio.ReadWriter, error) {
 	bufrw := bufio.NewReadWriter(bufio.NewReader(t.in), bufio.NewWriter(t.out))
 	conn := &NopConn{
 		ReadCloser: t.in,
 		Writer:     t.out,
 	}
 	return conn, bufrw, nil
3115c5a2
 }