123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- package client // import "github.com/docker/docker/client"
- import (
- "bytes"
- "context"
- "fmt"
- "io"
- "net/http"
- "strings"
- "testing"
- "github.com/docker/docker/api/types"
- "github.com/docker/docker/api/types/registry"
- "github.com/docker/docker/errdefs"
- "gotest.tools/v3/assert"
- is "gotest.tools/v3/assert/cmp"
- )
- func TestImagePushReferenceError(t *testing.T) {
- client := &Client{
- client: newMockClient(func(req *http.Request) (*http.Response, error) {
- return nil, nil
- }),
- }
- // An empty reference is an invalid reference
- _, err := client.ImagePush(context.Background(), "", types.ImagePushOptions{})
- if err == nil || !strings.Contains(err.Error(), "invalid reference format") {
- t.Fatalf("expected an error, got %v", err)
- }
- // An canonical reference cannot be pushed
- _, err = client.ImagePush(context.Background(), "repo@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", types.ImagePushOptions{})
- if err == nil || err.Error() != "cannot push a digest reference" {
- t.Fatalf("expected an error, got %v", err)
- }
- }
- func TestImagePushAnyError(t *testing.T) {
- client := &Client{
- client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
- }
- _, err := client.ImagePush(context.Background(), "myimage", types.ImagePushOptions{})
- assert.Check(t, is.ErrorType(err, errdefs.IsSystem))
- }
- func TestImagePushStatusUnauthorizedError(t *testing.T) {
- client := &Client{
- client: newMockClient(errorMock(http.StatusUnauthorized, "Unauthorized error")),
- }
- _, err := client.ImagePush(context.Background(), "myimage", types.ImagePushOptions{})
- assert.Check(t, is.ErrorType(err, errdefs.IsUnauthorized))
- }
- func TestImagePushWithUnauthorizedErrorAndPrivilegeFuncError(t *testing.T) {
- client := &Client{
- client: newMockClient(errorMock(http.StatusUnauthorized, "Unauthorized error")),
- }
- privilegeFunc := func() (string, error) {
- return "", fmt.Errorf("Error requesting privilege")
- }
- _, err := client.ImagePush(context.Background(), "myimage", types.ImagePushOptions{
- PrivilegeFunc: privilegeFunc,
- })
- if err == nil || err.Error() != "Error requesting privilege" {
- t.Fatalf("expected an error requesting privilege, got %v", err)
- }
- }
- func TestImagePushWithUnauthorizedErrorAndAnotherUnauthorizedError(t *testing.T) {
- client := &Client{
- client: newMockClient(errorMock(http.StatusUnauthorized, "Unauthorized error")),
- }
- privilegeFunc := func() (string, error) {
- return "a-auth-header", nil
- }
- _, err := client.ImagePush(context.Background(), "myimage", types.ImagePushOptions{
- PrivilegeFunc: privilegeFunc,
- })
- assert.Check(t, is.ErrorType(err, errdefs.IsUnauthorized))
- }
- func TestImagePushWithPrivilegedFuncNoError(t *testing.T) {
- expectedURL := "/images/myimage/push"
- client := &Client{
- client: 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)
- }
- auth := req.Header.Get(registry.AuthHeader)
- if auth == "NotValid" {
- return &http.Response{
- StatusCode: http.StatusUnauthorized,
- Body: io.NopCloser(bytes.NewReader([]byte("Invalid credentials"))),
- }, nil
- }
- if auth != "IAmValid" {
- return nil, fmt.Errorf("invalid auth header: expected %s, got %s", "IAmValid", auth)
- }
- query := req.URL.Query()
- tag := query.Get("tag")
- if tag != "tag" {
- return nil, fmt.Errorf("tag not set in URL query properly. Expected '%s', got %s", "tag", tag)
- }
- return &http.Response{
- StatusCode: http.StatusOK,
- Body: io.NopCloser(bytes.NewReader([]byte("hello world"))),
- }, nil
- }),
- }
- privilegeFunc := func() (string, error) {
- return "IAmValid", nil
- }
- resp, err := client.ImagePush(context.Background(), "myimage:tag", types.ImagePushOptions{
- RegistryAuth: "NotValid",
- PrivilegeFunc: privilegeFunc,
- })
- if err != nil {
- t.Fatal(err)
- }
- body, err := io.ReadAll(resp)
- if err != nil {
- t.Fatal(err)
- }
- if string(body) != "hello world" {
- t.Fatalf("expected 'hello world', got %s", string(body))
- }
- }
- func TestImagePushWithoutErrors(t *testing.T) {
- expectedOutput := "hello world"
- expectedURLFormat := "/images/%s/push"
- testCases := []struct {
- all bool
- reference string
- expectedImage string
- expectedTag string
- }{
- {
- all: false,
- reference: "myimage",
- expectedImage: "myimage",
- expectedTag: "latest",
- },
- {
- all: false,
- reference: "myimage:tag",
- expectedImage: "myimage",
- expectedTag: "tag",
- },
- {
- all: true,
- reference: "myimage",
- expectedImage: "myimage",
- expectedTag: "",
- },
- {
- all: true,
- reference: "myimage:anything",
- expectedImage: "myimage",
- expectedTag: "",
- },
- }
- for _, tc := range testCases {
- tc := tc
- t.Run(fmt.Sprintf("%s,all-tags=%t", tc.reference, tc.all), func(t *testing.T) {
- client := &Client{
- client: newMockClient(func(req *http.Request) (*http.Response, error) {
- expectedURL := fmt.Sprintf(expectedURLFormat, tc.expectedImage)
- if !strings.HasPrefix(req.URL.Path, expectedURL) {
- return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL)
- }
- query := req.URL.Query()
- tag := query.Get("tag")
- if tag != tc.expectedTag {
- return nil, fmt.Errorf("tag not set in URL query properly. Expected '%s', got %s", tc.expectedTag, tag)
- }
- return &http.Response{
- StatusCode: http.StatusOK,
- Body: io.NopCloser(bytes.NewReader([]byte(expectedOutput))),
- }, nil
- }),
- }
- resp, err := client.ImagePush(context.Background(), tc.reference, types.ImagePushOptions{
- All: tc.all,
- })
- if err != nil {
- t.Fatal(err)
- }
- body, err := io.ReadAll(resp)
- if err != nil {
- t.Fatal(err)
- }
- if string(body) != expectedOutput {
- t.Fatalf("expected '%s', got %s", expectedOutput, string(body))
- }
- })
- }
- }
|