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 }