github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/internal/controllers/core/tiltfile/filewatch_test.go (about) 1 package tiltfile 2 3 import ( 4 "context" 5 "strings" 6 "testing" 7 8 ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" 9 10 "github.com/tilt-dev/tilt/pkg/apis" 11 "github.com/tilt-dev/tilt/pkg/apis/core/v1alpha1" 12 13 "github.com/google/go-cmp/cmp" 14 "github.com/moby/buildkit/frontend/dockerfile/dockerignore" 15 "github.com/stretchr/testify/assert" 16 "github.com/stretchr/testify/require" 17 "k8s.io/apimachinery/pkg/api/equality" 18 19 "github.com/tilt-dev/tilt/internal/container" 20 "github.com/tilt-dev/tilt/internal/controllers/fake" 21 "github.com/tilt-dev/tilt/internal/k8s/testyaml" 22 "github.com/tilt-dev/tilt/internal/store" 23 "github.com/tilt-dev/tilt/internal/testutils" 24 "github.com/tilt-dev/tilt/internal/testutils/manifestbuilder" 25 "github.com/tilt-dev/tilt/internal/testutils/tempdir" 26 "github.com/tilt-dev/tilt/pkg/model" 27 ) 28 29 func TestFileWatch_basic(t *testing.T) { 30 f := newFWFixture(t) 31 32 target := model.LocalTarget{ 33 Name: "foo", 34 Deps: []string{"."}, 35 } 36 f.SetManifestLocalTarget(target) 37 38 f.RequireFileWatchSpecEqual(target.ID(), v1alpha1.FileWatchSpec{WatchedPaths: []string{"."}}) 39 } 40 41 func TestFileWatch_disabledOnCIMode(t *testing.T) { 42 f := newFWFixture(t) 43 44 f.inputs.EngineMode = store.EngineModeCI 45 46 target := model.LocalTarget{ 47 Name: "foo", 48 Deps: []string{"."}, 49 } 50 f.SetManifestLocalTarget(target) 51 m := model.Manifest{Name: "foo"}.WithDeployTarget(target) 52 f.SetManifest(m) 53 54 actualSet := ToFileWatchObjects(f.inputs, make(disableSourceMap)) 55 assert.Empty(t, actualSet) 56 } 57 58 func TestFileWatch_IgnoreOutputsImageRefs(t *testing.T) { 59 f := newFWFixture(t) 60 61 target := model.MustNewImageTarget(container.MustParseSelector("img")). 62 WithBuildDetails(model.CustomBuild{ 63 CmdImageSpec: v1alpha1.CmdImageSpec{OutputsImageRefTo: f.JoinPath("ref.txt")}, 64 Deps: []string{f.Path()}, 65 }) 66 67 m := manifestbuilder.New(f, "sancho"). 68 WithK8sYAML(testyaml.SanchoYAML). 69 WithImageTarget(target). 70 Build() 71 f.SetManifest(m) 72 73 f.RequireFileWatchSpecEqual(target.ID(), v1alpha1.FileWatchSpec{ 74 WatchedPaths: []string{f.Path()}, 75 Ignores: []v1alpha1.IgnoreDef{ 76 {BasePath: f.Path(), Patterns: []string{"ref.txt"}}, 77 }, 78 }) 79 } 80 81 func TestFileWatch_ConfigFiles(t *testing.T) { 82 f := newFWFixture(t) 83 84 f.SetTiltIgnoreContents("**/foo") 85 f.inputs.ConfigFiles = append(f.inputs.ConfigFiles, "path_to_watch", "stop") 86 87 id := model.TargetID{Type: model.TargetTypeConfigs, Name: model.TargetName(model.MainTiltfileManifestName)} 88 f.RequireFileWatchSpecEqual(id, v1alpha1.FileWatchSpec{ 89 WatchedPaths: []string{"path_to_watch", "stop"}, 90 Ignores: []v1alpha1.IgnoreDef{ 91 {BasePath: f.Path(), Patterns: []string{"**/foo"}}, 92 }, 93 }) 94 } 95 96 func TestFileWatch_IgnoreTiltIgnore(t *testing.T) { 97 f := newFWFixture(t) 98 99 target := model.LocalTarget{ 100 Name: "foo", 101 Deps: []string{"."}, 102 } 103 f.SetManifestLocalTarget(target) 104 f.SetTiltIgnoreContents("**/foo") 105 f.RequireFileWatchSpecEqual(target.ID(), v1alpha1.FileWatchSpec{ 106 WatchedPaths: []string{"."}, 107 Ignores: []v1alpha1.IgnoreDef{ 108 {BasePath: f.Path(), Patterns: []string{"**/foo"}}, 109 }, 110 }) 111 } 112 113 func TestFileWatch_IgnoreWatchSettings(t *testing.T) { 114 f := newFWFixture(t) 115 116 target := model.LocalTarget{ 117 Name: "foo", 118 Deps: []string{"."}, 119 } 120 f.SetManifestLocalTarget(target) 121 122 f.inputs.WatchSettings.Ignores = append(f.inputs.WatchSettings.Ignores, model.Dockerignore{ 123 LocalPath: f.Path(), 124 Patterns: []string{"**/foo"}, 125 }) 126 127 f.RequireFileWatchSpecEqual(target.ID(), v1alpha1.FileWatchSpec{ 128 WatchedPaths: []string{"."}, 129 Ignores: []v1alpha1.IgnoreDef{ 130 {BasePath: f.Path(), Patterns: []string{"**/foo"}}, 131 }, 132 }) 133 } 134 135 func TestFileWatch_PickUpTiltIgnoreChanges(t *testing.T) { 136 f := newFWFixture(t) 137 138 target := model.LocalTarget{ 139 Name: "foo", 140 Deps: []string{"."}, 141 } 142 f.SetManifestLocalTarget(target) 143 f.SetTiltIgnoreContents("**/foo") 144 f.RequireFileWatchSpecEqual(target.ID(), v1alpha1.FileWatchSpec{ 145 WatchedPaths: []string{"."}, 146 Ignores: []v1alpha1.IgnoreDef{ 147 {BasePath: f.Path(), Patterns: []string{"**/foo"}}, 148 }, 149 }) 150 151 f.SetTiltIgnoreContents("**foo\n!bar/baz/foo") 152 f.RequireFileWatchSpecEqual(target.ID(), v1alpha1.FileWatchSpec{ 153 WatchedPaths: []string{"."}, 154 Ignores: []v1alpha1.IgnoreDef{ 155 {BasePath: f.Path(), Patterns: []string{"**foo", "!bar/baz/foo"}}, 156 }, 157 }) 158 } 159 160 type fwFixture struct { 161 t testing.TB 162 ctx context.Context 163 cli ctrlclient.Client 164 *tempdir.TempDirFixture 165 inputs WatchInputs 166 } 167 168 func newFWFixture(t *testing.T) *fwFixture { 169 cli := fake.NewFakeTiltClient() 170 171 ctx, _, _ := testutils.CtxAndAnalyticsForTest() 172 ctx, cancel := context.WithCancel(ctx) 173 174 tmpdir := tempdir.NewTempDirFixture(t) 175 tmpdir.Chdir() 176 177 f := &fwFixture{ 178 t: t, 179 ctx: ctx, 180 cli: cli, 181 TempDirFixture: tmpdir, 182 inputs: WatchInputs{TiltfileManifestName: model.MainTiltfileManifestName}, 183 } 184 185 t.Cleanup(func() { 186 cancel() 187 }) 188 189 return f 190 } 191 192 type fileWatchDiffer struct { 193 expected v1alpha1.FileWatchSpec 194 actual v1alpha1.FileWatchSpec 195 } 196 197 func (f fileWatchDiffer) String() string { 198 return cmp.Diff(f.expected, f.actual) 199 } 200 201 func (f *fwFixture) RequireFileWatchSpecEqual(targetID model.TargetID, spec v1alpha1.FileWatchSpec) { 202 f.t.Helper() 203 204 actualSet := ToFileWatchObjects(f.inputs, make(disableSourceMap)) 205 actual, ok := actualSet[apis.SanitizeName(targetID.String())] 206 require.True(f.T(), ok, "No filewatch found for %s", targetID) 207 fwd := &fileWatchDiffer{expected: spec, actual: actual.GetSpec().(v1alpha1.FileWatchSpec)} 208 require.True(f.T(), equality.Semantic.DeepEqual(actual.GetSpec(), spec), "FileWatch spec was not equal: %v", fwd) 209 } 210 211 func (f *fwFixture) SetManifestLocalTarget(target model.LocalTarget) { 212 m := model.Manifest{Name: "foo"}.WithDeployTarget(target) 213 f.SetManifest(m) 214 } 215 216 func (f *fwFixture) SetManifest(m model.Manifest) { 217 for i, original := range f.inputs.Manifests { 218 if original.Name == m.Name { 219 f.inputs.Manifests[i] = m 220 return 221 } 222 } 223 f.inputs.Manifests = append(f.inputs.Manifests, m) 224 } 225 226 func (f *fwFixture) SetTiltIgnoreContents(s string) { 227 patterns, err := dockerignore.ReadAll(strings.NewReader(s)) 228 assert.NoError(f.T(), err) 229 f.inputs.Tiltignore = model.Dockerignore{ 230 LocalPath: f.Path(), 231 Patterns: patterns, 232 } 233 }