mirror of
https://github.com/DominicBreuker/pspy.git
synced 2025-12-21 03:34:50 +00:00
experiment with some tests
This commit is contained in:
22
cmd/root.go
22
cmd/root.go
@@ -4,10 +4,14 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"os/signal"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
"github.com/dominicbreuker/pspy/internal/config"
|
"github.com/dominicbreuker/pspy/internal/config"
|
||||||
"github.com/dominicbreuker/pspy/internal/logger"
|
"github.com/dominicbreuker/pspy/internal/inotify"
|
||||||
|
"github.com/dominicbreuker/pspy/internal/logging"
|
||||||
|
"github.com/dominicbreuker/pspy/internal/process"
|
||||||
"github.com/dominicbreuker/pspy/internal/pspy"
|
"github.com/dominicbreuker/pspy/internal/pspy"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
@@ -71,9 +75,19 @@ func root(cmd *cobra.Command, args []string) {
|
|||||||
LogPS: logPS,
|
LogPS: logPS,
|
||||||
LogFS: logFS,
|
LogFS: logFS,
|
||||||
}
|
}
|
||||||
logger := logger.NewLogger()
|
logger := logging.NewLogger()
|
||||||
pspy.Start(cfg, logger)
|
iw := inotify.NewInotifyWatcher()
|
||||||
// pspy.Watch(rDirs, dirs, logPS, logFS)
|
pscan := process.NewProcfsScanner()
|
||||||
|
|
||||||
|
sigCh := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(sigCh, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
|
||||||
|
|
||||||
|
exit, err := pspy.Start(cfg, logger, iw, pscan, sigCh)
|
||||||
|
if err != nil {
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
<-exit
|
||||||
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Execute() {
|
func Execute() {
|
||||||
|
|||||||
@@ -6,6 +6,18 @@ import (
|
|||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type InotifyWatcher struct{}
|
||||||
|
|
||||||
|
func NewInotifyWatcher() *InotifyWatcher {
|
||||||
|
return &InotifyWatcher{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *InotifyWatcher) Setup(rdirs, dirs []string) (chan struct{}, chan string, error) {
|
||||||
|
triggerCh := make(chan struct{})
|
||||||
|
fsEventCh := make(chan string)
|
||||||
|
return triggerCh, fsEventCh, nil
|
||||||
|
}
|
||||||
|
|
||||||
type Inotify struct {
|
type Inotify struct {
|
||||||
fd int
|
fd int
|
||||||
watchers map[int]*watcher
|
watchers map[int]*watcher
|
||||||
|
|||||||
@@ -1,18 +1,16 @@
|
|||||||
package logger
|
package logging
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Logger is the logger used to print to the command line
|
|
||||||
type Logger struct {
|
type Logger struct {
|
||||||
infoLogger *log.Logger
|
infoLogger *log.Logger
|
||||||
errorLogger *log.Logger
|
errorLogger *log.Logger
|
||||||
eventLogger *log.Logger
|
eventLogger *log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLogger creates a new logger instance
|
|
||||||
func NewLogger() *Logger {
|
func NewLogger() *Logger {
|
||||||
return &Logger{
|
return &Logger{
|
||||||
infoLogger: log.New(os.Stdout, "", 0),
|
infoLogger: log.New(os.Stdout, "", 0),
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package logger
|
package logging
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@@ -6,8 +6,20 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ProcfsScanner struct{}
|
||||||
|
|
||||||
|
func NewProcfsScanner() *ProcfsScanner {
|
||||||
|
return &ProcfsScanner{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ProcfsScanner) Setup(triggerCh chan struct{}, interval time.Duration) (chan string, error) {
|
||||||
|
psEventCh := make(chan string)
|
||||||
|
return psEventCh, nil
|
||||||
|
}
|
||||||
|
|
||||||
type ProcList map[int]string
|
type ProcList map[int]string
|
||||||
|
|
||||||
func NewProcList() *ProcList {
|
func NewProcList() *ProcList {
|
||||||
|
|||||||
@@ -1,40 +1,54 @@
|
|||||||
package pspy
|
package pspy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
|
||||||
"syscall"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/dominicbreuker/pspy/internal/config"
|
"github.com/dominicbreuker/pspy/internal/config"
|
||||||
"github.com/dominicbreuker/pspy/internal/inotify"
|
"github.com/dominicbreuker/pspy/internal/inotify"
|
||||||
"github.com/dominicbreuker/pspy/internal/logger"
|
|
||||||
"github.com/dominicbreuker/pspy/internal/process"
|
"github.com/dominicbreuker/pspy/internal/process"
|
||||||
"github.com/dominicbreuker/pspy/internal/walker"
|
"github.com/dominicbreuker/pspy/internal/walker"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Start(cfg config.Config, logger *logger.Logger) {
|
type Logger interface {
|
||||||
fmt.Printf("Config: %+v\n", cfg)
|
Infof(format string, v ...interface{})
|
||||||
|
Errorf(format string, v ...interface{})
|
||||||
|
Eventf(format string, v ...interface{})
|
||||||
|
}
|
||||||
|
|
||||||
triggerCh, fsEventCh, err := setupInotify(cfg.RDirs, cfg.Dirs)
|
type InotifyWatcher interface {
|
||||||
|
Setup(rdirs, dirs []string) (chan struct{}, chan string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProcfsScanner interface {
|
||||||
|
Setup(triggerCh chan struct{}, interval time.Duration) (chan string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Start(cfg config.Config, logger Logger, inotify InotifyWatcher, pscan ProcfsScanner, sigCh chan os.Signal) (chan struct{}, error) {
|
||||||
|
logger.Infof("Config: %+v\n", cfg)
|
||||||
|
|
||||||
|
triggerCh, fsEventCh, err := inotify.Setup(cfg.RDirs, cfg.Dirs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Errorf("Can't set up inotify watchers: %v\n", err)
|
logger.Errorf("Can't set up inotify watchers: %v\n", err)
|
||||||
|
return nil, errors.New("inotify error")
|
||||||
}
|
}
|
||||||
psEventCh, err := setupProcfsScanner(triggerCh, 100*time.Millisecond)
|
psEventCh, err := pscan.Setup(triggerCh, 100*time.Millisecond)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Errorf("Can't set up procfs scanner: %+v\n", err)
|
logger.Errorf("Can't set up procfs scanner: %+v\n", err)
|
||||||
|
return nil, errors.New("procfs scanner error")
|
||||||
}
|
}
|
||||||
|
|
||||||
sigCh := make(chan os.Signal, 1)
|
exit := make(chan struct{})
|
||||||
signal.Notify(sigCh, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
|
|
||||||
|
|
||||||
|
go func() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case se := <-sigCh:
|
case se := <-sigCh:
|
||||||
logger.Infof("Exiting program... (%s)\n", se)
|
logger.Infof("Exiting program... (%s)\n", se)
|
||||||
os.Exit(0)
|
exit <- struct{}{}
|
||||||
case fe := <-fsEventCh:
|
case fe := <-fsEventCh:
|
||||||
if cfg.LogFS {
|
if cfg.LogFS {
|
||||||
logger.Eventf("FS: %+v\n", fe)
|
logger.Eventf("FS: %+v\n", fe)
|
||||||
@@ -45,17 +59,8 @@ func Start(cfg config.Config, logger *logger.Logger) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}()
|
||||||
|
return exit, nil
|
||||||
func setupInotify(rdirs, dirs []string) (chan struct{}, chan string, error) {
|
|
||||||
triggerCh := make(chan struct{})
|
|
||||||
fsEventCh := make(chan string)
|
|
||||||
return triggerCh, fsEventCh, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func setupProcfsScanner(triggerCh chan struct{}, interval time.Duration) (chan string, error) {
|
|
||||||
psEventCh := make(chan string)
|
|
||||||
return psEventCh, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const MaxInt = int(^uint(0) >> 1)
|
const MaxInt = int(^uint(0) >> 1)
|
||||||
|
|||||||
133
internal/pspy/pspy_test.go
Normal file
133
internal/pspy/pspy_test.go
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
package pspy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/dominicbreuker/pspy/internal/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestStart(t *testing.T) {
|
||||||
|
cfg := config.Config{
|
||||||
|
RDirs: []string{"rdir"},
|
||||||
|
Dirs: []string{"dir"},
|
||||||
|
LogFS: true,
|
||||||
|
LogPS: true,
|
||||||
|
}
|
||||||
|
mockLogger := newMockLogger()
|
||||||
|
mockIW := newMockInotifyWatcher(nil)
|
||||||
|
mockPS := newMockProcfsScanner(nil)
|
||||||
|
sigCh := make(chan os.Signal)
|
||||||
|
|
||||||
|
exit, err := Start(cfg, mockLogger, mockIW, mockPS, sigCh)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpcted error: %v", err)
|
||||||
|
}
|
||||||
|
mockIW.fsEventCh <- "some fs event"
|
||||||
|
expectMsg(t, mockLogger.Event, "FS: some fs event\n")
|
||||||
|
|
||||||
|
mockPS.psEventCh <- "some ps event"
|
||||||
|
expectMsg(t, mockLogger.Event, "CMD: some ps event\n")
|
||||||
|
|
||||||
|
sigCh <- syscall.SIGINT
|
||||||
|
expectExit(t, exit)
|
||||||
|
}
|
||||||
|
|
||||||
|
func expectMsg(t *testing.T, ch chan string, msg string) {
|
||||||
|
select {
|
||||||
|
case received := <-ch:
|
||||||
|
if received != msg {
|
||||||
|
t.Fatalf("Wanted to receive %s but got %s", msg, received)
|
||||||
|
}
|
||||||
|
case <-time.After(500 * time.Millisecond):
|
||||||
|
t.Fatalf("Did not receive message in time. Wanted: %s", msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func expectExit(t *testing.T, ch chan struct{}) {
|
||||||
|
select {
|
||||||
|
case <-ch:
|
||||||
|
return
|
||||||
|
case <-time.After(500 * time.Millisecond):
|
||||||
|
t.Fatalf("Did not receive exit signal in time")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ##### Mocks #####
|
||||||
|
|
||||||
|
// Logger
|
||||||
|
|
||||||
|
type mockLogger struct {
|
||||||
|
Info chan string
|
||||||
|
Error chan string
|
||||||
|
Event chan string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMockLogger() *mockLogger {
|
||||||
|
return &mockLogger{
|
||||||
|
Info: make(chan string, 10),
|
||||||
|
Error: make(chan string, 10),
|
||||||
|
Event: make(chan string, 10),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *mockLogger) Infof(format string, v ...interface{}) {
|
||||||
|
l.Info <- fmt.Sprintf(format, v...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *mockLogger) Errorf(format string, v ...interface{}) {
|
||||||
|
l.Error <- fmt.Sprintf(format, v...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *mockLogger) Eventf(format string, v ...interface{}) {
|
||||||
|
l.Event <- fmt.Sprintf(format, v...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InotfiyWatcher
|
||||||
|
|
||||||
|
type mockInotifyWatcher struct {
|
||||||
|
triggerCh chan struct{}
|
||||||
|
fsEventCh chan string
|
||||||
|
setupErr error
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMockInotifyWatcher(setupErr error) *mockInotifyWatcher {
|
||||||
|
return &mockInotifyWatcher{
|
||||||
|
triggerCh: make(chan struct{}),
|
||||||
|
fsEventCh: make(chan string),
|
||||||
|
setupErr: setupErr,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *mockInotifyWatcher) Setup(rdirs, dirs []string) (chan struct{}, chan string, error) {
|
||||||
|
if i.setupErr != nil {
|
||||||
|
return nil, nil, i.setupErr
|
||||||
|
}
|
||||||
|
return i.triggerCh, i.fsEventCh, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProcfsScanner
|
||||||
|
|
||||||
|
type mockProcfsScanner struct {
|
||||||
|
triggerCh chan struct{}
|
||||||
|
interval time.Duration
|
||||||
|
psEventCh chan string
|
||||||
|
setupErr error
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMockProcfsScanner(setupErr error) *mockProcfsScanner {
|
||||||
|
return &mockProcfsScanner{
|
||||||
|
psEventCh: make(chan string),
|
||||||
|
setupErr: setupErr,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *mockProcfsScanner) Setup(triggerCh chan struct{}, interval time.Duration) (chan string, error) {
|
||||||
|
if p.setupErr != nil {
|
||||||
|
return nil, p.setupErr
|
||||||
|
}
|
||||||
|
return p.psEventCh, nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user