github.com/rish1988/moby@v25.0.2+incompatible/client/image_build_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  	"reflect"
    10  	"strings"
    11  	"testing"
    12  
    13  	"github.com/docker/docker/api/types"
    14  	"github.com/docker/docker/api/types/container"
    15  	"github.com/docker/docker/api/types/registry"
    16  	"github.com/docker/docker/errdefs"
    17  	units "github.com/docker/go-units"
    18  	"gotest.tools/v3/assert"
    19  	is "gotest.tools/v3/assert/cmp"
    20  )
    21  
    22  func TestImageBuildError(t *testing.T) {
    23  	client := &Client{
    24  		client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
    25  	}
    26  	_, err := client.ImageBuild(context.Background(), nil, types.ImageBuildOptions{})
    27  	assert.Check(t, is.ErrorType(err, errdefs.IsSystem))
    28  }
    29  
    30  func TestImageBuild(t *testing.T) {
    31  	v1 := "value1"
    32  	v2 := "value2"
    33  	emptyRegistryConfig := "bnVsbA=="
    34  	buildCases := []struct {
    35  		buildOptions           types.ImageBuildOptions
    36  		expectedQueryParams    map[string]string
    37  		expectedTags           []string
    38  		expectedRegistryConfig string
    39  	}{
    40  		{
    41  			buildOptions: types.ImageBuildOptions{
    42  				SuppressOutput: true,
    43  				NoCache:        true,
    44  				Remove:         true,
    45  				ForceRemove:    true,
    46  				PullParent:     true,
    47  			},
    48  			expectedQueryParams: map[string]string{
    49  				"q":       "1",
    50  				"nocache": "1",
    51  				"rm":      "1",
    52  				"forcerm": "1",
    53  				"pull":    "1",
    54  			},
    55  			expectedTags:           []string{},
    56  			expectedRegistryConfig: emptyRegistryConfig,
    57  		},
    58  		{
    59  			buildOptions: types.ImageBuildOptions{
    60  				SuppressOutput: false,
    61  				NoCache:        false,
    62  				Remove:         false,
    63  				ForceRemove:    false,
    64  				PullParent:     false,
    65  			},
    66  			expectedQueryParams: map[string]string{
    67  				"q":       "",
    68  				"nocache": "",
    69  				"rm":      "0",
    70  				"forcerm": "",
    71  				"pull":    "",
    72  			},
    73  			expectedTags:           []string{},
    74  			expectedRegistryConfig: emptyRegistryConfig,
    75  		},
    76  		{
    77  			buildOptions: types.ImageBuildOptions{
    78  				RemoteContext: "remoteContext",
    79  				Isolation:     container.Isolation("isolation"),
    80  				CPUSetCPUs:    "2",
    81  				CPUSetMems:    "12",
    82  				CPUShares:     20,
    83  				CPUQuota:      10,
    84  				CPUPeriod:     30,
    85  				Memory:        256,
    86  				MemorySwap:    512,
    87  				ShmSize:       10,
    88  				CgroupParent:  "cgroup_parent",
    89  				Dockerfile:    "Dockerfile",
    90  			},
    91  			expectedQueryParams: map[string]string{
    92  				"remote":       "remoteContext",
    93  				"isolation":    "isolation",
    94  				"cpusetcpus":   "2",
    95  				"cpusetmems":   "12",
    96  				"cpushares":    "20",
    97  				"cpuquota":     "10",
    98  				"cpuperiod":    "30",
    99  				"memory":       "256",
   100  				"memswap":      "512",
   101  				"shmsize":      "10",
   102  				"cgroupparent": "cgroup_parent",
   103  				"dockerfile":   "Dockerfile",
   104  				"rm":           "0",
   105  			},
   106  			expectedTags:           []string{},
   107  			expectedRegistryConfig: emptyRegistryConfig,
   108  		},
   109  		{
   110  			buildOptions: types.ImageBuildOptions{
   111  				BuildArgs: map[string]*string{
   112  					"ARG1": &v1,
   113  					"ARG2": &v2,
   114  					"ARG3": nil,
   115  				},
   116  			},
   117  			expectedQueryParams: map[string]string{
   118  				"buildargs": `{"ARG1":"value1","ARG2":"value2","ARG3":null}`,
   119  				"rm":        "0",
   120  			},
   121  			expectedTags:           []string{},
   122  			expectedRegistryConfig: emptyRegistryConfig,
   123  		},
   124  		{
   125  			buildOptions: types.ImageBuildOptions{
   126  				Ulimits: []*units.Ulimit{
   127  					{
   128  						Name: "nproc",
   129  						Hard: 65557,
   130  						Soft: 65557,
   131  					},
   132  					{
   133  						Name: "nofile",
   134  						Hard: 20000,
   135  						Soft: 40000,
   136  					},
   137  				},
   138  			},
   139  			expectedQueryParams: map[string]string{
   140  				"ulimits": `[{"Name":"nproc","Hard":65557,"Soft":65557},{"Name":"nofile","Hard":20000,"Soft":40000}]`,
   141  				"rm":      "0",
   142  			},
   143  			expectedTags:           []string{},
   144  			expectedRegistryConfig: emptyRegistryConfig,
   145  		},
   146  		{
   147  			buildOptions: types.ImageBuildOptions{
   148  				AuthConfigs: map[string]registry.AuthConfig{
   149  					"https://index.docker.io/v1/": {
   150  						Auth: "dG90bwo=",
   151  					},
   152  				},
   153  			},
   154  			expectedQueryParams: map[string]string{
   155  				"rm": "0",
   156  			},
   157  			expectedTags:           []string{},
   158  			expectedRegistryConfig: "eyJodHRwczovL2luZGV4LmRvY2tlci5pby92MS8iOnsiYXV0aCI6ImRHOTBid289In19",
   159  		},
   160  	}
   161  	for _, buildCase := range buildCases {
   162  		expectedURL := "/build"
   163  		client := &Client{
   164  			client: newMockClient(func(r *http.Request) (*http.Response, error) {
   165  				if !strings.HasPrefix(r.URL.Path, expectedURL) {
   166  					return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, r.URL)
   167  				}
   168  				// Check request headers
   169  				registryConfig := r.Header.Get("X-Registry-Config")
   170  				if registryConfig != buildCase.expectedRegistryConfig {
   171  					return nil, fmt.Errorf("X-Registry-Config header not properly set in the request. Expected '%s', got %s", buildCase.expectedRegistryConfig, registryConfig)
   172  				}
   173  				contentType := r.Header.Get("Content-Type")
   174  				if contentType != "application/x-tar" {
   175  					return nil, fmt.Errorf("Content-type header not properly set in the request. Expected 'application/x-tar', got %s", contentType)
   176  				}
   177  
   178  				// Check query parameters
   179  				query := r.URL.Query()
   180  				for key, expected := range buildCase.expectedQueryParams {
   181  					actual := query.Get(key)
   182  					if actual != expected {
   183  						return nil, fmt.Errorf("%s not set in URL query properly. Expected '%s', got %s", key, expected, actual)
   184  					}
   185  				}
   186  
   187  				// Check tags
   188  				if len(buildCase.expectedTags) > 0 {
   189  					tags := query["t"]
   190  					if !reflect.DeepEqual(tags, buildCase.expectedTags) {
   191  						return nil, fmt.Errorf("t (tags) not set in URL query properly. Expected '%s', got %s", buildCase.expectedTags, tags)
   192  					}
   193  				}
   194  
   195  				headers := http.Header{}
   196  				headers.Add("Server", "Docker/v1.23 (MyOS)")
   197  				return &http.Response{
   198  					StatusCode: http.StatusOK,
   199  					Body:       io.NopCloser(bytes.NewReader([]byte("body"))),
   200  					Header:     headers,
   201  				}, nil
   202  			}),
   203  		}
   204  		buildResponse, err := client.ImageBuild(context.Background(), nil, buildCase.buildOptions)
   205  		if err != nil {
   206  			t.Fatal(err)
   207  		}
   208  		if buildResponse.OSType != "MyOS" {
   209  			t.Fatalf("expected OSType to be 'MyOS', got %s", buildResponse.OSType)
   210  		}
   211  		response, err := io.ReadAll(buildResponse.Body)
   212  		if err != nil {
   213  			t.Fatal(err)
   214  		}
   215  		buildResponse.Body.Close()
   216  		if string(response) != "body" {
   217  			t.Fatalf("expected Body to contain 'body' string, got %s", response)
   218  		}
   219  	}
   220  }
   221  
   222  func TestGetDockerOS(t *testing.T) {
   223  	cases := map[string]string{
   224  		"Docker/v1.22 (linux)":   "linux",
   225  		"Docker/v1.22 (windows)": "windows",
   226  		"Foo/v1.22 (bar)":        "",
   227  	}
   228  	for header, os := range cases {
   229  		g := getDockerOS(header)
   230  		if g != os {
   231  			t.Fatalf("Expected %s, got %s", os, g)
   232  		}
   233  	}
   234  }