github.com/google/cadvisor@v0.49.1/manager/container_test.go (about) 1 // Copyright 2014 Google Inc. All Rights Reserved. 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 // Per-container manager. 16 17 package manager 18 19 import ( 20 "fmt" 21 "reflect" 22 "sync" 23 "testing" 24 "time" 25 26 "github.com/google/cadvisor/cache/memory" 27 "github.com/google/cadvisor/collector" 28 "github.com/google/cadvisor/container" 29 containertest "github.com/google/cadvisor/container/testing" 30 info "github.com/google/cadvisor/info/v1" 31 itest "github.com/google/cadvisor/info/v1/test" 32 v2 "github.com/google/cadvisor/info/v2" 33 34 "github.com/stretchr/testify/assert" 35 "github.com/stretchr/testify/require" 36 37 clock "k8s.io/utils/clock/testing" 38 ) 39 40 const ( 41 containerName = "/container" 42 testLongHousekeeping = time.Second 43 ) 44 45 // Create a containerData instance for a test. 46 func setupContainerData(t *testing.T, spec info.ContainerSpec) (*containerData, *containertest.MockContainerHandler, *memory.InMemoryCache, *clock.FakeClock) { 47 mockHandler := containertest.NewMockContainerHandler(containerName) 48 mockHandler.On("GetSpec").Return( 49 spec, 50 nil, 51 ) 52 memoryCache := memory.New(60, nil) 53 fakeClock := clock.NewFakeClock(time.Now()) 54 ret, err := newContainerData(containerName, memoryCache, mockHandler, false, &collector.GenericCollectorManager{}, 60*time.Second, true, fakeClock) 55 if err != nil { 56 t.Fatal(err) 57 } 58 return ret, mockHandler, memoryCache, fakeClock 59 } 60 61 // Create a containerData instance for a test and add a default GetSpec mock. 62 func newTestContainerData(t *testing.T) (*containerData, *containertest.MockContainerHandler, *memory.InMemoryCache, *clock.FakeClock) { 63 return setupContainerData(t, itest.GenerateRandomContainerSpec(4)) 64 } 65 66 func TestUpdateSubcontainers(t *testing.T) { 67 subcontainers := []info.ContainerReference{ 68 {Name: "/container/ee0103"}, 69 {Name: "/container/abcd"}, 70 {Name: "/container/something"}, 71 } 72 cd, mockHandler, _, _ := newTestContainerData(t) 73 mockHandler.On("ListContainers", container.ListSelf).Return( 74 subcontainers, 75 nil, 76 ) 77 78 err := cd.updateSubcontainers() 79 if err != nil { 80 t.Fatal(err) 81 } 82 83 if len(cd.info.Subcontainers) != len(subcontainers) { 84 t.Errorf("Received %v subcontainers, should be %v", len(cd.info.Subcontainers), len(subcontainers)) 85 } 86 87 for _, sub := range cd.info.Subcontainers { 88 found := false 89 for _, sub2 := range subcontainers { 90 if sub.Name == sub2.Name { 91 found = true 92 } 93 } 94 if !found { 95 t.Errorf("Received unknown sub container %v", sub) 96 } 97 } 98 99 mockHandler.AssertExpectations(t) 100 } 101 102 func TestUpdateSubcontainersWithError(t *testing.T) { 103 cd, mockHandler, _, _ := newTestContainerData(t) 104 mockHandler.On("ListContainers", container.ListSelf).Return( 105 []info.ContainerReference{}, 106 fmt.Errorf("some error"), 107 ) 108 mockHandler.On("Exists").Return(true) 109 110 assert.NotNil(t, cd.updateSubcontainers()) 111 assert.Empty(t, cd.info.Subcontainers, "subcontainers should not be populated on failure") 112 mockHandler.AssertExpectations(t) 113 } 114 115 func TestUpdateSubcontainersWithErrorOnDeadContainer(t *testing.T) { 116 cd, mockHandler, _, _ := newTestContainerData(t) 117 mockHandler.On("ListContainers", container.ListSelf).Return( 118 []info.ContainerReference{}, 119 fmt.Errorf("some error"), 120 ) 121 mockHandler.On("Exists").Return(false) 122 123 assert.Nil(t, cd.updateSubcontainers()) 124 mockHandler.AssertExpectations(t) 125 } 126 127 func checkNumStats(t *testing.T, memoryCache *memory.InMemoryCache, numStats int) { 128 var empty time.Time 129 stats, err := memoryCache.RecentStats(containerName, empty, empty, -1) 130 require.Nil(t, err) 131 assert.Len(t, stats, numStats) 132 } 133 134 func TestUpdateStats(t *testing.T) { 135 statsList := itest.GenerateRandomStats(1, 4, 1*time.Second) 136 stats := statsList[0] 137 138 cd, mockHandler, memoryCache, _ := newTestContainerData(t) 139 mockHandler.On("GetStats").Return( 140 stats, 141 nil, 142 ) 143 144 err := cd.updateStats() 145 if err != nil { 146 t.Fatal(err) 147 } 148 149 checkNumStats(t, memoryCache, 1) 150 mockHandler.AssertExpectations(t) 151 } 152 153 func TestUpdateSpec(t *testing.T) { 154 spec := itest.GenerateRandomContainerSpec(4) 155 cd, mockHandler, _, _ := newTestContainerData(t) 156 mockHandler.On("GetSpec").Return( 157 spec, 158 nil, 159 ) 160 161 err := cd.updateSpec() 162 if err != nil { 163 t.Fatal(err) 164 } 165 166 mockHandler.AssertExpectations(t) 167 } 168 169 func TestGetInfo(t *testing.T) { 170 spec := itest.GenerateRandomContainerSpec(4) 171 subcontainers := []info.ContainerReference{ 172 {Name: "/container/ee0103"}, 173 {Name: "/container/abcd"}, 174 {Name: "/container/something"}, 175 } 176 cd, mockHandler, _, _ := setupContainerData(t, spec) 177 mockHandler.On("ListContainers", container.ListSelf).Return( 178 subcontainers, 179 nil, 180 ) 181 mockHandler.Aliases = []string{"a1", "a2"} 182 183 info, err := cd.GetInfo(true) 184 if err != nil { 185 t.Fatal(err) 186 } 187 188 mockHandler.AssertExpectations(t) 189 190 if len(info.Subcontainers) != len(subcontainers) { 191 t.Errorf("Received %v subcontainers, should be %v", len(info.Subcontainers), len(subcontainers)) 192 } 193 194 for _, sub := range info.Subcontainers { 195 found := false 196 for _, sub2 := range subcontainers { 197 if sub.Name == sub2.Name { 198 found = true 199 } 200 } 201 if !found { 202 t.Errorf("Received unknown sub container %v", sub) 203 } 204 } 205 206 if !reflect.DeepEqual(spec, info.Spec) { 207 t.Errorf("received wrong container spec") 208 } 209 210 if info.Name != mockHandler.Name { 211 t.Errorf("received wrong container name: received %v; should be %v", info.Name, mockHandler.Name) 212 } 213 } 214 215 func TestOnDemandHousekeeping(t *testing.T) { 216 statsList := itest.GenerateRandomStats(1, 4, 1*time.Second) 217 stats := statsList[0] 218 219 cd, mockHandler, memoryCache, fakeClock := newTestContainerData(t) 220 mockHandler.On("GetStats").Return(stats, nil) 221 defer func() { 222 err := cd.Stop() 223 assert.NoError(t, err) 224 }() 225 226 // 0 seconds should always trigger an update 227 go cd.OnDemandHousekeeping(0 * time.Second) 228 cd.housekeepingTick(fakeClock.NewTimer(time.Minute).C(), testLongHousekeeping) 229 230 fakeClock.Step(2 * time.Second) 231 232 // This should return without requiring a housekeepingTick because stats have been updated recently enough 233 cd.OnDemandHousekeeping(3 * time.Second) 234 235 go cd.OnDemandHousekeeping(1 * time.Second) 236 cd.housekeepingTick(fakeClock.NewTimer(time.Minute).C(), testLongHousekeeping) 237 238 checkNumStats(t, memoryCache, 2) 239 mockHandler.AssertExpectations(t) 240 } 241 242 func TestConcurrentOnDemandHousekeeping(t *testing.T) { 243 statsList := itest.GenerateRandomStats(1, 4, 1*time.Second) 244 stats := statsList[0] 245 246 cd, mockHandler, memoryCache, fakeClock := newTestContainerData(t) 247 mockHandler.On("GetStats").Return(stats, nil) 248 defer func() { 249 err := cd.Stop() 250 assert.NoError(t, err) 251 }() 252 253 numConcurrentCalls := 5 254 var waitForHousekeeping sync.WaitGroup 255 waitForHousekeeping.Add(numConcurrentCalls) 256 onDemandCache := []chan struct{}{} 257 for i := 0; i < numConcurrentCalls; i++ { 258 go func() { 259 cd.OnDemandHousekeeping(0 * time.Second) 260 waitForHousekeeping.Done() 261 }() 262 // Wait for work to be queued 263 onDemandCache = append(onDemandCache, <-cd.onDemandChan) 264 } 265 // Requeue work: 266 for _, ch := range onDemandCache { 267 cd.onDemandChan <- ch 268 } 269 270 go cd.housekeepingTick(fakeClock.NewTimer(time.Minute).C(), testLongHousekeeping) 271 // Ensure that all queued calls return with only a single call to housekeepingTick 272 waitForHousekeeping.Wait() 273 274 checkNumStats(t, memoryCache, 1) 275 mockHandler.AssertExpectations(t) 276 } 277 278 func TestOnDemandHousekeepingReturnsAfterStopped(t *testing.T) { 279 statsList := itest.GenerateRandomStats(1, 4, 1*time.Second) 280 stats := statsList[0] 281 282 cd, mockHandler, memoryCache, fakeClock := newTestContainerData(t) 283 mockHandler.On("GetStats").Return(stats, nil) 284 285 // trigger housekeeping update 286 go cd.OnDemandHousekeeping(0 * time.Second) 287 cd.housekeepingTick(fakeClock.NewTimer(time.Minute).C(), testLongHousekeeping) 288 289 checkNumStats(t, memoryCache, 1) 290 291 fakeClock.Step(2 * time.Second) 292 293 err := cd.Stop() 294 assert.NoError(t, err) 295 // housekeeping tick should detect stop and not store any more metrics 296 assert.False(t, cd.housekeepingTick(fakeClock.NewTimer(time.Minute).C(), testLongHousekeeping)) 297 fakeClock.Step(1 * time.Second) 298 // on demand housekeeping should not block and return 299 cd.OnDemandHousekeeping(-1 * time.Second) 300 301 mockHandler.AssertExpectations(t) 302 } 303 304 func TestOnDemandHousekeepingRace(t *testing.T) { 305 statsList := itest.GenerateRandomStats(1, 4, 1*time.Second) 306 stats := statsList[0] 307 308 cd, mockHandler, _, _ := newTestContainerData(t) 309 mockHandler.On("GetStats").Return(stats, nil) 310 311 wg := sync.WaitGroup{} 312 wg.Add(1002) 313 314 go func() { 315 time.Sleep(10 * time.Millisecond) 316 err := cd.Start() 317 assert.NoError(t, err) 318 wg.Done() 319 }() 320 321 go func() { 322 t.Log("starting on demand goroutine") 323 for i := 0; i < 1000; i++ { 324 go func() { 325 time.Sleep(1 * time.Microsecond) 326 cd.OnDemandHousekeeping(0 * time.Millisecond) 327 wg.Done() 328 }() 329 } 330 wg.Done() 331 }() 332 wg.Wait() 333 } 334 335 var psOutput = [][]byte{ 336 []byte("root 15886 2 23:51 0.1 0.0 0 0 I 00:00:00 kworker/u8:3-ev 3 -\nroot 15887 2 23:51 0.0 0.0 0 0 I< 00:00:00 kworker/1:2H 1 -\nubuntu 15888 1804 23:51 0.0 0.0 2832 10176 R+ 00:00:00 ps 1 8:devices:/user.slice,6:pids:/user.slice/user-1000.slice/session-3.scope,5:blkio:/user.slice,2:cpu,cpuacct:/user.slice,1:na"), 337 []byte("root 104 2 21:34 0.0 0.0 0 0 I< 00:00:00 kthrotld 3 -\nroot 105 2 21:34 0.0 0.0 0 0 S 00:00:00 irq/41-aerdrv 0 -\nroot 107 2 21:34 0.0 0.0 0 0 I< 00:00:00 DWC Notificatio 3 -\nroot 109 2 21:34 0.0 0.0 0 0 S< 00:00:00 vchiq-slot/0 1 -\nroot 110 2 21:34 0.0 0.0 0 0 S< 00:00:00 vchiq-recy/0 3 -"), 338 } 339 340 func TestParseProcessList(t *testing.T) { 341 for i, ps := range psOutput { 342 t.Run(fmt.Sprintf("iteration %d", i), func(tt *testing.T) { 343 cd := &containerData{} 344 _, err := cd.parseProcessList("/", true, ps) 345 // checking *only* parsing errors - otherwise /proc would have to be emulated. 346 assert.NoError(tt, err) 347 }) 348 } 349 } 350 351 var psLine = []struct { 352 name string 353 line string 354 cadvisorContainer string 355 isHostNamespace bool 356 process *v2.ProcessInfo 357 err error 358 cd *containerData 359 }{ 360 { 361 name: "plain process with cgroup", 362 line: "ubuntu 15888 1804 23:51 0.1 0.0 2832 10176 R+ 00:10:00 cadvisor 1 10:cpuset:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,9:devices:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,8:pids:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,7:memory:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,6:freezer:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,5:perf_event:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,4:blkio:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,3:cpu,cpuacct:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,2:net_cls,net_prio:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,1:name=systemd:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831", 363 cadvisorContainer: "/docker/cadvisor", 364 isHostNamespace: true, 365 process: &v2.ProcessInfo{ 366 User: "ubuntu", 367 Pid: 15888, 368 Ppid: 1804, 369 StartTime: "23:51", 370 PercentCpu: 0.1, 371 PercentMemory: 0.0, 372 RSS: 2899968, 373 VirtualSize: 10420224, 374 Status: "R+", 375 RunningTime: "00:10:00", 376 CgroupPath: "/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831", 377 Cmd: "cadvisor", 378 Psr: 1, 379 }, 380 cd: &containerData{ 381 info: containerInfo{ContainerReference: info.ContainerReference{Name: "/"}}, 382 }, 383 }, 384 { 385 name: "process with space in name and no cgroup", 386 line: "root 107 2 21:34 0.0 0.1 3 4 I< 00:20:00 DWC Notificatio 3 -", 387 cadvisorContainer: "/docker/cadvisor", 388 process: &v2.ProcessInfo{ 389 User: "root", 390 Pid: 107, 391 Ppid: 2, 392 StartTime: "21:34", 393 PercentCpu: 0.0, 394 PercentMemory: 0.1, 395 RSS: 3072, 396 VirtualSize: 4096, 397 Status: "I<", 398 RunningTime: "00:20:00", 399 CgroupPath: "/", 400 Cmd: "DWC Notificatio", 401 Psr: 3, 402 }, 403 cd: &containerData{ 404 info: containerInfo{ContainerReference: info.ContainerReference{Name: "/"}}, 405 }, 406 }, 407 { 408 name: "process with highly unusual name (one 2 three 4 five 6 eleven), cgroup to be ignored", 409 line: "root 107 2 21:34 0.0 0.1 3 4 I< 00:20:00 one 2 three 4 five 6 eleven 3 10:cpuset:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,9:devices:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,8:pids:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,7:memory:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,6:freezer:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,5:perf_event:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,4:blkio:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,3:cpu,cpuacct:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,2:net_cls,net_prio:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,1:name=systemd:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831", 410 cadvisorContainer: "/docker/cadvisor", 411 isHostNamespace: true, 412 process: &v2.ProcessInfo{ 413 User: "root", 414 Pid: 107, 415 Ppid: 2, 416 StartTime: "21:34", 417 PercentCpu: 0.0, 418 PercentMemory: 0.1, 419 RSS: 3072, 420 VirtualSize: 4096, 421 Status: "I<", 422 RunningTime: "00:20:00", 423 Cmd: "one 2 three 4 five 6 eleven", 424 Psr: 3, 425 CgroupPath: "/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831", 426 }, 427 cd: &containerData{ 428 info: containerInfo{ContainerReference: info.ContainerReference{Name: "/"}}, 429 }, 430 }, 431 { 432 name: "wrong field count", 433 line: "ps output it is not", 434 cadvisorContainer: "/docker/cadvisor", 435 err: fmt.Errorf("expected at least 13 fields, found 5: output: \"ps output it is not\""), 436 cd: &containerData{}, 437 }, 438 { 439 name: "ps running in cadvisor container should be ignored", 440 line: "root 107 2 21:34 0.0 0.1 3 4 I< 00:20:00 ps 3 10:cpuset:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,9:devices:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,8:pids:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,7:memory:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,6:freezer:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,5:perf_event:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,4:blkio:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,3:cpu,cpuacct:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,2:net_cls,net_prio:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,1:name=systemd:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831", 441 cadvisorContainer: "/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831", 442 cd: &containerData{ 443 info: containerInfo{ContainerReference: info.ContainerReference{Name: "/"}}, 444 }, 445 }, 446 { 447 name: "non-root container but process belongs to the container", 448 line: "root 107 2 21:34 0.0 0.1 3 4 I< 00:20:00 sleep inf 3 10:cpuset:/docker/some-random-container,9:devices:/docker/some-random-container,8:pids:/docker/some-random-container,7:memory:/docker/some-random-container,6:freezer:/docker/some-random-container,5:perf_event:/docker/some-random-container,4:blkio:/docker/some-random-container,3:cpu,cpuacct:/docker/some-random-container,2:net_cls,net_prio:/docker/some-random-container,1:name=systemd:/docker/some-random-container", 449 process: &v2.ProcessInfo{ 450 User: "root", 451 Pid: 107, 452 Ppid: 2, 453 StartTime: "21:34", 454 PercentCpu: 0.0, 455 PercentMemory: 0.1, 456 RSS: 3072, 457 VirtualSize: 4096, 458 Status: "I<", 459 RunningTime: "00:20:00", 460 Cmd: "sleep inf", 461 Psr: 3, 462 }, 463 cadvisorContainer: "/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831", 464 cd: &containerData{ 465 info: containerInfo{ContainerReference: info.ContainerReference{Name: "/docker/some-random-container"}}, 466 }, 467 }, 468 { 469 name: "non-root container and process belonging to another container", 470 line: "root 107 2 21:34 0.0 0.1 3 4 I< 00:20:00 sleep inf 3 10:cpuset:/docker/some-random-container,9:devices:/docker/some-random-container,8:pids:/docker/some-random-container,7:memory:/docker/some-random-container,6:freezer:/docker/some-random-container,5:perf_event:/docker/some-random-container,4:blkio:/docker/some-random-container,3:cpu,cpuacct:/docker/some-random-container,2:net_cls,net_prio:/docker/some-random-container,1:name=systemd:/docker/some-random-container", 471 cadvisorContainer: "/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831", 472 cd: &containerData{ 473 info: containerInfo{ContainerReference: info.ContainerReference{Name: "/docker/some-other-container"}}, 474 }, 475 }, 476 } 477 478 func TestParsePsLine(t *testing.T) { 479 for _, ps := range psLine { 480 t.Run(ps.name, func(tt *testing.T) { 481 process, err := ps.cd.parsePsLine(ps.line, ps.cadvisorContainer, ps.isHostNamespace) 482 assert.Equal(tt, ps.err, err) 483 assert.EqualValues(tt, ps.process, process) 484 }) 485 } 486 } 487 488 var cgroupCases = []struct { 489 name string 490 cgroups string 491 path string 492 }{ 493 { 494 name: "no cgroup", 495 cgroups: "-", 496 path: "/", 497 }, 498 { 499 name: "random and meaningless string", 500 cgroups: "/this/is/a/path/to/some.file", 501 path: "/", 502 }, 503 { 504 name: "0::-type cgroup", 505 cgroups: "0::/docker/some-cgroup", 506 path: "/docker/some-cgroup", 507 }, 508 { 509 name: "memory cgroup", 510 cgroups: "4:memory:/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6,2:net_cls:/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6", 511 path: "/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6", 512 }, 513 { 514 name: "cpu,cpuacct cgroup", 515 cgroups: "4:cpu,cpuacct:/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6,2:net_cls:/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6", 516 path: "/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6", 517 }, 518 { 519 name: "cpu cgroup", 520 cgroups: "4:cpu:/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6,2:net_cls:/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6", 521 path: "/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6", 522 }, 523 { 524 name: "cpuacct cgroup", 525 cgroups: "4:cpuacct:/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6,2:net_cls:/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6", 526 path: "/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6", 527 }, 528 } 529 530 func TestGetCgroupPath(t *testing.T) { 531 for _, cgroup := range cgroupCases { 532 t.Run(cgroup.name, func(tt *testing.T) { 533 cd := &containerData{} 534 path := cd.getCgroupPath(cgroup.cgroups) 535 assert.Equal(t, cgroup.path, path) 536 }) 537 } 538 }