github.com/GoogleContainerTools/skaffold@v1.39.18/pkg/skaffold/kubernetes/loader/load_test.go (about)

     1  /*
     2  Copyright 2021 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 loader
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"io/ioutil"
    23  	"testing"
    24  
    25  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/config"
    26  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/graph"
    27  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/kubectl"
    28  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/runner/runcontext"
    29  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
    30  	"github.com/GoogleContainerTools/skaffold/testutil"
    31  )
    32  
    33  type ImageLoadingTest = struct {
    34  	description   string
    35  	cluster       string
    36  	deployed      []graph.Artifact
    37  	commands      util.Command
    38  	shouldErr     bool
    39  	expectedError string
    40  }
    41  
    42  func TestLoadImagesInKindNodes(t *testing.T) {
    43  	tests := []ImageLoadingTest{
    44  		{
    45  			description: "load image",
    46  			cluster:     "kind",
    47  			deployed:    []graph.Artifact{{Tag: "tag1"}},
    48  			commands: testutil.
    49  				CmdRunOut("kubectl --context kubecontext --namespace namespace get nodes -ojsonpath='{@.items[*].status.images[*].names[*]}'", "").
    50  				AndRunOut("kind load docker-image --name kind tag1", "output: image loaded"),
    51  		},
    52  		{
    53  			description: "load missing image",
    54  			cluster:     "other-kind",
    55  			deployed:    []graph.Artifact{{Tag: "tag1"}, {Tag: "tag2"}},
    56  			commands: testutil.
    57  				CmdRunOut("kubectl --context kubecontext --namespace namespace get nodes -ojsonpath='{@.items[*].status.images[*].names[*]}'", "docker.io/library/tag1").
    58  				AndRunOut("kind load docker-image --name other-kind tag2", "output: image loaded"),
    59  		},
    60  		{
    61  			description: "no new images",
    62  			cluster:     "kind",
    63  			deployed:    []graph.Artifact{{Tag: "tag0"}, {Tag: "docker.io/library/tag1"}, {Tag: "docker.io/tag2"}, {Tag: "gcr.io/test/tag3"}, {Tag: "someregistry.com/tag4"}},
    64  			commands: testutil.
    65  				CmdRunOut("kubectl --context kubecontext --namespace namespace get nodes -ojsonpath='{@.items[*].status.images[*].names[*]}'", "docker.io/library/tag0 docker.io/library/tag1 docker.io/library/tag2 gcr.io/test/tag3 someregistry.com/tag4"),
    66  		},
    67  		{
    68  			description: "inspect error",
    69  			deployed:    []graph.Artifact{{Tag: "tag"}},
    70  			commands: testutil.
    71  				CmdRunOutErr("kubectl --context kubecontext --namespace namespace get nodes -ojsonpath='{@.items[*].status.images[*].names[*]}'", "", errors.New("BUG")),
    72  			shouldErr:     true,
    73  			expectedError: "unable to inspect",
    74  		},
    75  		{
    76  			description: "load error",
    77  			cluster:     "kind",
    78  			deployed:    []graph.Artifact{{Tag: "tag"}},
    79  			commands: testutil.
    80  				CmdRunOut("kubectl --context kubecontext --namespace namespace get nodes -ojsonpath='{@.items[*].status.images[*].names[*]}'", "").
    81  				AndRunOutErr("kind load docker-image --name kind tag", "output: error!", errors.New("BUG")),
    82  			shouldErr:     true,
    83  			expectedError: "output: error!",
    84  		},
    85  		{
    86  			description: "no artifact",
    87  			deployed:    []graph.Artifact{},
    88  		},
    89  	}
    90  
    91  	runImageLoadingTests(t, tests, func(i *ImageLoader, test ImageLoadingTest) error {
    92  		return i.loadImagesInKindNodes(context.Background(), ioutil.Discard, test.cluster, test.deployed)
    93  	})
    94  }
    95  
    96  func TestLoadImagesInK3dNodes(t *testing.T) {
    97  	tests := []ImageLoadingTest{
    98  		{
    99  			description: "load image",
   100  			cluster:     "k3d",
   101  			deployed:    []graph.Artifact{{Tag: "tag1"}},
   102  			commands: testutil.
   103  				CmdRunOut("kubectl --context kubecontext --namespace namespace get nodes -ojsonpath='{@.items[*].status.images[*].names[*]}'", "").
   104  				AndRunOut("k3d image import --cluster k3d tag1", "output: image loaded"),
   105  		},
   106  		{
   107  			description: "load missing image",
   108  			cluster:     "other-k3d",
   109  			deployed:    []graph.Artifact{{Tag: "tag1"}, {Tag: "tag2"}},
   110  			commands: testutil.
   111  				CmdRunOut("kubectl --context kubecontext --namespace namespace get nodes -ojsonpath='{@.items[*].status.images[*].names[*]}'", "docker.io/library/tag1").
   112  				AndRunOut("k3d image import --cluster other-k3d tag2", "output: image loaded"),
   113  		},
   114  		{
   115  			description: "no new images",
   116  			cluster:     "k3d",
   117  			deployed:    []graph.Artifact{{Tag: "tag0"}, {Tag: "docker.io/library/tag1"}, {Tag: "docker.io/tag2"}, {Tag: "gcr.io/test/tag3"}, {Tag: "someregistry.com/tag4"}},
   118  			commands: testutil.
   119  				CmdRunOut("kubectl --context kubecontext --namespace namespace get nodes -ojsonpath='{@.items[*].status.images[*].names[*]}'", "docker.io/library/tag0 docker.io/library/tag1 docker.io/library/tag2 gcr.io/test/tag3 someregistry.com/tag4"),
   120  		},
   121  		{
   122  			description: "inspect error",
   123  			deployed:    []graph.Artifact{{Tag: "tag"}},
   124  			commands: testutil.
   125  				CmdRunOutErr("kubectl --context kubecontext --namespace namespace get nodes -ojsonpath='{@.items[*].status.images[*].names[*]}'", "", errors.New("BUG")),
   126  			shouldErr:     true,
   127  			expectedError: "unable to inspect",
   128  		},
   129  		{
   130  			description: "load error",
   131  			cluster:     "k3d",
   132  			deployed:    []graph.Artifact{{Tag: "tag"}},
   133  			commands: testutil.
   134  				CmdRunOut("kubectl --context kubecontext --namespace namespace get nodes -ojsonpath='{@.items[*].status.images[*].names[*]}'", "").
   135  				AndRunOutErr("k3d image import --cluster k3d tag", "output: error!", errors.New("BUG")),
   136  			shouldErr:     true,
   137  			expectedError: "output: error!",
   138  		},
   139  		{
   140  			description: "no artifact",
   141  			deployed:    []graph.Artifact{},
   142  		},
   143  	}
   144  
   145  	runImageLoadingTests(t, tests, func(i *ImageLoader, test ImageLoadingTest) error {
   146  		return i.loadImagesInK3dNodes(context.Background(), ioutil.Discard, test.cluster, test.deployed)
   147  	})
   148  }
   149  
   150  func runImageLoadingTests(t *testing.T, tests []ImageLoadingTest, loadingFunc func(i *ImageLoader, test ImageLoadingTest) error) {
   151  	for _, test := range tests {
   152  		testutil.Run(t, test.description, func(t *testutil.T) {
   153  			t.Override(&util.DefaultExecCommand, test.commands)
   154  
   155  			runCtx := &runcontext.RunContext{
   156  				Opts: config.SkaffoldOptions{
   157  					Namespace: "namespace",
   158  				},
   159  				KubeContext: "kubecontext",
   160  			}
   161  
   162  			i := NewImageLoader(runCtx.KubeContext, kubectl.NewCLI(runCtx, ""))
   163  			err := loadingFunc(i, test)
   164  
   165  			if test.shouldErr {
   166  				t.CheckErrorContains(test.expectedError, err)
   167  			} else {
   168  				t.CheckNoError(err)
   169  			}
   170  		})
   171  	}
   172  }
   173  
   174  func TestImagesToLoad(t *testing.T) {
   175  	tests := []struct {
   176  		name           string
   177  		localImages    []graph.Artifact
   178  		deployerImages []graph.Artifact
   179  		builtImages    []graph.Artifact
   180  		expectedImages []graph.Artifact
   181  	}{
   182  		{
   183  			name:           "single image marked as local",
   184  			localImages:    []graph.Artifact{{ImageName: "image1", Tag: "foo"}},
   185  			deployerImages: []graph.Artifact{{ImageName: "image1", Tag: "foo"}},
   186  			builtImages:    []graph.Artifact{{ImageName: "image1", Tag: "foo"}},
   187  			expectedImages: []graph.Artifact{{ImageName: "image1", Tag: "foo"}},
   188  		},
   189  		{
   190  			name:           "single image, but not marked as local",
   191  			localImages:    []graph.Artifact{},
   192  			deployerImages: []graph.Artifact{{ImageName: "image1", Tag: "foo"}},
   193  			builtImages:    []graph.Artifact{{ImageName: "image1", Tag: "foo"}},
   194  			expectedImages: nil,
   195  		},
   196  		{
   197  			name:           "single image, marked as local but not found in deployer's manifests",
   198  			localImages:    []graph.Artifact{{ImageName: "image1", Tag: "foo"}},
   199  			deployerImages: []graph.Artifact{},
   200  			builtImages:    []graph.Artifact{{ImageName: "image1", Tag: "foo"}},
   201  			expectedImages: nil,
   202  		},
   203  		{
   204  			name:           "single image marked as local, with ko prefix and Go import path with uppercase characters",
   205  			localImages:    []graph.Artifact{{ImageName: "ko://example.com/Organization/Image1", Tag: "Foo"}},
   206  			deployerImages: []graph.Artifact{{ImageName: "example.com/organization/image1", Tag: "Foo"}},
   207  			builtImages:    []graph.Artifact{{ImageName: "ko://example.com/Organization/Image1", Tag: "Foo"}},
   208  			expectedImages: []graph.Artifact{{ImageName: "ko://example.com/Organization/Image1", Tag: "Foo"}},
   209  		},
   210  		{
   211  			name:           "two images marked as local",
   212  			localImages:    []graph.Artifact{{ImageName: "image1", Tag: "foo"}, {ImageName: "image2", Tag: "bar"}},
   213  			deployerImages: []graph.Artifact{{ImageName: "image1", Tag: "foo"}, {ImageName: "image2", Tag: "bar"}},
   214  			builtImages:    []graph.Artifact{{ImageName: "image1", Tag: "foo"}, {ImageName: "image2", Tag: "bar"}},
   215  			expectedImages: []graph.Artifact{{ImageName: "image1", Tag: "foo"}, {ImageName: "image2", Tag: "bar"}},
   216  		},
   217  		{
   218  			name:           "two images, one marked as local and one not",
   219  			localImages:    []graph.Artifact{{ImageName: "image2", Tag: "bar"}},
   220  			deployerImages: []graph.Artifact{{ImageName: "image1", Tag: "foo"}, {ImageName: "image2", Tag: "bar"}},
   221  			builtImages:    []graph.Artifact{{ImageName: "image1", Tag: "foo"}, {ImageName: "image2", Tag: "bar"}},
   222  			expectedImages: []graph.Artifact{{ImageName: "image2", Tag: "bar"}},
   223  		},
   224  		{
   225  			name:           "two images, marked as local but only one found from the deployer's manifests",
   226  			localImages:    []graph.Artifact{{ImageName: "image1", Tag: "foo"}, {ImageName: "image2", Tag: "bar"}},
   227  			deployerImages: []graph.Artifact{{ImageName: "image2", Tag: "bar"}},
   228  			builtImages:    []graph.Artifact{{ImageName: "image1", Tag: "foo"}, {ImageName: "image2", Tag: "bar"}},
   229  			expectedImages: []graph.Artifact{{ImageName: "image2", Tag: "bar"}},
   230  		},
   231  	}
   232  
   233  	for _, test := range tests {
   234  		testutil.Run(t, test.name, func(t *testutil.T) {
   235  			t.CheckDeepEqual(test.expectedImages, imagesToLoad(test.localImages, test.deployerImages, test.builtImages))
   236  		})
   237  	}
   238  }