github.com/GoogleContainerTools/skaffold/v2@v2.13.2/integration/verify_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 integration 18 19 import ( 20 "os" 21 "path/filepath" 22 "strings" 23 "testing" 24 25 "github.com/google/uuid" 26 27 "github.com/GoogleContainerTools/skaffold/v2/integration/skaffold" 28 "github.com/GoogleContainerTools/skaffold/v2/testutil" 29 ) 30 31 func TestLocalVerifyPassingTestsWithEnvVar(t *testing.T) { 32 MarkIntegrationTest(t, CanRunWithoutGcp) 33 tmp := t.TempDir() 34 logFile := filepath.Join(tmp, uuid.New().String()+"logs.json") 35 36 rpcPort := randomPort() 37 // `--default-repo=` is used to cancel the default repo that is set by default. 38 out, err := skaffold.Verify("--default-repo=", "--rpc-port", rpcPort, 39 "--event-log-file", logFile, "--env-file", "verify.env").InDir("testdata/verify-succeed").RunWithCombinedOutput(t) 40 logs := string(out) 41 42 testutil.CheckError(t, false, err) 43 testutil.CheckContains(t, "Hello from Docker!", logs) 44 testutil.CheckContains(t, "foo-var", logs) 45 testutil.CheckContains(t, "alpine-1", logs) 46 testutil.CheckContains(t, "alpine-2", logs) 47 48 // verify logs are in the event output as well 49 b, err := os.ReadFile(logFile + ".v2") 50 if err != nil { 51 t.Fatalf("error reading %s", logFile+".v2") 52 } 53 v2EventLogs := string(b) 54 testutil.CheckContains(t, "Hello from Docker!", v2EventLogs) 55 testutil.CheckContains(t, "foo-var", v2EventLogs) 56 57 // TODO(aaron-prindle) verify that SUCCEEDED event is found where expected 58 } 59 60 func TestVerifyWithNotCreatedNetwork(t *testing.T) { 61 MarkIntegrationTest(t, CanRunWithoutGcp) 62 // `--default-repo=` is used to cancel the default repo that is set by default. 63 logs, err := skaffold.Verify("--default-repo=", "--env-file", "verify.env", "--docker-network", "not-created-network").InDir("testdata/verify-succeed").RunWithCombinedOutput(t) 64 testutil.CheckError(t, true, err) 65 testutil.CheckContains(t, "network not-created-network not found", string(logs)) 66 } 67 68 func TestLocalVerifyOneTestFailsWithEnvVar(t *testing.T) { 69 MarkIntegrationTest(t, CanRunWithoutGcp) 70 tmp := t.TempDir() 71 logFile := filepath.Join(tmp, uuid.New().String()+"logs.json") 72 73 rpcPort := randomPort() 74 // `--default-repo=` is used to cancel the default repo that is set by default. 75 out, err := skaffold.Verify("--default-repo=", "--rpc-port", rpcPort, 76 "--event-log-file", logFile, "--env-file", "verify.env").InDir("testdata/verify-fail").RunWithCombinedOutput(t) 77 logs := string(out) 78 79 testutil.CheckError(t, true, err) 80 testutil.CheckContains(t, "Hello from Docker!", logs) 81 testutil.CheckContains(t, "foo-var", logs) 82 83 // verify logs are in the event output as well 84 b, err := os.ReadFile(logFile + ".v2") 85 if err != nil { 86 t.Fatalf("error reading %s", logFile+".v2") 87 } 88 v2EventLogs := string(b) 89 testutil.CheckContains(t, "Hello from Docker!", v2EventLogs) 90 testutil.CheckContains(t, "foo-var", v2EventLogs) 91 92 // TODO(aaron-prindle) verify that FAILED event is found where expected 93 } 94 95 func TestVerifyNoTestsFails(t *testing.T) { 96 MarkIntegrationTest(t, CanRunWithoutGcp) 97 // `--default-repo=` is used to cancel the default repo that is set by default. 98 out, err := skaffold.Verify("--default-repo=").InDir("testdata/verify-no-tests").RunWithCombinedOutput(t) 99 logs := string(out) 100 101 testutil.CheckError(t, true, err) 102 testutil.CheckContains(t, "verify command expects non-zero number of test cases", logs) 103 } 104 105 func TestKubernetesJobVerifyPassingTestsWithEnvVar(t *testing.T) { 106 MarkIntegrationTest(t, CanRunWithoutGcp) 107 tmp := t.TempDir() 108 logFile := filepath.Join(tmp, uuid.New().String()+"logs.json") 109 110 rpcPort := randomPort() 111 // `--default-repo=` is used to cancel the default repo that is set by default. 112 ns, _ := SetupNamespace(t) 113 out, err := skaffold.Verify("--default-repo=", "--rpc-port", rpcPort, 114 "--event-log-file", logFile, "--env-file", "verify.env").InNs(ns.Name).InDir("testdata/verify-succeed-k8s").RunWithCombinedOutput(t) 115 logs := string(out) 116 117 testutil.CheckError(t, false, err) 118 testutil.CheckContains(t, "Hello from Docker!", logs) 119 testutil.CheckContains(t, "foo-var", logs) 120 testutil.CheckContains(t, "verify-succeed-k8s-1", logs) 121 testutil.CheckContains(t, "alpine-2", logs) 122 123 // verify logs are in the event output as well 124 b, err := os.ReadFile(logFile + ".v2") 125 if err != nil { 126 t.Fatalf("error reading %s", logFile+".v2") 127 } 128 v2EventLogs := string(b) 129 testutil.CheckContains(t, "Hello from Docker!", v2EventLogs) 130 testutil.CheckContains(t, "foo-var", v2EventLogs) 131 132 // TODO(aaron-prindle) verify that SUCCEEDED event is found where expected 133 } 134 135 func TestKubernetesJobVerifyEnvVarFromJobManifest(t *testing.T) { 136 MarkIntegrationTest(t, CanRunWithoutGcp) 137 tmp := t.TempDir() 138 logFile := filepath.Join(tmp, uuid.New().String()+"logs.json") 139 140 rpcPort := randomPort() 141 // `--default-repo=` is used to cancel the default repo that is set by default. 142 out, err := skaffold.Verify("--default-repo=", "--rpc-port", rpcPort, 143 "--event-log-file", logFile, "-p", "with-job-manifest").InDir("testdata/verify-succeed-k8s").RunWithCombinedOutput(t) 144 logs := string(out) 145 146 testutil.CheckError(t, false, err) 147 testutil.CheckContains(t, "ZZZ with-job-manifest", logs) 148 } 149 150 func TestKubernetesJobVerifyOneTestFailsWithEnvVar(t *testing.T) { 151 MarkIntegrationTest(t, CanRunWithoutGcp) 152 tmp := t.TempDir() 153 logFile := filepath.Join(tmp, uuid.New().String()+"logs.json") 154 155 rpcPort := randomPort() 156 // `--default-repo=` is used to cancel the default repo that is set by default. 157 ns, _ := SetupNamespace(t) 158 out, err := skaffold.Verify("--default-repo=", "--rpc-port", rpcPort, 159 "--event-log-file", logFile, "--env-file", "verify.env").InNs(ns.Name).InDir("testdata/verify-fail-k8s").RunWithCombinedOutput(t) 160 logs := string(out) 161 162 testutil.CheckError(t, true, err) 163 testutil.CheckContains(t, "Hello from Docker!", logs) 164 testutil.CheckContains(t, "foo-var", logs) 165 166 // verify logs are in the event output as well 167 b, err := os.ReadFile(logFile + ".v2") 168 if err != nil { 169 t.Fatalf("error reading %s", logFile+".v2") 170 } 171 v2EventLogs := string(b) 172 testutil.CheckContains(t, "Hello from Docker!", v2EventLogs) 173 testutil.CheckContains(t, "foo-var", v2EventLogs) 174 175 // TODO(aaron-prindle) verify that FAILED event is found where expected 176 } 177 178 func TestNoDuplicateLogsLocal(t *testing.T) { 179 tests := []struct { 180 description string 181 dir string 182 profile string 183 shouldErr bool 184 expectedUniqueLogs []string 185 }{ 186 { 187 description: "no duplicated logs in docker actions, success execution", 188 dir: "testdata/verify-succeed", 189 profile: "no-duplicated-logs", 190 expectedUniqueLogs: []string{ 191 "[alpine-1] alpine-1", 192 "[alpine-1] bye alpine-1", 193 }, 194 }, 195 { 196 description: "no duplicated logs in docker actions, fail execution", 197 dir: "testdata/verify-fail", 198 profile: "no-duplicated-logs", 199 shouldErr: true, 200 expectedUniqueLogs: []string{ 201 "[alpine-1] alpine-1", 202 "[alpine-1] bye alpine-1", 203 "[alpine-2] alpine-2", 204 "[alpine-2] bye alpine-2", 205 }, 206 }, 207 } 208 209 for _, test := range tests { 210 testutil.Run(t, test.description, func(t *testutil.T) { 211 MarkIntegrationTest(t.T, CanRunWithoutGcp) 212 213 args := []string{"-p", test.profile} 214 out, err := skaffold.Verify(args...).InDir(test.dir).RunWithCombinedOutput(t.T) 215 216 t.CheckError(test.shouldErr, err) 217 218 logs := string(out) 219 checkUniqueLogs(t, logs, test.expectedUniqueLogs) 220 }) 221 } 222 } 223 224 func TestNoDuplicateLogsK8SJobs(t *testing.T) { 225 tests := []struct { 226 description string 227 dir string 228 profile string 229 shouldErr bool 230 expectedUniqueLogs []string 231 }{ 232 { 233 description: "no duplicated logs in k8s actions, success execution", 234 dir: "testdata/verify-succeed-k8s", 235 profile: "no-duplicated-logs", 236 expectedUniqueLogs: []string{ 237 "[no-duplicated-logs-1] alpine-1", 238 "[no-duplicated-logs-1] bye alpine-1", 239 }, 240 }, 241 { 242 description: "no duplicated logs in k8s actions, fail execution", 243 dir: "testdata/verify-fail-k8s", 244 profile: "no-duplicated-logs", 245 shouldErr: true, 246 expectedUniqueLogs: []string{ 247 "[alpine-1] alpine-1", 248 "[alpine-1] bye alpine-1", 249 "[alpine-2] alpine-2", 250 "[alpine-2] bye alpine-2", 251 }, 252 }, 253 } 254 255 for _, test := range tests { 256 testutil.Run(t, test.description, func(t *testutil.T) { 257 MarkIntegrationTest(t.T, CanRunWithoutGcp) 258 259 args := []string{"-p", test.profile} 260 ns, _ := SetupNamespace(t.T) 261 out, err := skaffold.Verify(args...).InNs(ns.Name).InDir(test.dir).RunWithCombinedOutput(t.T) 262 263 t.CheckError(test.shouldErr, err) 264 265 logs := string(out) 266 checkUniqueLogs(t, logs, test.expectedUniqueLogs) 267 }) 268 } 269 } 270 271 func TestTimeoutK8s(t *testing.T) { 272 tests := []struct { 273 description string 274 dir string 275 profile string 276 shouldErr bool 277 expectedLogs []string 278 notExpectedLogs []string 279 }{ 280 { 281 description: "K8s - One test fail due to timeout", 282 dir: "testdata/verify-fail-k8s", 283 profile: "fail-timeout", 284 shouldErr: true, 285 expectedLogs: []string{ 286 `1 error(s) occurred:`, 287 `* "alpine-3" running k8s job timed out after : 5s`, 288 }, 289 notExpectedLogs: []string{ 290 `[alpine-3] bye alpine-3`, 291 }, 292 }, 293 { 294 description: "K8s - Two tests with different timeouts", 295 dir: "testdata/verify-fail-k8s", 296 profile: "fail-two-test-timeout", 297 shouldErr: true, 298 expectedLogs: []string{ 299 `[alpine-4] alpine-4`, 300 `[alpine-5] alpine-5`, 301 `* "alpine-4" running k8s job timed out after : 6s`, 302 `* "alpine-5" running k8s job timed out after : 5s`, 303 }, 304 notExpectedLogs: []string{ 305 `[alpine-4] bye alpine-4`, 306 `[alpine-5] bye alpine-5`, 307 }, 308 }, 309 { 310 description: "K8s - Two tests, one fail other succeed", 311 dir: "testdata/verify-fail-k8s", 312 profile: "fail-only-one-test-timeout", 313 shouldErr: true, 314 expectedLogs: []string{ 315 `[alpine-6] alpine-6`, 316 `[alpine-7] alpine-7`, 317 `[alpine-7] bye alpine-7`, 318 `* "alpine-6" running k8s job timed out after : 6s`, 319 }, 320 notExpectedLogs: []string{ 321 `[alpine-6] bye alpine-6`, 322 }, 323 }, 324 { 325 description: "K8s - Two tests with timeouts, all succeed", 326 dir: "testdata/verify-succeed-k8s", 327 profile: "succeed-with-timeout", 328 expectedLogs: []string{ 329 `[alpine-8] alpine-8`, 330 `[alpine-8] bye alpine-8`, 331 `[alpine-9] alpine-9`, 332 `[alpine-9] bye alpine-9`, 333 }, 334 notExpectedLogs: []string{ 335 `* "alpine-8" running k8s job timed out after : 20s`, 336 `* "alpine-9" running k8s job timed out after : 25s`, 337 }, 338 }, 339 { 340 description: "K8s - Two tests, one with timeout, all succeed", 341 dir: "testdata/verify-succeed-k8s", 342 profile: "succeed-all-one-with-timeout", 343 expectedLogs: []string{ 344 `[alpine-10] alpine-10`, 345 `[alpine-10] bye alpine-10`, 346 `[alpine-11] alpine-11`, 347 `[alpine-11] bye alpine-11`, 348 }, 349 notExpectedLogs: []string{ 350 `* "alpine-11" running k8s job timed out after : 25s`, 351 }, 352 }, 353 } 354 355 for _, test := range tests { 356 testutil.Run(t, test.description, func(t *testutil.T) { 357 MarkIntegrationTest(t.T, CanRunWithoutGcp) 358 359 args := []string{"-p", test.profile} 360 ns, _ := SetupNamespace(t.T) 361 out, err := skaffold.Verify(args...).InNs(ns.Name).InDir(test.dir).RunWithCombinedOutput(t.T) 362 logs := string(out) 363 364 t.CheckError(test.shouldErr, err) 365 366 for _, el := range test.expectedLogs { 367 t.CheckContains(el, logs) 368 } 369 370 for _, nel := range test.notExpectedLogs { 371 testutil.CheckNotContains(t.T, nel, logs) 372 } 373 }) 374 } 375 } 376 377 func TestTimeoutDocker(t *testing.T) { 378 tests := []struct { 379 description string 380 dir string 381 profile string 382 shouldErr bool 383 expectedLogs []string 384 notExpectedLogs []string 385 }{ 386 { 387 description: "Docker - One test fail due to timeout", 388 dir: "testdata/verify-fail", 389 profile: "fail-timeout", 390 shouldErr: true, 391 expectedLogs: []string{ 392 `1 error(s) occurred:`, 393 `* verify test failed: "alpine-1" running container image "alpine:3.15.4" timed out after : 5s`, 394 }, 395 notExpectedLogs: []string{ 396 `[alpine-1] bye alpine-1`, 397 }, 398 }, 399 { 400 description: "Docker - Two tests with different timeouts", 401 dir: "testdata/verify-fail", 402 profile: "fail-two-test-timeout", 403 shouldErr: true, 404 expectedLogs: []string{ 405 `[alpine-2] alpine-2`, 406 `[alpine-1] alpine-1`, 407 `* verify test failed: "alpine-1" running container image "alpine:3.15.4" timed out after : 6s`, 408 `* verify test failed: "alpine-2" running container image "alpine:3.15.4" timed out after : 5s`, 409 }, 410 notExpectedLogs: []string{ 411 `[alpine-1] bye alpine-1`, 412 `[alpine-2] bye alpine-2`, 413 }, 414 }, 415 { 416 description: "Docker - Two tests, one fail other succeed", 417 dir: "testdata/verify-fail", 418 profile: "fail-only-one-test-timeout", 419 shouldErr: true, 420 expectedLogs: []string{ 421 `[alpine-1] alpine-1`, 422 `[alpine-2] alpine-2`, 423 `[alpine-2] bye alpine-2`, 424 `* verify test failed: "alpine-1" running container image "alpine:3.15.4" timed out after : 6s`, 425 }, 426 notExpectedLogs: []string{ 427 `[alpine-1] bye alpine-1`, 428 }, 429 }, 430 { 431 description: "Docker - Two tests with timeouts, all succeed", 432 dir: "testdata/verify-succeed", 433 profile: "succeed-with-timeout", 434 expectedLogs: []string{ 435 `[alpine-1] alpine-1`, 436 `[alpine-1] bye alpine-1`, 437 `[alpine-2] alpine-2`, 438 `[alpine-2] bye alpine-2`, 439 }, 440 notExpectedLogs: []string{ 441 `* verify test failed: "alpine-1" running container image "alpine:3.15.4" timed out after : 20s`, 442 `* verify test failed: "alpine-2" running container image "alpine:3.15.4" timed out after : 25s`, 443 }, 444 }, 445 { 446 description: "Docker - Two tests, one with timeout, all succeed", 447 dir: "testdata/verify-succeed", 448 profile: "succeed-all-one-with-timeout", 449 expectedLogs: []string{ 450 `[alpine-1] alpine-1`, 451 `[alpine-1] bye alpine-1`, 452 `[alpine-2] alpine-2`, 453 `[alpine-2] bye alpine-2`, 454 }, 455 notExpectedLogs: []string{ 456 `* verify test failed: "alpine-2" running container image "alpine:3.15.4" timed out after : 25s`, 457 }, 458 }, 459 } 460 461 for _, test := range tests { 462 testutil.Run(t, test.description, func(t *testutil.T) { 463 MarkIntegrationTest(t.T, CanRunWithoutGcp) 464 465 args := []string{"-p", test.profile} 466 out, err := skaffold.Verify(args...).InDir(test.dir).RunWithCombinedOutput(t.T) 467 logs := string(out) 468 469 t.CheckError(test.shouldErr, err) 470 471 for _, el := range test.expectedLogs { 472 t.CheckContains(el, logs) 473 } 474 475 for _, nel := range test.notExpectedLogs { 476 testutil.CheckNotContains(t.T, nel, logs) 477 } 478 }) 479 } 480 } 481 482 func checkUniqueLogs(t *testutil.T, logs string, expectedUniqueLogs []string) { 483 for _, uniqueLog := range expectedUniqueLogs { 484 timesFound := strings.Count(logs, uniqueLog) 485 if timesFound != 1 { 486 t.Fatalf(`Log message "%v" found %v times, expected exactly 1 time`, uniqueLog, timesFound) 487 } 488 } 489 } 490 491 func TestVerify_WithLocalArtifact(t *testing.T) { 492 tests := []struct { 493 description string 494 dir string 495 profile string 496 shouldErr bool 497 shouldBuild bool 498 expectedMsgs []string 499 notExpectedMsgs []string 500 }{ 501 { 502 description: "build and verify", 503 dir: "testdata/verify-succeed", 504 profile: "local-built-artifact", 505 shouldBuild: true, 506 expectedMsgs: []string{ 507 "Tags used in verification:", 508 "- localtask ->", 509 "[localtask] Hello world ! 0", 510 "[alpine-1] alpine-1", 511 }, 512 notExpectedMsgs: []string{ 513 "- img-not-used-in-verify ->", 514 }, 515 }, 516 { 517 description: "fail due not found image", 518 dir: "testdata/verify-succeed-k8s", 519 profile: "local-built-artifact", 520 shouldErr: true, 521 expectedMsgs: []string{ 522 "1 error(s) occurred", 523 "creating container for localtask: ErrImagePull", 524 }, 525 }, 526 } 527 528 for _, test := range tests { 529 testutil.Run(t, test.description, func(t *testutil.T) { 530 MarkIntegrationTest(t.T, CanRunWithoutGcp) 531 532 ns, _ := SetupNamespace(t.T) 533 534 args := []string{"-p", test.profile} 535 536 if test.shouldBuild { 537 tmpfile := testutil.TempFile(t.T, "", []byte{}) 538 skaffold.Build(append(args, "--file-output", tmpfile)...).InDir(test.dir).RunOrFail(t.T) 539 args = append(args, "--build-artifacts", tmpfile) 540 } 541 542 out, err := skaffold.Verify(args...).InDir(test.dir).InNs(ns.Name).RunWithCombinedOutput(t.T) 543 logs := string(out) 544 545 t.CheckError(test.shouldErr, err) 546 547 for _, expectedMsg := range test.expectedMsgs { 548 t.CheckContains(expectedMsg, logs) 549 } 550 551 for _, notExpectedMsg := range test.notExpectedMsgs { 552 testutil.CheckNotContains(t.T, notExpectedMsg, logs) 553 } 554 }) 555 } 556 }