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 }