github.com/opencontainers/runc@v1.2.0-rc.1.0.20240520010911-492dc558cdd6/libcontainer/system/proc_test.go (about) 1 package system 2 3 import ( 4 "errors" 5 "math/bits" 6 "os" 7 "reflect" 8 "strconv" 9 "testing" 10 ) 11 12 var procdata = map[string]Stat_t{ 13 "4902 (gunicorn: maste) S 4885 4902 4902 0 -1 4194560 29683 29929 61 83 78 16 96 17 20 0 1 0 9126532 52965376 1903 18446744073709551615 4194304 7461796 140733928751520 140733928698072 139816984959091 0 0 16781312 137447943 1 0 0 17 3 0 0 9 0 0 9559488 10071156 33050624 140733928758775 140733928758945 140733928758945 140733928759264 0": { 14 Name: "gunicorn: maste", 15 State: 'S', 16 StartTime: 9126532, 17 }, 18 "9534 (cat) R 9323 9534 9323 34828 9534 4194304 95 0 0 0 0 0 0 0 20 0 1 0 9214966 7626752 168 18446744073709551615 4194304 4240332 140732237651568 140732237650920 140570710391216 0 0 0 0 0 0 0 17 1 0 0 0 0 0 6340112 6341364 21553152 140732237653865 140732237653885 140732237653885 140732237656047 0": { 19 Name: "cat", 20 State: 'R', 21 StartTime: 9214966, 22 }, 23 "12345 ((ugly )pr()cess() R 9323 9534 9323 34828 9534 4194304 95 0 0 0 0 0 0 0 20 0 1 0 9214966 7626752 168 18446744073709551615 4194304 4240332 140732237651568 140732237650920 140570710391216 0 0 0 0 0 0 0 17 1 0 0 0 0 0 6340112 6341364 21553152 140732237653865 140732237653885 140732237653885 140732237656047 0": { 24 Name: "(ugly )pr()cess(", 25 State: 'R', 26 StartTime: 9214966, 27 }, 28 "24767 (irq/44-mei_me) S 2 0 0 0 -1 2129984 0 0 0 0 0 0 0 0 -51 0 1 0 8722075 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 0 0 0 17 1 50 1 0 0 0 0 0 0 0 0 0 0 0": { 29 Name: "irq/44-mei_me", 30 State: 'S', 31 StartTime: 8722075, 32 }, 33 "0 () I 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0": { 34 Name: "", 35 State: 'I', 36 StartTime: 0, 37 }, 38 // Not entirely correct, but minimally viable input (StartTime and a space after). 39 "1 (woo hoo) S 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 ": { 40 Name: "woo hoo", 41 State: 'S', 42 StartTime: 4, 43 }, 44 } 45 46 func TestParseStat(t *testing.T) { 47 for line, exp := range procdata { 48 st, err := parseStat(line) 49 if err != nil { 50 t.Errorf("input %q, unexpected error %v", line, err) 51 } else if !reflect.DeepEqual(st, exp) { 52 t.Errorf("input %q, expected %+v, got %+v", line, exp, st) 53 } 54 } 55 } 56 57 func TestParseStatBadInput(t *testing.T) { 58 cases := []struct { 59 desc, input string 60 }{ 61 { 62 "no (", 63 "123 ) S 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", 64 }, 65 { 66 "no )", 67 "123 ( S 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", 68 }, 69 { 70 ") at end", 71 "123 (cmd) S 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)", 72 }, 73 { 74 "misplaced ()", 75 "123 )one( S 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", 76 }, 77 { 78 "misplaced empty ()", 79 "123 )( S 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", 80 }, 81 { 82 "empty line", 83 "", 84 }, 85 { 86 "short line", 87 "123 (cmd) S 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", 88 }, 89 { 90 "short line (no space after stime)", 91 "123 (cmd) S 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 42", 92 }, 93 { 94 "bad stime", 95 "123 (cmd) S 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 ", 96 }, 97 { 98 "bad stime 2", // would be valid if not -1 99 "123 (cmd) S -1 ", 100 }, 101 { 102 "a tad short", 103 "1234 (cmd) ", 104 }, 105 { 106 "bad stime", 107 "123 (cmd) S 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1", 108 }, 109 } 110 for _, c := range cases { 111 st, err := parseStat(c.input) 112 if err == nil { 113 t.Errorf("case %q, expected error, got nil, %+v", c.desc, st) 114 } 115 } 116 } 117 118 func BenchmarkParseStat(b *testing.B) { 119 var ( 120 st, exp Stat_t 121 line string 122 err error 123 ) 124 125 for i := 0; i != b.N; i++ { 126 for line, exp = range procdata { 127 st, err = parseStat(line) 128 } 129 } 130 if err != nil { 131 b.Fatal(err) 132 } 133 if !reflect.DeepEqual(st, exp) { 134 b.Fatal("wrong result") 135 } 136 } 137 138 func BenchmarkParseRealStat(b *testing.B) { 139 var ( 140 st Stat_t 141 err error 142 total int 143 ) 144 b.StopTimer() 145 fd, err := os.Open("/proc") 146 if err != nil { 147 b.Fatal(err) 148 } 149 defer fd.Close() 150 151 for i := 0; i != b.N; i++ { 152 count := 0 153 if _, err := fd.Seek(0, 0); err != nil { 154 b.Fatal(err) 155 } 156 names, err := fd.Readdirnames(-1) 157 if err != nil { 158 b.Fatal(err) 159 } 160 for _, n := range names { 161 pid, err := strconv.ParseUint(n, 10, bits.UintSize) 162 if err != nil { 163 continue 164 } 165 b.StartTimer() 166 st, err = Stat(int(pid)) 167 b.StopTimer() 168 if err != nil { 169 // Ignore a process that just finished. 170 if errors.Is(err, os.ErrNotExist) { 171 continue 172 } 173 b.Fatal(err) 174 } 175 count++ 176 } 177 total += count 178 } 179 b.Logf("N: %d, parsed %d pids, last stat: %+v, err: %v", b.N, total, st, err) 180 }