TestConcurrentlyCreateAndDeleteContainers is a regression test for #93771, which ensures kubelet would not panic on concurrent writes to `dockerService.containerCleanupInfos`.
(t *testing.T)
| 63 | // TestConcurrentlyCreateAndDeleteContainers is a regression test for #93771, which ensures |
| 64 | // kubelet would not panic on concurrent writes to `dockerService.containerCleanupInfos`. |
| 65 | func TestConcurrentlyCreateAndDeleteContainers(t *testing.T) { |
| 66 | ds, _, _ := newTestDockerService() |
| 67 | podName, namespace := "foo", "bar" |
| 68 | containerName, image := "sidecar", "logger" |
| 69 | |
| 70 | const count = 20 |
| 71 | configs := make([]*runtimeapi.ContainerConfig, 0, count) |
| 72 | sConfigs := make([]*runtimeapi.PodSandboxConfig, 0, count) |
| 73 | for i := 0; i < count; i++ { |
| 74 | s := makeSandboxConfig(fmt.Sprintf("%s%d", podName, i), |
| 75 | fmt.Sprintf("%s%d", namespace, i), fmt.Sprintf("%d", i), 0) |
| 76 | labels := map[string]string{"concurrent-test": fmt.Sprintf("label%d", i)} |
| 77 | c := makeContainerConfig(s, fmt.Sprintf("%s%d", containerName, i), |
| 78 | fmt.Sprintf("%s:v%d", image, i), uint32(i), labels, nil) |
| 79 | sConfigs = append(sConfigs, s) |
| 80 | configs = append(configs, c) |
| 81 | } |
| 82 | |
| 83 | containerIDs := make( |
| 84 | chan string, |
| 85 | len(configs), |
| 86 | ) // make channel non-blocking to simulate concurrent containers creation |
| 87 | |
| 88 | var ( |
| 89 | creationWg sync.WaitGroup |
| 90 | deletionWg sync.WaitGroup |
| 91 | ) |
| 92 | |
| 93 | creationWg.Add(len(configs)) |
| 94 | |
| 95 | go func() { |
| 96 | creationWg.Wait() |
| 97 | close(containerIDs) |
| 98 | }() |
| 99 | for i := range configs { |
| 100 | go func(i int) { |
| 101 | defer creationWg.Done() |
| 102 | // We don't care about the sandbox id; pass a bogus one. |
| 103 | sandboxID := fmt.Sprintf("sandboxid%d", i) |
| 104 | req := &runtimeapi.CreateContainerRequest{ |
| 105 | PodSandboxId: sandboxID, |
| 106 | Config: configs[i], |
| 107 | SandboxConfig: sConfigs[i], |
| 108 | } |
| 109 | createResp, err := ds.CreateContainer(getTestCTX(), req) |
| 110 | if err != nil { |
| 111 | t.Errorf("CreateContainer: %v", err) |
| 112 | return |
| 113 | } |
| 114 | containerIDs <- createResp.ContainerId |
| 115 | }(i) |
| 116 | } |
| 117 | |
| 118 | for containerID := range containerIDs { |
| 119 | deletionWg.Add(1) |
| 120 | go func(id string) { |
| 121 | defer deletionWg.Done() |
| 122 | _, err := ds.RemoveContainer( |
nothing calls this directly
no test coverage detected
searching dependent graphs…