github.com/elastic/gosigar@v0.14.3/sigar_linux_test.go (about) 1 package gosigar_test 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "math/rand" 7 "os" 8 "path/filepath" 9 "strconv" 10 "testing" 11 "time" 12 13 sigar "github.com/elastic/gosigar" 14 "github.com/stretchr/testify/assert" 15 ) 16 17 var procd string 18 19 func setUp(t testing.TB) { 20 var err error 21 procd, err = ioutil.TempDir("", "sigarTests") 22 if err != nil { 23 t.Fatal(err) 24 } 25 sigar.Procd = procd 26 } 27 28 func tearDown(t testing.TB) { 29 sigar.Procd = "/proc" 30 err := os.RemoveAll(procd) 31 if err != nil { 32 t.Fatal(err) 33 } 34 } 35 36 func TestLinuxProcState(t *testing.T) { 37 setUp(t) 38 defer tearDown(t) 39 40 var procNames = []string{ 41 "cron", 42 "a very long process name", 43 "(sd-pam)", 44 "]", 45 "(", 46 } 47 48 for _, n := range procNames { 49 func() { 50 pid := rand.Int() 51 pidDir := filepath.Join(procd, strconv.Itoa(pid)) 52 err := os.Mkdir(pidDir, 0755) 53 if err != nil { 54 t.Fatal(err) 55 } 56 defer os.RemoveAll(pidDir) 57 pidStatFile := filepath.Join(pidDir, "stat") 58 writePidStats(pid, n, pidStatFile) 59 if err != nil { 60 t.Fatal(err) 61 } 62 63 pidStatusFile := filepath.Join(pidDir, "status") 64 uid := 123456789 65 writePidStatus(n, pid, uid, pidStatusFile) 66 if err != nil { 67 t.Fatal(err) 68 } 69 70 state := sigar.ProcState{} 71 if assert.NoError(t, state.Get(pid)) { 72 expected := sigar.ProcState{ 73 Name: n, 74 Username: strconv.Itoa(uid), 75 State: 'S', 76 Ppid: 1, 77 Pgid: 2, 78 Tty: 4, 79 Priority: 15, 80 Nice: 16, 81 Processor: 36, 82 } 83 assert.Equal(t, expected, state) 84 } 85 }() 86 } 87 } 88 89 func TestLinuxCPU(t *testing.T) { 90 setUp(t) 91 defer tearDown(t) 92 93 tests := []struct { 94 stat string 95 user uint64 96 }{ 97 {"cpu 25 1 2 3 4 5 6 7", 25}, 98 // Ignore empty lines 99 {"cpu ", 0}, 100 } 101 102 statFile := procd + "/stat" 103 for _, test := range tests { 104 func() { 105 statContents := []byte(test.stat) 106 err := ioutil.WriteFile(statFile, statContents, 0644) 107 if err != nil { 108 t.Fatal(err) 109 } 110 defer os.RemoveAll(statFile) 111 112 cpu := sigar.Cpu{} 113 if assert.NoError(t, cpu.Get()) { 114 assert.Equal(t, uint64(test.user), cpu.User, "cpu.User") 115 } 116 }() 117 } 118 } 119 120 func TestLinuxCollectCpuStats(t *testing.T) { 121 setUp(t) 122 defer tearDown(t) 123 124 statFile := procd + "/stat" 125 statContents := []byte("cpu 25 1 2 3 4 5 6 7") 126 err := ioutil.WriteFile(statFile, statContents, 0644) 127 if err != nil { 128 t.Fatal(err) 129 } 130 131 concreteSigar := &sigar.ConcreteSigar{} 132 cpuUsages, stop := concreteSigar.CollectCpuStats(500 * time.Millisecond) 133 134 assert.Equal(t, sigar.Cpu{ 135 User: uint64(25), 136 Nice: uint64(1), 137 Sys: uint64(2), 138 Idle: uint64(3), 139 Wait: uint64(4), 140 Irq: uint64(5), 141 SoftIrq: uint64(6), 142 Stolen: uint64(7), 143 }, <-cpuUsages) 144 145 statContents = []byte("cpu 30 3 7 10 25 55 36 65") 146 err = ioutil.WriteFile(statFile, statContents, 0644) 147 if err != nil { 148 t.Fatal(err) 149 } 150 151 assert.Equal(t, sigar.Cpu{ 152 User: uint64(5), 153 Nice: uint64(2), 154 Sys: uint64(5), 155 Idle: uint64(7), 156 Wait: uint64(21), 157 Irq: uint64(50), 158 SoftIrq: uint64(30), 159 Stolen: uint64(58), 160 }, <-cpuUsages) 161 162 stop <- struct{}{} 163 } 164 165 func TestLinuxMemAndSwap(t *testing.T) { 166 setUp(t) 167 defer tearDown(t) 168 169 meminfoContents := ` 170 MemTotal: 374256 kB 171 MemFree: 274460 kB 172 Buffers: 9764 kB 173 Cached: 38648 kB 174 SwapCached: 0 kB 175 Active: 33772 kB 176 Inactive: 31184 kB 177 Active(anon): 16572 kB 178 Inactive(anon): 552 kB 179 Active(file): 17200 kB 180 Inactive(file): 30632 kB 181 Unevictable: 0 kB 182 Mlocked: 0 kB 183 SwapTotal: 786428 kB 184 SwapFree: 786428 kB 185 Dirty: 0 kB 186 Writeback: 0 kB 187 AnonPages: 16564 kB 188 Mapped: 6612 kB 189 Shmem: 584 kB 190 Slab: 19092 kB 191 SReclaimable: 9128 kB 192 SUnreclaim: 9964 kB 193 KernelStack: 672 kB 194 PageTables: 1864 kB 195 NFS_Unstable: 0 kB 196 Bounce: 0 kB 197 WritebackTmp: 0 kB 198 CommitLimit: 973556 kB 199 Committed_AS: 55880 kB 200 VmallocTotal: 34359738367 kB 201 VmallocUsed: 21428 kB 202 VmallocChunk: 34359713596 kB 203 HardwareCorrupted: 0 kB 204 AnonHugePages: 0 kB 205 HugePages_Total: 0 206 HugePages_Free: 0 207 HugePages_Rsvd: 0 208 HugePages_Surp: 0 209 Hugepagesize: 2048 kB 210 DirectMap4k: 59328 kB 211 DirectMap2M: 333824 kB 212 ` 213 214 meminfoFile := procd + "/meminfo" 215 err := ioutil.WriteFile(meminfoFile, []byte(meminfoContents), 0444) 216 if err != nil { 217 t.Fatal(err) 218 } 219 220 mem := sigar.Mem{} 221 if assert.NoError(t, mem.Get()) { 222 assert.Equal(t, uint64(374256*1024), mem.Total) 223 assert.Equal(t, uint64(274460*1024), mem.Free) 224 assert.Equal(t, uint64(mem.Total-mem.Free), mem.Used) 225 assert.Equal(t, uint64((274460+9764+38648)*1024), mem.ActualFree) 226 assert.Equal(t, uint64(mem.Total-mem.ActualFree), mem.ActualUsed) 227 } 228 229 swap := sigar.Swap{} 230 if assert.NoError(t, swap.Get()) { 231 assert.Equal(t, uint64(786428*1024), swap.Total) 232 assert.Equal(t, uint64(786428*1024), swap.Free) 233 } 234 } 235 236 func TestLinuxMemAndSwapKernel_3_14(t *testing.T) { 237 setUp(t) 238 defer tearDown(t) 239 240 meminfoContents := ` 241 MemTotal: 500184 kB 242 MemFree: 31360 kB 243 MemAvailable: 414168 kB 244 Buffers: 28740 kB 245 Cached: 325408 kB 246 SwapCached: 264 kB 247 Active: 195476 kB 248 Inactive: 198612 kB 249 Active(anon): 14920 kB 250 Inactive(anon): 27268 kB 251 Active(file): 180556 kB 252 Inactive(file): 171344 kB 253 Unevictable: 0 kB 254 Mlocked: 0 kB 255 SwapTotal: 524284 kB 256 SwapFree: 520352 kB 257 Dirty: 0 kB 258 Writeback: 0 kB 259 AnonPages: 39772 kB 260 Mapped: 24132 kB 261 Shmem: 2236 kB 262 Slab: 57988 kB 263 SReclaimable: 43524 kB 264 SUnreclaim: 14464 kB 265 KernelStack: 2464 kB 266 PageTables: 3096 kB 267 NFS_Unstable: 0 kB 268 Bounce: 0 kB 269 WritebackTmp: 0 kB 270 CommitLimit: 774376 kB 271 Committed_AS: 490916 kB 272 VmallocTotal: 34359738367 kB 273 VmallocUsed: 0 kB 274 VmallocChunk: 0 kB 275 HardwareCorrupted: 0 kB 276 AnonHugePages: 0 kB 277 CmaTotal: 0 kB 278 CmaFree: 0 kB 279 HugePages_Total: 0 280 HugePages_Free: 0 281 HugePages_Rsvd: 0 282 HugePages_Surp: 0 283 Hugepagesize: 2048 kB 284 DirectMap4k: 63424 kB 285 DirectMap2M: 460800 kB 286 ` 287 288 meminfoFile := procd + "/meminfo" 289 err := ioutil.WriteFile(meminfoFile, []byte(meminfoContents), 0444) 290 if err != nil { 291 t.Fatal(err) 292 } 293 294 mem := sigar.Mem{} 295 if assert.NoError(t, mem.Get()) { 296 assert.Equal(t, uint64(500184*1024), mem.Total) 297 assert.Equal(t, uint64(31360*1024), mem.Free) 298 assert.Equal(t, uint64(414168*1024), mem.ActualFree) 299 assert.Equal(t, uint64(mem.Total-mem.Free), mem.Used) 300 assert.Equal(t, uint64(mem.Total-mem.ActualFree), mem.ActualUsed) 301 } 302 303 swap := sigar.Swap{} 304 if assert.NoError(t, swap.Get()) { 305 assert.Equal(t, uint64(524284*1024), swap.Total) 306 assert.Equal(t, uint64(520352*1024), swap.Free) 307 } 308 } 309 310 func TestLinuxMemAndSwapMissingMemTotal(t *testing.T) { 311 setUp(t) 312 defer tearDown(t) 313 314 meminfoContents := ` 315 MemFree: 31360 kB 316 MemAvailable: 414168 kB 317 Buffers: 28740 kB 318 Cached: 325408 kB 319 SwapCached: 264 kB 320 Active: 195476 kB 321 Inactive: 198612 kB 322 Active(anon): 14920 kB 323 Inactive(anon): 27268 kB 324 Active(file): 180556 kB 325 Inactive(file): 171344 kB 326 Unevictable: 0 kB 327 Mlocked: 0 kB 328 SwapTotal: 524284 kB 329 SwapFree: 520352 kB 330 Dirty: 0 kB 331 Writeback: 0 kB 332 AnonPages: 39772 kB 333 Mapped: 24132 kB 334 Shmem: 2236 kB 335 Slab: 57988 kB 336 SReclaimable: 43524 kB 337 SUnreclaim: 14464 kB 338 KernelStack: 2464 kB 339 PageTables: 3096 kB 340 NFS_Unstable: 0 kB 341 Bounce: 0 kB 342 WritebackTmp: 0 kB 343 CommitLimit: 774376 kB 344 Committed_AS: 490916 kB 345 VmallocTotal: 34359738367 kB 346 VmallocUsed: 0 kB 347 VmallocChunk: 0 kB 348 HardwareCorrupted: 0 kB 349 AnonHugePages: 0 kB 350 CmaTotal: 0 kB 351 CmaFree: 0 kB 352 HugePages_Total: 0 353 HugePages_Free: 0 354 HugePages_Rsvd: 0 355 HugePages_Surp: 0 356 Hugepagesize: 2048 kB 357 DirectMap4k: 63424 kB 358 DirectMap2M: 460800 kB 359 ` 360 361 meminfoFile := procd + "/meminfo" 362 err := ioutil.WriteFile(meminfoFile, []byte(meminfoContents), 0444) 363 if err != nil { 364 t.Fatal(err) 365 } 366 367 mem := sigar.Mem{} 368 if assert.NoError(t, mem.Get()) { 369 assert.Equal(t, uint64(0), mem.Total) 370 assert.Equal(t, uint64(31360*1024), mem.Free) 371 assert.Equal(t, uint64(414168*1024), mem.ActualFree) 372 } 373 374 swap := sigar.Swap{} 375 if assert.NoError(t, swap.Get()) { 376 assert.Equal(t, uint64(524284*1024), swap.Total) 377 assert.Equal(t, uint64(520352*1024), swap.Free) 378 } 379 } 380 381 func TestLinuxMemAndSwapKernel_3_14_memavailable_zero(t *testing.T) { 382 setUp(t) 383 defer tearDown(t) 384 385 meminfoContents := ` 386 MemTotal: 148535680 kB 387 MemFree: 417356 kB 388 MemAvailable: 0 kB 389 Buffers: 1728 kB 390 Cached: 129928 kB 391 SwapCached: 8208 kB 392 Active: 141088676 kB 393 Inactive: 5568132 kB 394 Active(anon): 141076780 kB 395 Inactive(anon): 5556936 kB 396 Active(file): 11896 kB 397 Inactive(file): 11196 kB 398 Unevictable: 3648 kB 399 Mlocked: 3648 kB 400 SwapTotal: 4882428 kB 401 SwapFree: 0 kB 402 Dirty: 808 kB 403 Writeback: 220 kB 404 AnonPages: 146521272 kB 405 Mapped: 41384 kB 406 Shmem: 105864 kB 407 Slab: 522648 kB 408 SReclaimable: 233508 kB 409 SUnreclaim: 289140 kB 410 KernelStack: 85024 kB 411 PageTables: 368760 kB 412 NFS_Unstable: 0 kB 413 Bounce: 0 kB 414 WritebackTmp: 0 kB 415 CommitLimit: 79150268 kB 416 Committed_AS: 272491684 kB 417 VmallocTotal: 34359738367 kB 418 VmallocUsed: 0 kB 419 VmallocChunk: 0 kB 420 HardwareCorrupted: 0 kB 421 AnonHugePages: 78061568 kB 422 ShmemHugePages: 0 kB 423 ShmemPmdMapped: 0 kB 424 CmaTotal: 0 kB 425 CmaFree: 0 kB 426 HugePages_Total: 0 427 HugePages_Free: 0 428 HugePages_Rsvd: 0 429 HugePages_Surp: 0 430 Hugepagesize: 2048 kB 431 DirectMap4k: 124388 kB 432 DirectMap2M: 5105664 kB 433 DirectMap1G: 147849216 kB 434 ` 435 436 meminfoFile := procd + "/meminfo" 437 err := ioutil.WriteFile(meminfoFile, []byte(meminfoContents), 0444) 438 if err != nil { 439 t.Fatal(err) 440 } 441 442 mem := sigar.Mem{} 443 if assert.NoError(t, mem.Get()) { 444 assert.Equal(t, uint64(148535680*1024), mem.Total) 445 assert.Equal(t, uint64(417356*1024), mem.Free) 446 assert.Equal(t, uint64(0), mem.ActualFree) 447 } 448 449 swap := sigar.Swap{} 450 if assert.NoError(t, swap.Get()) { 451 assert.Equal(t, uint64(4882428*1024), swap.Total) 452 assert.Equal(t, uint64(0), swap.Free) 453 } 454 455 } 456 457 func TestLinuxHugeTLBPages(t *testing.T) { 458 setUp(t) 459 defer tearDown(t) 460 461 meminfoContents := ` 462 MemTotal: 374256 kB 463 MemFree: 274460 kB 464 Buffers: 9764 kB 465 Cached: 38648 kB 466 SwapCached: 0 kB 467 Active: 33772 kB 468 Inactive: 31184 kB 469 Active(anon): 16572 kB 470 Inactive(anon): 552 kB 471 Active(file): 17200 kB 472 Inactive(file): 30632 kB 473 Unevictable: 0 kB 474 Mlocked: 0 kB 475 SwapTotal: 786428 kB 476 SwapFree: 786428 kB 477 Dirty: 0 kB 478 Writeback: 0 kB 479 AnonPages: 16564 kB 480 Mapped: 6612 kB 481 Shmem: 584 kB 482 Slab: 19092 kB 483 SReclaimable: 9128 kB 484 SUnreclaim: 9964 kB 485 KernelStack: 672 kB 486 PageTables: 1864 kB 487 NFS_Unstable: 0 kB 488 Bounce: 0 kB 489 WritebackTmp: 0 kB 490 CommitLimit: 973556 kB 491 Committed_AS: 55880 kB 492 VmallocTotal: 34359738367 kB 493 VmallocUsed: 21428 kB 494 VmallocChunk: 34359713596 kB 495 HardwareCorrupted: 0 kB 496 AnonHugePages: 0 kB 497 HugePages_Total: 16 498 HugePages_Free: 14 499 HugePages_Rsvd: 2 500 HugePages_Surp: 0 501 Hugepagesize: 2048 kB 502 DirectMap4k: 59328 kB 503 DirectMap2M: 333824 kB 504 ` 505 506 meminfoFile := procd + "/meminfo" 507 err := ioutil.WriteFile(meminfoFile, []byte(meminfoContents), 0444) 508 if err != nil { 509 t.Fatal(err) 510 } 511 512 hugePages := sigar.HugeTLBPages{} 513 if assert.NoError(t, hugePages.Get()) { 514 assert.Equal(t, uint64(16), hugePages.Total) 515 assert.Equal(t, uint64(14), hugePages.Free) 516 assert.Equal(t, uint64(2), hugePages.Reserved) 517 assert.Equal(t, uint64(0), hugePages.Surplus) 518 assert.Equal(t, uint64(2048*1024), hugePages.DefaultSize) 519 assert.Equal(t, uint64(4*2048*1024), hugePages.TotalAllocatedSize) 520 } 521 } 522 523 func TestFDUsage(t *testing.T) { 524 setUp(t) 525 defer tearDown(t) 526 527 // There is no Uint63 until 2.0 528 open := uint64(rand.Uint32()) 529 unused := uint64(rand.Uint32()) 530 max := uint64(rand.Uint32()) 531 fileNRContents := fmt.Sprintf("%d %d %d", open, unused, max) 532 533 fileNRPath := procd + "/sys/fs" 534 os.MkdirAll(fileNRPath, 0755) 535 fileNRFile := fileNRPath + "/file-nr" 536 err := ioutil.WriteFile(fileNRFile, []byte(fileNRContents), 0444) 537 if err != nil { 538 t.Fatal(err) 539 } 540 541 fd := sigar.FDUsage{} 542 if assert.NoError(t, fd.Get()) { 543 assert.Equal(t, open, fd.Open) 544 assert.Equal(t, unused, fd.Unused) 545 assert.Equal(t, max, fd.Max) 546 } 547 } 548 549 func TestProcFDUsage(t *testing.T) { 550 setUp(t) 551 defer tearDown(t) 552 553 pid := rand.Intn(32768) 554 pidDir := fmt.Sprintf("%s/%d", procd, pid) 555 err := os.Mkdir(pidDir, 0755) 556 if err != nil { 557 t.Fatal(err) 558 } 559 soft := uint64(rand.Uint32()) 560 // subtract to prevent the posibility of overflow 561 if soft != 0 { 562 soft -= 1 563 } 564 // max sure hard is always bigger than soft 565 hard := soft + uint64(rand.Uint32()) 566 567 limitsContents := `Limit Soft Limit Hard Limit Units 568 Max cpu time unlimited unlimited seconds 569 Max file size unlimited unlimited bytes 570 Max data size unlimited unlimited bytes 571 Max stack size 8388608 unlimited bytes 572 Max core file size 0 unlimited bytes 573 Max resident set unlimited unlimited bytes 574 Max processes 29875 29875 processes 575 Max open files %d %d files 576 Max locked memory 65536 65536 bytes 577 Max address space unlimited unlimited bytes 578 Max file locks unlimited unlimited locks 579 Max pending signals 29875 29875 signals 580 Max msgqueue size 819200 819200 bytes 581 Max nice priority 0 0 582 Max realtime priority 0 0 583 Max realtime timeout unlimited unlimited us 584 ` 585 586 limitsContents = fmt.Sprintf(limitsContents, soft, hard) 587 588 limitsFile := pidDir + "/limits" 589 err = ioutil.WriteFile(limitsFile, []byte(limitsContents), 0444) 590 if err != nil { 591 t.Fatal(err) 592 } 593 open := rand.Intn(32768) 594 if err = writeFDs(pid, open); err != nil { 595 t.Fatal(err) 596 } 597 598 procFD := sigar.ProcFDUsage{} 599 if assert.NoError(t, procFD.Get(pid)) { 600 assert.Equal(t, uint64(open), procFD.Open) 601 assert.Equal(t, soft, procFD.SoftLimit) 602 assert.Equal(t, hard, procFD.HardLimit) 603 } 604 } 605 606 func writeFDs(pid int, count int) error { 607 fdDir := fmt.Sprintf("%s/%d/fd", procd, pid) 608 err := os.Mkdir(fdDir, 0755) 609 if err != nil { 610 return err 611 } 612 613 for i := 0; i < count; i++ { 614 fdPath := fmt.Sprintf("%s/%d", fdDir, i) 615 f, err := os.Create(fdPath) 616 if err != nil { 617 return err 618 } 619 f.Close() 620 } 621 return nil 622 } 623 624 func writePidStats(pid int, procName string, path string) error { 625 stats := "S 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 " + 626 "20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 " + 627 "35 36 37 38 39" 628 629 statContents := []byte(fmt.Sprintf("%d (%s) %s", pid, procName, stats)) 630 return ioutil.WriteFile(path, statContents, 0644) 631 } 632 633 func writePidStatus(name string, pid int, uid int, pidStatusFile string) error { 634 status := ` 635 Name: %s 636 State: R (running) 637 Tgid: 5452 638 Pid: %d 639 PPid: 743 640 TracerPid: 0 641 Uid: %d %d %d %d 642 Gid: 100 100 100 100 643 FDSize: 256 644 Groups: 100 14 16 645 VmPeak: 5004 kB 646 VmSize: 5004 kB 647 VmLck: 0 kB 648 VmHWM: 476 kB 649 VmRSS: 476 kB 650 RssAnon: 352 kB 651 RssFile: 120 kB 652 RssShmem: 4 kB 653 VmData: 156 kB 654 VmStk: 88 kB 655 VmExe: 68 kB 656 VmLib: 1412 kB 657 VmPTE: 20 kb 658 VmSwap: 0 kB 659 HugetlbPages: 0 kB 660 Threads: 1 661 SigQ: 0/28578 662 SigPnd: 0000000000000000 663 ShdPnd: 0000000000000000 664 SigBlk: 0000000000000000 665 SigIgn: 0000000000000000 666 SigCgt: 0000000000000000 667 CapInh: 00000000fffffeff 668 CapPrm: 0000000000000000 669 CapEff: 0000000000000000 670 CapBnd: ffffffffffffffff 671 Seccomp: 0 672 voluntary_ctxt_switches: 0 673 nonvoluntary_ctxt_switches: 1` 674 675 statusContents := []byte(fmt.Sprintf(status, name, pid, uid)) 676 return ioutil.WriteFile(pidStatusFile, statusContents, 0644) 677 }