Skip to content

Commit

Permalink
Fix for Test_Connections currently fails intermittently on Linux (and
Browse files Browse the repository at this point in the history
maybe other OSs).

On inspection, Go closes TCP connections when they go out of scope and
are garbage collected. I've re-written Test_Connections() to avoid
closing until the test has finished.

Other changes:
- Close connections properly in TestConnections so running go test -times=N works.
- t.Skip() can not be called inside a test go-routine.
- Make sure that Test_AllProcesses_cmdLine doesn't ignore failures.
- Some minor style changes motivated by staticcheck warnings.
  • Loading branch information
tbarker25 committed Aug 19, 2021
1 parent f86a042 commit 79896a1
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 110 deletions.
7 changes: 2 additions & 5 deletions process/process_linux.go
Expand Up @@ -351,7 +351,7 @@ func (p *Process) PageFaultsWithContext(ctx context.Context) (*PageFaultsStat, e
func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {
pids, err := common.CallPgrepWithContext(ctx, invoke, p.Pid)
if err != nil {
if pids == nil || len(pids) == 0 {
if len(pids) == 0 {
return nil, ErrorNoChildren
}
return nil, err
Expand Down Expand Up @@ -705,10 +705,7 @@ func (p *Process) fillFromCmdlineWithContext(ctx context.Context) (string, error
return "", err
}
ret := strings.FieldsFunc(string(cmdline), func(r rune) bool {
if r == '\u0000' {
return true
}
return false
return r == '\u0000'
})

return strings.Join(ret, " "), nil
Expand Down
108 changes: 58 additions & 50 deletions process/process_test.go
Expand Up @@ -418,14 +418,14 @@ func Test_Process_Exe(t *testing.T) {

func Test_Process_CpuPercent(t *testing.T) {
p := testGetProcess()
percent, err := p.Percent(0)
_, err := p.Percent(0)
skipIfNotImplementedErr(t, err)
if err != nil {
t.Errorf("error %v", err)
}
duration := time.Duration(1000) * time.Microsecond
time.Sleep(duration)
percent, err = p.Percent(0)
percent, err := p.Percent(0)
if err != nil {
t.Errorf("error %v", err)
}
Expand Down Expand Up @@ -498,46 +498,50 @@ func Test_Parent(t *testing.T) {

func Test_Connections(t *testing.T) {
p := testGetProcess()
ch0 := make(chan string)
ch1 := make(chan string)

addr, err := net.ResolveTCPAddr("tcp", "localhost:0") // dynamically get a random open port from OS
if err != nil {
t.Fatalf("unable to resolve localhost: %v", err)
}
l, err := net.ListenTCP(addr.Network(), addr)
if err != nil {
t.Fatalf("unable to listen on %v: %v", addr, err)
}
defer l.Close()

tcpServerAddr := l.Addr().String()
tcpServerAddrIP := strings.Split(tcpServerAddr, ":")[0]
tcpServerAddrPort, err := strconv.ParseUint(strings.Split(tcpServerAddr, ":")[1], 10, 32)
if err != nil {
t.Fatalf("unable to parse tcpServerAddr port: %v", err)
}

go func() { // TCP listening goroutine
addr, err := net.ResolveTCPAddr("tcp", "localhost:0") // dynamically get a random open port from OS
conn, err := l.Accept()
if err != nil {
t.Skip("unable to resolve localhost:", err)
panic(err)
}
l, err := net.ListenTCP(addr.Network(), addr)
defer conn.Close()

_, err = ioutil.ReadAll(conn)
if err != nil {
t.Skip(fmt.Sprintf("unable to listen on %v: %v", addr, err))
panic(err)
}
defer l.Close()
ch0 <- l.Addr().String()
for {
conn, err := l.Accept()
if err != nil {
t.Skip("unable to accept connection:", err)
}
ch1 <- l.Addr().String()
defer conn.Close()
}
}()
go func() { // TCP client goroutine
tcpServerAddr := <-ch0
net.Dial("tcp", tcpServerAddr)
}()

tcpServerAddr := <-ch1
tcpServerAddrIP := strings.Split(tcpServerAddr, ":")[0]
tcpServerAddrPort, err := strconv.ParseUint(strings.Split(tcpServerAddr, ":")[1], 10, 32)
conn, err := net.Dial("tcp", tcpServerAddr)
if err != nil {
t.Errorf("unable to parse tcpServerAddr port: %v", err)
t.Fatalf("unable to dial %v: %v", tcpServerAddr, err)
}
defer conn.Close()

c, err := p.Connections()
skipIfNotImplementedErr(t, err)
if err != nil {
t.Errorf("error %v", err)
t.Fatalf("error %v", err)
}
if len(c) == 0 {
t.Errorf("no connections found")
t.Fatal("no connections found")
}
found := 0
for _, connection := range c {
Expand All @@ -546,7 +550,7 @@ func Test_Connections(t *testing.T) {
}
}
if found != 2 { // two established connections, one for the server, the other for the client
t.Errorf(fmt.Sprintf("wrong connections: %+v", c))
t.Fatalf("wrong connections: %+v", c)
}
}

Expand Down Expand Up @@ -747,34 +751,38 @@ func Test_Process_Environ(t *testing.T) {

func Test_AllProcesses_cmdLine(t *testing.T) {
procs, err := Processes()
if err == nil {
for _, proc := range procs {
var exeName string
var cmdLine string

exeName, _ = proc.Exe()
cmdLine, err = proc.Cmdline()
if err != nil {
cmdLine = "Error: " + err.Error()
}

t.Logf("Process #%v: Name: %v / CmdLine: %v\n", proc.Pid, exeName, cmdLine)
skipIfNotImplementedErr(t, err)
if err != nil {
t.Fatalf("getting processes error %v", err)
}
for _, proc := range procs {
var exeName string
var cmdLine string

exeName, _ = proc.Exe()
cmdLine, err = proc.Cmdline()
if err != nil {
cmdLine = "Error: " + err.Error()
}

t.Logf("Process #%v: Name: %v / CmdLine: %v\n", proc.Pid, exeName, cmdLine)
}
}

func Test_AllProcesses_environ(t *testing.T) {
procs, err := Processes()
if err == nil {
for _, proc := range procs {
exeName, _ := proc.Exe()
environ, err := proc.Environ()
if err != nil {
environ = []string{"Error: " + err.Error() }
}

t.Logf("Process #%v: Name: %v / Environment Variables: %v\n", proc.Pid, exeName, environ)
skipIfNotImplementedErr(t, err)
if err != nil {
t.Fatalf("getting processes error %v", err)
}
for _, proc := range procs {
exeName, _ := proc.Exe()
environ, err := proc.Environ()
if err != nil {
environ = []string{"Error: " + err.Error()}
}

t.Logf("Process #%v: Name: %v / Environment Variables: %v\n", proc.Pid, exeName, environ)
}
}

Expand Down
7 changes: 2 additions & 5 deletions v3/process/process_linux.go
Expand Up @@ -351,7 +351,7 @@ func (p *Process) PageFaultsWithContext(ctx context.Context) (*PageFaultsStat, e
func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {
pids, err := common.CallPgrepWithContext(ctx, invoke, p.Pid)
if err != nil {
if pids == nil || len(pids) == 0 {
if len(pids) == 0 {
return nil, ErrorNoChildren
}
return nil, err
Expand Down Expand Up @@ -678,10 +678,7 @@ func (p *Process) fillFromCmdlineWithContext(ctx context.Context) (string, error
return "", err
}
ret := strings.FieldsFunc(string(cmdline), func(r rune) bool {
if r == '\u0000' {
return true
}
return false
return r == '\u0000'
})

return strings.Join(ret, " "), nil
Expand Down
108 changes: 58 additions & 50 deletions v3/process/process_test.go
Expand Up @@ -420,14 +420,14 @@ func Test_Process_Exe(t *testing.T) {

func Test_Process_CpuPercent(t *testing.T) {
p := testGetProcess()
percent, err := p.Percent(0)
_, err := p.Percent(0)
skipIfNotImplementedErr(t, err)
if err != nil {
t.Errorf("error %v", err)
}
duration := time.Duration(1000) * time.Microsecond
time.Sleep(duration)
percent, err = p.Percent(0)
percent, err := p.Percent(0)
if err != nil {
t.Errorf("error %v", err)
}
Expand Down Expand Up @@ -500,46 +500,50 @@ func Test_Parent(t *testing.T) {

func Test_Connections(t *testing.T) {
p := testGetProcess()
ch0 := make(chan string)
ch1 := make(chan string)

addr, err := net.ResolveTCPAddr("tcp", "localhost:0") // dynamically get a random open port from OS
if err != nil {
t.Fatalf("unable to resolve localhost: %v", err)
}
l, err := net.ListenTCP(addr.Network(), addr)
if err != nil {
t.Fatalf("unable to listen on %v: %v", addr, err)
}
defer l.Close()

tcpServerAddr := l.Addr().String()
tcpServerAddrIP := strings.Split(tcpServerAddr, ":")[0]
tcpServerAddrPort, err := strconv.ParseUint(strings.Split(tcpServerAddr, ":")[1], 10, 32)
if err != nil {
t.Fatalf("unable to parse tcpServerAddr port: %v", err)
}

go func() { // TCP listening goroutine
addr, err := net.ResolveTCPAddr("tcp", "localhost:0") // dynamically get a random open port from OS
conn, err := l.Accept()
if err != nil {
t.Skip("unable to resolve localhost:", err)
panic(err)
}
l, err := net.ListenTCP(addr.Network(), addr)
defer conn.Close()

_, err = ioutil.ReadAll(conn)
if err != nil {
t.Skip(fmt.Sprintf("unable to listen on %v: %v", addr, err))
panic(err)
}
defer l.Close()
ch0 <- l.Addr().String()
for {
conn, err := l.Accept()
if err != nil {
t.Skip("unable to accept connection:", err)
}
ch1 <- l.Addr().String()
defer conn.Close()
}
}()
go func() { // TCP client goroutine
tcpServerAddr := <-ch0
net.Dial("tcp", tcpServerAddr)
}()

tcpServerAddr := <-ch1
tcpServerAddrIP := strings.Split(tcpServerAddr, ":")[0]
tcpServerAddrPort, err := strconv.ParseUint(strings.Split(tcpServerAddr, ":")[1], 10, 32)
conn, err := net.Dial("tcp", tcpServerAddr)
if err != nil {
t.Errorf("unable to parse tcpServerAddr port: %v", err)
t.Fatalf("unable to dial %v: %v", tcpServerAddr, err)
}
defer conn.Close()

c, err := p.Connections()
skipIfNotImplementedErr(t, err)
if err != nil {
t.Errorf("error %v", err)
t.Fatalf("error %v", err)
}
if len(c) == 0 {
t.Errorf("no connections found")
t.Fatal("no connections found")
}
found := 0
for _, connection := range c {
Expand All @@ -548,7 +552,7 @@ func Test_Connections(t *testing.T) {
}
}
if found != 2 { // two established connections, one for the server, the other for the client
t.Errorf(fmt.Sprintf("wrong connections: %+v", c))
t.Fatalf("wrong connections: %+v", c)
}
}

Expand Down Expand Up @@ -749,34 +753,38 @@ func Test_Process_Environ(t *testing.T) {

func Test_AllProcesses_cmdLine(t *testing.T) {
procs, err := Processes()
if err == nil {
for _, proc := range procs {
var exeName string
var cmdLine string

exeName, _ = proc.Exe()
cmdLine, err = proc.Cmdline()
if err != nil {
cmdLine = "Error: " + err.Error()
}

t.Logf("Process #%v: Name: %v / CmdLine: %v\n", proc.Pid, exeName, cmdLine)
skipIfNotImplementedErr(t, err)
if err != nil {
t.Fatalf("getting processes error %v", err)
}
for _, proc := range procs {
var exeName string
var cmdLine string

exeName, _ = proc.Exe()
cmdLine, err = proc.Cmdline()
if err != nil {
cmdLine = "Error: " + err.Error()
}

t.Logf("Process #%v: Name: %v / CmdLine: %v\n", proc.Pid, exeName, cmdLine)
}
}

func Test_AllProcesses_environ(t *testing.T) {
procs, err := Processes()
if err == nil {
for _, proc := range procs {
exeName, _ := proc.Exe()
environ, err := proc.Environ()
if err != nil {
environ = []string{"Error: " + err.Error() }
}

t.Logf("Process #%v: Name: %v / Environment Variables: %v\n", proc.Pid, exeName, environ)
skipIfNotImplementedErr(t, err)
if err != nil {
t.Fatalf("getting processes error %v", err)
}
for _, proc := range procs {
exeName, _ := proc.Exe()
environ, err := proc.Environ()
if err != nil {
environ = []string{"Error: " + err.Error()}
}

t.Logf("Process #%v: Name: %v / Environment Variables: %v\n", proc.Pid, exeName, environ)
}
}

Expand Down

0 comments on commit 79896a1

Please sign in to comment.