diff --git a/api/server/server_unit_test.go b/api/server/server_unit_test.go index f8068a29c5..c51ea6fc0d 100644 --- a/api/server/server_unit_test.go +++ b/api/server/server_unit_test.go @@ -7,11 +7,13 @@ import ( "io" "net/http" "net/http/httptest" + "reflect" "strings" "testing" "github.com/dotcloud/docker/api" "github.com/dotcloud/docker/engine" + "github.com/dotcloud/docker/pkg/version" ) func TestGetBoolParam(t *testing.T) { @@ -111,8 +113,105 @@ func TestGetInfo(t *testing.T) { if v.GetInt("Containers") != 1 { t.Fatalf("%#v\n", v) } - if r.HeaderMap.Get("Content-Type") != "application/json" { - t.Fatalf("%#v\n", r) + assertContentType(r, "application/json", t) +} + +func TestGetImagesJSON(t *testing.T) { + eng := engine.New() + var called bool + eng.Register("images", func(job *engine.Job) engine.Status { + called = true + v := createEnvFromGetImagesJSONStruct(sampleImage) + if _, err := v.WriteTo(job.Stdout); err != nil { + return job.Error(err) + } + return engine.StatusOK + }) + r := serveRequest("GET", "/images/json", nil, eng, t) + if !called { + t.Fatal("handler was not called") + } + assertHttpNotError(r, t) + assertContentType(r, "application/json", t) + var observed getImagesJSONStruct + if err := json.Unmarshal(r.Body.Bytes(), &observed); err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(observed, sampleImage) { + t.Errorf("Expected %#v but got %#v", sampleImage, observed) + } +} + +func TestGetImagesJSONFilter(t *testing.T) { + eng := engine.New() + filter := "nothing" + eng.Register("images", func(job *engine.Job) engine.Status { + filter = job.Getenv("filter") + return engine.StatusOK + }) + serveRequest("GET", "/images/json?filter=aaaa", nil, eng, t) + if filter != "aaaa" { + t.Errorf("%#v", filter) + } +} + +func TestGetImagesJSONFilters(t *testing.T) { + eng := engine.New() + filter := "nothing" + eng.Register("images", func(job *engine.Job) engine.Status { + filter = job.Getenv("filters") + return engine.StatusOK + }) + serveRequest("GET", "/images/json?filters=nnnn", nil, eng, t) + if filter != "nnnn" { + t.Errorf("%#v", filter) + } +} + +func TestGetImagesJSONAll(t *testing.T) { + eng := engine.New() + allFilter := "-1" + eng.Register("images", func(job *engine.Job) engine.Status { + allFilter = job.Getenv("all") + return engine.StatusOK + }) + serveRequest("GET", "/images/json?all=1", nil, eng, t) + if allFilter != "1" { + t.Errorf("%#v", allFilter) + } +} + +func TestGetImagesJSONLegacyFormat(t *testing.T) { + eng := engine.New() + var called bool + eng.Register("images", func(job *engine.Job) engine.Status { + called = true + outsLegacy := engine.NewTable("Created", 0) + outsLegacy.Add(createEnvFromGetImagesJSONStruct(sampleImage)) + if _, err := outsLegacy.WriteListTo(job.Stdout); err != nil { + return job.Error(err) + } + return engine.StatusOK + }) + r := serveRequestUsingVersion("GET", "/images/json", "1.6", nil, eng, t) + if !called { + t.Fatal("handler was not called") + } + assertHttpNotError(r, t) + assertContentType(r, "application/json", t) + images := engine.NewTable("Created", 0) + if _, err := images.ReadListFrom(r.Body.Bytes()); err != nil { + t.Fatal(err) + } + if images.Len() != 1 { + t.Fatalf("Expected 1 image, %d found", images.Len()) + } + image := images.Data[0] + if image.Get("Tag") != "test-tag" { + t.Errorf("Expected tag 'test-tag', found '%s'", image.Get("Tag")) + } + if image.Get("Repository") != "test-name" { + t.Errorf("Expected repository 'test-name', found '%s'", image.Get("Repository")) } } @@ -123,12 +222,12 @@ func TestGetContainersByName(t *testing.T) { eng.Register("container_inspect", func(job *engine.Job) engine.Status { called = true if job.Args[0] != name { - t.Fatalf("name != '%s': %#v", name, job.Args[0]) + t.Errorf("name != '%s': %#v", name, job.Args[0]) } if api.APIVERSION.LessThan("1.12") && !job.GetenvBool("dirty") { - t.Fatal("dirty env variable not set") + t.Errorf("dirty env variable not set") } else if api.APIVERSION.GreaterThanOrEqualTo("1.12") && job.GetenvBool("dirty") { - t.Fatal("dirty env variable set when it shouldn't") + t.Errorf("dirty env variable set when it shouldn't") } v := &engine.Env{} v.SetBool("dirty", true) @@ -141,9 +240,7 @@ func TestGetContainersByName(t *testing.T) { if !called { t.Fatal("handler was not called") } - if r.HeaderMap.Get("Content-Type") != "application/json" { - t.Fatalf("%#v\n", r) - } + assertContentType(r, "application/json", t) var stdoutJson interface{} if err := json.Unmarshal(r.Body.Bytes(), &stdoutJson); err != nil { t.Fatalf("%#v", err) @@ -178,21 +275,19 @@ func TestGetEvents(t *testing.T) { if !called { t.Fatal("handler was not called") } - if r.HeaderMap.Get("Content-Type") != "application/json" { - t.Fatalf("%#v\n", r) - } + assertContentType(r, "application/json", t) var stdout_json struct { Since int Until int } if err := json.Unmarshal(r.Body.Bytes(), &stdout_json); err != nil { - t.Fatalf("%#v", err) + t.Fatal(err) } if stdout_json.Since != 1 { - t.Fatalf("since != 1: %#v", stdout_json.Since) + t.Errorf("since != 1: %#v", stdout_json.Since) } if stdout_json.Until != 0 { - t.Fatalf("until != 0: %#v", stdout_json.Until) + t.Errorf("until != 0: %#v", stdout_json.Until) } } @@ -357,12 +452,16 @@ func TestGetImagesByName(t *testing.T) { } func serveRequest(method, target string, body io.Reader, eng *engine.Engine, t *testing.T) *httptest.ResponseRecorder { + return serveRequestUsingVersion(method, target, api.APIVERSION, body, eng, t) +} + +func serveRequestUsingVersion(method, target string, version version.Version, body io.Reader, eng *engine.Engine, t *testing.T) *httptest.ResponseRecorder { r := httptest.NewRecorder() req, err := http.NewRequest(method, target, body) if err != nil { t.Fatal(err) } - if err := ServeRequest(eng, api.APIVERSION, r, req); err != nil { + if err := ServeRequest(eng, version, r, req); err != nil { t.Fatal(err) } return r @@ -388,3 +487,46 @@ func toJson(data interface{}, t *testing.T) io.Reader { } return &buf } + +func assertContentType(recorder *httptest.ResponseRecorder, content_type string, t *testing.T) { + if recorder.HeaderMap.Get("Content-Type") != content_type { + t.Fatalf("%#v\n", recorder) + } +} + +// XXX: Duplicated from integration/utils_test.go, but maybe that's OK as that +// should die as soon as we converted all integration tests? +// assertHttpNotError expect the given response to not have an error. +// Otherwise the it causes the test to fail. +func assertHttpNotError(r *httptest.ResponseRecorder, t *testing.T) { + // Non-error http status are [200, 400) + if r.Code < http.StatusOK || r.Code >= http.StatusBadRequest { + t.Fatal(fmt.Errorf("Unexpected http error: %v", r.Code)) + } +} + +func createEnvFromGetImagesJSONStruct(data getImagesJSONStruct) *engine.Env { + v := &engine.Env{} + v.SetList("RepoTags", data.RepoTags) + v.Set("Id", data.Id) + v.SetInt64("Created", data.Created) + v.SetInt64("Size", data.Size) + v.SetInt64("VirtualSize", data.VirtualSize) + return v +} + +type getImagesJSONStruct struct { + RepoTags []string + Id string + Created int64 + Size int64 + VirtualSize int64 +} + +var sampleImage getImagesJSONStruct = getImagesJSONStruct{ + RepoTags: []string{"test-name:test-tag"}, + Id: "ID", + Created: 999, + Size: 777, + VirtualSize: 666, +} diff --git a/integration/api_test.go b/integration/api_test.go index f5e5599e3f..0da96ccd1e 100644 --- a/integration/api_test.go +++ b/integration/api_test.go @@ -9,7 +9,6 @@ import ( "net" "net/http" "net/http/httptest" - "strings" "testing" "time" @@ -20,109 +19,6 @@ import ( "github.com/dotcloud/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar" ) -func TestGetImagesJSON(t *testing.T) { - eng := NewTestEngine(t) - defer mkDaemonFromEngine(eng, t).Nuke() - - job := eng.Job("images") - initialImages, err := job.Stdout.AddListTable() - if err != nil { - t.Fatal(err) - } - if err := job.Run(); err != nil { - t.Fatal(err) - } - - req, err := http.NewRequest("GET", "/images/json?all=0", nil) - if err != nil { - t.Fatal(err) - } - - r := httptest.NewRecorder() - - if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil { - t.Fatal(err) - } - assertHttpNotError(r, t) - - images := engine.NewTable("Created", 0) - if _, err := images.ReadListFrom(r.Body.Bytes()); err != nil { - t.Fatal(err) - } - - if images.Len() != initialImages.Len() { - t.Errorf("Expected %d image, %d found", initialImages.Len(), images.Len()) - } - - found := false - for _, img := range images.Data { - if strings.Contains(img.GetList("RepoTags")[0], unitTestImageName) { - found = true - break - } - } - if !found { - t.Errorf("Expected image %s, %+v found", unitTestImageName, images) - } - - r2 := httptest.NewRecorder() - - // all=1 - - initialImages = getAllImages(eng, t) - - req2, err := http.NewRequest("GET", "/images/json?all=true", nil) - if err != nil { - t.Fatal(err) - } - if err := server.ServeRequest(eng, api.APIVERSION, r2, req2); err != nil { - t.Fatal(err) - } - assertHttpNotError(r2, t) - - images2 := engine.NewTable("Id", 0) - if _, err := images2.ReadListFrom(r2.Body.Bytes()); err != nil { - t.Fatal(err) - } - - if images2.Len() != initialImages.Len() { - t.Errorf("Expected %d image, %d found", initialImages.Len(), images2.Len()) - } - - found = false - for _, img := range images2.Data { - if img.Get("Id") == unitTestImageID { - found = true - break - } - } - if !found { - t.Errorf("Retrieved image Id differs, expected %s, received %+v", unitTestImageID, images2) - } - - r3 := httptest.NewRecorder() - - // filter=a - req3, err := http.NewRequest("GET", "/images/json?filter=aaaaaaaaaa", nil) - if err != nil { - t.Fatal(err) - } - - if err := server.ServeRequest(eng, api.APIVERSION, r3, req3); err != nil { - t.Fatal(err) - } - assertHttpNotError(r3, t) - - images3 := engine.NewTable("Id", 0) - if _, err := images3.ReadListFrom(r3.Body.Bytes()); err != nil { - t.Fatal(err) - } - - if images3.Len() != 0 { - t.Errorf("Expected 0 image, %d found", images3.Len()) - } -} - func TestGetContainersJSON(t *testing.T) { eng := NewTestEngine(t) defer mkDaemonFromEngine(eng, t).Nuke()