github.com/GoogleContainerTools/skaffold@v1.39.18/pkg/skaffold/test/test_factory_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 test 18 19 import ( 20 "bytes" 21 "context" 22 "errors" 23 "io/ioutil" 24 "os" 25 "path/filepath" 26 "testing" 27 28 "github.com/docker/docker/client" 29 30 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/config" 31 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker" 32 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/graph" 33 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/runner/runcontext" 34 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest" 35 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/util" 36 "github.com/GoogleContainerTools/skaffold/testutil" 37 testEvent "github.com/GoogleContainerTools/skaffold/testutil/event" 38 ) 39 40 func TestNoTestDependencies(t *testing.T) { 41 testutil.Run(t, "", func(t *testutil.T) { 42 t.Override(&docker.NewAPIClient, func(context.Context, docker.Config) (docker.LocalDaemon, error) { return nil, nil }) 43 44 cfg := &mockConfig{} 45 tester, err := NewTester(context.Background(), cfg, func(imageName string) (bool, error) { return true, nil }) 46 t.CheckNoError(err) 47 deps, err := tester.TestDependencies(context.Background(), &latest.Artifact{ImageName: "foo"}) 48 t.CheckNoError(err) 49 t.CheckEmpty(deps) 50 }) 51 } 52 53 func TestTestDependencies(t *testing.T) { 54 testutil.Run(t, "", func(t *testutil.T) { 55 tmpDir := t.NewTempDir().Touch("tests/test1.yaml", "tests/test2.yaml", "test3.yaml") 56 57 cfg := &mockConfig{ 58 tests: []*latest.TestCase{ 59 {StructureTests: []string{"./tests/*"}, Workspace: tmpDir.Root(), ImageName: "foo"}, 60 {}, 61 {StructureTests: []string{"test3.yaml"}, Workspace: tmpDir.Root(), ImageName: "foo"}, 62 }, 63 } 64 65 tester, err := NewTester(context.Background(), cfg, func(imageName string) (bool, error) { return true, nil }) 66 t.CheckNoError(err) 67 deps, err := tester.TestDependencies(context.Background(), &latest.Artifact{ImageName: "foo"}) 68 69 expectedDeps := tmpDir.Paths("tests/test1.yaml", "tests/test2.yaml", "test3.yaml") 70 t.CheckNoError(err) 71 t.CheckDeepEqual(expectedDeps, deps) 72 }) 73 } 74 75 func TestWrongPattern(t *testing.T) { 76 testutil.Run(t, "", func(t *testutil.T) { 77 cfg := &mockConfig{ 78 tests: []*latest.TestCase{{ 79 ImageName: "image", 80 StructureTests: []string{"[]"}, 81 }}, 82 } 83 84 tester, err := NewTester(context.Background(), cfg, func(imageName string) (bool, error) { return true, nil }) 85 t.CheckNoError(err) 86 87 _, err = tester.TestDependencies(context.Background(), &latest.Artifact{ImageName: "image"}) 88 t.CheckError(true, err) 89 testEvent.InitializeState([]latest.Pipeline{{}}) 90 91 err = tester.Test(context.Background(), ioutil.Discard, []graph.Artifact{{ 92 ImageName: "image", 93 Tag: "image:tag", 94 }}) 95 t.CheckError(true, err) 96 }) 97 } 98 99 func TestNoTest(t *testing.T) { 100 testutil.Run(t, "", func(t *testutil.T) { 101 cfg := &mockConfig{} 102 103 tester, err := NewTester(context.Background(), cfg, func(imageName string) (bool, error) { return true, nil }) 104 t.CheckNoError(err) 105 106 err = tester.Test(context.Background(), ioutil.Discard, nil) 107 108 t.CheckNoError(err) 109 }) 110 } 111 112 func TestTestSuccess(t *testing.T) { 113 testutil.Run(t, "", func(t *testutil.T) { 114 tmpDir := t.NewTempDir().Touch("tests/test1.yaml", "tests/test2.yaml", "test3.yaml") 115 116 t.Override(&util.DefaultExecCommand, testutil. 117 CmdRun("container-structure-test test -v warn --image image:tag --config "+tmpDir.Path("tests/test1.yaml")+" --config "+tmpDir.Path("tests/test2.yaml")). 118 AndRun("container-structure-test test -v warn --image image:tag --config "+tmpDir.Path("test3.yaml"))) 119 120 cfg := &mockConfig{ 121 tests: []*latest.TestCase{ 122 { 123 ImageName: "image", 124 Workspace: tmpDir.Root(), 125 StructureTests: []string{"./tests/*"}, 126 }, 127 {}, 128 { 129 ImageName: "image", 130 Workspace: tmpDir.Root(), 131 StructureTests: []string{"test3.yaml"}, 132 }, 133 { 134 // This is image is not built so it won't be tested. 135 ImageName: "not-built", 136 StructureTests: []string{"./tests/*"}, 137 }, 138 }, 139 } 140 141 imagesAreLocal := true 142 tester, err := NewTester(context.Background(), cfg, func(imageName string) (bool, error) { return imagesAreLocal, nil }) 143 t.CheckNoError(err) 144 err = tester.Test(context.Background(), ioutil.Discard, []graph.Artifact{{ 145 ImageName: "image", 146 Tag: "image:tag", 147 }}) 148 t.CheckNoError(err) 149 }) 150 } 151 152 func TestTestSuccessRemoteImage(t *testing.T) { 153 testutil.Run(t, "", func(t *testutil.T) { 154 t.NewTempDir().Touch("test.yaml").Chdir() 155 t.Override(&util.DefaultExecCommand, testutil.CmdRun("container-structure-test test -v warn --image image:tag --config test.yaml")) 156 t.Override(&docker.NewAPIClient, func(context.Context, docker.Config) (docker.LocalDaemon, error) { 157 return fakeLocalDaemon(&testutil.FakeAPIClient{}), nil 158 }) 159 160 cfg := &mockConfig{ 161 tests: []*latest.TestCase{{ 162 ImageName: "image", 163 StructureTests: []string{"test.yaml"}, 164 }}, 165 } 166 167 imagesAreLocal := false 168 tester, err := NewTester(context.Background(), cfg, func(imageName string) (bool, error) { return imagesAreLocal, nil }) 169 t.CheckNoError(err) 170 171 err = tester.Test(context.Background(), ioutil.Discard, []graph.Artifact{{ 172 ImageName: "image", 173 Tag: "image:tag", 174 }}) 175 176 t.CheckNoError(err) 177 }) 178 } 179 180 func TestTestFailureRemoteImage(t *testing.T) { 181 testutil.Run(t, "", func(t *testutil.T) { 182 t.NewTempDir().Touch("test.yaml").Chdir() 183 t.Override(&util.DefaultExecCommand, testutil.CmdRun("container-structure-test test -v warn --image image:tag --config test.yaml")) 184 t.Override(&docker.NewAPIClient, func(context.Context, docker.Config) (docker.LocalDaemon, error) { 185 return fakeLocalDaemon(&testutil.FakeAPIClient{ErrImagePull: true}), nil 186 }) 187 188 cfg := &mockConfig{ 189 tests: []*latest.TestCase{{ 190 ImageName: "image", 191 StructureTests: []string{"test.yaml"}, 192 }}, 193 } 194 195 imagesAreLocal := false 196 tester, err := NewTester(context.Background(), cfg, func(imageName string) (bool, error) { return imagesAreLocal, nil }) 197 t.CheckNoError(err) 198 199 err = tester.Test(context.Background(), ioutil.Discard, []graph.Artifact{{ 200 ImageName: "image", 201 Tag: "image:tag", 202 }}) 203 204 t.CheckErrorContains(`unable to docker pull image image:tag`, err) 205 }) 206 } 207 208 func TestTestFailure(t *testing.T) { 209 testutil.Run(t, "", func(t *testutil.T) { 210 t.NewTempDir().Touch("test.yaml").Chdir() 211 212 t.Override(&util.DefaultExecCommand, testutil.CmdRunErr( 213 "container-structure-test test -v warn --image broken-image:tag --config test.yaml", 214 errors.New("FAIL"), 215 )) 216 217 cfg := &mockConfig{ 218 tests: []*latest.TestCase{ 219 { 220 ImageName: "broken-image", 221 StructureTests: []string{"test.yaml"}, 222 }, 223 }, 224 } 225 226 tester, err := NewTester(context.Background(), cfg, func(imageName string) (bool, error) { return true, nil }) 227 t.CheckNoError(err) 228 229 err = tester.Test(context.Background(), ioutil.Discard, []graph.Artifact{{ 230 ImageName: "broken-image", 231 Tag: "broken-image:tag", 232 }}) 233 t.CheckError(true, err) 234 }) 235 } 236 237 func TestTestMuted(t *testing.T) { 238 testutil.Run(t, "", func(t *testutil.T) { 239 tmpDir := t.NewTempDir().Touch("test.yaml") 240 t.Override(&util.DefaultExecCommand, testutil.CmdRun("container-structure-test test -v warn --image image:tag --config "+tmpDir.Path("test.yaml"))) 241 242 cfg := &mockConfig{ 243 tests: []*latest.TestCase{{ 244 ImageName: "image", 245 Workspace: tmpDir.Root(), 246 StructureTests: []string{"test.yaml"}, 247 }}, 248 muted: config.Muted{ 249 Phases: []string{"test"}, 250 }, 251 } 252 253 var buf bytes.Buffer 254 tester, err := NewTester(context.Background(), cfg, func(imageName string) (bool, error) { return true, nil }) 255 t.CheckNoError(err) 256 257 err = tester.Test(context.Background(), &buf, []graph.Artifact{{ 258 ImageName: "image", 259 Tag: "image:tag", 260 }}) 261 262 t.CheckNoError(err) 263 t.CheckContains("- writing logs to "+filepath.Join(os.TempDir(), "skaffold", "test.log"), buf.String()) 264 }) 265 } 266 267 func fakeLocalDaemon(api client.CommonAPIClient) docker.LocalDaemon { 268 return docker.NewLocalDaemon(api, nil, false, nil) 269 } 270 271 type mockConfig struct { 272 runcontext.RunContext // Embedded to provide the default values. 273 tests []*latest.TestCase 274 muted config.Muted 275 } 276 277 func (c *mockConfig) Muted() config.Muted { return c.muted } 278 279 func (c *mockConfig) TestCases() []*latest.TestCase { return c.tests }