github.com/tilt-dev/tilt@v0.36.0/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  		{
    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  // Assert that the repo extension path, if specified, is used for extension location
    65  func TestRepoSubpath(t *testing.T) {
    66  	f := newFixture(t)
    67  	repo := f.setupRepoSubpath("subpath")
    68  
    69  	ext := v1alpha1.Extension{
    70  		ObjectMeta: metav1.ObjectMeta{
    71  			Name: "my-repo:my-ext",
    72  		},
    73  		Spec: v1alpha1.ExtensionSpec{
    74  			RepoName: "my-repo",
    75  			RepoPath: "my-ext",
    76  			Args:     []string{"--namespaces=foo"},
    77  		},
    78  	}
    79  	f.Create(&ext)
    80  
    81  	f.MustGet(types.NamespacedName{Name: "my-repo:my-ext"}, &ext)
    82  
    83  	p := f.JoinPath("my-repo", "subpath", "my-ext", "Tiltfile")
    84  	require.Equal(t, p, ext.Status.Path)
    85  
    86  	var tf v1alpha1.Tiltfile
    87  	f.MustGet(types.NamespacedName{Name: "my-repo:my-ext"}, &tf)
    88  	require.Equal(t, tf.Spec, v1alpha1.TiltfileSpec{
    89  		Path:      p,
    90  		Labels:    map[string]string{"extension.my-repo_my-ext": "extension.my-repo_my-ext"},
    91  		RestartOn: &v1alpha1.RestartOnSpec{FileWatches: []string{"configs:my-repo:my-ext"}},
    92  		Args:      []string{"--namespaces=foo"},
    93  	})
    94  
    95  	assert.Equal(t, f.ma.Counts, []analytics.CountEvent{
    96  		{
    97  			Name: "api.extension.load",
    98  			Tags: map[string]string{
    99  				"ext_path":      "my-ext",
   100  				"repo_type":     "file",
   101  				"repo_url_hash": tiltanalytics.HashSHA1(repo.Spec.URL),
   102  			},
   103  			N: 1,
   104  		},
   105  	})
   106  }
   107  
   108  func TestCleanupTiltfile(t *testing.T) {
   109  	f := newFixture(t)
   110  	f.setupRepo()
   111  
   112  	ext := v1alpha1.Extension{
   113  		ObjectMeta: metav1.ObjectMeta{
   114  			Name: "my-repo:my-ext",
   115  		},
   116  		Spec: v1alpha1.ExtensionSpec{
   117  			RepoName: "my-repo",
   118  			RepoPath: "my-ext",
   119  		},
   120  	}
   121  	f.Create(&ext)
   122  
   123  	f.MustGet(types.NamespacedName{Name: "my-repo:my-ext"}, &ext)
   124  
   125  	p := f.JoinPath("my-repo", "my-ext", "Tiltfile")
   126  
   127  	var tf v1alpha1.Tiltfile
   128  	f.MustGet(types.NamespacedName{Name: "my-repo:my-ext"}, &tf)
   129  	require.Equal(t, p, tf.Spec.Path)
   130  
   131  	f.Delete(&ext)
   132  	assert.False(t, f.Get(types.NamespacedName{Name: "my-repo:my-ext"}, &tf))
   133  }
   134  
   135  func TestMissing(t *testing.T) {
   136  	f := newFixture(t)
   137  	f.setupRepo()
   138  
   139  	ext := v1alpha1.Extension{
   140  		ObjectMeta: metav1.ObjectMeta{
   141  			Name: "my-repo:my-ext",
   142  		},
   143  		Spec: v1alpha1.ExtensionSpec{
   144  			RepoName: "my-repo",
   145  			RepoPath: "my-ext2",
   146  		},
   147  	}
   148  	f.Create(&ext)
   149  
   150  	f.MustGet(types.NamespacedName{Name: "my-repo:my-ext"}, &ext)
   151  	p := f.JoinPath("my-repo", "my-ext2", "Tiltfile")
   152  	require.Equal(t, ext.Status.Error,
   153  		fmt.Sprintf("no extension tiltfile found at %s", p), ext.Status.Error)
   154  }
   155  
   156  // Verify that args are propagated to the tiltfile when changed.
   157  func TestChangeArgs(t *testing.T) {
   158  	f := newFixture(t)
   159  	f.setupRepo()
   160  
   161  	ext := v1alpha1.Extension{
   162  		ObjectMeta: metav1.ObjectMeta{
   163  			Name: "ext",
   164  		},
   165  		Spec: v1alpha1.ExtensionSpec{
   166  			RepoName: "my-repo",
   167  			RepoPath: "my-ext",
   168  			Args:     []string{"--namespace=bar"},
   169  		},
   170  	}
   171  	f.Create(&ext)
   172  
   173  	f.MustGet(types.NamespacedName{Name: "ext"}, &ext)
   174  
   175  	ext.Spec.Args = []string{"--namespace=foo"}
   176  	f.Update(&ext)
   177  
   178  	var tf v1alpha1.Tiltfile
   179  	f.MustGet(types.NamespacedName{Name: "ext"}, &tf)
   180  	require.Equal(t, []string{"--namespace=foo"}, tf.Spec.Args)
   181  }
   182  
   183  // Verify that no errors get printed if the extension
   184  // appears in the apiserver before the repo appears.
   185  func TestExtensionBeforeRepo(t *testing.T) {
   186  	f := newFixture(t)
   187  
   188  	nn := types.NamespacedName{Name: "ext"}
   189  	ext := v1alpha1.Extension{
   190  		ObjectMeta: metav1.ObjectMeta{
   191  			Name: "ext",
   192  		},
   193  		Spec: v1alpha1.ExtensionSpec{
   194  			RepoName: "my-repo",
   195  			RepoPath: "my-ext",
   196  		},
   197  	}
   198  	f.Create(&ext)
   199  
   200  	f.MustGet(nn, &ext)
   201  	assert.Equal(t, "extension repo not found: my-repo", ext.Status.Error)
   202  	assert.Equal(t, "", f.Stdout())
   203  
   204  	f.setupRepo()
   205  	f.MustReconcile(nn)
   206  	f.MustGet(nn, &ext)
   207  	assert.Equal(t, "", ext.Status.Error)
   208  	assert.Equal(t, f.JoinPath("my-repo", "my-ext", "Tiltfile"), ext.Status.Path)
   209  	assert.Equal(t, "", f.Stdout())
   210  }
   211  
   212  type fixture struct {
   213  	*fake.ControllerFixture
   214  	*tempdir.TempDirFixture
   215  	r  *Reconciler
   216  	ma *analytics.MemoryAnalytics
   217  }
   218  
   219  func newFixture(t *testing.T) *fixture {
   220  	cfb := fake.NewControllerFixtureBuilder(t)
   221  	tf := tempdir.NewTempDirFixture(t)
   222  
   223  	o := tiltanalytics.NewFakeOpter(analytics.OptIn)
   224  	ma, ta := tiltanalytics.NewMemoryTiltAnalyticsForTest(o)
   225  
   226  	r := NewReconciler(cfb.Client, v1alpha1.NewScheme(), ta)
   227  	return &fixture{
   228  		ControllerFixture: cfb.Build(r),
   229  		TempDirFixture:    tf,
   230  		r:                 r,
   231  		ma:                ma,
   232  	}
   233  }
   234  
   235  func (f *fixture) setupRepo() *v1alpha1.ExtensionRepo {
   236  	p := f.JoinPath("my-repo", "my-ext", "Tiltfile")
   237  	f.WriteFile(p, "print('hello-world')")
   238  
   239  	repo := v1alpha1.ExtensionRepo{
   240  		ObjectMeta: metav1.ObjectMeta{
   241  			Name: "my-repo",
   242  		},
   243  		Spec: v1alpha1.ExtensionRepoSpec{
   244  			URL: fmt.Sprintf("file://%s", f.JoinPath("my-repo")),
   245  		},
   246  		Status: v1alpha1.ExtensionRepoStatus{
   247  			Path: f.JoinPath("my-repo"),
   248  		},
   249  	}
   250  	f.Create(&repo)
   251  	return &repo
   252  }
   253  
   254  func (f *fixture) setupRepoSubpath(subpath string) *v1alpha1.ExtensionRepo {
   255  	p := f.JoinPath("my-repo", subpath, "my-ext", "Tiltfile")
   256  	f.WriteFile(p, "print('hello-world')")
   257  
   258  	repo := v1alpha1.ExtensionRepo{
   259  		ObjectMeta: metav1.ObjectMeta{
   260  			Name: "my-repo",
   261  		},
   262  		Spec: v1alpha1.ExtensionRepoSpec{
   263  			URL:        fmt.Sprintf("file://%s", f.JoinPath("my-repo")),
   264  			GitSubpath: subpath,
   265  		},
   266  		Status: v1alpha1.ExtensionRepoStatus{
   267  			Path: f.JoinPath("my-repo"),
   268  		},
   269  	}
   270  	f.Create(&repo)
   271  	return &repo
   272  }