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  }