github.com/GoogleContainerTools/skaffold@v1.39.18/pkg/skaffold/event/v2/event_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 v2 18 19 import ( 20 "errors" 21 "io/ioutil" 22 "os" 23 "path/filepath" 24 "strings" 25 "sync/atomic" 26 "testing" 27 "time" 28 29 //nolint:golint,staticcheck 30 "github.com/golang/protobuf/jsonpb" 31 "github.com/mitchellh/go-homedir" 32 33 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest" 34 proto "github.com/GoogleContainerTools/skaffold/proto/v2" 35 "github.com/GoogleContainerTools/skaffold/testutil" 36 ) 37 38 var targetPort = proto.IntOrString{Type: 0, IntVal: 2001} 39 40 func TestGetLogEvents(t *testing.T) { 41 for step := 0; step < 1000; step++ { 42 ev := newHandler() 43 44 ev.logEvent(&proto.Event{ 45 EventType: &proto.Event_SkaffoldLogEvent{ 46 SkaffoldLogEvent: &proto.SkaffoldLogEvent{Message: "OLD"}, 47 }, 48 }) 49 go func() { 50 ev.logEvent(&proto.Event{ 51 EventType: &proto.Event_SkaffoldLogEvent{ 52 SkaffoldLogEvent: &proto.SkaffoldLogEvent{Message: "FRESH"}, 53 }, 54 }) 55 ev.logEvent(&proto.Event{ 56 EventType: &proto.Event_SkaffoldLogEvent{ 57 SkaffoldLogEvent: &proto.SkaffoldLogEvent{Message: "POISON PILL"}, 58 }, 59 }) 60 }() 61 62 var received int32 63 ev.forEachEvent(func(e *proto.Event) error { 64 if e.GetSkaffoldLogEvent().Message == "POISON PILL" { 65 return errors.New("Done") 66 } 67 68 atomic.AddInt32(&received, 1) 69 return nil 70 }) 71 72 if atomic.LoadInt32(&received) != 2 { 73 t.Fatalf("Expected %d events, Got %d (Step: %d)", 2, received, step) 74 } 75 } 76 } 77 78 func wait(t *testing.T, condition func() bool) { 79 ticker := time.NewTicker(10 * time.Millisecond) 80 defer ticker.Stop() 81 82 timeout := time.NewTimer(5 * time.Second) 83 defer timeout.Stop() 84 85 for { 86 select { 87 case <-ticker.C: 88 if condition() { 89 return 90 } 91 92 case <-timeout.C: 93 t.Fatal("Timed out waiting") 94 } 95 } 96 } 97 98 func TestSaveEventsToFile(t *testing.T) { 99 f, err := ioutil.TempFile("", "") 100 if err != nil { 101 t.Fatalf("getting temp file: %v", err) 102 } 103 t.Cleanup(func() { os.Remove(f.Name()) }) 104 if err := f.Close(); err != nil { 105 t.Fatalf("error closing tmp file: %v", err) 106 } 107 108 // add some events to the event log 109 handler.eventLog = []*proto.Event{ 110 { 111 EventType: &proto.Event_BuildSubtaskEvent{}, 112 }, { 113 EventType: &proto.Event_TaskEvent{}, 114 }, 115 } 116 117 // save events to file 118 if err := SaveEventsToFile(f.Name()); err != nil { 119 t.Fatalf("error saving events to file: %v", err) 120 } 121 122 // ensure that the events in the file match the event log 123 contents, err := ioutil.ReadFile(f.Name()) 124 if err != nil { 125 t.Fatalf("reading tmp file: %v", err) 126 } 127 128 var logEntries []*proto.Event 129 entries := strings.Split(string(contents), "\n") 130 for _, e := range entries { 131 if e == "" { 132 continue 133 } 134 var logEntry proto.Event 135 if err := jsonpb.UnmarshalString(e, &logEntry); err != nil { 136 t.Errorf("error converting http response %s to proto: %s", e, err.Error()) 137 } 138 logEntries = append(logEntries, &logEntry) 139 } 140 141 buildCompleteEvent, devLoopCompleteEvent := 0, 0 142 for _, entry := range logEntries { 143 t.Log(entry.GetEventType()) 144 switch entry.GetEventType().(type) { 145 case *proto.Event_BuildSubtaskEvent: 146 buildCompleteEvent++ 147 t.Logf("build event %d: %v", buildCompleteEvent, entry) 148 case *proto.Event_TaskEvent: 149 devLoopCompleteEvent++ 150 t.Logf("dev loop event %d: %v", devLoopCompleteEvent, entry) 151 default: 152 t.Logf("unknown event: %v", entry) 153 } 154 } 155 156 // make sure we have exactly 1 build entry and 1 dev loop complete entry 157 testutil.CheckDeepEqual(t, 2, len(logEntries)) 158 testutil.CheckDeepEqual(t, 1, buildCompleteEvent) 159 testutil.CheckDeepEqual(t, 1, devLoopCompleteEvent) 160 } 161 162 func TestSaveLastLog(t *testing.T) { 163 f, err := ioutil.TempFile("", "") 164 if err != nil { 165 t.Fatalf("getting temp file: %v", err) 166 } 167 t.Cleanup(func() { os.Remove(f.Name()) }) 168 if err := f.Close(); err != nil { 169 t.Fatalf("error closing tmp file: %v", err) 170 } 171 172 // add some events to the event log. Include irrelevant events to test that they are ignored 173 handler.eventLog = []*proto.Event{ 174 { 175 EventType: &proto.Event_BuildSubtaskEvent{}, 176 }, { 177 EventType: &proto.Event_SkaffoldLogEvent{ 178 SkaffoldLogEvent: &proto.SkaffoldLogEvent{Message: "Message 1\n"}, 179 }, 180 }, { 181 EventType: &proto.Event_DeploySubtaskEvent{}, 182 }, { 183 EventType: &proto.Event_SkaffoldLogEvent{ 184 SkaffoldLogEvent: &proto.SkaffoldLogEvent{Message: "Message 2\n"}, 185 }, 186 }, { 187 EventType: &proto.Event_PortEvent{}, 188 }, 189 } 190 191 // save events to file 192 if err := SaveLastLog(f.Name()); err != nil { 193 t.Fatalf("error saving log to file: %v", err) 194 } 195 196 // ensure that the events in the file match the event log 197 b, err := ioutil.ReadFile(f.Name()) 198 if err != nil { 199 t.Fatalf("reading tmp file: %v", err) 200 } 201 202 // make sure that the contents of the file match the expected result. 203 expectedText := `Message 1 204 Message 2 205 ` 206 testutil.CheckDeepEqual(t, expectedText, string(b)) 207 } 208 209 func TestLastLogFile(t *testing.T) { 210 homeDir, _ := homedir.Dir() 211 tests := []struct { 212 name string 213 fp string 214 expected string 215 }{ 216 { 217 name: "Empty string passed in", 218 fp: "", 219 expected: filepath.Join(homeDir, ".skaffold", "last.log"), 220 }, 221 { 222 name: "Non-empty string passed in", 223 fp: filepath.Join("/", "tmp"), 224 expected: filepath.Join("/", "tmp"), 225 }, 226 } 227 228 for _, test := range tests { 229 testutil.Run(t, test.name, func(t *testutil.T) { 230 actual, _ := lastLogFile(test.fp) 231 t.CheckDeepEqual(test.expected, actual) 232 }) 233 } 234 } 235 236 type config struct { 237 pipes []latest.Pipeline 238 kubectx string 239 } 240 241 func (c config) GetKubeContext() string { return c.kubectx } 242 func (c config) AutoBuild() bool { return true } 243 func (c config) AutoDeploy() bool { return true } 244 func (c config) AutoSync() bool { return true } 245 func (c config) GetPipelines() []latest.Pipeline { return c.pipes } 246 func (c config) GetRunID() string { return "run-id" } 247 248 func mockCfg(pipes []latest.Pipeline, kubectx string) config { 249 return config{ 250 pipes: pipes, 251 kubectx: kubectx, 252 } 253 }