github.com/GoogleContainerTools/skaffold@v1.39.18/pkg/skaffold/trigger/triggers_test.go (about)

     1  /*
     2  Copyright 2019 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 trigger
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"fmt"
    23  	"testing"
    24  	"time"
    25  
    26  	"github.com/google/go-cmp/cmp"
    27  	"github.com/rjeczalik/notify"
    28  
    29  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
    30  	fsNotify "github.com/GoogleContainerTools/skaffold/pkg/skaffold/trigger/fsnotify"
    31  	"github.com/GoogleContainerTools/skaffold/testutil"
    32  )
    33  
    34  func TestNewTrigger(t *testing.T) {
    35  	tests := []struct {
    36  		description       string
    37  		trigger           string
    38  		watchPollInterval int
    39  		expected          Trigger
    40  		shouldErr         bool
    41  	}{
    42  		{
    43  			description:       "polling trigger",
    44  			trigger:           "polling",
    45  			watchPollInterval: 1,
    46  			expected: &pollTrigger{
    47  				Interval: 1 * time.Millisecond,
    48  			},
    49  		},
    50  		{
    51  			description:       "notify trigger",
    52  			trigger:           "notify",
    53  			watchPollInterval: 1,
    54  			expected: fsNotify.New(map[string]struct{}{
    55  				"../workspace":            {},
    56  				"../some/other/workspace": {}}, nil, 1),
    57  		},
    58  		{
    59  			description: "manual trigger",
    60  			trigger:     "manual",
    61  			expected:    &manualTrigger{},
    62  		},
    63  		{
    64  			description: "unknown trigger",
    65  			trigger:     "unknown",
    66  			shouldErr:   true,
    67  		},
    68  	}
    69  	for _, test := range tests {
    70  		testutil.Run(t, test.description, func(t *testutil.T) {
    71  			cfg := &mockConfig{
    72  				trigger:           test.trigger,
    73  				watchPollInterval: test.watchPollInterval,
    74  				artifacts: []*latest.Artifact{
    75  					{Workspace: "../workspace"},
    76  					{Workspace: "../workspace"},
    77  					{Workspace: "../some/other/workspace"},
    78  				},
    79  			}
    80  
    81  			got, err := NewTrigger(cfg, nil)
    82  
    83  			t.CheckError(test.shouldErr, err)
    84  			if !test.shouldErr {
    85  				t.CheckDeepEqual(test.expected, got, cmp.AllowUnexported(fsNotify.Trigger{}), cmp.Comparer(ignoreFuncComparer), cmp.AllowUnexported(manualTrigger{}), cmp.AllowUnexported(pollTrigger{}))
    86  			}
    87  		})
    88  	}
    89  }
    90  
    91  func ignoreFuncComparer(x, y func(path string, c chan<- notify.EventInfo, events ...notify.Event) error) bool {
    92  	if x == nil && y == nil {
    93  		return true
    94  	}
    95  	if x == nil || y == nil {
    96  		return false
    97  	}
    98  	return true // cannot assert function equality, so skip
    99  }
   100  
   101  func TestPollTrigger_Debounce(t *testing.T) {
   102  	trigger := &pollTrigger{}
   103  	got, want := trigger.Debounce(), true
   104  	testutil.CheckDeepEqual(t, want, got)
   105  }
   106  
   107  func TestPollTrigger_LogWatchToUser(t *testing.T) {
   108  	tests := []struct {
   109  		description string
   110  		isActive    bool
   111  		expected    string
   112  	}{
   113  		{
   114  			description: "active polling trigger",
   115  			isActive:    true,
   116  			expected:    "Watching for changes every 10ns...\n",
   117  		},
   118  		{
   119  			description: "inactive polling trigger",
   120  			isActive:    false,
   121  			expected:    "Not watching for changes...\n",
   122  		},
   123  	}
   124  	for _, test := range tests {
   125  		out := new(bytes.Buffer)
   126  
   127  		trigger := &pollTrigger{
   128  			Interval: 10,
   129  			isActive: func() bool {
   130  				return test.isActive
   131  			},
   132  		}
   133  		trigger.LogWatchToUser(out)
   134  
   135  		got, want := out.String(), test.expected
   136  		testutil.CheckDeepEqual(t, want, got)
   137  	}
   138  }
   139  
   140  func TestManualTrigger_Debounce(t *testing.T) {
   141  	trigger := &manualTrigger{}
   142  	got, want := trigger.Debounce(), false
   143  	testutil.CheckDeepEqual(t, want, got)
   144  }
   145  
   146  func TestManualTrigger_LogWatchToUser(t *testing.T) {
   147  	tests := []struct {
   148  		description string
   149  		isActive    bool
   150  		expected    string
   151  	}{
   152  		{
   153  			description: "active manual trigger",
   154  			isActive:    true,
   155  			expected:    "Press any key to rebuild/redeploy the changes\n",
   156  		},
   157  		{
   158  			description: "inactive manual trigger",
   159  			isActive:    false,
   160  			expected:    "Not watching for changes...\n",
   161  		},
   162  	}
   163  	for _, test := range tests {
   164  		out := new(bytes.Buffer)
   165  
   166  		trigger := &manualTrigger{
   167  			isActive: func() bool {
   168  				return test.isActive
   169  			},
   170  		}
   171  		trigger.LogWatchToUser(out)
   172  
   173  		got, want := out.String(), test.expected
   174  		testutil.CheckDeepEqual(t, want, got)
   175  	}
   176  }
   177  
   178  func TestStartTrigger(t *testing.T) {
   179  	tests := []struct {
   180  		description string
   181  		mockWatch   func(string, chan<- notify.EventInfo, ...notify.Event) error
   182  	}{
   183  		{
   184  			description: "fsNotify trigger works",
   185  			mockWatch: func(string, chan<- notify.EventInfo, ...notify.Event) error {
   186  				return nil
   187  			},
   188  		},
   189  		{
   190  			description: "fallback on polling trigger",
   191  			mockWatch: func(string, chan<- notify.EventInfo, ...notify.Event) error {
   192  				return fmt.Errorf("failed to start watch trigger")
   193  			},
   194  		},
   195  	}
   196  
   197  	for _, test := range tests {
   198  		testutil.Run(t, test.description, func(t *testutil.T) {
   199  			t.Override(&fsNotify.Watch, test.mockWatch)
   200  			trigger := fsNotify.New(nil, func() bool { return false }, 1)
   201  			_, err := StartTrigger(context.Background(), trigger)
   202  			time.Sleep(1 * time.Second)
   203  			t.CheckNoError(err)
   204  		})
   205  	}
   206  }
   207  
   208  type mockConfig struct {
   209  	trigger           string
   210  	watchPollInterval int
   211  	artifacts         []*latest.Artifact
   212  }
   213  
   214  func (c *mockConfig) Trigger() string               { return c.trigger }
   215  func (c *mockConfig) WatchPollInterval() int        { return c.watchPollInterval }
   216  func (c *mockConfig) Artifacts() []*latest.Artifact { return c.artifacts }