github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/internal/controllers/core/extension/reconciler_test.go (about) 1 package extension 2 3 import ( 4 "fmt" 5 "testing" 6 7 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 8 "k8s.io/apimachinery/pkg/types" 9 10 "github.com/stretchr/testify/assert" 11 "github.com/stretchr/testify/require" 12 13 "github.com/tilt-dev/wmclient/pkg/analytics" 14 15 tiltanalytics "github.com/tilt-dev/tilt/internal/analytics" 16 "github.com/tilt-dev/tilt/internal/controllers/fake" 17 "github.com/tilt-dev/tilt/internal/testutils/tempdir" 18 "github.com/tilt-dev/tilt/pkg/apis/core/v1alpha1" 19 ) 20 21 func TestDefault(t *testing.T) { 22 f := newFixture(t) 23 repo := f.setupRepo() 24 25 ext := v1alpha1.Extension{ 26 ObjectMeta: metav1.ObjectMeta{ 27 Name: "my-repo:my-ext", 28 }, 29 Spec: v1alpha1.ExtensionSpec{ 30 RepoName: "my-repo", 31 RepoPath: "my-ext", 32 Args: []string{"--namespaces=foo"}, 33 }, 34 } 35 f.Create(&ext) 36 37 f.MustGet(types.NamespacedName{Name: "my-repo:my-ext"}, &ext) 38 39 p := f.JoinPath("my-repo", "my-ext", "Tiltfile") 40 require.Equal(t, p, ext.Status.Path) 41 42 var tf v1alpha1.Tiltfile 43 f.MustGet(types.NamespacedName{Name: "my-repo:my-ext"}, &tf) 44 require.Equal(t, tf.Spec, v1alpha1.TiltfileSpec{ 45 Path: p, 46 Labels: map[string]string{"extension.my-repo_my-ext": "extension.my-repo_my-ext"}, 47 RestartOn: &v1alpha1.RestartOnSpec{FileWatches: []string{"configs:my-repo:my-ext"}}, 48 Args: []string{"--namespaces=foo"}, 49 }) 50 51 assert.Equal(t, f.ma.Counts, []analytics.CountEvent{ 52 analytics.CountEvent{ 53 Name: "api.extension.load", 54 Tags: map[string]string{ 55 "ext_path": "my-ext", 56 "repo_type": "file", 57 "repo_url_hash": tiltanalytics.HashSHA1(repo.Spec.URL), 58 }, 59 N: 1, 60 }, 61 }) 62 } 63 64 func TestCleanupTiltfile(t *testing.T) { 65 f := newFixture(t) 66 f.setupRepo() 67 68 ext := v1alpha1.Extension{ 69 ObjectMeta: metav1.ObjectMeta{ 70 Name: "my-repo:my-ext", 71 }, 72 Spec: v1alpha1.ExtensionSpec{ 73 RepoName: "my-repo", 74 RepoPath: "my-ext", 75 }, 76 } 77 f.Create(&ext) 78 79 f.MustGet(types.NamespacedName{Name: "my-repo:my-ext"}, &ext) 80 81 p := f.JoinPath("my-repo", "my-ext", "Tiltfile") 82 83 var tf v1alpha1.Tiltfile 84 f.MustGet(types.NamespacedName{Name: "my-repo:my-ext"}, &tf) 85 require.Equal(t, p, tf.Spec.Path) 86 87 f.Delete(&ext) 88 assert.False(t, f.Get(types.NamespacedName{Name: "my-repo:my-ext"}, &tf)) 89 } 90 91 func TestMissing(t *testing.T) { 92 f := newFixture(t) 93 f.setupRepo() 94 95 ext := v1alpha1.Extension{ 96 ObjectMeta: metav1.ObjectMeta{ 97 Name: "my-repo:my-ext", 98 }, 99 Spec: v1alpha1.ExtensionSpec{ 100 RepoName: "my-repo", 101 RepoPath: "my-ext2", 102 }, 103 } 104 f.Create(&ext) 105 106 f.MustGet(types.NamespacedName{Name: "my-repo:my-ext"}, &ext) 107 p := f.JoinPath("my-repo", "my-ext2", "Tiltfile") 108 require.Equal(t, ext.Status.Error, 109 fmt.Sprintf("no extension tiltfile found at %s", p), ext.Status.Error) 110 } 111 112 // Verify that args are propagated to the tiltfile when changed. 113 func TestChangeArgs(t *testing.T) { 114 f := newFixture(t) 115 f.setupRepo() 116 117 ext := v1alpha1.Extension{ 118 ObjectMeta: metav1.ObjectMeta{ 119 Name: "ext", 120 }, 121 Spec: v1alpha1.ExtensionSpec{ 122 RepoName: "my-repo", 123 RepoPath: "my-ext", 124 Args: []string{"--namespace=bar"}, 125 }, 126 } 127 f.Create(&ext) 128 129 f.MustGet(types.NamespacedName{Name: "ext"}, &ext) 130 131 ext.Spec.Args = []string{"--namespace=foo"} 132 f.Update(&ext) 133 134 var tf v1alpha1.Tiltfile 135 f.MustGet(types.NamespacedName{Name: "ext"}, &tf) 136 require.Equal(t, []string{"--namespace=foo"}, tf.Spec.Args) 137 } 138 139 // Verify that no errors get printed if the extension 140 // appears in the apiserver before the repo appears. 141 func TestExtensionBeforeRepo(t *testing.T) { 142 f := newFixture(t) 143 144 nn := types.NamespacedName{Name: "ext"} 145 ext := v1alpha1.Extension{ 146 ObjectMeta: metav1.ObjectMeta{ 147 Name: "ext", 148 }, 149 Spec: v1alpha1.ExtensionSpec{ 150 RepoName: "my-repo", 151 RepoPath: "my-ext", 152 }, 153 } 154 f.Create(&ext) 155 156 f.MustGet(nn, &ext) 157 assert.Equal(t, "extension repo not found: my-repo", ext.Status.Error) 158 assert.Equal(t, "", f.Stdout()) 159 160 f.setupRepo() 161 f.MustReconcile(nn) 162 f.MustGet(nn, &ext) 163 assert.Equal(t, "", ext.Status.Error) 164 assert.Equal(t, f.JoinPath("my-repo", "my-ext", "Tiltfile"), ext.Status.Path) 165 assert.Equal(t, "", f.Stdout()) 166 } 167 168 type fixture struct { 169 *fake.ControllerFixture 170 *tempdir.TempDirFixture 171 r *Reconciler 172 ma *analytics.MemoryAnalytics 173 } 174 175 func newFixture(t *testing.T) *fixture { 176 cfb := fake.NewControllerFixtureBuilder(t) 177 tf := tempdir.NewTempDirFixture(t) 178 179 o := tiltanalytics.NewFakeOpter(analytics.OptIn) 180 ma, ta := tiltanalytics.NewMemoryTiltAnalyticsForTest(o) 181 182 r := NewReconciler(cfb.Client, v1alpha1.NewScheme(), ta) 183 return &fixture{ 184 ControllerFixture: cfb.Build(r), 185 TempDirFixture: tf, 186 r: r, 187 ma: ma, 188 } 189 } 190 191 func (f *fixture) setupRepo() *v1alpha1.ExtensionRepo { 192 p := f.JoinPath("my-repo", "my-ext", "Tiltfile") 193 f.WriteFile(p, "print('hello-world')") 194 195 repo := v1alpha1.ExtensionRepo{ 196 ObjectMeta: metav1.ObjectMeta{ 197 Name: "my-repo", 198 }, 199 Spec: v1alpha1.ExtensionRepoSpec{ 200 URL: fmt.Sprintf("file://%s", f.JoinPath("my-repo")), 201 }, 202 Status: v1alpha1.ExtensionRepoStatus{ 203 Path: f.JoinPath("my-repo"), 204 }, 205 } 206 f.Create(&repo) 207 return &repo 208 }