gopkg.in/docker/docker.v20@v20.10.27/client/image_push_test.go (about)

     1  package client // import "github.com/docker/docker/client"
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"fmt"
     7  	"io"
     8  	"net/http"
     9  	"strings"
    10  	"testing"
    11  
    12  	"github.com/docker/docker/api/types"
    13  	"github.com/docker/docker/errdefs"
    14  )
    15  
    16  func TestImagePushReferenceError(t *testing.T) {
    17  	client := &Client{
    18  		client: newMockClient(func(req *http.Request) (*http.Response, error) {
    19  			return nil, nil
    20  		}),
    21  	}
    22  	// An empty reference is an invalid reference
    23  	_, err := client.ImagePush(context.Background(), "", types.ImagePushOptions{})
    24  	if err == nil || !strings.Contains(err.Error(), "invalid reference format") {
    25  		t.Fatalf("expected an error, got %v", err)
    26  	}
    27  	// An canonical reference cannot be pushed
    28  	_, err = client.ImagePush(context.Background(), "repo@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", types.ImagePushOptions{})
    29  	if err == nil || err.Error() != "cannot push a digest reference" {
    30  		t.Fatalf("expected an error, got %v", err)
    31  	}
    32  }
    33  
    34  func TestImagePushAnyError(t *testing.T) {
    35  	client := &Client{
    36  		client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
    37  	}
    38  	_, err := client.ImagePush(context.Background(), "myimage", types.ImagePushOptions{})
    39  	if !errdefs.IsSystem(err) {
    40  		t.Fatalf("expected a Server Error, got %[1]T: %[1]v", err)
    41  	}
    42  }
    43  
    44  func TestImagePushStatusUnauthorizedError(t *testing.T) {
    45  	client := &Client{
    46  		client: newMockClient(errorMock(http.StatusUnauthorized, "Unauthorized error")),
    47  	}
    48  	_, err := client.ImagePush(context.Background(), "myimage", types.ImagePushOptions{})
    49  	if !errdefs.IsUnauthorized(err) {
    50  		t.Fatalf("expected a Unauthorized Error, got %[1]T: %[1]v", err)
    51  	}
    52  }
    53  
    54  func TestImagePushWithUnauthorizedErrorAndPrivilegeFuncError(t *testing.T) {
    55  	client := &Client{
    56  		client: newMockClient(errorMock(http.StatusUnauthorized, "Unauthorized error")),
    57  	}
    58  	privilegeFunc := func() (string, error) {
    59  		return "", fmt.Errorf("Error requesting privilege")
    60  	}
    61  	_, err := client.ImagePush(context.Background(), "myimage", types.ImagePushOptions{
    62  		PrivilegeFunc: privilegeFunc,
    63  	})
    64  	if err == nil || err.Error() != "Error requesting privilege" {
    65  		t.Fatalf("expected an error requesting privilege, got %v", err)
    66  	}
    67  }
    68  
    69  func TestImagePushWithUnauthorizedErrorAndAnotherUnauthorizedError(t *testing.T) {
    70  	client := &Client{
    71  		client: newMockClient(errorMock(http.StatusUnauthorized, "Unauthorized error")),
    72  	}
    73  	privilegeFunc := func() (string, error) {
    74  		return "a-auth-header", nil
    75  	}
    76  	_, err := client.ImagePush(context.Background(), "myimage", types.ImagePushOptions{
    77  		PrivilegeFunc: privilegeFunc,
    78  	})
    79  	if !errdefs.IsUnauthorized(err) {
    80  		t.Fatalf("expected a Unauthorized Error, got %[1]T: %[1]v", err)
    81  	}
    82  }
    83  
    84  func TestImagePushWithPrivilegedFuncNoError(t *testing.T) {
    85  	expectedURL := "/images/myimage/push"
    86  	client := &Client{
    87  		client: newMockClient(func(req *http.Request) (*http.Response, error) {
    88  			if !strings.HasPrefix(req.URL.Path, expectedURL) {
    89  				return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL)
    90  			}
    91  			auth := req.Header.Get("X-Registry-Auth")
    92  			if auth == "NotValid" {
    93  				return &http.Response{
    94  					StatusCode: http.StatusUnauthorized,
    95  					Body:       io.NopCloser(bytes.NewReader([]byte("Invalid credentials"))),
    96  				}, nil
    97  			}
    98  			if auth != "IAmValid" {
    99  				return nil, fmt.Errorf("Invalid auth header : expected %s, got %s", "IAmValid", auth)
   100  			}
   101  			query := req.URL.Query()
   102  			tag := query.Get("tag")
   103  			if tag != "tag" {
   104  				return nil, fmt.Errorf("tag not set in URL query properly. Expected '%s', got %s", "tag", tag)
   105  			}
   106  			return &http.Response{
   107  				StatusCode: http.StatusOK,
   108  				Body:       io.NopCloser(bytes.NewReader([]byte("hello world"))),
   109  			}, nil
   110  		}),
   111  	}
   112  	privilegeFunc := func() (string, error) {
   113  		return "IAmValid", nil
   114  	}
   115  	resp, err := client.ImagePush(context.Background(), "myimage:tag", types.ImagePushOptions{
   116  		RegistryAuth:  "NotValid",
   117  		PrivilegeFunc: privilegeFunc,
   118  	})
   119  	if err != nil {
   120  		t.Fatal(err)
   121  	}
   122  	body, err := io.ReadAll(resp)
   123  	if err != nil {
   124  		t.Fatal(err)
   125  	}
   126  	if string(body) != "hello world" {
   127  		t.Fatalf("expected 'hello world', got %s", string(body))
   128  	}
   129  }
   130  
   131  func TestImagePushWithoutErrors(t *testing.T) {
   132  	expectedOutput := "hello world"
   133  	expectedURLFormat := "/images/%s/push"
   134  	testCases := []struct {
   135  		all           bool
   136  		reference     string
   137  		expectedImage string
   138  		expectedTag   string
   139  	}{
   140  		{
   141  			all:           false,
   142  			reference:     "myimage",
   143  			expectedImage: "myimage",
   144  			expectedTag:   "latest",
   145  		},
   146  		{
   147  			all:           false,
   148  			reference:     "myimage:tag",
   149  			expectedImage: "myimage",
   150  			expectedTag:   "tag",
   151  		},
   152  		{
   153  			all:           true,
   154  			reference:     "myimage",
   155  			expectedImage: "myimage",
   156  			expectedTag:   "",
   157  		},
   158  		{
   159  			all:           true,
   160  			reference:     "myimage:anything",
   161  			expectedImage: "myimage",
   162  			expectedTag:   "",
   163  		},
   164  	}
   165  	for _, tc := range testCases {
   166  		tc := tc
   167  		t.Run(fmt.Sprintf("%s,all-tags=%t", tc.reference, tc.all), func(t *testing.T) {
   168  			client := &Client{
   169  				client: newMockClient(func(req *http.Request) (*http.Response, error) {
   170  					expectedURL := fmt.Sprintf(expectedURLFormat, tc.expectedImage)
   171  					if !strings.HasPrefix(req.URL.Path, expectedURL) {
   172  						return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL)
   173  					}
   174  					query := req.URL.Query()
   175  					tag := query.Get("tag")
   176  					if tag != tc.expectedTag {
   177  						return nil, fmt.Errorf("tag not set in URL query properly. Expected '%s', got %s", tc.expectedTag, tag)
   178  					}
   179  					return &http.Response{
   180  						StatusCode: http.StatusOK,
   181  						Body:       io.NopCloser(bytes.NewReader([]byte(expectedOutput))),
   182  					}, nil
   183  				}),
   184  			}
   185  			resp, err := client.ImagePush(context.Background(), tc.reference, types.ImagePushOptions{
   186  				All: tc.all,
   187  			})
   188  			if err != nil {
   189  				t.Fatal(err)
   190  			}
   191  			body, err := io.ReadAll(resp)
   192  			if err != nil {
   193  				t.Fatal(err)
   194  			}
   195  			if string(body) != expectedOutput {
   196  				t.Fatalf("expected '%s', got %s", expectedOutput, string(body))
   197  			}
   198  		})
   199  	}
   200  }