github.com/GoogleContainerTools/skaffold@v1.39.18/pkg/skaffold/deploy/deploy_mux_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 deploy
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"fmt"
    23  	"io"
    24  	"io/ioutil"
    25  	"os"
    26  	"testing"
    27  
    28  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/access"
    29  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/debug"
    30  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/graph"
    31  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/log"
    32  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
    33  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/status"
    34  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/sync"
    35  	"github.com/GoogleContainerTools/skaffold/testutil"
    36  	testEvent "github.com/GoogleContainerTools/skaffold/testutil/event"
    37  )
    38  
    39  func NewMockDeployer() *MockDeployer { return &MockDeployer{labels: make(map[string]string)} }
    40  
    41  type MockDeployer struct {
    42  	labels          map[string]string
    43  	deployErr       error
    44  	dependencies    []string
    45  	dependenciesErr error
    46  	cleanupErr      error
    47  	renderResult    string
    48  	renderErr       error
    49  }
    50  
    51  func (m *MockDeployer) HasRunnableHooks() bool {
    52  	return true
    53  }
    54  
    55  func (m *MockDeployer) PreDeployHooks(context.Context, io.Writer) error {
    56  	return nil
    57  }
    58  
    59  func (m *MockDeployer) PostDeployHooks(context.Context, io.Writer) error {
    60  	return nil
    61  }
    62  
    63  func (m *MockDeployer) GetAccessor() access.Accessor {
    64  	return &access.NoopAccessor{}
    65  }
    66  
    67  func (m *MockDeployer) GetDebugger() debug.Debugger {
    68  	return &debug.NoopDebugger{}
    69  }
    70  
    71  func (m *MockDeployer) GetLogger() log.Logger {
    72  	return &log.NoopLogger{}
    73  }
    74  
    75  func (m *MockDeployer) GetStatusMonitor() status.Monitor {
    76  	return &status.NoopMonitor{}
    77  }
    78  
    79  func (m *MockDeployer) GetSyncer() sync.Syncer {
    80  	return &sync.NoopSyncer{}
    81  }
    82  
    83  func (m *MockDeployer) RegisterLocalImages(_ []graph.Artifact) {}
    84  
    85  func (m *MockDeployer) TrackBuildArtifacts(_ []graph.Artifact) {}
    86  
    87  func (m *MockDeployer) Dependencies() ([]string, error) {
    88  	return m.dependencies, m.dependenciesErr
    89  }
    90  
    91  func (m *MockDeployer) Cleanup(context.Context, io.Writer, bool) error {
    92  	return m.cleanupErr
    93  }
    94  
    95  func (m *MockDeployer) WithLabel(labels map[string]string) *MockDeployer {
    96  	m.labels = labels
    97  	return m
    98  }
    99  
   100  func (m *MockDeployer) WithDeployErr(err error) *MockDeployer {
   101  	m.deployErr = err
   102  	return m
   103  }
   104  
   105  func (m *MockDeployer) WithDependenciesErr(err error) *MockDeployer {
   106  	m.dependenciesErr = err
   107  	return m
   108  }
   109  
   110  func (m *MockDeployer) WithCleanupErr(err error) *MockDeployer {
   111  	m.cleanupErr = err
   112  	return m
   113  }
   114  
   115  func (m *MockDeployer) WithRenderErr(err error) *MockDeployer {
   116  	m.renderErr = err
   117  	return m
   118  }
   119  
   120  func (m *MockDeployer) Deploy(context.Context, io.Writer, []graph.Artifact) error {
   121  	return m.deployErr
   122  }
   123  
   124  func (m *MockDeployer) Render(_ context.Context, w io.Writer, _ []graph.Artifact, _ bool, _ string) error {
   125  	w.Write([]byte(m.renderResult))
   126  	return m.renderErr
   127  }
   128  
   129  func (m *MockDeployer) WithDependencies(dependencies []string) *MockDeployer {
   130  	m.dependencies = dependencies
   131  	return m
   132  }
   133  
   134  func (m *MockDeployer) WithRenderResult(renderResult string) *MockDeployer {
   135  	m.renderResult = renderResult
   136  	return m
   137  }
   138  
   139  func TestDeployerMux_Deploy(t *testing.T) {
   140  	tests := []struct {
   141  		name        string
   142  		namespaces1 []string
   143  		namespaces2 []string
   144  		err1        error
   145  		err2        error
   146  		expectedNs  []string
   147  		shouldErr   bool
   148  	}{
   149  		{
   150  			name:      "short-circuits when first call fails",
   151  			err1:      fmt.Errorf("failed in first"),
   152  			shouldErr: true,
   153  		},
   154  		{
   155  			name:      "when second call fails",
   156  			err2:      fmt.Errorf("failed in second"),
   157  			shouldErr: true,
   158  		},
   159  	}
   160  
   161  	for _, test := range tests {
   162  		t.Run(test.name, func(t *testing.T) {
   163  			testEvent.InitializeState([]latest.Pipeline{{
   164  				Deploy: latest.DeployConfig{},
   165  				Build: latest.BuildConfig{
   166  					BuildType: latest.BuildType{
   167  						LocalBuild: &latest.LocalBuild{},
   168  					},
   169  				}}})
   170  
   171  			deployerMux := NewDeployerMux([]Deployer{
   172  				NewMockDeployer().WithDeployErr(test.err1),
   173  				NewMockDeployer().WithDeployErr(test.err2),
   174  			}, false)
   175  
   176  			err := deployerMux.Deploy(context.Background(), nil, nil)
   177  
   178  			testutil.CheckError(t, test.shouldErr, err)
   179  		})
   180  	}
   181  }
   182  
   183  func TestDeployerMux_Dependencies(t *testing.T) {
   184  	tests := []struct {
   185  		name         string
   186  		deps1        []string
   187  		deps2        []string
   188  		err1         error
   189  		err2         error
   190  		expectedDeps []string
   191  		shouldErr    bool
   192  	}{
   193  		{
   194  			name:         "disjoint dependencies are combined",
   195  			deps1:        []string{"graph-a"},
   196  			deps2:        []string{"graph-b"},
   197  			expectedDeps: []string{"graph-a", "graph-b"},
   198  		},
   199  		{
   200  			name:         "repeated dependencies are not duplicated",
   201  			deps1:        []string{"graph-a", "graph-c"},
   202  			deps2:        []string{"graph-b", "graph-c"},
   203  			expectedDeps: []string{"graph-a", "graph-b", "graph-c"},
   204  		},
   205  		{
   206  			name:      "when first call fails",
   207  			deps1:     []string{"graph-a"},
   208  			err1:      fmt.Errorf("failed in first"),
   209  			deps2:     []string{"graph-b"},
   210  			shouldErr: true,
   211  		},
   212  		{
   213  			name:      "when second call fails",
   214  			deps1:     []string{"graph-a"},
   215  			deps2:     []string{"graph-b"},
   216  			err2:      fmt.Errorf("failed in second"),
   217  			shouldErr: true,
   218  		},
   219  	}
   220  
   221  	for _, test := range tests {
   222  		t.Run(test.name, func(t *testing.T) {
   223  			deployerMux := NewDeployerMux([]Deployer{
   224  				NewMockDeployer().WithDependencies(test.deps1).WithDependenciesErr(test.err1),
   225  				NewMockDeployer().WithDependencies(test.deps2).WithDependenciesErr(test.err2),
   226  			}, false)
   227  
   228  			dependencies, err := deployerMux.Dependencies()
   229  			testutil.CheckErrorAndDeepEqual(t, test.shouldErr, err, test.expectedDeps, dependencies)
   230  		})
   231  	}
   232  }
   233  
   234  func TestDeployerMux_Render(t *testing.T) {
   235  	tests := []struct {
   236  		name           string
   237  		render1        string
   238  		render2        string
   239  		err1           error
   240  		err2           error
   241  		expectedRender string
   242  		shouldErr      bool
   243  	}{
   244  		{
   245  			name:           "concatenates render results with separator",
   246  			render1:        "manifest-1",
   247  			render2:        "manifest-2",
   248  			expectedRender: "manifest-1\n---\nmanifest-2\n",
   249  		},
   250  		{
   251  			name:      "short-circuits when first call fails",
   252  			render1:   "manifest-1",
   253  			err1:      fmt.Errorf("failed in first"),
   254  			render2:   "manifest-2",
   255  			shouldErr: true,
   256  		},
   257  		{
   258  			name:      "short-circuits when second call fails",
   259  			render1:   "manifest-1",
   260  			render2:   "manifest-2",
   261  			err2:      fmt.Errorf("failed in first"),
   262  			shouldErr: true,
   263  		},
   264  	}
   265  
   266  	for _, test := range tests {
   267  		t.Run("output to writer "+test.name, func(t *testing.T) {
   268  			deployerMux := NewDeployerMux([]Deployer{
   269  				NewMockDeployer().WithRenderResult(test.render1).WithRenderErr(test.err1),
   270  				NewMockDeployer().WithRenderResult(test.render2).WithRenderErr(test.err2),
   271  			}, false)
   272  
   273  			buf := &bytes.Buffer{}
   274  			err := deployerMux.Render(context.Background(), buf, nil, true, "")
   275  			testutil.CheckErrorAndDeepEqual(t, test.shouldErr, err, test.expectedRender, buf.String())
   276  		})
   277  	}
   278  
   279  	t.Run("output to file", func(t *testing.T) {
   280  		// only check the good case here
   281  		test := tests[0]
   282  
   283  		tmpDir := testutil.NewTempDir(t)
   284  
   285  		deployerMux := NewDeployerMux([]Deployer{
   286  			NewMockDeployer().WithRenderResult(test.render1).WithRenderErr(test.err1),
   287  			NewMockDeployer().WithRenderResult(test.render2).WithRenderErr(test.err2),
   288  		}, false)
   289  
   290  		err := deployerMux.Render(context.Background(), nil, nil, true, tmpDir.Path("render"))
   291  		testutil.CheckError(t, false, err)
   292  
   293  		file, _ := os.Open(tmpDir.Path("render"))
   294  		content, _ := ioutil.ReadAll(file)
   295  		testutil.CheckErrorAndDeepEqual(t, test.shouldErr, err, test.expectedRender, string(content))
   296  	})
   297  }