github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/pkg/model/manifest_test.go (about)

     1  package model
     2  
     3  import (
     4  	"fmt"
     5  	"net/url"
     6  	"testing"
     7  
     8  	"github.com/stretchr/testify/assert"
     9  
    10  	"github.com/tilt-dev/tilt/internal/container"
    11  	"github.com/tilt-dev/tilt/pkg/apis/core/v1alpha1"
    12  )
    13  
    14  var portFwd8000 = []v1alpha1.Forward{{LocalPort: 8080}}
    15  var portFwd8001 = []v1alpha1.Forward{{LocalPort: 8081}}
    16  
    17  var img1 = container.MustParseSelector("blorg.io/blorgdev/blorg-frontend:tilt-361d98a2d335373f")
    18  var img2 = container.MustParseSelector("blorg.io/blorgdev/blorg-backend:tilt-361d98a2d335373f")
    19  
    20  var equalitytests = []struct {
    21  	name                string
    22  	m1                  Manifest
    23  	m2                  Manifest
    24  	expectedInvalidates bool
    25  }{
    26  	{
    27  		"empty manifests equal",
    28  		Manifest{},
    29  		Manifest{},
    30  		false,
    31  	},
    32  	{
    33  		"PortForwards unequal",
    34  		Manifest{}.WithDeployTarget(K8sTarget{
    35  			KubernetesApplySpec: v1alpha1.KubernetesApplySpec{
    36  				PortForwardTemplateSpec: &v1alpha1.PortForwardTemplateSpec{Forwards: portFwd8000},
    37  			},
    38  		}),
    39  		Manifest{}.WithDeployTarget(K8sTarget{
    40  			KubernetesApplySpec: v1alpha1.KubernetesApplySpec{
    41  				PortForwardTemplateSpec: &v1alpha1.PortForwardTemplateSpec{Forwards: portFwd8001},
    42  			},
    43  		}),
    44  		true,
    45  	},
    46  	{
    47  		"PortForwards equal",
    48  		Manifest{}.WithDeployTarget(K8sTarget{
    49  			KubernetesApplySpec: v1alpha1.KubernetesApplySpec{
    50  				PortForwardTemplateSpec: &v1alpha1.PortForwardTemplateSpec{Forwards: portFwd8000},
    51  			},
    52  		}),
    53  		Manifest{}.WithDeployTarget(K8sTarget{
    54  			KubernetesApplySpec: v1alpha1.KubernetesApplySpec{
    55  				PortForwardTemplateSpec: &v1alpha1.PortForwardTemplateSpec{Forwards: portFwd8000},
    56  			},
    57  		}),
    58  		false,
    59  	},
    60  	{
    61  		"ImageTarget.ImageMapSpec.Selector unequal",
    62  		Manifest{}.WithImageTarget(ImageTarget{ImageMapSpec: v1alpha1.ImageMapSpec{Selector: img1.RefFamiliarString()}}),
    63  		Manifest{}.WithImageTarget(ImageTarget{ImageMapSpec: v1alpha1.ImageMapSpec{Selector: img2.RefFamiliarString()}}),
    64  		true,
    65  	},
    66  	{
    67  		"ImageTarget.ConfigurationRef equal",
    68  		Manifest{}.WithImageTarget(ImageTarget{ImageMapSpec: v1alpha1.ImageMapSpec{Selector: img1.RefFamiliarString()}}),
    69  		Manifest{}.WithImageTarget(ImageTarget{ImageMapSpec: v1alpha1.ImageMapSpec{Selector: img1.RefFamiliarString()}}),
    70  		false,
    71  	},
    72  	{
    73  		"k8s.YAML equal",
    74  		Manifest{}.WithDeployTarget(NewK8sTargetForTesting("hello world")),
    75  		Manifest{}.WithDeployTarget(NewK8sTargetForTesting("hello world")),
    76  		false,
    77  	},
    78  	{
    79  		"k8s.YAML unequal",
    80  		Manifest{}.WithDeployTarget(NewK8sTargetForTesting("hello world")),
    81  		Manifest{}.WithDeployTarget(NewK8sTargetForTesting("goodbye world")),
    82  		true,
    83  	},
    84  	{
    85  		"TriggerMode equal",
    86  		Manifest{TriggerMode: TriggerModeManualWithAutoInit},
    87  		Manifest{TriggerMode: TriggerModeManualWithAutoInit},
    88  		false,
    89  	},
    90  	{
    91  		"TriggerMode unequal",
    92  		Manifest{TriggerMode: TriggerModeAuto},
    93  		Manifest{TriggerMode: TriggerModeManualWithAutoInit},
    94  		false,
    95  	},
    96  	{
    97  		"Name equal",
    98  		Manifest{Name: "foo"},
    99  		Manifest{Name: "bar"},
   100  		false,
   101  	},
   102  	{
   103  		"Name & k8s YAML unequal",
   104  		Manifest{Name: "foo"}.WithDeployTarget(NewK8sTargetForTesting("hello world")),
   105  		Manifest{Name: "bar"}.WithDeployTarget(NewK8sTargetForTesting("goodbye world")),
   106  		true,
   107  	},
   108  	{
   109  		"LocalTarget equal",
   110  		Manifest{}.WithDeployTarget(NewLocalTarget("foo", ToHostCmdInDir("beep boop", "path/to/tiltfile"), Cmd{}, []string{"bar", "baz"})),
   111  		Manifest{}.WithDeployTarget(NewLocalTarget("foo", ToHostCmdInDir("beep boop", "path/to/tiltfile"), Cmd{}, []string{"bar", "baz"})),
   112  		false,
   113  	},
   114  	{
   115  		"LocalTarget.Name unequal",
   116  		Manifest{}.WithDeployTarget(NewLocalTarget("foo", ToHostCmdInDir("beep boop", "path/to/tiltfile"), Cmd{}, []string{"bar", "baz"})),
   117  		Manifest{}.WithDeployTarget(NewLocalTarget("foooooo", ToHostCmdInDir("beep boop", "path/to/tiltfile"), Cmd{}, []string{"bar", "baz"})),
   118  		true,
   119  	},
   120  	{
   121  		"LocalTarget.UpdateCmd unequal",
   122  		Manifest{}.WithDeployTarget(NewLocalTarget("foo", ToHostCmdInDir("beep boop", "path/to/tiltfile"), Cmd{}, []string{"bar", "baz"})),
   123  		Manifest{}.WithDeployTarget(NewLocalTarget("foo", ToHostCmdInDir("bippity boppity", "path/to/tiltfile"), Cmd{}, []string{"bar", "baz"})),
   124  		true,
   125  	},
   126  	{
   127  		"LocalTarget.workdir unequal",
   128  		Manifest{}.WithDeployTarget(NewLocalTarget("foo", ToHostCmdInDir("beep boop", "path/to/tiltfile"), Cmd{}, []string{"bar", "baz"})),
   129  		Manifest{}.WithDeployTarget(NewLocalTarget("foo", ToHostCmdInDir("beep boop", "some/other/path"), Cmd{}, []string{"bar", "baz"})),
   130  		true,
   131  	},
   132  	{
   133  		"LocalTarget.Deps unequal and doesn't invalidate",
   134  		Manifest{}.WithDeployTarget(NewLocalTarget("foo", ToHostCmd("beep boop"), Cmd{}, []string{"bar", "baz"})),
   135  		Manifest{}.WithDeployTarget(NewLocalTarget("foo", ToHostCmd("beep boop"), Cmd{}, []string{"quux", "baz"})),
   136  		false,
   137  	},
   138  	{
   139  		"CustomBuild.Deps unequal and doesn't invalidate",
   140  		Manifest{}.WithImageTarget(ImageTarget{}.WithBuildDetails(CustomBuild{Deps: []string{"foo", "bar"}})),
   141  		Manifest{}.WithImageTarget(ImageTarget{}.WithBuildDetails(CustomBuild{Deps: []string{"bar", "quux"}})),
   142  		false,
   143  	},
   144  	{
   145  		"labels unequal and doesn't invalidate",
   146  		Manifest{}.WithLabels(map[string]string{"foo": "bar"}),
   147  		Manifest{}.WithLabels(map[string]string{"foo": "baz"}),
   148  		false,
   149  	},
   150  	{
   151  		"Links unequal and doesn't invalidate",
   152  		Manifest{}.WithDeployTarget(NewLocalTarget("foo", Cmd{}, Cmd{}, nil).WithLinks([]Link{
   153  			{Name: "bar", URL: mustURL("mysql://root:password@localhost:3306/mydbname")},
   154  		})),
   155  		Manifest{}.WithDeployTarget(NewLocalTarget("foo", Cmd{}, Cmd{}, nil).WithLinks([]Link{
   156  			// the username is changed because if not properly ignored, that will cause a panic due to url.Userinfo
   157  			// having unexported fields [everything else remains the same to avoid go-cmp short-circuiting elsewhere]
   158  			{Name: "bar", URL: mustURL("mysql://r00t:password@localhost:3306/mydbname")},
   159  		})),
   160  		false,
   161  	},
   162  }
   163  
   164  func TestManifestEquality(t *testing.T) {
   165  	for _, c := range equalitytests {
   166  		t.Run(c.name, func(t *testing.T) {
   167  			actualInvalidates := ChangesInvalidateBuild(c.m1, c.m2)
   168  
   169  			if actualInvalidates != c.expectedInvalidates {
   170  				t.Errorf("Expected m1 -> m2 invalidates build to be %t, but got %t\n\tm1: %+v\n\tm2: %+v", c.expectedInvalidates, actualInvalidates, c.m1, c.m2)
   171  			}
   172  		})
   173  	}
   174  }
   175  
   176  func TestDCTargetValidate(t *testing.T) {
   177  	targ := DockerComposeTarget{
   178  		Name: "blah",
   179  		Spec: v1alpha1.DockerComposeServiceSpec{
   180  			Service: "blah",
   181  			Project: v1alpha1.DockerComposeProject{
   182  				ConfigPaths: []string{"docker-compose.yml"},
   183  			},
   184  		},
   185  	}
   186  	err := targ.Validate()
   187  	assert.NoError(t, err)
   188  
   189  	noConfPath := DockerComposeTarget{Name: "blah"}
   190  	err = noConfPath.Validate()
   191  	if assert.Error(t, err) {
   192  		assert.Contains(t, err.Error(), "missing config path")
   193  	}
   194  
   195  	noName := DockerComposeTarget{
   196  		Spec: v1alpha1.DockerComposeServiceSpec{
   197  			Service: "blah",
   198  			Project: v1alpha1.DockerComposeProject{
   199  				ConfigPaths: []string{"docker-compose.yml"},
   200  			},
   201  		},
   202  	}
   203  	err = noName.Validate()
   204  	if assert.Error(t, err) {
   205  		assert.Contains(t, err.Error(), "missing name")
   206  	}
   207  }
   208  
   209  func TestHostCmdToString(t *testing.T) {
   210  	cmd := ToHostCmd("echo hi")
   211  	assert.Equal(t, "echo hi", cmd.String())
   212  }
   213  
   214  func mustURL(v string) *url.URL {
   215  	u, err := url.Parse(v)
   216  	if err != nil {
   217  		panic(fmt.Errorf("failed to parse URL[%s]: %v", v, err))
   218  	}
   219  	return u
   220  }