github.com/isyscore/isc-gobase@v1.5.3-0.20231218061332-cbc7451899e9/system/process/process_test.go (about)

     1  package process
     2  
     3  import (
     4  	"io"
     5  	"net"
     6  	"os"
     7  	"reflect"
     8  	"runtime"
     9  	"strconv"
    10  	"strings"
    11  	"sync"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/isyscore/isc-gobase/system/common"
    16  )
    17  
    18  var mu sync.Mutex
    19  
    20  func skipIfNotImplementedErr(t *testing.T, err error) {
    21  	if err == common.ErrNotImplementedError {
    22  		t.Skip("not implemented")
    23  	}
    24  }
    25  
    26  func testGetProcess() *Process {
    27  	checkPid := os.Getpid() // process.test
    28  	ret, _ := NewProcess(int32(checkPid))
    29  	return ret
    30  }
    31  
    32  func Test_Pids(t *testing.T) {
    33  	ret, err := Pids()
    34  	skipIfNotImplementedErr(t, err)
    35  	if err != nil {
    36  		t.Errorf("error %v", err)
    37  	}
    38  	if len(ret) == 0 {
    39  		t.Errorf("could not get pids %v", ret)
    40  	}
    41  }
    42  
    43  func Test_Pid_exists(t *testing.T) {
    44  	checkPid := os.Getpid()
    45  
    46  	ret, err := PidExists(int32(checkPid))
    47  	skipIfNotImplementedErr(t, err)
    48  	if err != nil {
    49  		t.Errorf("error %v", err)
    50  	}
    51  
    52  	if ret == false {
    53  		t.Errorf("could not get process exists: %v", ret)
    54  	}
    55  }
    56  
    57  func Test_NewProcess(t *testing.T) {
    58  	checkPid := os.Getpid()
    59  
    60  	ret, err := NewProcess(int32(checkPid))
    61  	skipIfNotImplementedErr(t, err)
    62  	if err != nil {
    63  		t.Errorf("error %v", err)
    64  	}
    65  	empty := &Process{}
    66  	if runtime.GOOS != "windows" { // Windows pid is 0
    67  		if empty == ret {
    68  			t.Errorf("error %v", ret)
    69  		}
    70  	}
    71  
    72  }
    73  
    74  func Test_Process_MemoryInfo(t *testing.T) {
    75  	p := testGetProcess()
    76  
    77  	v, err := p.MemoryInfo()
    78  	skipIfNotImplementedErr(t, err)
    79  	if err != nil {
    80  		t.Errorf("getting memory info error %v", err)
    81  	}
    82  	empty := MemoryInfoStat{}
    83  	if v == nil || *v == empty {
    84  		t.Errorf("could not get memory info %v", v)
    85  	}
    86  }
    87  
    88  func Test_Process_CmdLine(t *testing.T) {
    89  	p := testGetProcess()
    90  
    91  	v, err := p.Cmdline()
    92  	skipIfNotImplementedErr(t, err)
    93  	if err != nil {
    94  		t.Errorf("getting cmdline error %v", err)
    95  	}
    96  	if !strings.Contains(v, "process.test") {
    97  		t.Errorf("invalid cmd line %v", v)
    98  	}
    99  }
   100  
   101  func Test_Process_CmdLineSlice(t *testing.T) {
   102  	p := testGetProcess()
   103  
   104  	v, err := p.CmdlineSlice()
   105  	skipIfNotImplementedErr(t, err)
   106  	if err != nil {
   107  		t.Fatalf("getting cmdline slice error %v", err)
   108  	}
   109  	if !reflect.DeepEqual(v, os.Args) {
   110  		t.Errorf("returned cmdline slice not as expected:\nexp: %v\ngot: %v", os.Args, v)
   111  	}
   112  }
   113  
   114  func Test_Process_Ppid(t *testing.T) {
   115  	p := testGetProcess()
   116  
   117  	v, err := p.Ppid()
   118  	skipIfNotImplementedErr(t, err)
   119  	if err != nil {
   120  		t.Errorf("getting ppid error %v", err)
   121  	}
   122  	if v == 0 {
   123  		t.Errorf("return value is 0 %v", v)
   124  	}
   125  	expected := os.Getppid()
   126  	if v != int32(expected) {
   127  		t.Errorf("return value is %v, expected %v", v, expected)
   128  	}
   129  }
   130  
   131  func Test_Process_Nice(t *testing.T) {
   132  	p := testGetProcess()
   133  
   134  	n, err := p.Nice()
   135  	skipIfNotImplementedErr(t, err)
   136  	if err != nil {
   137  		t.Errorf("getting nice error %v", err)
   138  	}
   139  	if runtime.GOOS != "windows" && n != 0 && n != 20 && n != 8 {
   140  		t.Errorf("invalid nice: %d", n)
   141  	}
   142  }
   143  
   144  func Test_Process_NumThread(t *testing.T) {
   145  	p := testGetProcess()
   146  
   147  	n, err := p.NumThreads()
   148  	skipIfNotImplementedErr(t, err)
   149  	if err != nil {
   150  		t.Errorf("getting NumThread error %v", err)
   151  	}
   152  	if n < 0 {
   153  		t.Errorf("invalid NumThread: %d", n)
   154  	}
   155  }
   156  
   157  func Test_Process_Name(t *testing.T) {
   158  	p := testGetProcess()
   159  
   160  	n, err := p.Name()
   161  	skipIfNotImplementedErr(t, err)
   162  	if err != nil {
   163  		t.Errorf("getting name error %v", err)
   164  	}
   165  	if !strings.Contains(n, "process.test") {
   166  		t.Errorf("invalid Exe %s", n)
   167  	}
   168  }
   169  
   170  func Test_Process_Exe(t *testing.T) {
   171  	p := testGetProcess()
   172  
   173  	n, err := p.Exe()
   174  	skipIfNotImplementedErr(t, err)
   175  	if err != nil {
   176  		t.Errorf("getting Exe error %v", err)
   177  	}
   178  	if !strings.Contains(n, "process.test") {
   179  		t.Errorf("invalid Exe %s", n)
   180  	}
   181  }
   182  
   183  func Test_Process_CpuPercent(t *testing.T) {
   184  	p := testGetProcess()
   185  	_, err := p.Percent(0)
   186  	skipIfNotImplementedErr(t, err)
   187  	if err != nil {
   188  		t.Errorf("error %v", err)
   189  	}
   190  	duration := time.Duration(1000) * time.Microsecond
   191  	time.Sleep(duration)
   192  	percent, err := p.Percent(0)
   193  	if err != nil {
   194  		t.Errorf("error %v", err)
   195  	}
   196  
   197  	numcpu := runtime.NumCPU()
   198  	//	if percent < 0.0 || percent > 100.0*float64(numcpu) { // TODO
   199  	if percent < 0.0 {
   200  		t.Fatalf("CPUPercent value is invalid: %f, %d", percent, numcpu)
   201  	}
   202  }
   203  
   204  func Test_Process_CpuPercentLoop(t *testing.T) {
   205  	p := testGetProcess()
   206  	numcpu := runtime.NumCPU()
   207  
   208  	for i := 0; i < 2; i++ {
   209  		duration := time.Duration(100) * time.Microsecond
   210  		percent, err := p.Percent(duration)
   211  		skipIfNotImplementedErr(t, err)
   212  		if err != nil {
   213  			t.Errorf("error %v", err)
   214  		}
   215  		//	if percent < 0.0 || percent > 100.0*float64(numcpu) { // TODO
   216  		if percent < 0.0 {
   217  			t.Fatalf("CPUPercent value is invalid: %f, %d", percent, numcpu)
   218  		}
   219  	}
   220  }
   221  
   222  func Test_Process_CreateTime(t *testing.T) {
   223  	if os.Getenv("CIRCLECI") == "true" {
   224  		t.Skip("Skip CI")
   225  	}
   226  
   227  	p := testGetProcess()
   228  
   229  	c, err := p.CreateTime()
   230  	skipIfNotImplementedErr(t, err)
   231  	if err != nil {
   232  		t.Errorf("error %v", err)
   233  	}
   234  
   235  	if c < 1420000000 {
   236  		t.Errorf("process created time is wrong.")
   237  	}
   238  
   239  	gotElapsed := time.Since(time.Unix(c/1000, 0))
   240  	maxElapsed := 20 * time.Second
   241  
   242  	if gotElapsed >= maxElapsed {
   243  		t.Errorf("this process has not been running for %v", gotElapsed)
   244  	}
   245  }
   246  
   247  func Test_Parent(t *testing.T) {
   248  	p := testGetProcess()
   249  
   250  	c, err := p.Parent()
   251  	skipIfNotImplementedErr(t, err)
   252  	if err != nil {
   253  		t.Fatalf("error %v", err)
   254  	}
   255  	if c == nil {
   256  		t.Fatalf("could not get parent")
   257  	}
   258  	if c.Pid == 0 {
   259  		t.Fatalf("wrong parent pid")
   260  	}
   261  }
   262  
   263  func Test_Connections(t *testing.T) {
   264  	p := testGetProcess()
   265  
   266  	addr, err := net.ResolveTCPAddr("tcp", "localhost:0") // dynamically get a random open port from OS
   267  	if err != nil {
   268  		t.Fatalf("unable to resolve localhost: %v", err)
   269  	}
   270  	l, err := net.ListenTCP(addr.Network(), addr)
   271  	if err != nil {
   272  		t.Fatalf("unable to listen on %v: %v", addr, err)
   273  	}
   274  	defer func(l *net.TCPListener) {
   275  		_ = l.Close()
   276  	}(l)
   277  
   278  	tcpServerAddr := l.Addr().String()
   279  	tcpServerAddrIP := strings.Split(tcpServerAddr, ":")[0]
   280  	tcpServerAddrPort, err := strconv.ParseUint(strings.Split(tcpServerAddr, ":")[1], 10, 32)
   281  	if err != nil {
   282  		t.Fatalf("unable to parse tcpServerAddr port: %v", err)
   283  	}
   284  
   285  	serverEstablished := make(chan struct{})
   286  	go func() { // TCP listening goroutine
   287  		conn, err := l.Accept()
   288  		if err != nil {
   289  			panic(err)
   290  		}
   291  		defer func(conn net.Conn) {
   292  			_ = conn.Close()
   293  		}(conn)
   294  
   295  		serverEstablished <- struct{}{}
   296  		_, err = io.ReadAll(conn)
   297  		if err != nil {
   298  			panic(err)
   299  		}
   300  	}()
   301  
   302  	conn, err := net.Dial("tcp", tcpServerAddr)
   303  	if err != nil {
   304  		t.Fatalf("unable to dial %v: %v", tcpServerAddr, err)
   305  	}
   306  	defer func(conn net.Conn) {
   307  		_ = conn.Close()
   308  	}(conn)
   309  
   310  	// Rarely the call to net.Dial returns before the server connection is
   311  	// established. Wait so that the test doesn't fail.
   312  	<-serverEstablished
   313  
   314  	c, err := p.Connections()
   315  	skipIfNotImplementedErr(t, err)
   316  	if err != nil {
   317  		t.Fatalf("error %v", err)
   318  	}
   319  	if len(c) == 0 {
   320  		t.Fatal("no connections found")
   321  	}
   322  
   323  	serverConnections := 0
   324  	for _, connection := range c {
   325  		if connection.Laddr.IP == tcpServerAddrIP && connection.Laddr.Port == uint32(tcpServerAddrPort) && connection.Raddr.Port != 0 {
   326  			if connection.Status != "ESTABLISHED" {
   327  				t.Fatalf("expected server connection to be ESTABLISHED, have %+v", connection)
   328  			}
   329  			serverConnections++
   330  		}
   331  	}
   332  
   333  	clientConnections := 0
   334  	for _, connection := range c {
   335  		if connection.Raddr.IP == tcpServerAddrIP && connection.Raddr.Port == uint32(tcpServerAddrPort) {
   336  			if connection.Status != "ESTABLISHED" {
   337  				t.Fatalf("expected client connection to be ESTABLISHED, have %+v", connection)
   338  			}
   339  			clientConnections++
   340  		}
   341  	}
   342  
   343  	if serverConnections != 1 { // two established connections, one for the server, the other for the client
   344  		t.Fatalf("expected 1 server connection, have %d.\nDetails: %+v", serverConnections, c)
   345  	}
   346  
   347  	if clientConnections != 1 { // two established connections, one for the server, the other for the client
   348  		t.Fatalf("expected 1 server connection, have %d.\nDetails: %+v", clientConnections, c)
   349  	}
   350  }
   351  
   352  func Test_AllProcesses_cmdLine(t *testing.T) {
   353  	procs, err := Processes()
   354  	skipIfNotImplementedErr(t, err)
   355  	if err != nil {
   356  		t.Fatalf("getting processes error %v", err)
   357  	}
   358  	for _, proc := range procs {
   359  		var exeName string
   360  		var cmdLine string
   361  
   362  		exeName, _ = proc.Exe()
   363  		cmdLine, err = proc.Cmdline()
   364  		if err != nil {
   365  			cmdLine = "Error: " + err.Error()
   366  		}
   367  
   368  		t.Logf("Process #%v: Name: %v / CmdLine: %v\n", proc.Pid, exeName, cmdLine)
   369  	}
   370  }
   371  
   372  func Test_AllProcesses_environ(t *testing.T) {
   373  	procs, err := Processes()
   374  	skipIfNotImplementedErr(t, err)
   375  	if err != nil {
   376  		t.Fatalf("getting processes error %v", err)
   377  	}
   378  	for _, proc := range procs {
   379  		exeName, _ := proc.Exe()
   380  		environ, err := proc.Environ()
   381  		if err != nil {
   382  			environ = []string{"Error: " + err.Error()}
   383  		}
   384  
   385  		t.Logf("Process #%v: Name: %v / Environment Variables: %v\n", proc.Pid, exeName, environ)
   386  	}
   387  }
   388  
   389  func Test_AllProcesses_Cwd(t *testing.T) {
   390  	procs, err := Processes()
   391  	skipIfNotImplementedErr(t, err)
   392  	if err != nil {
   393  		t.Fatalf("getting processes error %v", err)
   394  	}
   395  	for _, proc := range procs {
   396  		exeName, _ := proc.Exe()
   397  		cwd, err := proc.Cwd()
   398  		if err != nil {
   399  			cwd = "Error: " + err.Error()
   400  		}
   401  
   402  		t.Logf("Process #%v: Name: %v / Current Working Directory: %s\n", proc.Pid, exeName, cwd)
   403  	}
   404  }
   405  
   406  func BenchmarkNewProcess(b *testing.B) {
   407  	checkPid := os.Getpid()
   408  	for i := 0; i < b.N; i++ {
   409  		_, _ = NewProcess(int32(checkPid))
   410  	}
   411  }
   412  
   413  func BenchmarkProcessName(b *testing.B) {
   414  	p := testGetProcess()
   415  	for i := 0; i < b.N; i++ {
   416  		_, _ = p.Name()
   417  	}
   418  }
   419  
   420  func BenchmarkProcessPpid(b *testing.B) {
   421  	p := testGetProcess()
   422  	for i := 0; i < b.N; i++ {
   423  		_, _ = p.Ppid()
   424  	}
   425  }