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 }