1package process
2
3import (
4	"fmt"
5	"io/ioutil"
6	"net"
7	"os"
8	"os/exec"
9	"os/user"
10	"path/filepath"
11	"reflect"
12	"runtime"
13	"strconv"
14	"strings"
15	"sync"
16	"testing"
17	"time"
18
19	"github.com/shirou/gopsutil/internal/common"
20	"github.com/stretchr/testify/assert"
21)
22
23var mu sync.Mutex
24
25func skipIfNotImplementedErr(t *testing.T, err error) {
26	if err == common.ErrNotImplementedError {
27		t.Skip("not implemented")
28	}
29}
30
31func testGetProcess() Process {
32	checkPid := os.Getpid() // process.test
33	ret, _ := NewProcess(int32(checkPid))
34	return *ret
35}
36
37func Test_Pids(t *testing.T) {
38	ret, err := Pids()
39	skipIfNotImplementedErr(t, err)
40	if err != nil {
41		t.Errorf("error %v", err)
42	}
43	if len(ret) == 0 {
44		t.Errorf("could not get pids %v", ret)
45	}
46}
47
48func Test_Pids_Fail(t *testing.T) {
49	if runtime.GOOS != "darwin" {
50		t.Skip("darwin only")
51	}
52
53	mu.Lock()
54	defer mu.Unlock()
55
56	invoke = common.FakeInvoke{Suffix: "fail"}
57	ret, err := Pids()
58	skipIfNotImplementedErr(t, err)
59	invoke = common.Invoke{}
60	if err != nil {
61		t.Errorf("error %v", err)
62	}
63	if len(ret) != 9 {
64		t.Errorf("wrong getted pid nums: %v/%d", ret, len(ret))
65	}
66}
67func Test_Pid_exists(t *testing.T) {
68	checkPid := os.Getpid()
69
70	ret, err := PidExists(int32(checkPid))
71	skipIfNotImplementedErr(t, err)
72	if err != nil {
73		t.Errorf("error %v", err)
74	}
75
76	if ret == false {
77		t.Errorf("could not get process exists: %v", ret)
78	}
79}
80
81func Test_NewProcess(t *testing.T) {
82	checkPid := os.Getpid()
83
84	ret, err := NewProcess(int32(checkPid))
85	skipIfNotImplementedErr(t, err)
86	if err != nil {
87		t.Errorf("error %v", err)
88	}
89	empty := &Process{}
90	if runtime.GOOS != "windows" { // Windows pid is 0
91		if empty == ret {
92			t.Errorf("error %v", ret)
93		}
94	}
95
96}
97
98func Test_Process_memory_maps(t *testing.T) {
99	checkPid := os.Getpid()
100
101	ret, err := NewProcess(int32(checkPid))
102	skipIfNotImplementedErr(t, err)
103	if err != nil {
104		t.Errorf("error %v", err)
105	}
106
107	// ungrouped memory maps
108	mmaps, err := ret.MemoryMaps(false)
109	skipIfNotImplementedErr(t, err)
110	if err != nil {
111		t.Errorf("memory map get error %v", err)
112	}
113	empty := MemoryMapsStat{}
114	for _, m := range *mmaps {
115		if m == empty {
116			t.Errorf("memory map get error %v", m)
117		}
118	}
119
120	// grouped memory maps
121	mmaps, err = ret.MemoryMaps(true)
122	skipIfNotImplementedErr(t, err)
123	if err != nil {
124		t.Errorf("memory map get error %v", err)
125	}
126	if len(*mmaps) != 1 {
127		t.Errorf("grouped memory maps length (%v) is not equal to 1", len(*mmaps))
128	}
129	if (*mmaps)[0] == empty {
130		t.Errorf("memory map is empty")
131	}
132}
133func Test_Process_MemoryInfo(t *testing.T) {
134	p := testGetProcess()
135
136	v, err := p.MemoryInfo()
137	skipIfNotImplementedErr(t, err)
138	if err != nil {
139		t.Errorf("getting memory info error %v", err)
140	}
141	empty := MemoryInfoStat{}
142	if v == nil || *v == empty {
143		t.Errorf("could not get memory info %v", v)
144	}
145}
146
147func Test_Process_CmdLine(t *testing.T) {
148	p := testGetProcess()
149
150	v, err := p.Cmdline()
151	skipIfNotImplementedErr(t, err)
152	if err != nil {
153		t.Errorf("getting cmdline error %v", err)
154	}
155	if !strings.Contains(v, "process.test") {
156		t.Errorf("invalid cmd line %v", v)
157	}
158}
159
160func Test_Process_CmdLineSlice(t *testing.T) {
161	p := testGetProcess()
162
163	v, err := p.CmdlineSlice()
164	skipIfNotImplementedErr(t, err)
165	if err != nil {
166		t.Fatalf("getting cmdline slice error %v", err)
167	}
168	if !reflect.DeepEqual(v, os.Args) {
169		t.Errorf("returned cmdline slice not as expected:\nexp: %v\ngot: %v", os.Args, v)
170	}
171}
172
173func Test_Process_Ppid(t *testing.T) {
174	p := testGetProcess()
175
176	v, err := p.Ppid()
177	skipIfNotImplementedErr(t, err)
178	if err != nil {
179		t.Errorf("getting ppid error %v", err)
180	}
181	if v == 0 {
182		t.Errorf("return value is 0 %v", v)
183	}
184	expected := os.Getppid()
185	if v != int32(expected) {
186		t.Errorf("return value is %v, expected %v", v, expected)
187	}
188}
189
190func Test_Process_Status(t *testing.T) {
191	p := testGetProcess()
192
193	v, err := p.Status()
194	skipIfNotImplementedErr(t, err)
195	if err != nil {
196		t.Errorf("getting status error %v", err)
197	}
198	if v != "R" && v != "S" {
199		t.Errorf("could not get state %v", v)
200	}
201}
202
203func Test_Process_Terminal(t *testing.T) {
204	p := testGetProcess()
205
206	_, err := p.Terminal()
207	skipIfNotImplementedErr(t, err)
208	if err != nil {
209		t.Errorf("getting terminal error %v", err)
210	}
211}
212
213func Test_Process_IOCounters(t *testing.T) {
214	p := testGetProcess()
215
216	v, err := p.IOCounters()
217	skipIfNotImplementedErr(t, err)
218	if err != nil {
219		t.Errorf("getting iocounter error %v", err)
220		return
221	}
222	empty := &IOCountersStat{}
223	if v == empty {
224		t.Errorf("error %v", v)
225	}
226}
227
228func Test_Process_NumCtx(t *testing.T) {
229	p := testGetProcess()
230
231	_, err := p.NumCtxSwitches()
232	skipIfNotImplementedErr(t, err)
233	if err != nil {
234		t.Errorf("getting numctx error %v", err)
235		return
236	}
237}
238
239func Test_Process_Nice(t *testing.T) {
240	p := testGetProcess()
241
242	n, err := p.Nice()
243	skipIfNotImplementedErr(t, err)
244	if err != nil {
245		t.Errorf("getting nice error %v", err)
246	}
247	if runtime.GOOS != "windows" && n != 0 && n != 20 && n != 8 {
248		t.Errorf("invalid nice: %d", n)
249	}
250}
251
252func Test_Process_Groups(t *testing.T) {
253	p := testGetProcess()
254
255	v, err := p.Groups()
256	skipIfNotImplementedErr(t, err)
257	if err != nil {
258		t.Errorf("getting groups error %v", err)
259	}
260	if len(v) == 0 {
261		t.Skip("Groups is empty")
262	}
263	if v[0] < 0 {
264		t.Errorf("invalid Groups: %v", v)
265	}
266}
267
268func Test_Process_NumThread(t *testing.T) {
269	p := testGetProcess()
270
271	n, err := p.NumThreads()
272	skipIfNotImplementedErr(t, err)
273	if err != nil {
274		t.Errorf("getting NumThread error %v", err)
275	}
276	if n < 0 {
277		t.Errorf("invalid NumThread: %d", n)
278	}
279}
280
281func Test_Process_Threads(t *testing.T) {
282	p := testGetProcess()
283
284	n, err := p.NumThreads()
285	skipIfNotImplementedErr(t, err)
286	if err != nil {
287		t.Errorf("getting NumThread error %v", err)
288	}
289	if n < 0 {
290		t.Errorf("invalid NumThread: %d", n)
291	}
292
293	ts, err := p.Threads()
294	skipIfNotImplementedErr(t, err)
295	if err != nil {
296		t.Errorf("getting Threads error %v", err)
297	}
298	if len(ts) != int(n) {
299		t.Errorf("unexpected number of threads: %v vs %v", len(ts), n)
300	}
301}
302
303func Test_Process_Name(t *testing.T) {
304	p := testGetProcess()
305
306	n, err := p.Name()
307	skipIfNotImplementedErr(t, err)
308	if err != nil {
309		t.Errorf("getting name error %v", err)
310	}
311	if !strings.Contains(n, "process.test") {
312		t.Errorf("invalid Exe %s", n)
313	}
314}
315
316func Test_Process_Long_Name_With_Spaces(t *testing.T) {
317	tmpdir, err := ioutil.TempDir("", "")
318	if err != nil {
319		t.Fatalf("unable to create temp dir %v", err)
320	}
321	defer os.RemoveAll(tmpdir) // clean up
322	tmpfilepath := filepath.Join(tmpdir, "loooong name with spaces.go")
323	tmpfile, err := os.Create(tmpfilepath)
324	if err != nil {
325		t.Fatalf("unable to create temp file %v", err)
326	}
327
328	tmpfilecontent := []byte("package main\nimport(\n\"time\"\n)\nfunc main(){\nfor range time.Tick(time.Second) {}\n}")
329	if _, err := tmpfile.Write(tmpfilecontent); err != nil {
330		tmpfile.Close()
331		t.Fatalf("unable to write temp file %v", err)
332	}
333	if err := tmpfile.Close(); err != nil {
334		t.Fatalf("unable to close temp file %v", err)
335	}
336
337	err = exec.Command("go", "build", "-o", tmpfile.Name()+".exe", tmpfile.Name()).Run()
338	if err != nil {
339		t.Fatalf("unable to build temp file %v", err)
340	}
341
342	cmd := exec.Command(tmpfile.Name() + ".exe")
343
344	assert.Nil(t, cmd.Start())
345	time.Sleep(100 * time.Millisecond)
346	p, err := NewProcess(int32(cmd.Process.Pid))
347	skipIfNotImplementedErr(t, err)
348	assert.Nil(t, err)
349
350	n, err := p.Name()
351	skipIfNotImplementedErr(t, err)
352	if err != nil {
353		t.Fatalf("getting name error %v", err)
354	}
355	basename := filepath.Base(tmpfile.Name() + ".exe")
356	if basename != n {
357		t.Fatalf("%s != %s", basename, n)
358	}
359	cmd.Process.Kill()
360}
361func Test_Process_Long_Name(t *testing.T) {
362	tmpdir, err := ioutil.TempDir("", "")
363	if err != nil {
364		t.Fatalf("unable to create temp dir %v", err)
365	}
366	defer os.RemoveAll(tmpdir) // clean up
367	tmpfilepath := filepath.Join(tmpdir, "looooooooooooooooooooong.go")
368	tmpfile, err := os.Create(tmpfilepath)
369	if err != nil {
370		t.Fatalf("unable to create temp file %v", err)
371	}
372
373	tmpfilecontent := []byte("package main\nimport(\n\"time\"\n)\nfunc main(){\nfor range time.Tick(time.Second) {}\n}")
374	if _, err := tmpfile.Write(tmpfilecontent); err != nil {
375		tmpfile.Close()
376		t.Fatalf("unable to write temp file %v", err)
377	}
378	if err := tmpfile.Close(); err != nil {
379		t.Fatalf("unable to close temp file %v", err)
380	}
381
382	err = exec.Command("go", "build", "-o", tmpfile.Name()+".exe", tmpfile.Name()).Run()
383	if err != nil {
384		t.Fatalf("unable to build temp file %v", err)
385	}
386
387	cmd := exec.Command(tmpfile.Name() + ".exe")
388
389	assert.Nil(t, cmd.Start())
390	time.Sleep(100 * time.Millisecond)
391	p, err := NewProcess(int32(cmd.Process.Pid))
392	skipIfNotImplementedErr(t, err)
393	assert.Nil(t, err)
394
395	n, err := p.Name()
396	skipIfNotImplementedErr(t, err)
397	if err != nil {
398		t.Fatalf("getting name error %v", err)
399	}
400	basename := filepath.Base(tmpfile.Name() + ".exe")
401	if basename != n {
402		t.Fatalf("%s != %s", basename, n)
403	}
404	cmd.Process.Kill()
405}
406func Test_Process_Exe(t *testing.T) {
407	p := testGetProcess()
408
409	n, err := p.Exe()
410	skipIfNotImplementedErr(t, err)
411	if err != nil {
412		t.Errorf("getting Exe error %v", err)
413	}
414	if !strings.Contains(n, "process.test") {
415		t.Errorf("invalid Exe %s", n)
416	}
417}
418
419func Test_Process_CpuPercent(t *testing.T) {
420	p := testGetProcess()
421	_, err := p.Percent(0)
422	skipIfNotImplementedErr(t, err)
423	if err != nil {
424		t.Errorf("error %v", err)
425	}
426	duration := time.Duration(1000) * time.Microsecond
427	time.Sleep(duration)
428	percent, err := p.Percent(0)
429	if err != nil {
430		t.Errorf("error %v", err)
431	}
432
433	numcpu := runtime.NumCPU()
434	//	if percent < 0.0 || percent > 100.0*float64(numcpu) { // TODO
435	if percent < 0.0 {
436		t.Fatalf("CPUPercent value is invalid: %f, %d", percent, numcpu)
437	}
438}
439
440func Test_Process_CpuPercentLoop(t *testing.T) {
441	p := testGetProcess()
442	numcpu := runtime.NumCPU()
443
444	for i := 0; i < 2; i++ {
445		duration := time.Duration(100) * time.Microsecond
446		percent, err := p.Percent(duration)
447		skipIfNotImplementedErr(t, err)
448		if err != nil {
449			t.Errorf("error %v", err)
450		}
451		//	if percent < 0.0 || percent > 100.0*float64(numcpu) { // TODO
452		if percent < 0.0 {
453			t.Fatalf("CPUPercent value is invalid: %f, %d", percent, numcpu)
454		}
455	}
456}
457
458func Test_Process_CreateTime(t *testing.T) {
459	if os.Getenv("CIRCLECI") == "true" {
460		t.Skip("Skip CI")
461	}
462
463	p := testGetProcess()
464
465	c, err := p.CreateTime()
466	skipIfNotImplementedErr(t, err)
467	if err != nil {
468		t.Errorf("error %v", err)
469	}
470
471	if c < 1420000000 {
472		t.Errorf("process created time is wrong.")
473	}
474
475	gotElapsed := time.Since(time.Unix(int64(c/1000), 0))
476	maxElapsed := time.Duration(5 * time.Second)
477
478	if gotElapsed >= maxElapsed {
479		t.Errorf("this process has not been running for %v", gotElapsed)
480	}
481}
482
483func Test_Parent(t *testing.T) {
484	p := testGetProcess()
485
486	c, err := p.Parent()
487	skipIfNotImplementedErr(t, err)
488	if err != nil {
489		t.Fatalf("error %v", err)
490	}
491	if c == nil {
492		t.Fatalf("could not get parent")
493	}
494	if c.Pid == 0 {
495		t.Fatalf("wrong parent pid")
496	}
497}
498
499func Test_Connections(t *testing.T) {
500	p := testGetProcess()
501
502	addr, err := net.ResolveTCPAddr("tcp", "localhost:0") // dynamically get a random open port from OS
503	if err != nil {
504		t.Fatalf("unable to resolve localhost: %v", err)
505	}
506	l, err := net.ListenTCP(addr.Network(), addr)
507	if err != nil {
508		t.Fatalf("unable to listen on %v: %v", addr, err)
509	}
510	defer l.Close()
511
512	tcpServerAddr := l.Addr().String()
513	tcpServerAddrIP := strings.Split(tcpServerAddr, ":")[0]
514	tcpServerAddrPort, err := strconv.ParseUint(strings.Split(tcpServerAddr, ":")[1], 10, 32)
515	if err != nil {
516		t.Fatalf("unable to parse tcpServerAddr port: %v", err)
517	}
518
519	serverEstablished := make(chan struct{})
520	go func() { // TCP listening goroutine
521		conn, err := l.Accept()
522		if err != nil {
523			panic(err)
524		}
525		defer conn.Close()
526
527		serverEstablished <- struct{}{}
528		_, err = ioutil.ReadAll(conn)
529		if err != nil {
530			panic(err)
531		}
532	}()
533
534	conn, err := net.Dial("tcp", tcpServerAddr)
535	if err != nil {
536		t.Fatalf("unable to dial %v: %v", tcpServerAddr, err)
537	}
538	defer conn.Close()
539
540	// Rarely the call to net.Dial returns before the server connection is
541	// established. Wait so that the test doesn't fail.
542	<-serverEstablished
543
544	c, err := p.Connections()
545	skipIfNotImplementedErr(t, err)
546	if err != nil {
547		t.Fatalf("error %v", err)
548	}
549	if len(c) == 0 {
550		t.Fatal("no connections found")
551	}
552
553	serverConnections := 0
554	for _, connection := range c {
555		if connection.Laddr.IP == tcpServerAddrIP && connection.Laddr.Port == uint32(tcpServerAddrPort) && connection.Raddr.Port != 0 {
556			if connection.Status != "ESTABLISHED" {
557				t.Fatalf("expected server connection to be ESTABLISHED, have %+v", connection)
558			}
559			serverConnections++
560		}
561	}
562
563	clientConnections := 0
564	for _, connection := range c {
565		if connection.Raddr.IP == tcpServerAddrIP && connection.Raddr.Port == uint32(tcpServerAddrPort) {
566			if connection.Status != "ESTABLISHED" {
567				t.Fatalf("expected client connection to be ESTABLISHED, have %+v", connection)
568			}
569			clientConnections++
570		}
571	}
572
573	if serverConnections != 1 { // two established connections, one for the server, the other for the client
574		t.Fatalf("expected 1 server connection, have %d.\nDetails: %+v", serverConnections, c)
575	}
576
577	if clientConnections != 1 { // two established connections, one for the server, the other for the client
578		t.Fatalf("expected 1 server connection, have %d.\nDetails: %+v", clientConnections, c)
579	}
580}
581
582func Test_Children(t *testing.T) {
583	p := testGetProcess()
584
585	var cmd *exec.Cmd
586	if runtime.GOOS == "windows" {
587		cmd = exec.Command("ping", "localhost", "-n", "4")
588	} else {
589		cmd = exec.Command("sleep", "3")
590	}
591	assert.Nil(t, cmd.Start())
592	time.Sleep(100 * time.Millisecond)
593
594	c, err := p.Children()
595	skipIfNotImplementedErr(t, err)
596	if err != nil {
597		t.Fatalf("error %v", err)
598	}
599	if len(c) == 0 {
600		t.Fatalf("children is empty")
601	}
602	found := false
603	for _, child := range c {
604		if child.Pid == int32(cmd.Process.Pid) {
605			found = true
606			break
607		}
608	}
609	if !found {
610		t.Errorf("could not find child %d", cmd.Process.Pid)
611	}
612}
613
614func Test_Username(t *testing.T) {
615	myPid := os.Getpid()
616	currentUser, _ := user.Current()
617	myUsername := currentUser.Username
618
619	process, _ := NewProcess(int32(myPid))
620	pidUsername, err := process.Username()
621	skipIfNotImplementedErr(t, err)
622	assert.Equal(t, myUsername, pidUsername)
623
624	t.Log(pidUsername)
625}
626
627func Test_CPUTimes(t *testing.T) {
628	pid := os.Getpid()
629	process, err := NewProcess(int32(pid))
630	skipIfNotImplementedErr(t, err)
631	assert.Nil(t, err)
632
633	spinSeconds := 0.2
634	cpuTimes0, err := process.Times()
635	skipIfNotImplementedErr(t, err)
636	assert.Nil(t, err)
637
638	// Spin for a duration of spinSeconds
639	t0 := time.Now()
640	tGoal := t0.Add(time.Duration(spinSeconds*1000) * time.Millisecond)
641	assert.Nil(t, err)
642	for time.Now().Before(tGoal) {
643		// This block intentionally left blank
644	}
645
646	cpuTimes1, err := process.Times()
647	assert.Nil(t, err)
648
649	if cpuTimes0 == nil || cpuTimes1 == nil {
650		t.FailNow()
651	}
652	measuredElapsed := cpuTimes1.Total() - cpuTimes0.Total()
653	message := fmt.Sprintf("Measured %fs != spun time of %fs\ncpuTimes0=%v\ncpuTimes1=%v",
654		measuredElapsed, spinSeconds, cpuTimes0, cpuTimes1)
655	assert.True(t, measuredElapsed > float64(spinSeconds)/5, message)
656	assert.True(t, measuredElapsed < float64(spinSeconds)*5, message)
657}
658
659func Test_OpenFiles(t *testing.T) {
660	pid := os.Getpid()
661	p, err := NewProcess(int32(pid))
662	skipIfNotImplementedErr(t, err)
663	assert.Nil(t, err)
664
665	v, err := p.OpenFiles()
666	skipIfNotImplementedErr(t, err)
667	assert.Nil(t, err)
668	assert.NotEmpty(t, v) // test always open files.
669
670	for _, vv := range v {
671		assert.NotEqual(t, "", vv.Path)
672	}
673}
674
675func Test_Kill(t *testing.T) {
676	var cmd *exec.Cmd
677	if runtime.GOOS == "windows" {
678		cmd = exec.Command("ping", "localhost", "-n", "4")
679	} else {
680		cmd = exec.Command("sleep", "3")
681	}
682	assert.Nil(t, cmd.Start())
683	time.Sleep(100 * time.Millisecond)
684	p, err := NewProcess(int32(cmd.Process.Pid))
685	skipIfNotImplementedErr(t, err)
686	assert.Nil(t, err)
687	err = p.Kill()
688	skipIfNotImplementedErr(t, err)
689	assert.Nil(t, err)
690	cmd.Wait()
691}
692
693func Test_IsRunning(t *testing.T) {
694	var cmd *exec.Cmd
695	if runtime.GOOS == "windows" {
696		cmd = exec.Command("ping", "localhost", "-n", "2")
697	} else {
698		cmd = exec.Command("sleep", "1")
699	}
700	cmd.Start()
701	p, err := NewProcess(int32(cmd.Process.Pid))
702	skipIfNotImplementedErr(t, err)
703	assert.Nil(t, err)
704	running, err := p.IsRunning()
705	skipIfNotImplementedErr(t, err)
706	if err != nil {
707		t.Fatalf("IsRunning error: %v", err)
708	}
709	if !running {
710		t.Fatalf("process should be found running")
711	}
712	cmd.Wait()
713	running, err = p.IsRunning()
714	skipIfNotImplementedErr(t, err)
715	if err != nil {
716		t.Fatalf("IsRunning error: %v", err)
717	}
718	if running {
719		t.Fatalf("process should NOT be found running")
720	}
721}
722
723func Test_Process_Environ(t *testing.T) {
724	tmpdir, err := ioutil.TempDir("", "")
725	if err != nil {
726		t.Fatalf("unable to create temp dir %v", err)
727	}
728	defer os.RemoveAll(tmpdir) // clean up
729	tmpfilepath := filepath.Join(tmpdir, "test.go")
730	tmpfile, err := os.Create(tmpfilepath)
731	if err != nil {
732		t.Fatalf("unable to create temp file %v", err)
733	}
734
735	tmpfilecontent := []byte("package main\nimport(\n\"time\"\n)\nfunc main(){\nfor range time.Tick(time.Second) {}\n}")
736	if _, err := tmpfile.Write(tmpfilecontent); err != nil {
737		tmpfile.Close()
738		t.Fatalf("unable to write temp file %v", err)
739	}
740	if err := tmpfile.Close(); err != nil {
741		t.Fatalf("unable to close temp file %v", err)
742	}
743
744	err = exec.Command("go", "build", "-o", tmpfile.Name()+".exe", tmpfile.Name()).Run()
745	if err != nil {
746		t.Fatalf("unable to build temp file %v", err)
747	}
748
749	cmd := exec.Command(tmpfile.Name() + ".exe")
750
751	cmd.Env = []string{"testkey=envvalue"}
752
753	assert.Nil(t, cmd.Start())
754	defer cmd.Process.Kill()
755	time.Sleep(100 * time.Millisecond)
756	p, err := NewProcess(int32(cmd.Process.Pid))
757	skipIfNotImplementedErr(t, err)
758	assert.Nil(t, err)
759
760	envs, err := p.Environ()
761	skipIfNotImplementedErr(t, err)
762	if err != nil {
763		t.Errorf("getting environ error %v", err)
764	}
765	var envvarFound bool
766	for _, envvar := range envs {
767		if envvar == "testkey=envvalue" {
768			envvarFound = true
769			break
770		}
771	}
772	if !envvarFound {
773		t.Error("environment variable not found")
774	}
775}
776
777func Test_AllProcesses_cmdLine(t *testing.T) {
778	procs, err := Processes()
779	skipIfNotImplementedErr(t, err)
780	if err != nil {
781		t.Fatalf("getting processes error %v", err)
782	}
783	for _, proc := range procs {
784		var exeName string
785		var cmdLine string
786
787		exeName, _ = proc.Exe()
788		cmdLine, err = proc.Cmdline()
789		if err != nil {
790			cmdLine = "Error: " + err.Error()
791		}
792
793		t.Logf("Process #%v: Name: %v / CmdLine: %v\n", proc.Pid, exeName, cmdLine)
794	}
795}
796
797func Test_AllProcesses_environ(t *testing.T) {
798	procs, err := Processes()
799	skipIfNotImplementedErr(t, err)
800	if err != nil {
801		t.Fatalf("getting processes error %v", err)
802	}
803	for _, proc := range procs {
804		exeName, _ := proc.Exe()
805		environ, err := proc.Environ()
806		if err != nil {
807			environ = []string{"Error: " + err.Error()}
808		}
809
810		t.Logf("Process #%v: Name: %v / Environment Variables: %v\n", proc.Pid, exeName, environ)
811	}
812}
813
814func BenchmarkNewProcess(b *testing.B) {
815	checkPid := os.Getpid()
816	for i := 0; i < b.N; i++ {
817		NewProcess(int32(checkPid))
818	}
819}
820
821func BenchmarkProcessName(b *testing.B) {
822	p := testGetProcess()
823	for i := 0; i < b.N; i++ {
824		p.Name()
825	}
826}
827
828func BenchmarkProcessPpid(b *testing.B) {
829	p := testGetProcess()
830	for i := 0; i < b.N; i++ {
831		p.Ppid()
832	}
833}
834