experiment with some tests

This commit is contained in:
Dominic Breuker
2018-02-23 22:26:57 +01:00
parent a517fe25de
commit d59ec7f1a8
7 changed files with 215 additions and 41 deletions

View File

@@ -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() {

View File

@@ -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

View File

@@ -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),

View File

@@ -1,4 +1,4 @@
package logger package logging
import ( import (
"bytes" "bytes"

View File

@@ -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 {

View File

@@ -1,61 +1,66 @@
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)
for { go func() {
select { for {
case se := <-sigCh: select {
logger.Infof("Exiting program... (%s)\n", se) case se := <-sigCh:
os.Exit(0) logger.Infof("Exiting program... (%s)\n", se)
case fe := <-fsEventCh: exit <- struct{}{}
if cfg.LogFS { case fe := <-fsEventCh:
logger.Eventf("FS: %+v\n", fe) if cfg.LogFS {
} logger.Eventf("FS: %+v\n", fe)
case pe := <-psEventCh: }
if cfg.LogPS { case pe := <-psEventCh:
logger.Eventf("CMD: %+v\n", pe) if cfg.LogPS {
logger.Eventf("CMD: %+v\n", pe)
}
} }
} }
} }()
} 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
View 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
}