mirror of
https://github.com/DominicBreuker/pspy.git
synced 2025-12-21 11:44:51 +00:00
234 lines
4.9 KiB
Go
234 lines
4.9 KiB
Go
package psscanner
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// GetPIDs
|
|
|
|
func TestGetPIDs(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
proc []string
|
|
procErrOpen error
|
|
procErrRead error
|
|
pids []int
|
|
err string
|
|
}{
|
|
{
|
|
name: "numbers-only",
|
|
proc: []string{"42", "somedir"},
|
|
procErrOpen: nil,
|
|
procErrRead: nil,
|
|
pids: []int{42},
|
|
err: "",
|
|
},
|
|
{
|
|
name: "multiple-entries",
|
|
proc: []string{"42", "13"},
|
|
procErrOpen: nil,
|
|
procErrRead: nil,
|
|
pids: []int{42, 13},
|
|
err: "",
|
|
},
|
|
{
|
|
name: "ignores-lte-0",
|
|
proc: []string{"0", "-1"},
|
|
procErrOpen: nil,
|
|
procErrRead: nil,
|
|
pids: []int{},
|
|
err: "",
|
|
},
|
|
{
|
|
name: "empty-procfs",
|
|
proc: []string{},
|
|
procErrOpen: nil,
|
|
procErrRead: nil,
|
|
pids: []int{},
|
|
err: "",
|
|
},
|
|
{
|
|
name: "handle-open-error",
|
|
proc: []string{},
|
|
procErrOpen: errors.New("file-system-error"),
|
|
procErrRead: nil,
|
|
pids: nil,
|
|
err: "opening proc dir: file-system-error",
|
|
},
|
|
{
|
|
name: "handle-read-error",
|
|
proc: []string{},
|
|
procErrOpen: nil,
|
|
procErrRead: errors.New("file-system-error"),
|
|
pids: nil,
|
|
err: "reading proc dir: file-system-error",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
defer mockDir("/proc", tt.proc, tt.procErrRead, tt.procErrOpen, t)()
|
|
pids, err := getPIDs()
|
|
if !reflect.DeepEqual(pids, tt.pids) {
|
|
t.Errorf("Wrong pids returned: got %v but want %v", pids, tt.pids)
|
|
}
|
|
if (err != nil || tt.err != "") && fmt.Sprintf("%v", err) != tt.err {
|
|
t.Errorf("Wrong error returned: got %v but want %s", err, tt.err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
type MockDir struct {
|
|
names []string
|
|
err error
|
|
}
|
|
|
|
func (f *MockDir) Close() error {
|
|
return nil
|
|
}
|
|
|
|
func min(a, b int) int {
|
|
if a > b {
|
|
return b
|
|
}
|
|
return a
|
|
}
|
|
|
|
func (f *MockDir) Readdirnames(n int) (names []string, err error) {
|
|
if n < 0 {
|
|
return f.names, f.err
|
|
}
|
|
return f.names[:min(n, len(f.names))], f.err
|
|
}
|
|
|
|
// Hook/chain a mocked file into the "open" variable
|
|
func mockDir(name string, names []string, errRead error, errOpen error, t *testing.T) func() {
|
|
oldopen := dirOpen
|
|
dirOpen = func(n string) (readDirNamesCloser, error) {
|
|
if name == n {
|
|
if testing.Verbose() {
|
|
t.Logf("opening mocked dir: %s", n)
|
|
}
|
|
return &MockDir{
|
|
names: names,
|
|
err: errRead,
|
|
}, errOpen
|
|
}
|
|
return oldopen(n)
|
|
}
|
|
return func() {
|
|
dirOpen = oldopen
|
|
}
|
|
}
|
|
|
|
type mockPidProcessor struct {
|
|
t *testing.T
|
|
pids []int
|
|
}
|
|
|
|
func (m *mockPidProcessor) processNewPid(pid int) {
|
|
if testing.Verbose() {
|
|
m.t.Logf("proc %d processed", pid)
|
|
}
|
|
m.pids = append(m.pids, pid)
|
|
}
|
|
|
|
var unit = struct{}{}
|
|
|
|
func TestRefresh(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
pl procList
|
|
newPids []int
|
|
plAfter procList
|
|
pidsProcessed []int
|
|
}{
|
|
{
|
|
name: "nominal",
|
|
pl: procList{},
|
|
newPids: []int{1, 2, 3},
|
|
plAfter: procList{1: unit, 2: unit, 3: unit},
|
|
pidsProcessed: []int{3, 2, 1},
|
|
},
|
|
{
|
|
name: "merge",
|
|
pl: procList{1: unit},
|
|
newPids: []int{1, 2, 3},
|
|
plAfter: procList{1: unit, 2: unit, 3: unit},
|
|
pidsProcessed: []int{3, 2},
|
|
},
|
|
{
|
|
name: "nothing-new",
|
|
pl: procList{1: unit, 2: unit, 3: unit},
|
|
newPids: []int{1, 2, 3},
|
|
plAfter: procList{1: unit, 2: unit, 3: unit},
|
|
pidsProcessed: []int{},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
defer mockPidList(tt.newPids, t)()
|
|
|
|
m := &mockPidProcessor{t, []int{}}
|
|
tt.pl.refresh(m)
|
|
|
|
if !reflect.DeepEqual(m.pids, tt.pidsProcessed) {
|
|
t.Errorf("Unexpected pids got processed: got %v but want %v", m.pids, tt.pidsProcessed)
|
|
}
|
|
if !reflect.DeepEqual(tt.pl, tt.plAfter) {
|
|
t.Errorf("Unexpected pids stored in procList: got %v but want %v", tt.pl, tt.plAfter)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// separate test for failing, only one case where getPids fails
|
|
func TestRefreshFail(t *testing.T) {
|
|
e := errors.New("file-system-error")
|
|
for _, tt := range []struct {
|
|
name string
|
|
errRead error
|
|
errOpen error
|
|
}{
|
|
{
|
|
name: "open-dir-fail",
|
|
errRead: nil,
|
|
errOpen: e,
|
|
},
|
|
{
|
|
name: "read-dir-fail",
|
|
errRead: e,
|
|
errOpen: nil,
|
|
},
|
|
} {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
defer mockDir("/proc", []string{}, tt.errRead, tt.errOpen, t)()
|
|
m := &mockPidProcessor{t, []int{}}
|
|
pl := procList{1: unit}
|
|
err := pl.refresh(m)
|
|
if err == nil {
|
|
t.Errorf("Expected an error")
|
|
} else {
|
|
if strings.Index(err.Error(), e.Error()) == -1 {
|
|
t.Errorf("Unexpected error: %v", err)
|
|
}
|
|
}
|
|
|
|
})
|
|
}
|
|
}
|
|
|
|
func mockPidList(pids []int, t *testing.T) func() {
|
|
dirs := make([]string, 0)
|
|
for _, pid := range pids {
|
|
dirs = append(dirs, fmt.Sprintf("%d", pid))
|
|
}
|
|
return mockDir("/proc", dirs, nil, nil, t)
|
|
}
|