github.com/GoogleContainerTools/skaffold@v1.39.18/pkg/skaffold/build/gcb/docker_test.go (about)

     1  /*
     2  Copyright 2019 The Skaffold Authors
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package gcb
    18  
    19  import (
    20  	"context"
    21  	"testing"
    22  
    23  	v1 "github.com/opencontainers/image-spec/specs-go/v1"
    24  	"google.golang.org/api/cloudbuild/v1"
    25  
    26  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/config"
    27  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker"
    28  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/platform"
    29  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
    30  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
    31  	"github.com/GoogleContainerTools/skaffold/testutil"
    32  )
    33  
    34  func TestDockerBuildSpec(t *testing.T) {
    35  	tests := []struct {
    36  		description string
    37  		artifact    *latest.Artifact
    38  		platforms   platform.Matcher
    39  		expected    cloudbuild.Build
    40  		shouldErr   bool
    41  	}{
    42  		{
    43  			description: "normal docker build",
    44  			artifact: &latest.Artifact{
    45  				ArtifactType: latest.ArtifactType{
    46  					DockerArtifact: &latest.DockerArtifact{
    47  						DockerfilePath: "Dockerfile",
    48  						BuildArgs: map[string]*string{
    49  							"arg1": util.StringPtr("value1"),
    50  							"arg2": nil,
    51  						},
    52  					},
    53  				},
    54  			},
    55  			expected: cloudbuild.Build{
    56  				LogsBucket: "bucket",
    57  				Source: &cloudbuild.Source{
    58  					StorageSource: &cloudbuild.StorageSource{
    59  						Bucket: "bucket",
    60  						Object: "object",
    61  					},
    62  				},
    63  				Steps: []*cloudbuild.BuildStep{{
    64  					Name: "docker/docker",
    65  					Args: []string{"build", "--tag", "nginx", "-f", "Dockerfile", "--build-arg", "arg1=value1", "--build-arg", "arg2", "."},
    66  				}},
    67  				Images: []string{"nginx"},
    68  				Options: &cloudbuild.BuildOptions{
    69  					DiskSizeGb:  100,
    70  					MachineType: "n1-standard-1",
    71  				},
    72  				Timeout: "10m",
    73  			},
    74  		},
    75  		{
    76  			description: "docker build with artifact dependencies",
    77  			artifact: &latest.Artifact{
    78  				ImageName: "img1",
    79  				ArtifactType: latest.ArtifactType{
    80  					DockerArtifact: &latest.DockerArtifact{
    81  						DockerfilePath: "Dockerfile",
    82  						BuildArgs: map[string]*string{
    83  							"arg1": util.StringPtr("value1"),
    84  							"arg2": nil,
    85  						},
    86  					},
    87  				},
    88  				Dependencies: []*latest.ArtifactDependency{{ImageName: "img2", Alias: "IMG2"}, {ImageName: "img3", Alias: "IMG3"}},
    89  			},
    90  			expected: cloudbuild.Build{
    91  				LogsBucket: "bucket",
    92  				Source: &cloudbuild.Source{
    93  					StorageSource: &cloudbuild.StorageSource{
    94  						Bucket: "bucket",
    95  						Object: "object",
    96  					},
    97  				},
    98  				Steps: []*cloudbuild.BuildStep{{
    99  					Name: "docker/docker",
   100  					Args: []string{"build", "--tag", "nginx", "-f", "Dockerfile", "--build-arg", "IMG2=img2:tag", "--build-arg", "IMG3=img3:tag", "--build-arg", "arg1=value1", "--build-arg", "arg2", "."},
   101  				}},
   102  				Images: []string{"nginx"},
   103  				Options: &cloudbuild.BuildOptions{
   104  					DiskSizeGb:  100,
   105  					MachineType: "n1-standard-1",
   106  				},
   107  				Timeout: "10m",
   108  			},
   109  		},
   110  		{
   111  			description: "buildkit `secret` option not supported in GCB",
   112  			artifact: &latest.Artifact{
   113  				ArtifactType: latest.ArtifactType{
   114  					DockerArtifact: &latest.DockerArtifact{
   115  						DockerfilePath: "Dockerfile",
   116  						Secrets: []*latest.DockerSecret{
   117  							{ID: "secret"},
   118  						},
   119  					},
   120  				},
   121  			},
   122  			shouldErr: true,
   123  		},
   124  		{
   125  			description: "buildkit `ssh` option not supported in GCB",
   126  			artifact: &latest.Artifact{
   127  				ArtifactType: latest.ArtifactType{
   128  					DockerArtifact: &latest.DockerArtifact{
   129  						DockerfilePath: "Dockerfile",
   130  						SSH:            "default",
   131  					},
   132  				},
   133  			},
   134  			shouldErr: true,
   135  		},
   136  
   137  		{
   138  			description: "cross-platform build",
   139  			artifact: &latest.Artifact{
   140  				ArtifactType: latest.ArtifactType{
   141  					DockerArtifact: &latest.DockerArtifact{
   142  						DockerfilePath: "Dockerfile",
   143  						BuildArgs: map[string]*string{
   144  							"arg1": util.StringPtr("value1"),
   145  							"arg2": nil,
   146  						},
   147  					},
   148  				},
   149  			},
   150  			platforms: platform.Matcher{Platforms: []v1.Platform{{Architecture: "arm", OS: "freebsd"}}},
   151  			expected: cloudbuild.Build{
   152  				LogsBucket: "bucket",
   153  				Source: &cloudbuild.Source{
   154  					StorageSource: &cloudbuild.StorageSource{
   155  						Bucket: "bucket",
   156  						Object: "object",
   157  					},
   158  				},
   159  				Steps: []*cloudbuild.BuildStep{{
   160  					Name: "docker/docker",
   161  					Args: []string{"build", "--tag", "nginx", "-f", "Dockerfile", "--platform", "freebsd/arm", "--build-arg", "arg1=value1", "--build-arg", "arg2", "."},
   162  					Env:  []string{"DOCKER_BUILDKIT=1"},
   163  				}},
   164  				Images: []string{"nginx"},
   165  				Options: &cloudbuild.BuildOptions{
   166  					DiskSizeGb:  100,
   167  					MachineType: "n1-standard-1",
   168  				},
   169  				Timeout: "10m",
   170  			},
   171  		},
   172  	}
   173  
   174  	for _, test := range tests {
   175  		testutil.Run(t, test.description, func(t *testutil.T) {
   176  			t.Override(&docker.EvalBuildArgs, func(_ config.RunMode, _ string, _ string, args map[string]*string, extra map[string]*string) (map[string]*string, error) {
   177  				m := make(map[string]*string)
   178  				for k, v := range args {
   179  					m[k] = v
   180  				}
   181  				for k, v := range extra {
   182  					m[k] = v
   183  				}
   184  				return m, nil
   185  			})
   186  
   187  			store := mockArtifactStore{
   188  				"img2": "img2:tag",
   189  				"img3": "img3:tag",
   190  			}
   191  
   192  			builder := NewBuilder(&mockBuilderContext{artifactStore: store}, &latest.GoogleCloudBuild{
   193  				DockerImage: "docker/docker",
   194  				DiskSizeGb:  100,
   195  				MachineType: "n1-standard-1",
   196  				Timeout:     "10m",
   197  			})
   198  
   199  			desc, err := builder.buildSpec(context.Background(), test.artifact, "nginx", test.platforms, "bucket", "object")
   200  			t.CheckErrorAndDeepEqual(test.shouldErr, err, test.expected, desc)
   201  		})
   202  	}
   203  }
   204  
   205  func TestPullCacheFrom(t *testing.T) {
   206  	tests := []struct {
   207  		description string
   208  		artifact    *latest.Artifact
   209  		tag         string
   210  		platforms   platform.Matcher
   211  		expected    []*cloudbuild.BuildStep
   212  		shouldErr   bool
   213  	}{
   214  		{
   215  			description: "multiple cache-from images",
   216  			artifact: &latest.Artifact{
   217  				ArtifactType: latest.ArtifactType{
   218  					DockerArtifact: &latest.DockerArtifact{
   219  						DockerfilePath: "Dockerfile",
   220  						CacheFrom:      []string{"from/image1", "from/image2"},
   221  					},
   222  				},
   223  			},
   224  			tag: "nginx2",
   225  			expected: []*cloudbuild.BuildStep{{
   226  				Name:       "docker/docker",
   227  				Entrypoint: "sh",
   228  				Args:       []string{"-c", "docker pull from/image1 || true"},
   229  			}, {
   230  				Name:       "docker/docker",
   231  				Entrypoint: "sh",
   232  				Args:       []string{"-c", "docker pull from/image2 || true"},
   233  			}, {
   234  				Name: "docker/docker",
   235  				Args: []string{"build", "--tag", "nginx2", "-f", "Dockerfile", "--cache-from", "from/image1", "--cache-from", "from/image2", "."},
   236  			}},
   237  		},
   238  		{
   239  			description: "cache-from self uses tagged image",
   240  			artifact: &latest.Artifact{
   241  				ImageName: "gcr.io/k8s-skaffold/test",
   242  				ArtifactType: latest.ArtifactType{
   243  					DockerArtifact: &latest.DockerArtifact{
   244  						DockerfilePath: "Dockerfile",
   245  						CacheFrom:      []string{"gcr.io/k8s-skaffold/test"},
   246  					},
   247  				},
   248  			},
   249  			tag: "gcr.io/k8s-skaffold/test:tagged",
   250  			expected: []*cloudbuild.BuildStep{{
   251  				Name:       "docker/docker",
   252  				Entrypoint: "sh",
   253  				Args:       []string{"-c", "docker pull gcr.io/k8s-skaffold/test:tagged || true"},
   254  			}, {
   255  				Name: "docker/docker",
   256  				Args: []string{"build", "--tag", "gcr.io/k8s-skaffold/test:tagged", "-f", "Dockerfile", "--cache-from", "gcr.io/k8s-skaffold/test:tagged", "."},
   257  			}},
   258  		},
   259  		{
   260  			description: "cross-platform cache-from images",
   261  			artifact: &latest.Artifact{
   262  				ArtifactType: latest.ArtifactType{
   263  					DockerArtifact: &latest.DockerArtifact{
   264  						DockerfilePath: "Dockerfile",
   265  						CacheFrom:      []string{"from/image1", "from/image2"},
   266  					},
   267  				},
   268  			},
   269  			tag:       "nginx2",
   270  			platforms: platform.Matcher{Platforms: []v1.Platform{{Architecture: "arm", OS: "freebsd"}}},
   271  			expected: []*cloudbuild.BuildStep{{
   272  				Name:       "docker/docker",
   273  				Entrypoint: "sh",
   274  				Args:       []string{"-c", "docker pull --platform freebsd/arm from/image1 || true"},
   275  			}, {
   276  				Name:       "docker/docker",
   277  				Entrypoint: "sh",
   278  				Args:       []string{"-c", "docker pull --platform freebsd/arm from/image2 || true"},
   279  			}, {
   280  				Name: "docker/docker",
   281  				Args: []string{"build", "--tag", "nginx2", "-f", "Dockerfile", "--platform", "freebsd/arm", "--cache-from", "from/image1", "--cache-from", "from/image2", "."},
   282  				Env:  []string{"DOCKER_BUILDKIT=1"},
   283  			}},
   284  		},
   285  	}
   286  
   287  	for _, test := range tests {
   288  		testutil.Run(t, test.description, func(t *testutil.T) {
   289  			t.Override(&docker.EvalBuildArgs, func(_ config.RunMode, _ string, _ string, args map[string]*string, _ map[string]*string) (map[string]*string, error) {
   290  				return args, nil
   291  			})
   292  			builder := NewBuilder(&mockBuilderContext{}, &latest.GoogleCloudBuild{
   293  				DockerImage: "docker/docker",
   294  			})
   295  			desc, err := builder.dockerBuildSpec(test.artifact, test.tag, test.platforms)
   296  
   297  			t.CheckErrorAndDeepEqual(test.shouldErr, err, test.expected, desc.Steps)
   298  		})
   299  	}
   300  }