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 }