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 }