github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/internal/controllers/apis/restarton/restarton_test.go (about)

     1  package restarton
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"strings"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/davecgh/go-spew/spew"
    11  	"github.com/stretchr/testify/assert"
    12  	"github.com/stretchr/testify/require"
    13  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    14  	"k8s.io/apimachinery/pkg/runtime/schema"
    15  	"k8s.io/apimachinery/pkg/types"
    16  	ctrl "sigs.k8s.io/controller-runtime"
    17  	"sigs.k8s.io/controller-runtime/pkg/builder"
    18  	ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
    19  	"sigs.k8s.io/controller-runtime/pkg/reconcile"
    20  
    21  	"github.com/tilt-dev/tilt/internal/controllers/fake"
    22  	"github.com/tilt-dev/tilt/internal/controllers/indexer"
    23  	"github.com/tilt-dev/tilt/pkg/apis/core/v1alpha1"
    24  )
    25  
    26  func TestExtractKeysForIndexer(t *testing.T) {
    27  	const ns = "fake-ns"
    28  
    29  	key := func(name string, kind string) indexer.Key {
    30  		return indexer.Key{
    31  			Name: types.NamespacedName{Namespace: ns, Name: name},
    32  			GVK: schema.GroupVersionKind{
    33  				Group:   "tilt.dev",
    34  				Version: "v1alpha1",
    35  				Kind:    kind,
    36  			},
    37  		}
    38  	}
    39  
    40  	fwKey := func(name string) indexer.Key {
    41  		return key(name, "FileWatch")
    42  	}
    43  
    44  	btnKey := func(name string) indexer.Key {
    45  		return key(name, "UIButton")
    46  	}
    47  
    48  	type tc struct {
    49  		restartOn *v1alpha1.RestartOnSpec
    50  		startOn   *v1alpha1.StartOnSpec
    51  		expected  []indexer.Key
    52  	}
    53  
    54  	tcs := []tc{
    55  		{nil, nil, []indexer.Key(nil)},
    56  		{
    57  			&v1alpha1.RestartOnSpec{FileWatches: []string{"foo"}},
    58  			nil,
    59  			[]indexer.Key{fwKey("foo")},
    60  		},
    61  		{
    62  			nil,
    63  			&v1alpha1.StartOnSpec{UIButtons: []string{"btn"}},
    64  			[]indexer.Key{btnKey("btn")},
    65  		},
    66  		{
    67  			&v1alpha1.RestartOnSpec{FileWatches: []string{"foo"}, UIButtons: []string{"bar"}},
    68  			&v1alpha1.StartOnSpec{UIButtons: []string{"baz"}},
    69  			[]indexer.Key{fwKey("foo"), btnKey("bar"), btnKey("baz")},
    70  		},
    71  	}
    72  
    73  	for _, tc := range tcs {
    74  		keys := extractKeysForIndexer(ns, tc.restartOn, tc.startOn)
    75  		assert.ElementsMatchf(t, tc.expected, keys,
    76  			"Indexer keys did not match\nRestartOnSpec: %s\nStartOnSpec: %s",
    77  			strings.TrimSpace(spew.Sdump(tc.restartOn)),
    78  			spew.Sdump(tc.startOn))
    79  	}
    80  }
    81  
    82  func TestFetchObjects(t *testing.T) {
    83  	f := fake.NewControllerFixtureBuilder(t).Build(noopController{})
    84  
    85  	f.Create(&v1alpha1.FileWatch{ObjectMeta: metav1.ObjectMeta{Name: "fw1"}})
    86  	f.Create(&v1alpha1.FileWatch{ObjectMeta: metav1.ObjectMeta{Name: "fw2"}})
    87  	f.Create(&v1alpha1.UIButton{ObjectMeta: metav1.ObjectMeta{Name: "btn1"}})
    88  	f.Create(&v1alpha1.UIButton{ObjectMeta: metav1.ObjectMeta{Name: "btn2"}})
    89  
    90  	triggerObjs, err := FetchObjects(f.Context(), f.Client,
    91  		&v1alpha1.RestartOnSpec{
    92  			FileWatches: []string{"fw1", "fw2", "fw3"},
    93  			UIButtons:   []string{"btn1"},
    94  		},
    95  		&v1alpha1.StartOnSpec{
    96  			UIButtons: []string{"btn2", "btn3"},
    97  		})
    98  	require.NoError(t, err)
    99  	assert.NotNil(t, triggerObjs.FileWatches["fw1"])
   100  	assert.NotNil(t, triggerObjs.FileWatches["fw2"])
   101  	// fw3 doesn't exist but should have been silently ignored
   102  	assert.Nil(t, triggerObjs.FileWatches["fw3"])
   103  
   104  	assert.NotNil(t, triggerObjs.UIButtons["btn1"])
   105  	assert.NotNil(t, triggerObjs.UIButtons["btn2"])
   106  	// btn3 doesn't exist but should have been silently ignored
   107  	assert.Nil(t, triggerObjs.UIButtons["btn3"])
   108  }
   109  
   110  func TestFetchObjects_Error(t *testing.T) {
   111  	cli := &explodingReader{err: errors.New("oh no")}
   112  	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
   113  	defer cancel()
   114  	triggerObjs, err := FetchObjects(ctx, cli, &v1alpha1.RestartOnSpec{FileWatches: []string{"fw"}}, nil)
   115  	require.Error(t, err, "FetchObjects should have failed with an error")
   116  	require.Empty(t, triggerObjs.FileWatches)
   117  	require.Empty(t, triggerObjs.UIButtons)
   118  }
   119  
   120  type noopController struct{}
   121  
   122  func (n noopController) CreateBuilder(_ ctrl.Manager) (*builder.Builder, error) {
   123  	return nil, nil
   124  }
   125  
   126  func (n noopController) Reconcile(_ context.Context, _ reconcile.Request) (reconcile.Result, error) {
   127  	return reconcile.Result{}, nil
   128  }
   129  
   130  type explodingReader struct {
   131  	err error
   132  }
   133  
   134  func (e explodingReader) Get(_ context.Context, _ ctrlclient.ObjectKey, _ ctrlclient.Object, _ ...ctrlclient.GetOption) error {
   135  	return e.err
   136  }
   137  
   138  func (e explodingReader) List(_ context.Context, _ ctrlclient.ObjectList, _ ...ctrlclient.ListOption) error {
   139  	return e.err
   140  }