github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/internal/hud/webview/convert_test.go (about) 1 package webview 2 3 import ( 4 "testing" 5 "time" 6 7 v1 "k8s.io/api/core/v1" 8 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 9 "k8s.io/apimachinery/pkg/util/uuid" 10 11 "github.com/tilt-dev/tilt/internal/store/k8sconv" 12 "github.com/tilt-dev/tilt/pkg/apis/core/v1alpha1" 13 14 "github.com/stretchr/testify/assert" 15 "github.com/stretchr/testify/require" 16 17 ctrltiltfile "github.com/tilt-dev/tilt/internal/controllers/core/tiltfile" 18 "github.com/tilt-dev/tilt/internal/k8s" 19 "github.com/tilt-dev/tilt/internal/k8s/testyaml" 20 "github.com/tilt-dev/tilt/internal/store" 21 "github.com/tilt-dev/tilt/internal/testutils/tempdir" 22 "github.com/tilt-dev/tilt/internal/timecmp" 23 "github.com/tilt-dev/tilt/pkg/logger" 24 "github.com/tilt-dev/tilt/pkg/model" 25 proto_webview "github.com/tilt-dev/tilt/pkg/webview" 26 ) 27 28 var fooManifest = model.Manifest{Name: "foo"}.WithDeployTarget(model.K8sTarget{}) 29 30 func completeProtoView(t *testing.T, s store.EngineState) *proto_webview.View { 31 st := store.NewTestingStore() 32 st.SetState(s) 33 34 view, err := LogUpdate(st, 0) 35 require.NoError(t, err) 36 37 view.UiSession = ToUISession(s) 38 39 resources, err := ToUIResourceList(s, make(map[string][]v1alpha1.DisableSource)) 40 require.NoError(t, err) 41 view.UiResources = resources 42 43 sortUIResources(view.UiResources, s.ManifestDefinitionOrder) 44 45 return view 46 } 47 48 func TestStateToWebViewRelativeEditPaths(t *testing.T) { 49 f := tempdir.NewTempDirFixture(t) 50 51 m := model.Manifest{ 52 Name: "foo", 53 }.WithDeployTarget(model.K8sTarget{}).WithImageTarget(model.ImageTarget{}. 54 WithDockerImage(v1alpha1.DockerImageSpec{Context: f.JoinPath("a", "b", "c")})) 55 56 state := newState([]model.Manifest{m}) 57 ms := state.ManifestTargets[m.Name].State 58 ms.BuildHistory = []model.BuildRecord{ 59 {}, 60 } 61 ms.MutableBuildStatus(m.ImageTargets[0].ID()).PendingFileChanges = 62 map[string]time.Time{ 63 f.JoinPath("a", "b", "c", "foo"): time.Now(), 64 f.JoinPath("a", "b", "c", "d", "e"): time.Now(), 65 } 66 v := completeProtoView(t, *state) 67 68 require.Len(t, v.UiResources, 2) 69 } 70 71 func TestStateToWebViewPortForwards(t *testing.T) { 72 m := model.Manifest{ 73 Name: "foo", 74 }.WithDeployTarget(model.K8sTarget{ 75 KubernetesApplySpec: v1alpha1.KubernetesApplySpec{ 76 PortForwardTemplateSpec: &v1alpha1.PortForwardTemplateSpec{ 77 Forwards: []v1alpha1.Forward{ 78 {LocalPort: 8000, ContainerPort: 5000}, 79 {LocalPort: 7000, ContainerPort: 5001}, 80 {LocalPort: 5000, ContainerPort: 5002, Host: "127.0.0.2", Name: "dashboard"}, 81 {LocalPort: 6000, ContainerPort: 5003, Name: "debugger"}, 82 }, 83 }, 84 }, 85 }) 86 state := newState([]model.Manifest{m}) 87 v := completeProtoView(t, *state) 88 89 expected := []v1alpha1.UIResourceLink{ 90 v1alpha1.UIResourceLink{URL: "http://localhost:8000/"}, 91 v1alpha1.UIResourceLink{URL: "http://localhost:7000/"}, 92 v1alpha1.UIResourceLink{URL: "http://127.0.0.2:5000/", Name: "dashboard"}, 93 v1alpha1.UIResourceLink{URL: "http://localhost:6000/", Name: "debugger"}, 94 } 95 res, _ := findResource(m.Name, v) 96 assert.Equal(t, expected, res.EndpointLinks) 97 } 98 99 func TestStateToWebViewLinksAndPortForwards(t *testing.T) { 100 m := model.Manifest{ 101 Name: "foo", 102 }.WithDeployTarget(model.K8sTarget{ 103 KubernetesApplySpec: v1alpha1.KubernetesApplySpec{ 104 PortForwardTemplateSpec: &v1alpha1.PortForwardTemplateSpec{ 105 Forwards: []v1alpha1.Forward{ 106 {LocalPort: 8000, ContainerPort: 5000}, 107 {LocalPort: 8001, ContainerPort: 5001, Name: "debugger"}, 108 }, 109 }, 110 }, 111 Links: []model.Link{ 112 model.MustNewLink("www.apple.edu", "apple"), 113 model.MustNewLink("www.zombo.com", "zombo"), 114 }, 115 }) 116 state := newState([]model.Manifest{m}) 117 v := completeProtoView(t, *state) 118 119 expected := []v1alpha1.UIResourceLink{ 120 v1alpha1.UIResourceLink{URL: "www.apple.edu", Name: "apple"}, 121 v1alpha1.UIResourceLink{URL: "www.zombo.com", Name: "zombo"}, 122 v1alpha1.UIResourceLink{URL: "http://localhost:8000/"}, 123 v1alpha1.UIResourceLink{URL: "http://localhost:8001/", Name: "debugger"}, 124 } 125 res, _ := findResource(m.Name, v) 126 assert.Equal(t, expected, res.EndpointLinks) 127 } 128 129 func TestStateToWebViewLocalResourceLink(t *testing.T) { 130 m := model.Manifest{ 131 Name: "foo", 132 }.WithDeployTarget(model.LocalTarget{ 133 Links: []model.Link{ 134 model.MustNewLink("www.apple.edu", "apple"), 135 model.MustNewLink("www.zombo.com", "zombo"), 136 }, 137 }) 138 state := newState([]model.Manifest{m}) 139 v := completeProtoView(t, *state) 140 141 expected := []v1alpha1.UIResourceLink{ 142 v1alpha1.UIResourceLink{URL: "www.apple.edu", Name: "apple"}, 143 v1alpha1.UIResourceLink{URL: "www.zombo.com", Name: "zombo"}, 144 } 145 res, _ := findResource(m.Name, v) 146 assert.Equal(t, expected, res.EndpointLinks) 147 } 148 149 func TestStateToViewUnresourcedYAMLManifest(t *testing.T) { 150 mn := model.UnresourcedYAMLManifestName 151 m := model.Manifest{Name: mn}.WithDeployTarget(k8s.MustTarget(mn.TargetName(), testyaml.SanchoYAML)) 152 state := newState([]model.Manifest{m}) 153 v := completeProtoView(t, *state) 154 155 assert.Equal(t, 2, len(v.UiResources)) 156 157 r, _ := findResource(m.Name, v) 158 assert.Equal(t, "", lastBuild(r).Error) 159 } 160 161 func TestStateToViewK8sTargetsIncludeDisplayNames(t *testing.T) { 162 m := model.Manifest{Name: "foo"}.WithDeployTarget(model.K8sTarget{}) 163 state := newState([]model.Manifest{m}) 164 krs := state.ManifestTargets["foo"].State.K8sRuntimeState() 165 krs.ApplyFilter = &k8sconv.KubernetesApplyFilter{ 166 DeployedRefs: []v1.ObjectReference{ 167 {Kind: "Namespace", Name: "foo"}, 168 {Kind: "Secret", Name: "foo"}, 169 }, 170 } 171 state.ManifestTargets["foo"].State.RuntimeState = krs 172 173 v := completeProtoView(t, *state) 174 175 assert.Equal(t, 2, len(v.UiResources)) 176 177 r, _ := findResource(m.Name, v) 178 179 assert.Equal(t, []string{"foo:namespace", "foo:secret"}, r.K8sResourceInfo.DisplayNames) 180 } 181 182 func TestStateToViewTiltfileLog(t *testing.T) { 183 es := newState([]model.Manifest{}) 184 spanID := ctrltiltfile.SpanIDForLoadCount("(Tiltfile)", 1) 185 es.LogStore.Append( 186 store.NewLogAction(store.MainTiltfileManifestName, spanID, logger.InfoLvl, nil, []byte("hello")), 187 nil) 188 v := completeProtoView(t, *es) 189 _, ok := findResource("(Tiltfile)", v) 190 require.True(t, ok, "no resource named (Tiltfile) found") 191 assert.Equal(t, "hello", v.LogList.Segments[0].Text) 192 assert.Equal(t, "(Tiltfile)", v.LogList.Spans[string(spanID)].ManifestName) 193 } 194 195 func TestNeedsNudgeSet(t *testing.T) { 196 state := newState(nil) 197 198 m := fooManifest 199 targ := store.NewManifestTarget(m) 200 targ.State = &store.ManifestState{} 201 state.UpsertManifestTarget(targ) 202 203 v := completeProtoView(t, *state) 204 205 assert.False(t, v.UiSession.Status.NeedsAnalyticsNudge, 206 "LastSuccessfulDeployTime not set, so NeedsNudge should not be set") 207 208 targ.State = &store.ManifestState{LastSuccessfulDeployTime: time.Now()} 209 state.UpsertManifestTarget(targ) 210 211 v = completeProtoView(t, *state) 212 assert.True(t, v.UiSession.Status.NeedsAnalyticsNudge) 213 } 214 215 func TestTriggerMode(t *testing.T) { 216 state := newState(nil) 217 m := fooManifest 218 targ := store.NewManifestTarget(m) 219 targ.Manifest.TriggerMode = model.TriggerModeManualWithAutoInit 220 targ.State = &store.ManifestState{} 221 state.UpsertManifestTarget(targ) 222 223 v := completeProtoView(t, *state) 224 assert.Equal(t, 2, len(v.UiResources)) 225 226 newM, _ := findResource(model.ManifestName("foo"), v) 227 assert.Equal(t, model.TriggerModeManualWithAutoInit, model.TriggerMode(newM.TriggerMode)) 228 } 229 230 func TestFeatureFlags(t *testing.T) { 231 state := newState(nil) 232 state.Features = map[string]bool{"foo_feature": true} 233 234 v := completeProtoView(t, *state) 235 assert.Equal(t, v.UiSession.Status.FeatureFlags, []v1alpha1.UIFeatureFlag{ 236 v1alpha1.UIFeatureFlag{Name: "foo_feature", Value: true}, 237 }) 238 } 239 240 func TestReadinessCheckFailing(t *testing.T) { 241 m := model.Manifest{ 242 Name: "foo", 243 }.WithDeployTarget(model.K8sTarget{}) 244 state := newState([]model.Manifest{m}) 245 state.ManifestTargets[m.Name].State.RuntimeState = store.NewK8sRuntimeStateWithPods(m, v1alpha1.Pod{ 246 Name: "pod-id", 247 Status: "Running", 248 Phase: "Running", 249 Containers: []v1alpha1.Container{ 250 { 251 Ready: false, 252 }, 253 }, 254 }) 255 256 v := completeProtoView(t, *state) 257 rv, ok := findResource(m.Name, v) 258 require.True(t, ok) 259 require.Equal(t, v1alpha1.RuntimeStatusPending, rv.RuntimeStatus) 260 require.Equal(t, "False", string(readyCondition(rv).Status)) 261 } 262 263 func TestRuntimeErrorAndDisabled(t *testing.T) { 264 m := model.Manifest{ 265 Name: "foo", 266 }.WithDeployTarget(model.K8sTarget{}) 267 state := newState([]model.Manifest{m}) 268 mt := state.ManifestTargets[m.Name] 269 mt.State.RuntimeState = store.NewK8sRuntimeStateWithPods(m, v1alpha1.Pod{ 270 Name: "pod-id", 271 Status: "Error", 272 Phase: string(v1.PodFailed), 273 Containers: []v1alpha1.Container{ 274 { 275 Ready: false, 276 }, 277 }, 278 }) 279 280 state.ConfigMaps["foo-disable"] = &v1alpha1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "disabled"}, Data: map[string]string{"isDisabled": "true"}} 281 disableSources := map[string][]v1alpha1.DisableSource{ 282 "foo": { 283 {ConfigMap: &v1alpha1.ConfigMapDisableSource{Name: "foo-disable", Key: "isDisabled"}}, 284 }, 285 } 286 uiResources, err := ToUIResourceList(*state, disableSources) 287 require.NoError(t, err) 288 require.Equal(t, m.Name.String(), uiResources[1].Name) 289 290 rv := uiResources[1].Status 291 rc := readyCondition(rv) 292 require.Equal(t, "False", string(rc.Status)) 293 require.Equal(t, "Disabled", rc.Reason) 294 uc := upToDateCondition(rv) 295 require.Equal(t, "False", string(uc.Status)) 296 require.Equal(t, "Disabled", uc.Reason) 297 require.Equal(t, v1alpha1.RuntimeStatusNone, rv.RuntimeStatus) 298 require.Equal(t, v1alpha1.UpdateStatusNone, rv.UpdateStatus) 299 } 300 301 func TestLocalResource(t *testing.T) { 302 cmd := model.Cmd{ 303 Argv: []string{"make", "test"}, 304 Dir: "path/to/tiltfile", 305 } 306 lt := model.NewLocalTarget("my-local", cmd, model.Cmd{}, []string{"/foo/bar", "/baz/qux"}) 307 m := model.Manifest{ 308 Name: "test", 309 }.WithDeployTarget(lt) 310 311 state := newState([]model.Manifest{m}) 312 lrs := store.LocalRuntimeState{Status: v1alpha1.RuntimeStatusNotApplicable} 313 state.ManifestTargets[m.Name].State.RuntimeState = lrs 314 v := completeProtoView(t, *state) 315 316 assert.Equal(t, 2, len(v.UiResources)) 317 r := v.UiResources[1] 318 rs := r.Status 319 assert.Equal(t, "test", r.Name) 320 assert.Equal(t, v1alpha1.RuntimeStatusNotApplicable, rs.RuntimeStatus) 321 require.Equal(t, "False", string(readyCondition(rs).Status)) 322 require.Len(t, rs.Specs, 1) 323 spec := rs.Specs[0] 324 require.Equal(t, v1alpha1.UIResourceTargetTypeLocal, spec.Type) 325 require.False(t, spec.HasLiveUpdate) 326 } 327 328 func TestBuildHistory(t *testing.T) { 329 br1 := model.BuildRecord{ 330 StartTime: time.Now().Add(-1 * time.Hour), 331 FinishTime: time.Now().Add(-50 * time.Minute), 332 Reason: model.BuildReasonFlagInit, 333 BuildTypes: []model.BuildType{model.BuildTypeImage, model.BuildTypeK8s}, 334 } 335 br2 := model.BuildRecord{ 336 StartTime: time.Now().Add(-45 * time.Minute), 337 FinishTime: time.Now().Add(-44 * time.Minute), 338 Reason: model.BuildReasonFlagChangedFiles, 339 BuildTypes: []model.BuildType{model.BuildTypeLiveUpdate}, 340 } 341 br3 := model.BuildRecord{ 342 StartTime: time.Now().Add(-20 * time.Minute), 343 FinishTime: time.Now().Add(-19 * time.Minute), 344 Reason: model.BuildReasonFlagChangedFiles, 345 BuildTypes: []model.BuildType{model.BuildTypeImage, model.BuildTypeK8s}, 346 } 347 buildRecords := []model.BuildRecord{br1, br2, br3} 348 349 m := model.Manifest{Name: "foo"}.WithDeployTarget(model.K8sTarget{}) 350 state := newState([]model.Manifest{m}) 351 state.ManifestTargets[m.Name].State.BuildHistory = buildRecords 352 353 v := completeProtoView(t, *state) 354 require.Equal(t, 2, len(v.UiResources)) 355 r := v.UiResources[1] 356 require.Equal(t, "foo", r.Name) 357 358 rs := r.Status 359 require.Len(t, rs.BuildHistory, 3) 360 361 for i, actual := range rs.BuildHistory { 362 expected := buildRecords[i] 363 timecmp.AssertTimeEqual(t, expected.StartTime, actual.StartTime) 364 timecmp.AssertTimeEqual(t, expected.FinishTime, actual.FinishTime) 365 require.False(t, actual.IsCrashRebuild) 366 } 367 } 368 369 func TestSpecs(t *testing.T) { 370 luSpec := v1alpha1.LiveUpdateSpec{ 371 BasePath: ".", 372 Syncs: []v1alpha1.LiveUpdateSync{{LocalPath: "foo", ContainerPath: "bar"}}, 373 } 374 luTarg := model.ImageTarget{}.WithLiveUpdateSpec("sancho", luSpec).WithBuildDetails(model.DockerBuild{}) 375 376 mNoLiveUpd := model.Manifest{Name: "noLiveUpd"}.WithImageTarget(model.ImageTarget{}).WithDeployTarget(model.K8sTarget{}) 377 mLiveUpd := model.Manifest{Name: "liveUpd"}.WithImageTarget(luTarg).WithDeployTarget(model.K8sTarget{}) 378 mLocal := model.Manifest{Name: "local"}.WithDeployTarget(model.LocalTarget{}) 379 380 expected := []struct { 381 name string 382 targetTypes []v1alpha1.UIResourceTargetType 383 hasLiveUpdate bool 384 }{ 385 {"noLiveUpd", []v1alpha1.UIResourceTargetType{v1alpha1.UIResourceTargetTypeImage, v1alpha1.UIResourceTargetTypeKubernetes}, false}, 386 {"liveUpd", []v1alpha1.UIResourceTargetType{v1alpha1.UIResourceTargetTypeImage, v1alpha1.UIResourceTargetTypeKubernetes}, true}, 387 {"local", []v1alpha1.UIResourceTargetType{v1alpha1.UIResourceTargetTypeLocal}, false}, 388 } 389 state := newState([]model.Manifest{mNoLiveUpd, mLiveUpd, mLocal}) 390 v := completeProtoView(t, *state) 391 392 require.Equal(t, 4, len(v.UiResources)) 393 for i, r := range v.UiResources { 394 if i == 0 { 395 continue // skip Tiltfile 396 } 397 expected := expected[i-1] 398 require.Equal(t, expected.name, r.Name, "name mismatch for resource at index %d", i) 399 observedTypes := []v1alpha1.UIResourceTargetType{} 400 var iTargHasLU bool 401 rs := r.Status 402 for _, spec := range rs.Specs { 403 observedTypes = append(observedTypes, spec.Type) 404 if spec.Type == v1alpha1.UIResourceTargetTypeImage { 405 iTargHasLU = spec.HasLiveUpdate 406 } 407 } 408 require.ElementsMatch(t, expected.targetTypes, observedTypes, "for resource %q", r.Name) 409 require.Equal(t, expected.hasLiveUpdate, iTargHasLU, "for resource %q", r.Name) 410 } 411 } 412 413 func TestDisableResourceStatus(t *testing.T) { 414 for _, tc := range []struct { 415 name string 416 configMaps []*v1alpha1.ConfigMap 417 disableSources []v1alpha1.DisableSource 418 // `expected.Sources` will be automatically set to `disableSources`'s value 419 expected v1alpha1.DisableResourceStatus 420 }{ 421 { 422 "disabled", 423 []*v1alpha1.ConfigMap{{ObjectMeta: metav1.ObjectMeta{Name: "disable-m1"}, Data: map[string]string{"isDisabled": "true"}}}, 424 []v1alpha1.DisableSource{{ConfigMap: &v1alpha1.ConfigMapDisableSource{Name: "disable-m1", Key: "isDisabled"}}}, 425 v1alpha1.DisableResourceStatus{ 426 EnabledCount: 0, 427 DisabledCount: 1, 428 State: v1alpha1.DisableStateDisabled, 429 }, 430 }, 431 { 432 "some disabled", 433 []*v1alpha1.ConfigMap{ 434 {ObjectMeta: metav1.ObjectMeta{Name: "disable-m1a"}, Data: map[string]string{"isDisabled": "true"}}, 435 {ObjectMeta: metav1.ObjectMeta{Name: "disable-m1b"}, Data: map[string]string{"isDisabled": "true"}}, 436 {ObjectMeta: metav1.ObjectMeta{Name: "disable-m1c"}, Data: map[string]string{"isDisabled": "false"}}, 437 }, 438 []v1alpha1.DisableSource{ 439 {ConfigMap: &v1alpha1.ConfigMapDisableSource{Name: "disable-m1a", Key: "isDisabled"}}, 440 {ConfigMap: &v1alpha1.ConfigMapDisableSource{Name: "disable-m1b", Key: "isDisabled"}}, 441 {ConfigMap: &v1alpha1.ConfigMapDisableSource{Name: "disable-m1c", Key: "isDisabled"}}, 442 }, 443 v1alpha1.DisableResourceStatus{ 444 EnabledCount: 1, 445 DisabledCount: 2, 446 State: v1alpha1.DisableStateDisabled, 447 }, 448 }, 449 { 450 "no sources - enabled", 451 nil, 452 nil, 453 v1alpha1.DisableResourceStatus{ 454 EnabledCount: 0, 455 DisabledCount: 0, 456 Sources: nil, 457 State: v1alpha1.DisableStateEnabled, 458 }, 459 }, 460 { 461 "missing ConfigMap - pending", 462 nil, 463 []v1alpha1.DisableSource{{ConfigMap: &v1alpha1.ConfigMapDisableSource{Name: "disable-m1", Key: "isDisabled"}}}, 464 v1alpha1.DisableResourceStatus{ 465 EnabledCount: 0, 466 DisabledCount: 0, 467 State: v1alpha1.DisableStatePending, 468 }, 469 }, 470 { 471 "error trumps all", 472 []*v1alpha1.ConfigMap{ 473 {ObjectMeta: metav1.ObjectMeta{Name: "enabled"}, Data: map[string]string{"isDisabled": "false"}}, 474 {ObjectMeta: metav1.ObjectMeta{Name: "disabled"}, Data: map[string]string{"isDisabled": "true"}}, 475 {ObjectMeta: metav1.ObjectMeta{Name: "error"}, Data: map[string]string{}}, 476 }, 477 []v1alpha1.DisableSource{ 478 {ConfigMap: &v1alpha1.ConfigMapDisableSource{Name: "enabled", Key: "isDisabled"}}, 479 {ConfigMap: &v1alpha1.ConfigMapDisableSource{Name: "disabled", Key: "isDisabled"}}, 480 {ConfigMap: &v1alpha1.ConfigMapDisableSource{Name: "error", Key: "isDisabled"}}, 481 {ConfigMap: &v1alpha1.ConfigMapDisableSource{Name: "pending", Key: "isDisabled"}}, 482 }, 483 v1alpha1.DisableResourceStatus{ 484 EnabledCount: 1, 485 DisabledCount: 2, 486 State: v1alpha1.DisableStateError, 487 }, 488 }, 489 { 490 "pending trumps enabled/disabled", 491 []*v1alpha1.ConfigMap{ 492 {ObjectMeta: metav1.ObjectMeta{Name: "enabled"}, Data: map[string]string{"isDisabled": "false"}}, 493 {ObjectMeta: metav1.ObjectMeta{Name: "disabled"}, Data: map[string]string{"isDisabled": "true"}}, 494 }, 495 []v1alpha1.DisableSource{ 496 {ConfigMap: &v1alpha1.ConfigMapDisableSource{Name: "enabled", Key: "isDisabled"}}, 497 {ConfigMap: &v1alpha1.ConfigMapDisableSource{Name: "pending", Key: "isDisabled"}}, 498 {ConfigMap: &v1alpha1.ConfigMapDisableSource{Name: "disabled", Key: "isDisabled"}}, 499 }, 500 v1alpha1.DisableResourceStatus{ 501 EnabledCount: 1, 502 DisabledCount: 1, 503 State: v1alpha1.DisableStatePending, 504 }, 505 }, 506 } { 507 t.Run(tc.name, func(t *testing.T) { 508 m := model.Manifest{Name: "testmanifest"}.WithDeployTarget(model.LocalTarget{}) 509 state := newState([]model.Manifest{m}) 510 state.ConfigMaps = make(map[string]*v1alpha1.ConfigMap) 511 for _, cm := range tc.configMaps { 512 state.ConfigMaps[cm.Name] = cm 513 } 514 disableSources := map[string][]v1alpha1.DisableSource{ 515 m.Name.String(): tc.disableSources, 516 } 517 uiResources, err := ToUIResourceList(*state, disableSources) 518 require.NoError(t, err) 519 520 require.Equal(t, 2, len(uiResources)) 521 require.Equal(t, "(Tiltfile)", uiResources[0].Name) 522 require.Equal(t, m.Name.String(), uiResources[1].Name) 523 tc.expected.Sources = tc.disableSources 524 require.Equal(t, tc.expected, uiResources[1].Status.DisableStatus) 525 }) 526 } 527 } 528 529 func TestTiltfileNameCollision(t *testing.T) { 530 m := model.Manifest{Name: "collision"}.WithDeployTarget(model.LocalTarget{}) 531 state := newState([]model.Manifest{m}) 532 state.Tiltfiles["collision"] = &v1alpha1.Tiltfile{} 533 state.TiltfileDefinitionOrder = append(state.TiltfileDefinitionOrder, "collision") 534 state.TiltfileStates["collision"] = &store.ManifestState{ 535 Name: model.MainTiltfileManifestName, 536 BuildStatuses: make(map[model.TargetID]*store.BuildStatus), 537 DisableState: v1alpha1.DisableStateEnabled, 538 CurrentBuilds: make(map[string]model.BuildRecord), 539 } 540 541 _, err := ToUIResourceList(*state, nil) 542 require.EqualError(t, err, `Tiltfile "collision" has the same name as a local resource`) 543 } 544 545 func TestExtensionNameCollision(t *testing.T) { 546 m := model.Manifest{Name: "collision"}.WithDeployTarget(model.K8sTarget{}) 547 state := newState([]model.Manifest{m}) 548 549 extensionGVK := v1alpha1.SchemeGroupVersion.WithKind("Extension") 550 controller := true 551 state.Tiltfiles["collision"] = &v1alpha1.Tiltfile{ 552 ObjectMeta: metav1.ObjectMeta{ 553 OwnerReferences: []metav1.OwnerReference{ 554 { 555 APIVersion: extensionGVK.GroupVersion().String(), 556 Kind: extensionGVK.Kind, 557 UID: uuid.NewUUID(), 558 Controller: &controller, 559 }, 560 }, 561 }, 562 } 563 state.TiltfileDefinitionOrder = append(state.TiltfileDefinitionOrder, "collision") 564 state.TiltfileStates["collision"] = &store.ManifestState{ 565 Name: model.MainTiltfileManifestName, 566 BuildStatuses: make(map[model.TargetID]*store.BuildStatus), 567 DisableState: v1alpha1.DisableStateEnabled, 568 CurrentBuilds: make(map[string]model.BuildRecord), 569 } 570 571 _, err := ToUIResourceList(*state, nil) 572 require.EqualError(t, err, `Extension "collision" has the same name as a Kubernetes resource`) 573 } 574 575 func findResource(n model.ManifestName, view *proto_webview.View) (v1alpha1.UIResourceStatus, bool) { 576 for _, r := range view.UiResources { 577 if r.Name == n.String() { 578 return r.Status, true 579 } 580 } 581 return v1alpha1.UIResourceStatus{}, false 582 } 583 584 func lastBuild(r v1alpha1.UIResourceStatus) v1alpha1.UIBuildTerminated { 585 if len(r.BuildHistory) == 0 { 586 return v1alpha1.UIBuildTerminated{} 587 } 588 589 return r.BuildHistory[0] 590 } 591 592 func readyCondition(rs v1alpha1.UIResourceStatus) *v1alpha1.UIResourceCondition { 593 for _, c := range rs.Conditions { 594 if c.Type == v1alpha1.UIResourceReady { 595 return &c 596 } 597 } 598 return nil 599 } 600 601 func upToDateCondition(rs v1alpha1.UIResourceStatus) *v1alpha1.UIResourceCondition { 602 for _, c := range rs.Conditions { 603 if c.Type == v1alpha1.UIResourceUpToDate { 604 return &c 605 } 606 } 607 return nil 608 }