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 }