File: proc_test.go

package info (click to toggle)
runc 1.3.3%2Bds1-3
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 3,136 kB
  • sloc: sh: 2,298; ansic: 1,125; makefile: 229
file content (180 lines) | stat: -rw-r--r-- 4,789 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
package system

import (
	"errors"
	"math/bits"
	"os"
	"reflect"
	"strconv"
	"testing"
)

var procdata = map[string]Stat_t{
	"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": {
		Name:      "gunicorn: maste",
		State:     'S',
		StartTime: 9126532,
	},
	"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": {
		Name:      "cat",
		State:     'R',
		StartTime: 9214966,
	},
	"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": {
		Name:      "(ugly )pr()cess(",
		State:     'R',
		StartTime: 9214966,
	},
	"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": {
		Name:      "irq/44-mei_me",
		State:     'S',
		StartTime: 8722075,
	},
	"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": {
		Name:      "",
		State:     'I',
		StartTime: 0,
	},
	// Not entirely correct, but minimally viable input (StartTime and a space after).
	"1 (woo hoo) S 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 ": {
		Name:      "woo hoo",
		State:     'S',
		StartTime: 4,
	},
}

func TestParseStat(t *testing.T) {
	for line, exp := range procdata {
		st, err := parseStat(line)
		if err != nil {
			t.Errorf("input %q, unexpected error %v", line, err)
		} else if !reflect.DeepEqual(st, exp) {
			t.Errorf("input %q, expected %+v, got %+v", line, exp, st)
		}
	}
}

func TestParseStatBadInput(t *testing.T) {
	cases := []struct {
		desc, input string
	}{
		{
			"no (",
			"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",
		},
		{
			"no )",
			"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",
		},
		{
			") at end",
			"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)",
		},
		{
			"misplaced ()",
			"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",
		},
		{
			"misplaced empty ()",
			"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",
		},
		{
			"empty line",
			"",
		},
		{
			"short line",
			"123 (cmd) S 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0",
		},
		{
			"short line (no space after stime)",
			"123 (cmd) S 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 42",
		},
		{
			"bad stime",
			"123 (cmd) S 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 ",
		},
		{
			"bad stime 2", // would be valid if not -1
			"123 (cmd) S                   -1 ",
		},
		{
			"a tad short",
			"1234 (cmd) ",
		},
		{
			"bad stime",
			"123 (cmd) S 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1",
		},
	}
	for _, c := range cases {
		st, err := parseStat(c.input)
		if err == nil {
			t.Errorf("case %q, expected error, got nil, %+v", c.desc, st)
		}
	}
}

func BenchmarkParseStat(b *testing.B) {
	var (
		st, exp Stat_t
		line    string
		err     error
	)

	for i := 0; i != b.N; i++ {
		for line, exp = range procdata {
			st, err = parseStat(line)
		}
	}
	if err != nil {
		b.Fatal(err)
	}
	if !reflect.DeepEqual(st, exp) {
		b.Fatal("wrong result")
	}
}

func BenchmarkParseRealStat(b *testing.B) {
	var (
		st    Stat_t
		err   error
		total int
	)
	b.StopTimer()
	fd, err := os.Open("/proc")
	if err != nil {
		b.Fatal(err)
	}
	defer fd.Close()

	for i := 0; i != b.N; i++ {
		count := 0
		if _, err := fd.Seek(0, 0); err != nil {
			b.Fatal(err)
		}
		names, err := fd.Readdirnames(-1)
		if err != nil {
			b.Fatal(err)
		}
		for _, n := range names {
			pid, err := strconv.ParseUint(n, 10, bits.UintSize)
			if err != nil {
				continue
			}
			b.StartTimer()
			st, err = Stat(int(pid))
			b.StopTimer()
			if err != nil {
				// Ignore a process that just finished.
				if errors.Is(err, os.ErrNotExist) {
					continue
				}
				b.Fatal(err)
			}
			count++
		}
		total += count
	}
	b.Logf("N: %d, parsed %d pids, last stat: %+v, err: %v", b.N, total, st, err)
}