1// Copyright 2018 The Prometheus Authors
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14package procfs
15
16import (
17	"reflect"
18	"sort"
19	"testing"
20)
21
22func TestSelf(t *testing.T) {
23	fs := getProcFixtures(t)
24
25	p1, err := fs.Proc(26231)
26	if err != nil {
27		t.Fatal(err)
28	}
29	p2, err := fs.Self()
30	if err != nil {
31		t.Fatal(err)
32	}
33
34	if !reflect.DeepEqual(p1, p2) {
35		t.Errorf("want process %v, have %v", p1, p2)
36	}
37}
38
39func TestAllProcs(t *testing.T) {
40	procs, err := getProcFixtures(t).AllProcs()
41	if err != nil {
42		t.Fatal(err)
43	}
44	sort.Sort(procs)
45	for i, p := range []*Proc{{PID: 584}, {PID: 26231}} {
46		if want, have := p.PID, procs[i].PID; want != have {
47			t.Errorf("want processes %d, have %d", want, have)
48		}
49	}
50}
51
52func TestCmdLine(t *testing.T) {
53	for _, tt := range []struct {
54		process int
55		want    []string
56	}{
57		{process: 26231, want: []string{"vim", "test.go", "+10"}},
58		{process: 26232, want: []string{}},
59		{process: 26233, want: []string{"com.github.uiautomator"}},
60	} {
61		p1, err := getProcFixtures(t).Proc(tt.process)
62		if err != nil {
63			t.Fatal(err)
64		}
65		c1, err := p1.CmdLine()
66		if err != nil {
67			t.Fatal(err)
68		}
69		if !reflect.DeepEqual(tt.want, c1) {
70			t.Errorf("want cmdline %v, have %v", tt.want, c1)
71		}
72	}
73}
74
75func TestWchan(t *testing.T) {
76	for _, tt := range []struct {
77		process int
78		want    string
79	}{
80		{process: 26231, want: "poll_schedule_timeout"},
81		{process: 26232, want: ""},
82	} {
83		p1, err := getProcFixtures(t).Proc(tt.process)
84		if err != nil {
85			t.Fatal(err)
86		}
87		c1, err := p1.Wchan()
88		if err != nil {
89			t.Fatal(err)
90		}
91		if !reflect.DeepEqual(tt.want, c1) {
92			t.Errorf("want wchan %v, have %v", tt.want, c1)
93		}
94	}
95}
96
97func TestComm(t *testing.T) {
98	for _, tt := range []struct {
99		process int
100		want    string
101	}{
102		{process: 26231, want: "vim"},
103		{process: 26232, want: "ata_sff"},
104	} {
105		p1, err := getProcFixtures(t).Proc(tt.process)
106		if err != nil {
107			t.Fatal(err)
108		}
109		c1, err := p1.Comm()
110		if err != nil {
111			t.Fatal(err)
112		}
113		if !reflect.DeepEqual(tt.want, c1) {
114			t.Errorf("want comm %v, have %v", tt.want, c1)
115		}
116	}
117}
118
119func TestExecutable(t *testing.T) {
120	for _, tt := range []struct {
121		process int
122		want    string
123	}{
124		{process: 26231, want: "/usr/bin/vim"},
125		{process: 26232, want: ""},
126	} {
127		p, err := getProcFixtures(t).Proc(tt.process)
128		if err != nil {
129			t.Fatal(err)
130		}
131		exe, err := p.Executable()
132		if err != nil {
133			t.Fatal(err)
134		}
135		if !reflect.DeepEqual(tt.want, exe) {
136			t.Errorf("want absolute path to exe %v, have %v", tt.want, exe)
137		}
138	}
139}
140
141func TestCwd(t *testing.T) {
142	for _, tt := range []struct {
143		process    int
144		want       string
145		brokenLink bool
146	}{
147		{process: 26231, want: "/usr/bin"},
148		{process: 26232, want: "/does/not/exist", brokenLink: true},
149		{process: 26233, want: ""},
150	} {
151		p, err := getProcFixtures(t).Proc(tt.process)
152		if err != nil {
153			t.Fatal(err)
154		}
155		wd, err := p.Cwd()
156		if err != nil {
157			t.Fatal(err)
158		}
159		if !reflect.DeepEqual(tt.want, wd) {
160			if wd == "" && tt.brokenLink {
161				// Allow the result to be empty when can't os.Readlink broken links
162				continue
163			}
164			t.Errorf("want absolute path to cwd %v, have %v", tt.want, wd)
165		}
166	}
167}
168
169func TestRoot(t *testing.T) {
170	for _, tt := range []struct {
171		process    int
172		want       string
173		brokenLink bool
174	}{
175		{process: 26231, want: "/"},
176		{process: 26232, want: "/does/not/exist", brokenLink: true},
177		{process: 26233, want: ""},
178	} {
179		p, err := getProcFixtures(t).Proc(tt.process)
180		if err != nil {
181			t.Fatal(err)
182		}
183		rdir, err := p.RootDir()
184		if err != nil {
185			t.Fatal(err)
186		}
187		if !reflect.DeepEqual(tt.want, rdir) {
188			if rdir == "" && tt.brokenLink {
189				// Allow the result to be empty when can't os.Readlink broken links
190				continue
191			}
192			t.Errorf("want absolute path to rootdir %v, have %v", tt.want, rdir)
193		}
194	}
195}
196
197func TestFileDescriptors(t *testing.T) {
198	p1, err := getProcFixtures(t).Proc(26231)
199	if err != nil {
200		t.Fatal(err)
201	}
202	fds, err := p1.FileDescriptors()
203	if err != nil {
204		t.Fatal(err)
205	}
206	sort.Sort(byUintptr(fds))
207	if want := []uintptr{0, 1, 2, 3, 10}; !reflect.DeepEqual(want, fds) {
208		t.Errorf("want fds %v, have %v", want, fds)
209	}
210}
211
212func TestFileDescriptorTargets(t *testing.T) {
213	p1, err := getProcFixtures(t).Proc(26231)
214	if err != nil {
215		t.Fatal(err)
216	}
217	fds, err := p1.FileDescriptorTargets()
218	if err != nil {
219		t.Fatal(err)
220	}
221	sort.Strings(fds)
222	var want = []string{
223		"../../symlinktargets/abc",
224		"../../symlinktargets/def",
225		"../../symlinktargets/ghi",
226		"../../symlinktargets/uvw",
227		"../../symlinktargets/xyz",
228	}
229	if !reflect.DeepEqual(want, fds) {
230		t.Errorf("want fds %v, have %v", want, fds)
231	}
232}
233
234func TestFileDescriptorsLen(t *testing.T) {
235	p1, err := getProcFixtures(t).Proc(26231)
236	if err != nil {
237		t.Fatal(err)
238	}
239	l, err := p1.FileDescriptorsLen()
240	if err != nil {
241		t.Fatal(err)
242	}
243	if want, have := 5, l; want != have {
244		t.Errorf("want fds %d, have %d", want, have)
245	}
246}
247
248func TestFileDescriptorsInfo(t *testing.T) {
249	p1, err := getProcFixtures(t).Proc(26231)
250	if err != nil {
251		t.Fatal(err)
252	}
253	fdinfos, err := p1.FileDescriptorsInfo()
254	if err != nil {
255		t.Fatal(err)
256	}
257	sort.Sort(fdinfos)
258	var want = ProcFDInfos{
259		ProcFDInfo{FD: "0", Pos: "0", Flags: "02004000", MntID: "13", InotifyInfos: []InotifyInfo{
260			InotifyInfo{WD: "3", Ino: "1", Sdev: "34", Mask: "fce"},
261			InotifyInfo{WD: "2", Ino: "1300016", Sdev: "fd00002", Mask: "fce"},
262			InotifyInfo{WD: "1", Ino: "2e0001", Sdev: "fd00000", Mask: "fce"},
263		}},
264		ProcFDInfo{FD: "1", Pos: "0", Flags: "02004002", MntID: "13", InotifyInfos: nil},
265		ProcFDInfo{FD: "10", Pos: "0", Flags: "02004002", MntID: "9", InotifyInfos: nil},
266		ProcFDInfo{FD: "2", Pos: "0", Flags: "02004002", MntID: "9", InotifyInfos: nil},
267		ProcFDInfo{FD: "3", Pos: "0", Flags: "02004002", MntID: "9", InotifyInfos: nil},
268	}
269	if !reflect.DeepEqual(want, fdinfos) {
270		t.Errorf("want fdinfos %+v, have %+v", want, fdinfos)
271	}
272}
273
274type byUintptr []uintptr
275
276func (a byUintptr) Len() int           { return len(a) }
277func (a byUintptr) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
278func (a byUintptr) Less(i, j int) bool { return a[i] < a[j] }
279