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