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  }