github.com/GoogleContainerTools/skaffold@v1.39.18/pkg/skaffold/hooks/sync_test.go (about) 1 /* 2 Copyright 2021 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 hooks 18 19 import ( 20 "bytes" 21 "context" 22 "fmt" 23 "io" 24 "path/filepath" 25 "strings" 26 "testing" 27 28 corev1 "k8s.io/api/core/v1" 29 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 30 "k8s.io/client-go/kubernetes" 31 fakeclient "k8s.io/client-go/kubernetes/fake" 32 33 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/kubectl" 34 kubernetesclient "github.com/GoogleContainerTools/skaffold/pkg/skaffold/kubernetes/client" 35 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/log" 36 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest" 37 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/util" 38 "github.com/GoogleContainerTools/skaffold/testutil" 39 ) 40 41 func TestSyncHooks(t *testing.T) { 42 testutil.Run(t, "TestSyncHooks", func(t *testutil.T) { 43 workDir, _ := filepath.Abs("./foo") 44 hooks := latest.SyncHooks{ 45 PreHooks: []latest.SyncHookItem{ 46 { 47 HostHook: &latest.HostHook{ 48 OS: []string{"linux", "darwin"}, 49 Command: []string{"sh", "-c", "echo pre-hook running with SKAFFOLD_IMAGE=$SKAFFOLD_IMAGE,SKAFFOLD_BUILD_CONTEXT=$SKAFFOLD_BUILD_CONTEXT,SKAFFOLD_FILES_ADDED_OR_MODIFIED=$SKAFFOLD_FILES_ADDED_OR_MODIFIED,SKAFFOLD_FILES_DELETED=$SKAFFOLD_FILES_DELETED,SKAFFOLD_KUBE_CONTEXT=$SKAFFOLD_KUBE_CONTEXT,SKAFFOLD_NAMESPACES=$SKAFFOLD_NAMESPACES"}, 50 }, 51 }, 52 { 53 HostHook: &latest.HostHook{ 54 OS: []string{"windows"}, 55 Command: []string{"cmd.exe", "/C", "echo pre-hook running with SKAFFOLD_IMAGE=%SKAFFOLD_IMAGE%,SKAFFOLD_BUILD_CONTEXT=%SKAFFOLD_BUILD_CONTEXT%,SKAFFOLD_FILES_ADDED_OR_MODIFIED=%SKAFFOLD_FILES_ADDED_OR_MODIFIED%,SKAFFOLD_FILES_DELETED=%SKAFFOLD_FILES_DELETED%,SKAFFOLD_KUBE_CONTEXT=%SKAFFOLD_KUBE_CONTEXT%,SKAFFOLD_NAMESPACES=%SKAFFOLD_NAMESPACES%"}, 56 }, 57 }, 58 { 59 ContainerHook: &latest.ContainerHook{ 60 Command: []string{"foo", "pre-hook"}, 61 }, 62 }, 63 }, 64 PostHooks: []latest.SyncHookItem{ 65 { 66 HostHook: &latest.HostHook{ 67 OS: []string{"linux", "darwin"}, 68 Command: []string{"sh", "-c", "echo post-hook running with SKAFFOLD_IMAGE=$SKAFFOLD_IMAGE,SKAFFOLD_BUILD_CONTEXT=$SKAFFOLD_BUILD_CONTEXT,SKAFFOLD_FILES_ADDED_OR_MODIFIED=$SKAFFOLD_FILES_ADDED_OR_MODIFIED,SKAFFOLD_FILES_DELETED=$SKAFFOLD_FILES_DELETED,SKAFFOLD_KUBE_CONTEXT=$SKAFFOLD_KUBE_CONTEXT,SKAFFOLD_NAMESPACES=$SKAFFOLD_NAMESPACES"}, 69 }, 70 }, 71 { 72 HostHook: &latest.HostHook{ 73 OS: []string{"windows"}, 74 Command: []string{"cmd.exe", "/C", "echo post-hook running with SKAFFOLD_IMAGE=%SKAFFOLD_IMAGE%,SKAFFOLD_BUILD_CONTEXT=%SKAFFOLD_BUILD_CONTEXT%,SKAFFOLD_FILES_ADDED_OR_MODIFIED=%SKAFFOLD_FILES_ADDED_OR_MODIFIED%,SKAFFOLD_FILES_DELETED=%SKAFFOLD_FILES_DELETED%,SKAFFOLD_KUBE_CONTEXT=%SKAFFOLD_KUBE_CONTEXT%,SKAFFOLD_NAMESPACES=%SKAFFOLD_NAMESPACES%"}, 75 }, 76 }, 77 { 78 ContainerHook: &latest.ContainerHook{ 79 Command: []string{"foo", "post-hook"}, 80 }, 81 }, 82 }, 83 } 84 preHostHookOut := fmt.Sprintf("pre-hook running with SKAFFOLD_IMAGE=gcr.io/foo/img1:latest,SKAFFOLD_BUILD_CONTEXT=%s,SKAFFOLD_FILES_ADDED_OR_MODIFIED=foo1;bar1,SKAFFOLD_FILES_DELETED=foo2;bar2,SKAFFOLD_KUBE_CONTEXT=context1,SKAFFOLD_NAMESPACES=np1,np2", workDir) 85 preContainerHookOut := "container pre-hook succeeded" 86 postHostHookOut := fmt.Sprintf("post-hook running with SKAFFOLD_IMAGE=gcr.io/foo/img1:latest,SKAFFOLD_BUILD_CONTEXT=%s,SKAFFOLD_FILES_ADDED_OR_MODIFIED=foo1;bar1,SKAFFOLD_FILES_DELETED=foo2;bar2,SKAFFOLD_KUBE_CONTEXT=context1,SKAFFOLD_NAMESPACES=np1,np2", workDir) 87 postContainerHookOut := "container post-hook succeeded" 88 89 artifact := &latest.Artifact{ 90 ImageName: "img1", 91 Workspace: workDir, 92 Sync: &latest.Sync{ 93 LifecycleHooks: hooks, 94 }, 95 } 96 image := "gcr.io/foo/img1:latest" 97 namespaces := []string{"np1", "np2"} 98 kubeContext := "context1" 99 opts, err := NewSyncEnvOpts(artifact, image, []string{"foo1", "bar1"}, []string{"foo2", "bar2"}, namespaces, kubeContext) 100 t.CheckNoError(err) 101 formatter := func(corev1.Pod, corev1.ContainerStatus, func() bool) log.Formatter { return mockLogFormatter{} } 102 runner := NewSyncRunner(&kubectl.CLI{KubeContext: kubeContext}, artifact.ImageName, image, namespaces, formatter, artifact.Sync.LifecycleHooks, opts) 103 104 t.Override(&util.DefaultExecCommand, 105 testutil.CmdRunWithOutput("kubectl --context context1 exec pod1 --namespace np1 -c container1 -- foo pre-hook", preContainerHookOut). 106 AndRunWithOutput("kubectl --context context1 exec pod1 --namespace np1 -c container1 -- foo post-hook", postContainerHookOut)) 107 t.Override(&kubernetesclient.Client, fakeKubernetesClient) 108 var preOut, postOut bytes.Buffer 109 err = runner.RunPreHooks(context.Background(), &preOut) 110 t.CheckNoError(err) 111 t.CheckContains(preHostHookOut, preOut.String()) 112 t.CheckContains(preContainerHookOut, strings.TrimRight(preOut.String(), "\r\n")) 113 err = runner.RunPostHooks(context.Background(), &postOut) 114 t.CheckNoError(err) 115 t.CheckContains(postHostHookOut, postOut.String()) 116 t.CheckContains(postContainerHookOut, postOut.String()) 117 }) 118 } 119 120 func fakeKubernetesClient(string) (kubernetes.Interface, error) { 121 pod := &corev1.Pod{ 122 ObjectMeta: metav1.ObjectMeta{ 123 Name: "pod1", 124 Namespace: "np1", 125 OwnerReferences: []metav1.OwnerReference{ 126 { 127 Name: "rs", 128 Kind: "ReplicaSet", 129 }, 130 }, 131 }, 132 Status: corev1.PodStatus{Phase: corev1.PodRunning}, 133 Spec: corev1.PodSpec{Containers: []corev1.Container{ 134 { 135 Name: "container1", 136 Image: "gcr.io/foo/img1:latest", 137 }, 138 }}, 139 } 140 return fakeclient.NewSimpleClientset(pod), nil 141 } 142 143 type mockLogFormatter struct{} 144 145 func (mockLogFormatter) Name() string { return "" } 146 147 func (mockLogFormatter) PrintLine(w io.Writer, s string) { fmt.Fprint(w, s) }