mirror of
https://github.com/DominicBreuker/pspy.git
synced 2025-12-21 03:34:50 +00:00
Streamlined procfile reading code to reduce number of required syscalls. This makes it easier to catch short lived processes.
This commit is contained in:
@@ -62,6 +62,7 @@ var triggerInterval int
|
|||||||
var colored bool
|
var colored bool
|
||||||
var debug bool
|
var debug bool
|
||||||
var ppid bool
|
var ppid bool
|
||||||
|
var cmdLength int
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rootCmd.PersistentFlags().BoolVarP(&logPS, "procevents", "p", true, "print new processes to stdout")
|
rootCmd.PersistentFlags().BoolVarP(&logPS, "procevents", "p", true, "print new processes to stdout")
|
||||||
@@ -72,6 +73,7 @@ func init() {
|
|||||||
rootCmd.PersistentFlags().BoolVarP(&colored, "color", "c", true, "color the printed events")
|
rootCmd.PersistentFlags().BoolVarP(&colored, "color", "c", true, "color the printed events")
|
||||||
rootCmd.PersistentFlags().BoolVarP(&debug, "debug", "", false, "print detailed error messages")
|
rootCmd.PersistentFlags().BoolVarP(&debug, "debug", "", false, "print detailed error messages")
|
||||||
rootCmd.PersistentFlags().BoolVarP(&ppid, "ppid", "", false, "record process ppids")
|
rootCmd.PersistentFlags().BoolVarP(&ppid, "ppid", "", false, "record process ppids")
|
||||||
|
rootCmd.PersistentFlags().IntVarP(&cmdLength, "truncate", "t", 2048, "truncate process cmds longer than this")
|
||||||
|
|
||||||
log.SetOutput(os.Stdout)
|
log.SetOutput(os.Stdout)
|
||||||
}
|
}
|
||||||
@@ -93,7 +95,7 @@ func root(cmd *cobra.Command, args []string) {
|
|||||||
fsw := fswatcher.NewFSWatcher()
|
fsw := fswatcher.NewFSWatcher()
|
||||||
defer fsw.Close()
|
defer fsw.Close()
|
||||||
|
|
||||||
pss := psscanner.NewPSScanner(ppid)
|
pss := psscanner.NewPSScanner(ppid, cmdLength)
|
||||||
|
|
||||||
sigCh := make(chan os.Signal)
|
sigCh := make(chan os.Signal)
|
||||||
signal.Notify(sigCh, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
|
signal.Notify(sigCh, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ package psscanner
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io"
|
||||||
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@@ -10,6 +11,7 @@ import (
|
|||||||
type PSScanner struct {
|
type PSScanner struct {
|
||||||
enablePpid bool
|
enablePpid bool
|
||||||
eventCh chan<- PSEvent
|
eventCh chan<- PSEvent
|
||||||
|
maxCmdLength int
|
||||||
}
|
}
|
||||||
|
|
||||||
type PSEvent struct {
|
type PSEvent struct {
|
||||||
@@ -33,10 +35,11 @@ func (evt PSEvent) String() string {
|
|||||||
"UID=%-5s PID=%-6d PPID=%-6d | %s", uid, evt.PID, evt.PPID, evt.CMD)
|
"UID=%-5s PID=%-6d PPID=%-6d | %s", uid, evt.PID, evt.PPID, evt.CMD)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPSScanner(ppid bool) *PSScanner {
|
func NewPSScanner(ppid bool, cmdLength int) *PSScanner {
|
||||||
return &PSScanner{
|
return &PSScanner{
|
||||||
enablePpid: ppid,
|
enablePpid: ppid,
|
||||||
eventCh: nil,
|
eventCh: nil,
|
||||||
|
maxCmdLength: cmdLength,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,8 +60,8 @@ func (p *PSScanner) Run(triggerCh chan struct{}) (chan PSEvent, chan error) {
|
|||||||
|
|
||||||
func (p *PSScanner) processNewPid(pid int) {
|
func (p *PSScanner) processNewPid(pid int) {
|
||||||
// quickly load data into memory before processing it, with preferance for cmd
|
// quickly load data into memory before processing it, with preferance for cmd
|
||||||
cmdLine, errCmdLine := cmdLineReader(pid)
|
cmdLine, errCmdLine := readFile(fmt.Sprintf("/proc/%d/cmdline", pid), p.maxCmdLength)
|
||||||
status, errStatus := procStatusReader(pid)
|
status, errStatus := readFile(fmt.Sprintf("/proc/%d/status", pid), 512)
|
||||||
|
|
||||||
cmd := "???" // process probably terminated
|
cmd := "???" // process probably terminated
|
||||||
if errCmdLine == nil {
|
if errCmdLine == nil {
|
||||||
@@ -114,12 +117,22 @@ func (p *PSScanner) parseProcessStatus(status []byte) (int, int, error) {
|
|||||||
return uid, ppid, nil
|
return uid, ppid, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var procStatusReader = func(pid int) ([]byte, error) {
|
var open func(string) (io.ReadCloser, error) = func(s string) (io.ReadCloser, error) {
|
||||||
statPath := fmt.Sprintf("/proc/%d/status", pid)
|
return os.Open(s)
|
||||||
return ioutil.ReadFile(statPath)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var cmdLineReader = func(pid int) ([]byte, error) {
|
// no nonsense file reading
|
||||||
cmdPath := fmt.Sprintf("/proc/%d/cmdline", pid)
|
func readFile(filename string, maxlen int) ([]byte, error) {
|
||||||
return ioutil.ReadFile(cmdPath)
|
file, err := open(filename)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
buffer := make([]byte, maxlen)
|
||||||
|
n, err := file.Read(buffer)
|
||||||
|
if err != io.EOF && err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return buffer[:n], nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package psscanner
|
|||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@@ -12,22 +14,30 @@ const timeout = 100 * time.Millisecond
|
|||||||
|
|
||||||
func TestRun(t *testing.T) {
|
func TestRun(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
|
name string
|
||||||
pids []int
|
pids []int
|
||||||
events []string
|
events []string
|
||||||
}{
|
}{
|
||||||
{pids: []int{1, 2, 3}, events: []string{
|
{
|
||||||
|
name: "nominal",
|
||||||
|
pids: []int{1, 2, 3},
|
||||||
|
events: []string{
|
||||||
"UID=??? PID=3 | the-command",
|
"UID=??? PID=3 | the-command",
|
||||||
"UID=??? PID=2 | the-command",
|
"UID=??? PID=2 | the-command",
|
||||||
"UID=??? PID=1 | the-command",
|
"UID=??? PID=1 | the-command",
|
||||||
}},
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
restoreGetPIDs := mockPidList(tt.pids)
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
restoreCmdLineReader := mockCmdLineReader([]byte("the-command"), nil)
|
defer mockPidList(tt.pids)()
|
||||||
restoreProcStatusReader := mockProcStatusReader([]byte(""), nil) // don't mock read value since it's not worth it
|
for _, pid := range tt.pids {
|
||||||
|
defer mockPidCmdLine(pid, []byte("the-command"), nil, nil, t)()
|
||||||
|
defer mockPidStatus(pid, []byte{}, nil, nil, t)() // don't mock read value since it's not worth it
|
||||||
|
}
|
||||||
|
|
||||||
pss := NewPSScanner(false)
|
pss := NewPSScanner(false, 2048)
|
||||||
triggerCh := make(chan struct{})
|
triggerCh := make(chan struct{})
|
||||||
eventCh, errCh := pss.Run(triggerCh)
|
eventCh, errCh := pss.Run(triggerCh)
|
||||||
|
|
||||||
@@ -56,10 +66,7 @@ func TestRun(t *testing.T) {
|
|||||||
t.Errorf("Received unexpected error: %v", err)
|
t.Errorf("Received unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
})
|
||||||
restoreProcStatusReader()
|
|
||||||
restoreCmdLineReader()
|
|
||||||
restoreGetPIDs()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,21 +130,27 @@ func TestProcessNewPid(t *testing.T) {
|
|||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
enablePpid bool
|
enablePpid bool
|
||||||
|
truncate int
|
||||||
pid int
|
pid int
|
||||||
cmdLine []byte
|
cmdLine []byte
|
||||||
cmdLineErr error
|
cmdLineErrRead error
|
||||||
|
cmdLineErrOpen error
|
||||||
status []byte
|
status []byte
|
||||||
statusErr error
|
statusErrRead error
|
||||||
|
statusErrOpen error
|
||||||
expected PSEvent
|
expected PSEvent
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "nominal-no-ppid",
|
name: "nominal-no-ppid",
|
||||||
enablePpid: false,
|
enablePpid: false,
|
||||||
|
truncate: 100,
|
||||||
pid: 1,
|
pid: 1,
|
||||||
cmdLine: []byte("abc\x00123"),
|
cmdLine: []byte("abc\x00123"),
|
||||||
cmdLineErr: nil,
|
cmdLineErrRead: nil,
|
||||||
|
cmdLineErrOpen: nil,
|
||||||
status: completeStatus,
|
status: completeStatus,
|
||||||
statusErr: nil,
|
statusErrRead: nil,
|
||||||
|
statusErrOpen: nil,
|
||||||
expected: PSEvent{
|
expected: PSEvent{
|
||||||
UID: 0,
|
UID: 0,
|
||||||
PID: 1,
|
PID: 1,
|
||||||
@@ -148,11 +161,14 @@ func TestProcessNewPid(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "nominal-ppid",
|
name: "nominal-ppid",
|
||||||
enablePpid: true,
|
enablePpid: true,
|
||||||
|
truncate: 100,
|
||||||
pid: 1,
|
pid: 1,
|
||||||
cmdLine: []byte("abc\x00123"),
|
cmdLine: []byte("abc\x00123"),
|
||||||
cmdLineErr: nil,
|
cmdLineErrRead: nil,
|
||||||
|
cmdLineErrOpen: nil,
|
||||||
status: completeStatus,
|
status: completeStatus,
|
||||||
statusErr: nil,
|
statusErrRead: nil,
|
||||||
|
statusErrOpen: nil,
|
||||||
expected: PSEvent{
|
expected: PSEvent{
|
||||||
UID: 0,
|
UID: 0,
|
||||||
PID: 1,
|
PID: 1,
|
||||||
@@ -163,11 +179,14 @@ func TestProcessNewPid(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "empty-cmd-ok",
|
name: "empty-cmd-ok",
|
||||||
enablePpid: true,
|
enablePpid: true,
|
||||||
|
truncate: 100,
|
||||||
pid: 1,
|
pid: 1,
|
||||||
cmdLine: []byte{},
|
cmdLine: []byte{},
|
||||||
cmdLineErr: nil,
|
cmdLineErrRead: nil,
|
||||||
|
cmdLineErrOpen: nil,
|
||||||
status: completeStatus,
|
status: completeStatus,
|
||||||
statusErr: nil,
|
statusErrRead: nil,
|
||||||
|
statusErrOpen: nil,
|
||||||
expected: PSEvent{
|
expected: PSEvent{
|
||||||
UID: 0,
|
UID: 0,
|
||||||
PID: 1,
|
PID: 1,
|
||||||
@@ -175,14 +194,53 @@ func TestProcessNewPid(t *testing.T) {
|
|||||||
CMD: "",
|
CMD: "",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "cmd-truncate",
|
||||||
|
enablePpid: false,
|
||||||
|
truncate: 10,
|
||||||
|
pid: 1,
|
||||||
|
cmdLine: []byte("abc\x00123\x00alpha"),
|
||||||
|
cmdLineErrRead: nil,
|
||||||
|
cmdLineErrOpen: nil,
|
||||||
|
status: completeStatus,
|
||||||
|
statusErrRead: nil,
|
||||||
|
statusErrOpen: nil,
|
||||||
|
expected: PSEvent{
|
||||||
|
UID: 0,
|
||||||
|
PID: 1,
|
||||||
|
PPID: -1,
|
||||||
|
CMD: "abc 123 al",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "cmd-io-error",
|
name: "cmd-io-error",
|
||||||
enablePpid: true,
|
enablePpid: true,
|
||||||
|
truncate: 100,
|
||||||
pid: 2,
|
pid: 2,
|
||||||
cmdLine: nil,
|
cmdLine: nil,
|
||||||
cmdLineErr: errors.New("file-system-error"),
|
cmdLineErrRead: errors.New("file-system-error"),
|
||||||
|
cmdLineErrOpen: nil,
|
||||||
status: completeStatus,
|
status: completeStatus,
|
||||||
statusErr: nil,
|
statusErrRead: nil,
|
||||||
|
statusErrOpen: nil,
|
||||||
|
expected: PSEvent{
|
||||||
|
UID: 0,
|
||||||
|
PID: 2,
|
||||||
|
PPID: 5,
|
||||||
|
CMD: "???",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "cmd-io-error2",
|
||||||
|
enablePpid: true,
|
||||||
|
truncate: 100,
|
||||||
|
pid: 2,
|
||||||
|
cmdLine: nil,
|
||||||
|
cmdLineErrRead: nil,
|
||||||
|
cmdLineErrOpen: errors.New("file-system-error"),
|
||||||
|
status: completeStatus,
|
||||||
|
statusErrRead: nil,
|
||||||
|
statusErrOpen: nil,
|
||||||
expected: PSEvent{
|
expected: PSEvent{
|
||||||
UID: 0,
|
UID: 0,
|
||||||
PID: 2,
|
PID: 2,
|
||||||
@@ -193,11 +251,32 @@ func TestProcessNewPid(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "status-io-error",
|
name: "status-io-error",
|
||||||
enablePpid: true,
|
enablePpid: true,
|
||||||
|
truncate: 100,
|
||||||
pid: 2,
|
pid: 2,
|
||||||
cmdLine: []byte("some\x00cmd\x00123"),
|
cmdLine: []byte("some\x00cmd\x00123"),
|
||||||
cmdLineErr: nil,
|
cmdLineErrRead: nil,
|
||||||
|
cmdLineErrOpen: nil,
|
||||||
status: nil,
|
status: nil,
|
||||||
statusErr: errors.New("file-system-error"),
|
statusErrRead: errors.New("file-system-error"),
|
||||||
|
statusErrOpen: nil,
|
||||||
|
expected: PSEvent{
|
||||||
|
UID: -1,
|
||||||
|
PID: 2,
|
||||||
|
PPID: -1,
|
||||||
|
CMD: "some cmd 123",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "status-io-error2",
|
||||||
|
enablePpid: true,
|
||||||
|
truncate: 100,
|
||||||
|
pid: 2,
|
||||||
|
cmdLine: []byte("some\x00cmd\x00123"),
|
||||||
|
cmdLineErrRead: nil,
|
||||||
|
cmdLineErrOpen: nil,
|
||||||
|
status: nil,
|
||||||
|
statusErrRead: nil,
|
||||||
|
statusErrOpen: errors.New("file-system-error"),
|
||||||
expected: PSEvent{
|
expected: PSEvent{
|
||||||
UID: -1,
|
UID: -1,
|
||||||
PID: 2,
|
PID: 2,
|
||||||
@@ -208,11 +287,14 @@ func TestProcessNewPid(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "status-too-short",
|
name: "status-too-short",
|
||||||
enablePpid: true,
|
enablePpid: true,
|
||||||
|
truncate: 100,
|
||||||
pid: 3,
|
pid: 3,
|
||||||
cmdLine: []byte("some\x00cmd\x00123"),
|
cmdLine: []byte("some\x00cmd\x00123"),
|
||||||
cmdLineErr: nil,
|
cmdLineErrRead: nil,
|
||||||
|
cmdLineErrOpen: nil,
|
||||||
status: notEnoughLines,
|
status: notEnoughLines,
|
||||||
statusErr: nil,
|
statusErrRead: nil,
|
||||||
|
statusErrOpen: nil,
|
||||||
expected: PSEvent{
|
expected: PSEvent{
|
||||||
UID: -1,
|
UID: -1,
|
||||||
PID: 3,
|
PID: 3,
|
||||||
@@ -223,11 +305,14 @@ func TestProcessNewPid(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "status-empty",
|
name: "status-empty",
|
||||||
enablePpid: true,
|
enablePpid: true,
|
||||||
|
truncate: 100,
|
||||||
pid: 3,
|
pid: 3,
|
||||||
cmdLine: []byte("some\x00cmd\x00123"),
|
cmdLine: []byte("some\x00cmd\x00123"),
|
||||||
cmdLineErr: nil,
|
cmdLineErrRead: nil,
|
||||||
|
cmdLineErrOpen: nil,
|
||||||
status: []byte{},
|
status: []byte{},
|
||||||
statusErr: nil,
|
statusErrRead: nil,
|
||||||
|
statusErrOpen: nil,
|
||||||
expected: PSEvent{
|
expected: PSEvent{
|
||||||
UID: -1,
|
UID: -1,
|
||||||
PID: 3,
|
PID: 3,
|
||||||
@@ -238,11 +323,14 @@ func TestProcessNewPid(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "uid-line-too-short",
|
name: "uid-line-too-short",
|
||||||
enablePpid: true,
|
enablePpid: true,
|
||||||
|
truncate: 100,
|
||||||
pid: 3,
|
pid: 3,
|
||||||
cmdLine: []byte("some\x00cmd\x00123"),
|
cmdLine: []byte("some\x00cmd\x00123"),
|
||||||
cmdLineErr: nil,
|
cmdLineErrRead: nil,
|
||||||
|
cmdLineErrOpen: nil,
|
||||||
status: uidLineBroken,
|
status: uidLineBroken,
|
||||||
statusErr: nil,
|
statusErrRead: nil,
|
||||||
|
statusErrOpen: nil,
|
||||||
expected: PSEvent{
|
expected: PSEvent{
|
||||||
UID: -1,
|
UID: -1,
|
||||||
PID: 3,
|
PID: 3,
|
||||||
@@ -253,11 +341,14 @@ func TestProcessNewPid(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "uid-parse-error",
|
name: "uid-parse-error",
|
||||||
enablePpid: true,
|
enablePpid: true,
|
||||||
|
truncate: 100,
|
||||||
pid: 3,
|
pid: 3,
|
||||||
cmdLine: []byte("some\x00cmd\x00123"),
|
cmdLine: []byte("some\x00cmd\x00123"),
|
||||||
cmdLineErr: nil,
|
cmdLineErrRead: nil,
|
||||||
|
cmdLineErrOpen: nil,
|
||||||
status: uidNaN,
|
status: uidNaN,
|
||||||
statusErr: nil,
|
statusErrRead: nil,
|
||||||
|
statusErrOpen: nil,
|
||||||
expected: PSEvent{
|
expected: PSEvent{
|
||||||
UID: -1,
|
UID: -1,
|
||||||
PID: 3,
|
PID: 3,
|
||||||
@@ -268,11 +359,14 @@ func TestProcessNewPid(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "ppid-line-too-short",
|
name: "ppid-line-too-short",
|
||||||
enablePpid: true,
|
enablePpid: true,
|
||||||
|
truncate: 100,
|
||||||
pid: 3,
|
pid: 3,
|
||||||
cmdLine: []byte("some\x00cmd\x00123"),
|
cmdLine: []byte("some\x00cmd\x00123"),
|
||||||
cmdLineErr: nil,
|
cmdLineErrRead: nil,
|
||||||
|
cmdLineErrOpen: nil,
|
||||||
status: ppidLineShort,
|
status: ppidLineShort,
|
||||||
statusErr: nil,
|
statusErrRead: nil,
|
||||||
|
statusErrOpen: nil,
|
||||||
expected: PSEvent{
|
expected: PSEvent{
|
||||||
UID: -1,
|
UID: -1,
|
||||||
PID: 3,
|
PID: 3,
|
||||||
@@ -283,11 +377,14 @@ func TestProcessNewPid(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "ppid-parse-error",
|
name: "ppid-parse-error",
|
||||||
enablePpid: true,
|
enablePpid: true,
|
||||||
|
truncate: 100,
|
||||||
pid: 3,
|
pid: 3,
|
||||||
cmdLine: []byte("some\x00cmd\x00123"),
|
cmdLine: []byte("some\x00cmd\x00123"),
|
||||||
cmdLineErr: nil,
|
cmdLineErrRead: nil,
|
||||||
|
cmdLineErrOpen: nil,
|
||||||
status: ppidNaN,
|
status: ppidNaN,
|
||||||
statusErr: nil,
|
statusErrRead: nil,
|
||||||
|
statusErrOpen: nil,
|
||||||
expected: PSEvent{
|
expected: PSEvent{
|
||||||
UID: -1,
|
UID: -1,
|
||||||
PID: 3,
|
PID: 3,
|
||||||
@@ -298,11 +395,14 @@ func TestProcessNewPid(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "no-ppid-line-too-short",
|
name: "no-ppid-line-too-short",
|
||||||
enablePpid: false,
|
enablePpid: false,
|
||||||
|
truncate: 100,
|
||||||
pid: 3,
|
pid: 3,
|
||||||
cmdLine: []byte("some\x00cmd\x00123"),
|
cmdLine: []byte("some\x00cmd\x00123"),
|
||||||
cmdLineErr: nil,
|
cmdLineErrRead: nil,
|
||||||
|
cmdLineErrOpen: nil,
|
||||||
status: ppidLineShort,
|
status: ppidLineShort,
|
||||||
statusErr: nil,
|
statusErrRead: nil,
|
||||||
|
statusErrOpen: nil,
|
||||||
expected: PSEvent{
|
expected: PSEvent{
|
||||||
UID: 0,
|
UID: 0,
|
||||||
PID: 3,
|
PID: 3,
|
||||||
@@ -313,11 +413,14 @@ func TestProcessNewPid(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "no-ppid-parse-error",
|
name: "no-ppid-parse-error",
|
||||||
enablePpid: false,
|
enablePpid: false,
|
||||||
|
truncate: 100,
|
||||||
pid: 3,
|
pid: 3,
|
||||||
cmdLine: []byte("some\x00cmd\x00123"),
|
cmdLine: []byte("some\x00cmd\x00123"),
|
||||||
cmdLineErr: nil,
|
cmdLineErrRead: nil,
|
||||||
|
cmdLineErrOpen: nil,
|
||||||
status: ppidNaN,
|
status: ppidNaN,
|
||||||
statusErr: nil,
|
statusErrRead: nil,
|
||||||
|
statusErrOpen: nil,
|
||||||
expected: PSEvent{
|
expected: PSEvent{
|
||||||
UID: 0,
|
UID: 0,
|
||||||
PID: 3,
|
PID: 3,
|
||||||
@@ -329,14 +432,15 @@ func TestProcessNewPid(t *testing.T) {
|
|||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
defer mockCmdLineReader(tt.cmdLine, tt.cmdLineErr)()
|
defer mockPidCmdLine(tt.pid, tt.cmdLine, tt.cmdLineErrRead, tt.cmdLineErrOpen, t)()
|
||||||
defer mockProcStatusReader(tt.status, tt.statusErr)()
|
defer mockPidStatus(tt.pid, tt.status, tt.statusErrRead, tt.statusErrOpen, t)()
|
||||||
|
|
||||||
results := make(chan PSEvent, 1)
|
results := make(chan PSEvent, 1)
|
||||||
|
|
||||||
scanner := &PSScanner{
|
scanner := &PSScanner{
|
||||||
enablePpid: tt.enablePpid,
|
enablePpid: tt.enablePpid,
|
||||||
eventCh: results,
|
eventCh: results,
|
||||||
|
maxCmdLength: tt.truncate,
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
@@ -359,23 +463,44 @@ func TestProcessNewPid(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func mockCmdLineReader(cmdLine []byte, err error) (restore func()) {
|
func mockPidStatus(pid int, stat []byte, errRead error, errOpen error, t *testing.T) func() {
|
||||||
oldFunc := cmdLineReader
|
return mockFile(fmt.Sprintf("/proc/%d/status", pid), stat, errRead, errOpen, t)
|
||||||
cmdLineReader = func(pid int) ([]byte, error) {
|
|
||||||
return cmdLine, err
|
|
||||||
}
|
|
||||||
return func() {
|
|
||||||
cmdLineReader = oldFunc
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func mockProcStatusReader(stat []byte, err error) (restore func()) {
|
func mockPidCmdLine(pid int, cmdline []byte, errRead error, errOpen error, t *testing.T) func() {
|
||||||
oldFunc := procStatusReader
|
return mockFile(fmt.Sprintf("/proc/%d/cmdline", pid), cmdline, errRead, errOpen, t)
|
||||||
procStatusReader = func(pid int) ([]byte, error) {
|
}
|
||||||
return stat, err
|
|
||||||
|
type MockFile struct {
|
||||||
|
content []byte
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *MockFile) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *MockFile) Read(p []byte) (int, error) {
|
||||||
|
return copy(p, f.content), f.err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hook/chain a mocked file into the "open" variable
|
||||||
|
func mockFile(name string, content []byte, errRead error, errOpen error, t *testing.T) func() {
|
||||||
|
oldopen := open
|
||||||
|
open = func(n string) (io.ReadCloser, error) {
|
||||||
|
if name == n {
|
||||||
|
if testing.Verbose() {
|
||||||
|
t.Logf("opening mocked file: %s", n)
|
||||||
|
}
|
||||||
|
return &MockFile{
|
||||||
|
content: content,
|
||||||
|
err: errRead,
|
||||||
|
}, errOpen
|
||||||
|
}
|
||||||
|
return oldopen(n)
|
||||||
}
|
}
|
||||||
return func() {
|
return func() {
|
||||||
procStatusReader = oldFunc
|
open = oldopen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -383,22 +508,26 @@ func TestNewPSScanner(t *testing.T) {
|
|||||||
for _, tt := range []struct {
|
for _, tt := range []struct {
|
||||||
name string
|
name string
|
||||||
ppid bool
|
ppid bool
|
||||||
|
cmdlen int
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "without-ppid",
|
name: "without-ppid",
|
||||||
ppid: false,
|
ppid: false,
|
||||||
|
cmdlen: 30,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "with-ppid",
|
name: "with-ppid",
|
||||||
ppid: true,
|
ppid: true,
|
||||||
|
cmdlen: 5000,
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
expected := &PSScanner{
|
expected := &PSScanner{
|
||||||
enablePpid: tt.ppid,
|
enablePpid: tt.ppid,
|
||||||
eventCh: nil,
|
eventCh: nil,
|
||||||
|
maxCmdLength: tt.cmdlen,
|
||||||
}
|
}
|
||||||
new := NewPSScanner(tt.ppid)
|
new := NewPSScanner(tt.ppid, tt.cmdlen)
|
||||||
|
|
||||||
if !reflect.DeepEqual(new, expected) {
|
if !reflect.DeepEqual(new, expected) {
|
||||||
t.Errorf("Unexpected scanner initialisation state: got %#v but want %#v", new, expected)
|
t.Errorf("Unexpected scanner initialisation state: got %#v but want %#v", new, expected)
|
||||||
|
|||||||
Reference in New Issue
Block a user