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 := FS("fixtures")
24
25	p1, err := fs.NewProc(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 := FS("fixtures").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 := FS("fixtures").NewProc(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 TestComm(t *testing.T) {
76	for _, tt := range []struct {
77		process int
78		want    string
79	}{
80		{process: 26231, want: "vim"},
81		{process: 26232, want: "ata_sff"},
82	} {
83		p1, err := FS("fixtures").NewProc(tt.process)
84		if err != nil {
85			t.Fatal(err)
86		}
87		c1, err := p1.Comm()
88		if err != nil {
89			t.Fatal(err)
90		}
91		if !reflect.DeepEqual(tt.want, c1) {
92			t.Errorf("want comm %v, have %v", tt.want, c1)
93		}
94	}
95}
96
97func TestExecutable(t *testing.T) {
98	for _, tt := range []struct {
99		process int
100		want    string
101	}{
102		{process: 26231, want: "/usr/bin/vim"},
103		{process: 26232, want: ""},
104	} {
105		p, err := FS("fixtures").NewProc(tt.process)
106		if err != nil {
107			t.Fatal(err)
108		}
109		exe, err := p.Executable()
110		if err != nil {
111			t.Fatal(err)
112		}
113		if !reflect.DeepEqual(tt.want, exe) {
114			t.Errorf("want absolute path to exe %v, have %v", tt.want, exe)
115		}
116	}
117}
118
119func TestCwd(t *testing.T) {
120	for _, tt := range []struct {
121		process    int
122		want       string
123		brokenLink bool
124	}{
125		{process: 26231, want: "/usr/bin"},
126		{process: 26232, want: "/does/not/exist", brokenLink: true},
127		{process: 26233, want: ""},
128	} {
129		p, err := FS("fixtures").NewProc(tt.process)
130		if err != nil {
131			t.Fatal(err)
132		}
133		wd, err := p.Cwd()
134		if err != nil {
135			t.Fatal(err)
136		}
137		if !reflect.DeepEqual(tt.want, wd) {
138			if wd == "" && tt.brokenLink {
139				// Allow the result to be empty when can't os.Readlink broken links
140				continue
141			}
142			t.Errorf("want absolute path to cwd %v, have %v", tt.want, wd)
143		}
144	}
145}
146
147func TestRoot(t *testing.T) {
148	for _, tt := range []struct {
149		process    int
150		want       string
151		brokenLink bool
152	}{
153		{process: 26231, want: "/"},
154		{process: 26232, want: "/does/not/exist", brokenLink: true},
155		{process: 26233, want: ""},
156	} {
157		p, err := FS("fixtures").NewProc(tt.process)
158		if err != nil {
159			t.Fatal(err)
160		}
161		rdir, err := p.RootDir()
162		if err != nil {
163			t.Fatal(err)
164		}
165		if !reflect.DeepEqual(tt.want, rdir) {
166			if rdir == "" && tt.brokenLink {
167				// Allow the result to be empty when can't os.Readlink broken links
168				continue
169			}
170			t.Errorf("want absolute path to rootdir %v, have %v", tt.want, rdir)
171		}
172	}
173}
174
175func TestFileDescriptors(t *testing.T) {
176	p1, err := FS("fixtures").NewProc(26231)
177	if err != nil {
178		t.Fatal(err)
179	}
180	fds, err := p1.FileDescriptors()
181	if err != nil {
182		t.Fatal(err)
183	}
184	sort.Sort(byUintptr(fds))
185	if want := []uintptr{0, 1, 2, 3, 10}; !reflect.DeepEqual(want, fds) {
186		t.Errorf("want fds %v, have %v", want, fds)
187	}
188}
189
190func TestFileDescriptorTargets(t *testing.T) {
191	p1, err := FS("fixtures").NewProc(26231)
192	if err != nil {
193		t.Fatal(err)
194	}
195	fds, err := p1.FileDescriptorTargets()
196	if err != nil {
197		t.Fatal(err)
198	}
199	sort.Strings(fds)
200	var want = []string{
201		"../../symlinktargets/abc",
202		"../../symlinktargets/def",
203		"../../symlinktargets/ghi",
204		"../../symlinktargets/uvw",
205		"../../symlinktargets/xyz",
206	}
207	if !reflect.DeepEqual(want, fds) {
208		t.Errorf("want fds %v, have %v", want, fds)
209	}
210}
211
212func TestFileDescriptorsLen(t *testing.T) {
213	p1, err := FS("fixtures").NewProc(26231)
214	if err != nil {
215		t.Fatal(err)
216	}
217	l, err := p1.FileDescriptorsLen()
218	if err != nil {
219		t.Fatal(err)
220	}
221	if want, have := 5, l; want != have {
222		t.Errorf("want fds %d, have %d", want, have)
223	}
224}
225
226type byUintptr []uintptr
227
228func (a byUintptr) Len() int           { return len(a) }
229func (a byUintptr) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
230func (a byUintptr) Less(i, j int) bool { return a[i] < a[j] }
231