github.com/coreos/rocket@v1.30.1-0.20200224141603-171c416fac02/tests/rkt_api_service_test.go (about) 1 // Copyright 2015 The rkt Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // +build host coreos src kvm 16 17 package main 18 19 import ( 20 "bytes" 21 "encoding/json" 22 "fmt" 23 "os" 24 "path/filepath" 25 "reflect" 26 "strings" 27 "syscall" 28 "testing" 29 "time" 30 31 "github.com/appc/spec/schema" 32 "github.com/appc/spec/schema/types" 33 "github.com/coreos/gexpect" 34 "github.com/rkt/rkt/api/v1alpha" 35 "github.com/rkt/rkt/common" 36 "github.com/rkt/rkt/tests/testutils" 37 "golang.org/x/net/context" 38 ) 39 40 func startAPIService(t *testing.T, ctx *testutils.RktRunCtx) *gexpect.ExpectSubprocess { 41 noRktGid := false 42 rktGid, err := common.LookupGid(common.RktGroup) 43 if err != nil { 44 t.Logf("no %q group, will run api service with root, ONLY DO THIS FOR TESTING!", common.RktGroup) 45 noRktGid = true 46 } else { 47 if err := ctx.SetupDataDir(); err != nil { 48 t.Fatalf("failed to setup data directory: %v", err) 49 } 50 } 51 52 uid, _ := ctx.GetUidGidRktBinOwnerNotRoot() 53 54 t.Logf("Running rkt api service") 55 apisvcCmd := fmt.Sprintf("%s api-service", ctx.Cmd()) 56 57 if noRktGid { 58 return startRktAndCheckOutput(t, apisvcCmd, "API service running") 59 } 60 return startRktAsUidGidAndCheckOutput(t, apisvcCmd, "API service running", false, uid, rktGid) 61 } 62 63 func stopAPIService(t *testing.T, svc *gexpect.ExpectSubprocess) { 64 if err := svc.Cmd.Process.Signal(syscall.SIGINT); err != nil { 65 t.Fatalf("Failed to stop the api service: %v", err) 66 } 67 waitOrFail(t, svc, 0) 68 } 69 70 func checkPodState(t *testing.T, rawState string, apiState v1alpha.PodState) { 71 switch rawState { 72 case "embryo": 73 if apiState == v1alpha.PodState_POD_STATE_EMBRYO { 74 return 75 } 76 case "preparing": 77 if apiState == v1alpha.PodState_POD_STATE_PREPARING { 78 return 79 } 80 case "aborted prepare": 81 if apiState == v1alpha.PodState_POD_STATE_ABORTED_PREPARE { 82 return 83 } 84 case "running": 85 if apiState == v1alpha.PodState_POD_STATE_RUNNING { 86 return 87 } 88 case "deleting": 89 if apiState == v1alpha.PodState_POD_STATE_DELETING { 90 return 91 } 92 case "exited": 93 if apiState == v1alpha.PodState_POD_STATE_EXITED { 94 return 95 } 96 case "garbage", "exited garbage": 97 if apiState == v1alpha.PodState_POD_STATE_GARBAGE { 98 return 99 } 100 default: 101 t.Fatalf("Unexpected state: %v", rawState) 102 } 103 t.Errorf("Pod state returned by api-service (%q) is not equivalent to the state returned by 'rkt status' (%q)", apiState, rawState) 104 } 105 106 func checkPodApps(t *testing.T, rawPod *podInfo, apiApps []*v1alpha.App, hasAppState bool) { 107 rawApps := rawPod.apps 108 if len(rawApps) != len(apiApps) { 109 t.Errorf("Expected %d apps, saw %d apps returned by api service %v", len(rawApps), len(apiApps), apiApps) 110 } 111 112 for _, app := range apiApps { 113 appInfo, ok := rawApps[app.Name] 114 if !ok { 115 t.Errorf("Expected app (name: %q) in the app list", app.Name) 116 continue 117 } 118 119 appACName := types.MustACName(app.Name) 120 runtimeApp := rawPod.manifest.Apps.Get(*appACName) 121 if runtimeApp == nil { 122 t.Errorf("Expected app (name: %q) in the pod manifest", app.Name) 123 } 124 125 if hasAppState && appInfo.exitCode != int(app.ExitCode) { 126 t.Errorf("Expected %v, saw %v", appInfo.exitCode, app.ExitCode) 127 } 128 // Image hash in the pod manifest can be partial hash. 129 if !strings.HasPrefix(app.Image.Id, appInfo.image.id) { 130 t.Errorf("Expected partial hash of %q, saw %q", appInfo.image.id, app.Image.Id) 131 } 132 133 // Check app annotations. 134 checkAnnotations(t, runtimeApp.Annotations, app.Annotations) 135 } 136 } 137 138 func checkPodNetworks(t *testing.T, rawNets map[string]*networkInfo, apiNets []*v1alpha.Network) { 139 if len(rawNets) != len(apiNets) { 140 t.Errorf("Expected %d networks, saw %d networks returned by api service", len(rawNets), len(apiNets)) 141 } 142 143 // Each network should have a unique name, so iteration over one list is enough given 144 // the lengths of the two lists are equal. 145 for _, net := range apiNets { 146 if netInfo, ok := rawNets[net.Name]; ok { 147 if netInfo.ipv4 != net.Ipv4 { 148 t.Errorf("Expected %q, saw %q", netInfo.ipv4, net.Ipv4) 149 } 150 } else { 151 t.Errorf("Expected network (name: %q, ipv4: %q) in networks", netInfo.name, netInfo.ipv4) 152 } 153 } 154 } 155 156 // Check the pod's information by 'rkt status'. 157 func checkPod(t *testing.T, ctx *testutils.RktRunCtx, p *v1alpha.Pod, hasAppState, hasManifest bool, expectedGCTime time.Time) { 158 t.Logf("API Pod info: %v", p) 159 160 podInfo := getPodInfo(t, ctx, p.Id) 161 t.Logf("Pod info: %+v", podInfo) 162 163 if podInfo.id != p.Id { 164 t.Errorf("Expected %q, saw %q", podInfo.id, p.Id) 165 } 166 if podInfo.pid != int(p.Pid) { 167 t.Errorf("Expected %d, saw %d", podInfo.pid, p.Pid) 168 } 169 // The time accuracy returned by 'rkt status' stops at milliseconds. 170 accuracy := time.Millisecond.Nanoseconds() 171 if podInfo.createdAt/accuracy != p.CreatedAt/accuracy { 172 t.Errorf("Expected %d, saw %d", podInfo.createdAt, p.CreatedAt) 173 } 174 if podInfo.startedAt/accuracy != p.StartedAt/accuracy { 175 t.Errorf("Expected %d, saw %d", podInfo.startedAt, p.StartedAt) 176 } 177 178 // If expectedGCTime.IsZero() == true, then p.GcMarkedAt should also be zero. 179 actualTime := time.Unix(0, p.GcMarkedAt) 180 if !compareTime(expectedGCTime, actualTime) { 181 t.Errorf("API service returned an incorrect GC marked time. Got %q, Expect: %q", actualTime, expectedGCTime) 182 } 183 checkPodState(t, podInfo.state, p.State) 184 checkPodApps(t, podInfo, p.Apps, hasAppState) 185 checkPodNetworks(t, podInfo.networks, p.Networks) 186 187 expectedCgroupSuffix := "" 188 if podInfo.state == "running" { 189 machineID := fmt.Sprintf("rkt-%s", p.Id) 190 escapedmID := strings.Replace(machineID, "-", "\\x2d", -1) 191 expectedCgroupSuffix = fmt.Sprintf("/machine-%s.scope", escapedmID) 192 } 193 194 if !strings.HasSuffix(p.Cgroup, expectedCgroupSuffix) { 195 t.Errorf("Expected the cgroup suffix to have %q, but saw %q", expectedCgroupSuffix, p.Cgroup) 196 } 197 198 if hasManifest && podInfo.manifest.Annotations != nil { 199 checkAnnotations(t, podInfo.manifest.Annotations, p.Annotations) 200 } 201 202 msft, err := json.Marshal(podInfo.manifest) 203 if err != nil { 204 t.Errorf("Cannot marshal manifest: %v", err) 205 } 206 207 if hasManifest && !bytes.Equal(msft, p.Manifest) { 208 t.Errorf("Expected %q, saw %q", string(msft), string(p.Manifest)) 209 } else if !hasManifest && p.Manifest != nil { 210 t.Errorf("Expected nil manifest") 211 } 212 } 213 214 func checkPodBasicsWithGCTime(t *testing.T, ctx *testutils.RktRunCtx, p *v1alpha.Pod, expectedGCTime time.Time) { 215 checkPod(t, ctx, p, false, false, expectedGCTime) 216 } 217 218 func checkPodBasics(t *testing.T, ctx *testutils.RktRunCtx, p *v1alpha.Pod) { 219 checkPod(t, ctx, p, false, false, time.Time{}) 220 } 221 222 func checkPodDetails(t *testing.T, ctx *testutils.RktRunCtx, p *v1alpha.Pod) { 223 checkPod(t, ctx, p, true, true, time.Time{}) 224 } 225 226 // Check the image's information by 'rkt image list'. 227 func checkImage(t *testing.T, ctx *testutils.RktRunCtx, m *v1alpha.Image, hasManifest bool) { 228 imgInfo := getImageInfo(t, ctx, m.Id) 229 if imgInfo.id != m.Id { 230 t.Errorf("Expected %q, saw %q", imgInfo.id, m.Id) 231 } 232 if imgInfo.name != m.Name { 233 t.Errorf("Expected %q, saw %q", imgInfo.name, m.Name) 234 } 235 if imgInfo.version != m.Version { 236 t.Errorf("Expected %q, saw %q", imgInfo.version, m.Version) 237 } 238 if imgInfo.importTime != m.ImportTimestamp { 239 t.Errorf("Expected %q, saw %q", imgInfo.importTime, m.ImportTimestamp) 240 } 241 if imgInfo.size != m.Size { 242 t.Errorf("Expected size %d, saw %d", imgInfo.size, m.Size) 243 } 244 245 if hasManifest { 246 var mfst schema.ImageManifest 247 err := json.Unmarshal(imgInfo.manifest, &mfst) 248 if err != nil { 249 t.Fatal(err) 250 } 251 if mfst.Annotations != nil { 252 checkAnnotations(t, mfst.Annotations, m.Annotations) 253 } 254 } 255 256 if hasManifest && !bytes.Equal(imgInfo.manifest, m.Manifest) { 257 t.Errorf("Expected %q, saw %q", string(imgInfo.manifest), string(m.Manifest)) 258 } else if !hasManifest && m.Manifest != nil { 259 t.Errorf("Expected nil manifest") 260 } 261 } 262 263 func checkAnnotations(t *testing.T, expected types.Annotations, actual []*v1alpha.KeyValue) { 264 if len(expected) != len(actual) { 265 t.Fatalf("Expected annotation counts to equal, expected %d, got %d", len(expected), len(actual)) 266 } 267 for _, a := range actual { 268 val, ok := expected.Get(a.Key) 269 if !ok { 270 t.Fatalf("Expected annotation for key %q, got nothing", a.Key) 271 } 272 if val != a.Value { 273 t.Fatalf("Incorrect Annotation value, expected %q, got %q", val, a.Value) 274 } 275 } 276 } 277 278 func checkImageBasics(t *testing.T, ctx *testutils.RktRunCtx, m *v1alpha.Image) { 279 checkImage(t, ctx, m, false) 280 } 281 282 func checkImageDetails(t *testing.T, ctx *testutils.RktRunCtx, m *v1alpha.Image) { 283 checkImage(t, ctx, m, true) 284 } 285 286 func TestAPIServiceGetInfo(t *testing.T) { 287 ctx := testutils.NewRktRunCtx() 288 defer ctx.Cleanup() 289 290 svc := startAPIService(t, ctx) 291 defer stopAPIService(t, svc) 292 293 c, conn := newAPIClientOrFail(t, "localhost:15441") 294 defer conn.Close() 295 296 resp, err := c.GetInfo(context.Background(), &v1alpha.GetInfoRequest{}) 297 if err != nil { 298 t.Fatalf("Unexpected error: %v", err) 299 } 300 301 expectedAPIVersion := "1.0.0-alpha" 302 if resp.Info.ApiVersion != expectedAPIVersion { 303 t.Errorf("Expected api version to be %q, but saw %q", expectedAPIVersion, resp.Info.ApiVersion) 304 } 305 306 expectedGlobalFlags := &v1alpha.GlobalFlags{ 307 Dir: ctx.DataDir(), 308 SystemConfigDir: ctx.SystemDir(), 309 LocalConfigDir: ctx.LocalDir(), 310 UserConfigDir: ctx.UserDir(), 311 InsecureFlags: "none", 312 } 313 if !reflect.DeepEqual(resp.Info.GlobalFlags, expectedGlobalFlags) { 314 t.Errorf("Expected global flags to be %v, but saw %v", expectedGlobalFlags, resp.Info.GlobalFlags) 315 } 316 } 317 318 func NewAPIServiceListInspectPodsTest() testutils.Test { 319 return testutils.TestFunc(func(t *testing.T) { 320 ctx := testutils.NewRktRunCtx() 321 defer ctx.Cleanup() 322 323 svc := startAPIService(t, ctx) 324 defer stopAPIService(t, svc) 325 326 c, conn := newAPIClientOrFail(t, "localhost:15441") 327 defer conn.Close() 328 329 resp, err := c.ListPods(context.Background(), &v1alpha.ListPodsRequest{}) 330 if err != nil { 331 t.Fatalf("Unexpected error: %v", err) 332 } 333 334 if len(resp.Pods) != 0 { 335 t.Errorf("Unexpected result: %v, should see zero pods", resp.Pods) 336 } 337 338 patches := []string{"--exec=/inspect --print-msg=HELLO_API --exit-code=0"} 339 imageHash, err := patchImportAndFetchHash("rkt-inspect-print.aci", patches, t, ctx) 340 if err != nil { 341 t.Fatalf("%v", err) 342 } 343 imgID, err := types.NewHash(imageHash) 344 if err != nil { 345 t.Fatalf("Cannot generate types.Hash from %v: %v", imageHash, err) 346 } 347 348 podManifests := []struct { 349 mfst schema.PodManifest 350 net string 351 expectedExitCode int 352 }{ 353 { 354 // 1, Good pod. 355 schema.PodManifest{ 356 ACKind: schema.PodManifestKind, 357 ACVersion: schema.AppContainerVersion, 358 Apps: []schema.RuntimeApp{ 359 { 360 Name: types.ACName("rkt-inspect"), 361 Image: schema.RuntimeImage{ 362 Name: types.MustACIdentifier("coreos.com/rkt-inspect"), 363 ID: *imgID, 364 }, 365 Annotations: []types.Annotation{{Name: types.ACIdentifier("app-test"), Value: "app-test"}}, 366 }, 367 }, 368 Annotations: []types.Annotation{ 369 {Name: types.ACIdentifier("test"), Value: "test"}, 370 }, 371 }, 372 "default", 373 0, 374 }, 375 { 376 // 2, Bad pod, won't be launched correctly. 377 schema.PodManifest{ 378 ACKind: schema.PodManifestKind, 379 ACVersion: schema.AppContainerVersion, 380 Apps: []schema.RuntimeApp{ 381 { 382 Name: types.ACName("rkt-inspect"), 383 Image: schema.RuntimeImage{ 384 Name: types.MustACIdentifier("coreos.com/rkt-inspect"), 385 ID: *imgID, 386 }, 387 }, 388 }, 389 }, 390 "non-existent-network", 391 254, 392 }, 393 } 394 395 // Launch the pods. 396 for _, entry := range podManifests { 397 manifestFile := generatePodManifestFile(t, &entry.mfst) 398 defer os.Remove(manifestFile) 399 400 runCmd := fmt.Sprintf("%s run --net=%s --pod-manifest=%s", ctx.Cmd(), entry.net, manifestFile) 401 waitOrFail(t, spawnOrFail(t, runCmd), entry.expectedExitCode) 402 } 403 404 time.Sleep(delta) 405 406 gcCmd := fmt.Sprintf("%s gc --mark-only=true", ctx.Cmd()) 407 waitOrFail(t, spawnOrFail(t, gcCmd), 0) 408 409 gcTime := time.Now() 410 411 // ListPods(detail=false). 412 resp, err = c.ListPods(context.Background(), &v1alpha.ListPodsRequest{}) 413 if err != nil { 414 t.Fatalf("Unexpected error: %v", err) 415 } 416 417 if len(resp.Pods) != len(podManifests) { 418 t.Errorf("Unexpected result: %v, should see %v pods", len(resp.Pods), len(podManifests)) 419 } 420 421 for _, p := range resp.Pods { 422 checkPodBasicsWithGCTime(t, ctx, p, gcTime) 423 424 // Test InspectPod(). 425 inspectResp, err := c.InspectPod(context.Background(), &v1alpha.InspectPodRequest{Id: p.Id}) 426 if err != nil { 427 t.Fatalf("Unexpected error: %v", err) 428 } 429 checkPodDetails(t, ctx, inspectResp.Pod) 430 } 431 432 // ListPods(detail=true). 433 resp, err = c.ListPods(context.Background(), &v1alpha.ListPodsRequest{Detail: true}) 434 if err != nil { 435 t.Fatalf("Unexpected error: %v", err) 436 } 437 438 if len(resp.Pods) != len(podManifests) { 439 t.Errorf("Unexpected result: %v, should see %v pods", len(resp.Pods), len(podManifests)) 440 } 441 442 for _, p := range resp.Pods { 443 checkPodDetails(t, ctx, p) 444 } 445 446 // ListPods with corrupt pod directory 447 // Note that we don't checkPodDetails here, the failure this is testing is 448 // the api server panicking, which results in a list call hanging for ages 449 // and then failing. 450 // TODO: do further validation on the partial pods returned 451 for _, p := range resp.Pods { 452 numRemoved := 0 453 podDir := getPodDir(t, ctx, p.Id) 454 filepath.Walk(filepath.Join(podDir, "appsinfo"), filepath.WalkFunc(func(path string, info os.FileInfo, err error) error { 455 if err != nil { 456 return err 457 } 458 if info.Name() == "manifest" { 459 os.Remove(path) 460 numRemoved++ 461 } 462 return nil 463 })) 464 if numRemoved == 0 { 465 t.Fatalf("Expected to remove at least one app manifest for pod %v", p) 466 } 467 } 468 469 // ListPods(detail=true). 470 resp, err = c.ListPods(context.Background(), &v1alpha.ListPodsRequest{Detail: true}) 471 if err != nil { 472 t.Fatalf("Unexpected error: %v", err) 473 } 474 if len(resp.Pods) != len(podManifests) { 475 t.Fatalf("Expected %v pods, got %v pods", len(podManifests), len(resp.Pods)) 476 } 477 }) 478 } 479 480 func TestAPIServiceListInspectImages(t *testing.T) { 481 ctx := testutils.NewRktRunCtx() 482 defer ctx.Cleanup() 483 484 svc := startAPIService(t, ctx) 485 defer stopAPIService(t, svc) 486 487 c, conn := newAPIClientOrFail(t, "localhost:15441") 488 defer conn.Close() 489 490 resp, err := c.ListImages(context.Background(), &v1alpha.ListImagesRequest{}) 491 if err != nil { 492 t.Fatalf("Unexpected error: %v", err) 493 } 494 495 if len(resp.Images) != 0 { 496 t.Errorf("Unexpected result: %v, should see zero images", resp.Images) 497 } 498 499 _, err = patchImportAndFetchHash("rkt-inspect-sleep.aci", []string{"--exec=/inspect"}, t, ctx) 500 if err != nil { 501 t.Fatalf("%v", err) 502 } 503 504 // ListImages(detail=false). 505 resp, err = c.ListImages(context.Background(), &v1alpha.ListImagesRequest{}) 506 if err != nil { 507 t.Fatalf("Unexpected error: %v", err) 508 } 509 510 if len(resp.Images) == 0 { 511 t.Errorf("Unexpected result: %v, should see non-zero images", resp.Images) 512 } 513 514 for _, m := range resp.Images { 515 checkImageBasics(t, ctx, m) 516 517 // Test InspectImage(). 518 inspectResp, err := c.InspectImage(context.Background(), &v1alpha.InspectImageRequest{Id: m.Id}) 519 if err != nil { 520 t.Fatalf("Unexpected error: %v", err) 521 } 522 checkImageDetails(t, ctx, inspectResp.Image) 523 } 524 525 // ListImages(detail=true). 526 resp, err = c.ListImages(context.Background(), &v1alpha.ListImagesRequest{Detail: true}) 527 if err != nil { 528 t.Fatalf("Unexpected error: %v", err) 529 } 530 531 if len(resp.Images) == 0 { 532 t.Errorf("Unexpected result: %v, should see non-zero images", resp.Images) 533 } 534 535 for _, m := range resp.Images { 536 checkImageDetails(t, ctx, m) 537 } 538 } 539 540 func NewAPIServiceCgroupTest() testutils.Test { 541 return testutils.TestFunc(func(t *testing.T) { 542 ctx := testutils.NewRktRunCtx() 543 defer ctx.Cleanup() 544 545 svc := startAPIService(t, ctx) 546 defer stopAPIService(t, svc) 547 548 c, conn := newAPIClientOrFail(t, "localhost:15441") 549 defer conn.Close() 550 551 aciFileName := patchTestACI("rkt-inspect-interactive.aci", "--exec=/inspect --read-stdin") 552 defer os.Remove(aciFileName) 553 554 runCmd := fmt.Sprintf("%s --insecure-options=image run --interactive %s", ctx.Cmd(), aciFileName) 555 child := spawnOrFail(t, runCmd) 556 557 var resp *v1alpha.ListPodsResponse 558 var err error 559 done := make(chan struct{}) 560 561 // Wait the pods to be running. 562 go func() { 563 for { 564 // ListPods(detail=false). 565 resp, err = c.ListPods(context.Background(), &v1alpha.ListPodsRequest{}) 566 if err != nil { 567 t.Fatalf("Unexpected error: %v", err) 568 } 569 570 if len(resp.Pods) != 0 { 571 allRunning := true 572 for _, p := range resp.Pods { 573 if p.State != v1alpha.PodState_POD_STATE_RUNNING || p.Pid == -1 { 574 allRunning = false 575 break 576 } 577 } 578 if allRunning { 579 t.Logf("Pods are running") 580 close(done) 581 return 582 } 583 } 584 t.Logf("Pods are not in RUNNING state") 585 time.Sleep(time.Second) 586 } 587 }() 588 589 testutils.WaitOrTimeout(t, time.Second*60, done) 590 591 var cgroups []string 592 var subcgroups []string 593 594 for _, p := range resp.Pods { 595 checkPodBasics(t, ctx, p) 596 597 // Test InspectPod(). 598 inspectResp, err := c.InspectPod(context.Background(), &v1alpha.InspectPodRequest{Id: p.Id}) 599 if err != nil { 600 t.Fatalf("Unexpected error: %v", err) 601 } 602 checkPodDetails(t, ctx, inspectResp.Pod) 603 if p.Cgroup != "" { 604 cgroups = append(cgroups, p.Cgroup) 605 subcgroups = append(subcgroups, filepath.Join(p.Cgroup, "system.slice")) 606 } 607 } 608 609 // ListPods(detail=true). Filter according to the cgroup. 610 t.Logf("Calling ListPods with cgroup filter %v", cgroups) 611 resp, err = c.ListPods(context.Background(), &v1alpha.ListPodsRequest{ 612 Detail: true, 613 Filters: []*v1alpha.PodFilter{{Cgroups: cgroups}}, 614 }) 615 if err != nil { 616 t.Fatalf("Unexpected error: %v", err) 617 } 618 619 if len(resp.Pods) == 0 { 620 t.Errorf("Unexpected result: %v, should see non-zero pods", resp.Pods) 621 } 622 623 for _, p := range resp.Pods { 624 checkPodDetails(t, ctx, p) 625 } 626 627 t.Logf("Calling ListPods with subcgroup filter %v", subcgroups) 628 resp, err = c.ListPods(context.Background(), &v1alpha.ListPodsRequest{ 629 Detail: true, 630 Filters: []*v1alpha.PodFilter{{PodSubCgroups: subcgroups}}, 631 }) 632 if err != nil { 633 t.Fatalf("Unexpected error: %v", err) 634 } 635 636 if len(resp.Pods) == 0 { 637 t.Errorf("Unexpected result: %v, should see non-zero pods", resp.Pods) 638 } 639 640 for _, p := range resp.Pods { 641 checkPodDetails(t, ctx, p) 642 } 643 644 // Terminate the pod. 645 if err := child.SendLine("Good bye"); err != nil { 646 t.Fatalf("Failed to send message to the pod: %v", err) 647 } 648 waitOrFail(t, child, 0) 649 650 // Check that there's no cgroups returned for non-running pods. 651 cgroups = []string{} 652 resp, err = c.ListPods(context.Background(), &v1alpha.ListPodsRequest{}) 653 for _, p := range resp.Pods { 654 checkPodBasics(t, ctx, p) 655 if p.Cgroup != "" { 656 cgroups = append(cgroups, p.Cgroup) 657 } 658 } 659 if len(cgroups) != 0 { 660 t.Errorf("Unexpected cgroup returned by pods: %v", cgroups) 661 } 662 }) 663 }