github.com/GoogleContainerTools/skaffold/v2@v2.13.2/integration/exec_k8s_actions_test.go (about) 1 /* 2 Copyright 2023 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 "testing" 23 24 "github.com/google/uuid" 25 26 "github.com/GoogleContainerTools/skaffold/v2/integration/skaffold" 27 "github.com/GoogleContainerTools/skaffold/v2/testutil" 28 ) 29 30 func TestExec_K8SActions(t *testing.T) { 31 tests := []struct { 32 description string 33 action string 34 shouldErr bool 35 envFile string 36 expectedMsgs []string 37 notExpectedLogs []string 38 }{ 39 { 40 description: "fail due to action timeout", 41 action: "action-fail-timeout", 42 shouldErr: true, 43 expectedMsgs: []string{"context deadline exceeded"}, 44 notExpectedLogs: []string{"[task1] bye-from-task1"}, 45 }, 46 { 47 description: "fail with fail fast", 48 action: "action-fail-fast", 49 shouldErr: true, 50 expectedMsgs: []string{`error in task4 job execution, job failed`}, 51 notExpectedLogs: []string{"[task3] bye-from-task3"}, 52 }, 53 { 54 description: "fail with fail safe", 55 action: "action-fail-safe-logs", 56 shouldErr: true, 57 expectedMsgs: []string{ 58 "[task5l] hello-from-task5l", 59 "[task5l] bye-from-task5l", 60 `* error in task6l job execution, job failed`, 61 }, 62 }, 63 { 64 description: "action succeeded", 65 action: "action-succeeded-logs", 66 envFile: "exec.env", 67 expectedMsgs: []string{ 68 "[task7l] hello-from-env-file", 69 "[task7l] bye-from-env-file", 70 }, 71 }, 72 } 73 74 for _, test := range tests { 75 testutil.Run(t, test.description, func(t *testutil.T) { 76 MarkIntegrationTest(t.T, CanRunWithoutGcp) 77 args := []string{test.action} 78 79 if test.envFile != "" { 80 args = append(args, "--env-file", test.envFile) 81 } 82 ns, _ := SetupNamespace(t.T) 83 84 out, err := skaffold.Exec(args...).InNs(ns.Name).InDir("testdata/custom-actions-k8s").RunWithCombinedOutput(t.T) 85 t.CheckError(test.shouldErr, err) 86 logs := string(out) 87 88 for _, expectedMsg := range test.expectedMsgs { 89 t.CheckContains(expectedMsg, logs) 90 } 91 92 for _, nel := range test.notExpectedLogs { 93 testutil.CheckNotContains(t.T, nel, logs) 94 } 95 }) 96 } 97 } 98 99 func TestExec_K8SActionWithLocalArtifact(t *testing.T) { 100 tests := []struct { 101 description string 102 action string 103 shouldErr bool 104 shouldBuild bool 105 expectedMsgs []string 106 }{ 107 { 108 description: "fail due not found image", 109 action: "action-with-local-built-img-1", 110 shouldErr: true, 111 expectedMsgs: []string{ 112 "creating container for local-img-task1-1: ErrImagePull", 113 }, 114 }, 115 { 116 description: "build and run task", 117 action: "action-with-local-built-img-2", 118 shouldBuild: true, 119 expectedMsgs: []string{ 120 "[local-img-task1-2] Hello world from-local-img! 4", 121 }, 122 }, 123 } 124 125 for _, test := range tests { 126 testutil.Run(t, test.description, func(t *testutil.T) { 127 MarkIntegrationTest(t.T, CanRunWithoutGcp) 128 dir := "testdata/custom-actions-k8s" 129 args := []string{test.action} 130 ns, _ := SetupNamespace(t.T) 131 if test.shouldBuild { 132 tmpfile := testutil.TempFile(t.T, "", []byte{}) 133 skaffold.Build("--file-output", tmpfile, "--tag", uuid.New().String(), "--check-cluster-node-platforms=true").InNs(ns.Name).InDir(dir).RunOrFail(t.T) 134 args = append(args, "--build-artifacts", tmpfile) 135 } 136 137 out, err := skaffold.Exec(args...).InNs(ns.Name).InDir(dir).RunWithCombinedOutput(t.T) 138 t.CheckError(test.shouldErr, err) 139 140 for _, expectedMsg := range test.expectedMsgs { 141 t.CheckContains(expectedMsg, string(out)) 142 } 143 }) 144 } 145 } 146 147 func TestExec_K8SActionsEvents(t *testing.T) { 148 tests := []struct { 149 description string 150 action string 151 shouldErr bool 152 expectedLogs []string 153 }{ 154 { 155 description: "events for succeeded action", 156 action: "action-succeeded", 157 expectedLogs: []string{ 158 `"taskEvent":{"id":"Exec-0","task":"Exec","description":"Executing custom action action-succeeded","status":"InProgress"}}`, 159 `"execEvent":{"id":"task7","taskId":"Exec-0","status":"InProgress"}}`, 160 `"execEvent":{"id":"task8","taskId":"Exec-0","status":"InProgress"}}`, 161 `"execEvent":{"id":"task7","taskId":"Exec-0","status":"Succeeded"}}`, 162 `"execEvent":{"id":"task8","taskId":"Exec-0","status":"Succeeded"}}`, 163 // TODO(#8728): Uncomment this expected log line when the flaky behaviour is solved. 164 // `"taskEvent":{"id":"Exec-0","task":"Exec","status":"Succeeded"}}`, 165 }, 166 }, 167 { 168 description: "events for fail action - fail fast", 169 action: "action-fail-fast", 170 shouldErr: true, 171 expectedLogs: []string{ 172 `"taskEvent":{"id":"Exec-0","task":"Exec","description":"Executing custom action action-fail-fast","status":"InProgress"}}`, 173 `"execEvent":{"id":"task3","taskId":"Exec-0","status":"InProgress"}}`, 174 `"execEvent":{"id":"task4","taskId":"Exec-0","status":"InProgress"}}`, 175 `"execEvent":{"id":"task4","taskId":"Exec-0","status":"Failed","actionableErr":{"errCode":"UNKNOWN_ERROR","message":"error in task4 job execution, job failed"`, 176 `"execEvent":{"id":"task3","taskId":"Exec-0","status":"Failed","actionableErr":{"errCode":"UNKNOWN_ERROR","message":"error in task3 job execution, event type: ERROR"`, 177 `"taskEvent":{"id":"Exec-0","task":"Exec","status":"Failed","actionableErr":{"errCode":"UNKNOWN_ERROR","message":"error in task4 job execution, job failed"`, 178 }, 179 }, 180 { 181 description: "events for fail action - fail safe", 182 action: "action-fail-safe", 183 shouldErr: true, 184 expectedLogs: []string{ 185 `"taskEvent":{"id":"Exec-0","task":"Exec","description":"Executing custom action action-fail-safe","status":"InProgress"}}`, 186 `"execEvent":{"id":"task5","taskId":"Exec-0","status":"InProgress"}}`, 187 `"execEvent":{"id":"task6","taskId":"Exec-0","status":"InProgress"}}`, 188 `"execEvent":{"id":"task6","taskId":"Exec-0","status":"Failed","actionableErr":{"errCode":"UNKNOWN_ERROR","message":"error in task6 job execution, job failed"`, 189 `"execEvent":{"id":"task5","taskId":"Exec-0","status":"Succeeded"}}`, 190 `"taskEvent":{"id":"Exec-0","task":"Exec","status":"Failed","actionableErr":{"errCode":"UNKNOWN_ERROR","message":"1 error(s) occurred:\n* error in task6 job execution, job failed"`, 191 }, 192 }, 193 } 194 195 for _, test := range tests { 196 testutil.Run(t, test.description, func(t *testutil.T) { 197 MarkIntegrationTest(t.T, CanRunWithoutGcp) 198 ns, _ := SetupNamespace(t.T) 199 rpcAddr := randomPort() 200 tmp := t.TempDir() 201 logFile := filepath.Join(tmp, uuid.New().String()+"logs.json") 202 203 args := []string{test.action, "--rpc-port", rpcAddr, "--event-log-file", logFile} 204 205 _, err := skaffold.Exec(args...).InNs(ns.Name).InDir("testdata/custom-actions-k8s").RunWithCombinedOutput(t.T) 206 207 t.CheckError(test.shouldErr, err) 208 209 b, err := os.ReadFile(logFile + ".v2") 210 if err != nil { 211 t.Fatalf("error reading %s", logFile+".v2") 212 } 213 v2EventLogs := string(b) 214 for _, expectedLog := range test.expectedLogs { 215 t.CheckContains(expectedLog, v2EventLogs) 216 } 217 }) 218 } 219 }