From 26dc5931070ca143116a482460165a89252740a2 Mon Sep 17 00:00:00 2001 From: Zou Rui <21751189@zju.edu.cn> Date: Mon, 2 Apr 2018 15:10:52 +0800 Subject: [PATCH] test: add mock test for image operations on client side Signed-off-by: Zou Rui <21751189@zju.edu.cn> --- client/image.go | 69 --------------------------------- client/image_inspect.go | 21 ++++++++++ client/image_inspect_test.go | 74 ++++++++++++++++++++++++++++++++++++ client/image_list.go | 22 +++++++++++ client/image_list_test.go | 70 ++++++++++++++++++++++++++++++++++ client/image_pull.go | 24 ++++++++++++ client/image_pull_test.go | 60 +++++++++++++++++++++++++++++ client/image_remove.go | 19 +++++++++ client/image_remove_test.go | 48 +++++++++++++++++++++++ 9 files changed, 338 insertions(+), 69 deletions(-) delete mode 100644 client/image.go create mode 100644 client/image_inspect.go create mode 100644 client/image_inspect_test.go create mode 100644 client/image_list.go create mode 100644 client/image_list_test.go create mode 100644 client/image_pull.go create mode 100644 client/image_pull_test.go create mode 100644 client/image_remove.go create mode 100644 client/image_remove_test.go diff --git a/client/image.go b/client/image.go deleted file mode 100644 index 3fc1c55e4..000000000 --- a/client/image.go +++ /dev/null @@ -1,69 +0,0 @@ -package client - -import ( - "context" - "io" - "net/url" - - "github.com/alibaba/pouch/apis/types" -) - -// ImageInspect requests daemon to inspect an image. -func (client *APIClient) ImageInspect(ctx context.Context, name string) (types.ImageInfo, error) { - image := types.ImageInfo{} - - resp, err := client.get(ctx, "/images/"+name+"/json", nil, nil) - if err != nil { - return image, err - } - - defer ensureCloseReader(resp) - err = decodeBody(&image, resp.Body) - return image, err -} - -// ImagePull requests daemon to pull an image from registry. -func (client *APIClient) ImagePull(ctx context.Context, name, tag, encodedAuth string) (io.ReadCloser, error) { - q := url.Values{} - q.Set("fromImage", name) - q.Set("tag", tag) - - headers := map[string][]string{} - if encodedAuth != "" { - headers["X-Registry-Auth"] = []string{encodedAuth} - } - resp, err := client.post(ctx, "/images/create", q, nil, headers) - if err != nil { - return nil, err - } - return resp.Body, nil -} - -// ImageList requests daemon to list all images -func (client *APIClient) ImageList(ctx context.Context) ([]types.ImageInfo, error) { - resp, err := client.get(ctx, "/images/json", nil, nil) - if err != nil { - return nil, err - } - - imageList := []types.ImageInfo{} - - err = decodeBody(&imageList, resp.Body) - ensureCloseReader(resp) - - return imageList, err - -} - -// ImageRemove deletes an image. -func (client *APIClient) ImageRemove(ctx context.Context, name string, force bool) error { - q := url.Values{} - if force { - q.Set("force", "true") - } - - resp, err := client.delete(ctx, "/images/"+name, q, nil) - ensureCloseReader(resp) - - return err -} diff --git a/client/image_inspect.go b/client/image_inspect.go new file mode 100644 index 000000000..e7520b518 --- /dev/null +++ b/client/image_inspect.go @@ -0,0 +1,21 @@ +package client + +import ( + "context" + + "github.com/alibaba/pouch/apis/types" +) + +// ImageInspect requests daemon to inspect an image. +func (client *APIClient) ImageInspect(ctx context.Context, name string) (types.ImageInfo, error) { + image := types.ImageInfo{} + + resp, err := client.get(ctx, "/images/"+name+"/json", nil, nil) + if err != nil { + return image, err + } + + defer ensureCloseReader(resp) + err = decodeBody(&image, resp.Body) + return image, err +} diff --git a/client/image_inspect_test.go b/client/image_inspect_test.go new file mode 100644 index 000000000..ce174a235 --- /dev/null +++ b/client/image_inspect_test.go @@ -0,0 +1,74 @@ +package client + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "strings" + "testing" + + "github.com/alibaba/pouch/apis/types" + + "github.com/stretchr/testify/assert" +) + +func TestImageInspectServerError(t *testing.T) { + client := &APIClient{ + HTTPCli: newMockClient(errorMockResponse(http.StatusInternalServerError, "Server error")), + } + _, err := client.ImageInspect(context.Background(), "image_id") + if err == nil || !strings.Contains(err.Error(), "Server error") { + t.Fatalf("expected a Server Error, got %v", err) + } +} + +func TestImageInspectNotFoundError(t *testing.T) { + client := &APIClient{ + HTTPCli: newMockClient(errorMockResponse(http.StatusConflict, "Not Found")), + } + _, err := client.ImageInspect(context.Background(), "no image") + if err == nil || !strings.Contains(err.Error(), "Not Found") { + t.Fatalf("expected a Server Error, got %v", err) + } +} + +func TestImageInspect(t *testing.T) { + expectedURL := "/images/image_id" + + httpClient := newMockClient(func(req *http.Request) (*http.Response, error) { + if !strings.HasPrefix(req.URL.Path, expectedURL) { + return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) + } + if req.Method != "GET" { + return nil, fmt.Errorf("expected GET method, got %s", req.Method) + } + + imageInspectResp, err := json.Marshal(types.ImageInfo{ + ID: "1", + Size: int64(94), + }) + if err != nil { + return nil, err + } + + return &http.Response{ + StatusCode: http.StatusOK, + Body: ioutil.NopCloser(bytes.NewReader([]byte(imageInspectResp))), + }, nil + }) + + client := &APIClient{ + HTTPCli: httpClient, + } + + image, err := client.ImageInspect(context.Background(), "image_id") + if err != nil { + t.Fatal(err) + } + assert.Equal(t, image.ID, "1") + assert.Equal(t, image.Size, int64(94)) + +} diff --git a/client/image_list.go b/client/image_list.go new file mode 100644 index 000000000..bbf34516e --- /dev/null +++ b/client/image_list.go @@ -0,0 +1,22 @@ +package client + +import ( + "context" + "github.com/alibaba/pouch/apis/types" +) + +// ImageList requests daemon to list all images +func (client *APIClient) ImageList(ctx context.Context) ([]types.ImageInfo, error) { + resp, err := client.get(ctx, "/images/json", nil, nil) + if err != nil { + return nil, err + } + + imageList := []types.ImageInfo{} + + err = decodeBody(&imageList, resp.Body) + ensureCloseReader(resp) + + return imageList, err + +} diff --git a/client/image_list_test.go b/client/image_list_test.go new file mode 100644 index 000000000..1cfa6fc35 --- /dev/null +++ b/client/image_list_test.go @@ -0,0 +1,70 @@ +package client + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "strings" + "testing" + + "github.com/alibaba/pouch/apis/types" + + "github.com/stretchr/testify/assert" +) + +func TestImageListServerError(t *testing.T) { + client := &APIClient{ + HTTPCli: newMockClient(errorMockResponse(http.StatusInternalServerError, "Server error")), + } + _, err := client.ImageList(context.Background()) + if err == nil || !strings.Contains(err.Error(), "Server error") { + t.Fatalf("expected a Server Error, got %v", err) + } +} + +func TestImageList(t *testing.T) { + expectedURL := "/images" + + httpClient := newMockClient(func(req *http.Request) (*http.Response, error) { + if !strings.HasPrefix(req.URL.Path, expectedURL) { + return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) + } + if req.Method != "GET" { + return nil, fmt.Errorf("expected GET method, got %s", req.Method) + } + + imageListResp, err := json.Marshal([]types.ImageInfo{ + { + ID: "1", + Size: 703, + Os: "CentOS", + }, + { + ID: "2", + Size: 44, + Os: "Ubuntu TLS 16.04", + }, + }) + if err != nil { + return nil, err + } + + return &http.Response{ + StatusCode: http.StatusOK, + Body: ioutil.NopCloser(bytes.NewReader([]byte(imageListResp))), + }, nil + }) + + client := &APIClient{ + HTTPCli: httpClient, + } + + image, err := client.ImageList(context.Background()) + if err != nil { + t.Fatal(err) + } + assert.Equal(t, len(image), 2) +} diff --git a/client/image_pull.go b/client/image_pull.go new file mode 100644 index 000000000..de33c49c0 --- /dev/null +++ b/client/image_pull.go @@ -0,0 +1,24 @@ +package client + +import ( + "context" + "io" + "net/url" +) + +// ImagePull requests daemon to pull an image from registry. +func (client *APIClient) ImagePull(ctx context.Context, name, tag, encodedAuth string) (io.ReadCloser, error) { + q := url.Values{} + q.Set("fromImage", name) + q.Set("tag", tag) + + headers := map[string][]string{} + if encodedAuth != "" { + headers["X-Registry-Auth"] = []string{encodedAuth} + } + resp, err := client.post(ctx, "/images/create", q, nil, headers) + if err != nil { + return nil, err + } + return resp.Body, nil +} diff --git a/client/image_pull_test.go b/client/image_pull_test.go new file mode 100644 index 000000000..011c03f70 --- /dev/null +++ b/client/image_pull_test.go @@ -0,0 +1,60 @@ +package client + +import ( + "bytes" + "context" + "fmt" + "io/ioutil" + "net/http" + "strings" + "testing" +) + +func TestImagePullServerError(t *testing.T) { + client := &APIClient{ + HTTPCli: newMockClient(errorMockResponse(http.StatusInternalServerError, "Server error")), + } + _, err := client.ImagePull(context.Background(), "image_name", "image_tag", "auth") + if err == nil || !strings.Contains(err.Error(), "Server error") { + t.Fatalf("expected a Server Error, got %v", err) + } +} + +func TestImagePullWrongError(t *testing.T) { + client := &APIClient{ + HTTPCli: newMockClient(errorMockResponse(http.StatusNotFound, "Image not found")), + } + _, err := client.ImagePull(context.Background(), "image_name", "image_tag", "auth") + if err == nil || !strings.Contains(err.Error(), "Image not found") { + t.Fatalf("expected an Image Not Found Error, got %v", err) + } +} + +func TestImagePull(t *testing.T) { + expectedURL := "/images/create" + + httpClient := newMockClient(func(req *http.Request) (*http.Response, error) { + if !strings.HasPrefix(req.URL.Path, expectedURL) { + return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) + } + + if req.Method != "POST" { + return nil, fmt.Errorf("Expected POST method, got %s", req.Method) + } + + return &http.Response{ + StatusCode: http.StatusOK, + Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), + }, nil + }) + + client := &APIClient{ + HTTPCli: httpClient, + } + + _, err := client.ImagePull(context.Background(), "image_name", "image_tag", "auth") + if err != nil { + t.Fatal(err) + } + +} diff --git a/client/image_remove.go b/client/image_remove.go new file mode 100644 index 000000000..612bb832a --- /dev/null +++ b/client/image_remove.go @@ -0,0 +1,19 @@ +package client + +import ( + "context" + "net/url" +) + +// ImageRemove deletes an image. +func (client *APIClient) ImageRemove(ctx context.Context, name string, force bool) error { + q := url.Values{} + if force { + q.Set("force", "true") + } + + resp, err := client.delete(ctx, "/images/"+name, q, nil) + ensureCloseReader(resp) + + return err +} diff --git a/client/image_remove_test.go b/client/image_remove_test.go new file mode 100644 index 000000000..77302928b --- /dev/null +++ b/client/image_remove_test.go @@ -0,0 +1,48 @@ +package client + +import ( + "bytes" + "context" + "fmt" + "io/ioutil" + "net/http" + "strings" + "testing" +) + +func TestImageRemoveNotFoundError(t *testing.T) { + client := &APIClient{ + HTTPCli: newMockClient(errorMockResponse(http.StatusNotFound, "Not Found")), + } + err := client.ImageRemove(context.Background(), "no network", true) + if err == nil || !strings.Contains(err.Error(), "Not Found") { + t.Fatalf("expected a Not Found Error, got %v", err) + } +} + +func TestImageRemove(t *testing.T) { + expectedURL := "/images/image_id" + + httpClient := newMockClient(func(req *http.Request) (*http.Response, error) { + if !strings.HasPrefix(req.URL.Path, expectedURL) { + return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) + } + if req.Method != "DELETE" { + return nil, fmt.Errorf("expected DELETE method, got %s", req.Method) + } + + return &http.Response{ + StatusCode: http.StatusNoContent, + Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), + }, nil + }) + + client := &APIClient{ + HTTPCli: httpClient, + } + + err := client.ImageRemove(context.Background(), "image_id", false) + if err != nil { + t.Fatal(err) + } +}