A bunch of tests and mocking

This commit is contained in:
Marcel Otte 2022-01-30 00:16:59 +01:00
parent 8ca9615541
commit 9c5feeb672
9 changed files with 188 additions and 28 deletions

View File

@ -13,8 +13,8 @@ import (
) )
// Mockings // Mockings
var mock_exec_Command = exec.Command var mockExecCommand = exec.Command
var mock_cmd_Run = func(c *exec.Cmd) error { var mockCmdRun = func(c *exec.Cmd) error {
return c.Run() return c.Run()
} }
@ -81,8 +81,8 @@ func (b *Backup) PrepareRun() error {
} }
writer := io.MultiWriter(logfile) writer := io.MultiWriter(logfile)
b.logger = log.New(writer, b.Name, log.LstdFlags) b.logger = log.New(writer, b.Name, log.LstdFlags)
cmd := mock_exec_Command("chown", "-R", b.ExeUser, backupPath) cmd := mockExecCommand("chown", "-R", b.ExeUser, backupPath)
err = mock_cmd_Run(cmd) err = mockCmdRun(cmd)
if err != nil { if err != nil {
b.logger.Printf("chown for backup directory failed: %s", err) b.logger.Printf("chown for backup directory failed: %s", err)
return err return err
@ -107,10 +107,10 @@ func (b *Backup) Run() error {
log.Printf("ERROR: Script path is relative, aborting.") log.Printf("ERROR: Script path is relative, aborting.")
return fmt.Errorf("script path is relative, aborting") return fmt.Errorf("script path is relative, aborting")
} }
cmd := mock_exec_Command("/usr/bin/sh", b.ScriptPath) cmd := mockExecCommand("/usr/bin/sh", b.ScriptPath)
if b.ExeUser != "" { if b.ExeUser != "" {
// setup script environment including user to use // setup script environment including user to use
cmd = mock_exec_Command("sudo", "-E", "-u", b.ExeUser, "/usr/bin/sh", b.ScriptPath) cmd = mockExecCommand("sudo", "-E", "-u", b.ExeUser, "/usr/bin/sh", b.ScriptPath)
} }
b.logger.Printf("Running backup script of '%s'", b.Name) b.logger.Printf("Running backup script of '%s'", b.Name)
b.logger.Printf("Script is: %s", b.ScriptPath) b.logger.Printf("Script is: %s", b.ScriptPath)
@ -129,7 +129,7 @@ func (b *Backup) Run() error {
log.Printf("About to run: %s", cmd.String()) log.Printf("About to run: %s", cmd.String())
// run script // run script
err := mock_cmd_Run(cmd) err := mockCmdRun(cmd)
if err != nil { if err != nil {
log.Printf("Backup '%s' run failed", b.Name) log.Printf("Backup '%s' run failed", b.Name)
return err return err

View File

@ -14,12 +14,6 @@ func getCurrentFilePath() string {
return file return file
} }
type MockCmd struct{}
func (c *MockCmd) Run() error {
return nil
}
func TestFindBackupsForDevice(t *testing.T) { func TestFindBackupsForDevice(t *testing.T) {
var testBackups = Backups{} var testBackups = Backups{}
@ -119,7 +113,7 @@ func setupNewTestEnv(subdir string) {
func TestPrepareRun(t *testing.T) { func TestPrepareRun(t *testing.T) {
setupNewTestEnv("preparerun") setupNewTestEnv("preparerun")
mock_cmd_Run = func(c *exec.Cmd) error { mockCmdRun = func(c *exec.Cmd) error {
return nil return nil
} }
var testBkp = Backup{ var testBkp = Backup{
@ -142,7 +136,7 @@ func TestRun(t *testing.T) {
config.Devices["mytarget"].Name = "mytarget" config.Devices["mytarget"].Name = "mytarget"
config.Devices["mytarget"].UUID = "123-456-789-abc-def" config.Devices["mytarget"].UUID = "123-456-789-abc-def"
mock_cmd_Run = func(c *exec.Cmd) error { mockCmdRun = func(c *exec.Cmd) error {
return nil return nil
} }
var testBkp = Backup{ var testBkp = Backup{
@ -167,7 +161,7 @@ func TestRun(t *testing.T) {
t.Logf("Error which should not occur: %s", err) t.Logf("Error which should not occur: %s", err)
t.Fail() t.Fail()
} }
mock_cmd_Run = func(c *exec.Cmd) error { mockCmdRun = func(c *exec.Cmd) error {
return nil return nil
} }
} }

View File

@ -7,6 +7,9 @@ import (
"path" "path"
) )
var mockOsWriteFile = os.WriteFile
var mockOsReadFile = os.ReadFile
// Database is a simple string to string mapping, where arbitrary strings can be stored and safed to disk or loaded // Database is a simple string to string mapping, where arbitrary strings can be stored and safed to disk or loaded
type Database struct { type Database struct {
data map[string]string data map[string]string
@ -23,7 +26,7 @@ func (d *Database) Save() {
log.Printf("Writing database output to file: %s", jsonstr) log.Printf("Writing database output to file: %s", jsonstr)
saveDir, _ := path.Split(dbPath) saveDir, _ := path.Split(dbPath)
CreateDirectoryIfNotExists(saveDir) CreateDirectoryIfNotExists(saveDir)
err := os.WriteFile(dbPath, []byte(jsonstr), 0644) err := mockOsWriteFile(dbPath, []byte(jsonstr), 0644)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -32,7 +35,7 @@ func (d *Database) Save() {
// Load loads the database // Load loads the database
func (d *Database) Load() { func (d *Database) Load() {
if _, err := os.Stat(dbPath); err == nil { if _, err := os.Stat(dbPath); err == nil {
data, rferr := os.ReadFile(dbPath) data, rferr := mockOsReadFile(dbPath)
if rferr != nil { if rferr != nil {
panic(rferr) panic(rferr)
} }

23
database_test.go Normal file
View File

@ -0,0 +1,23 @@
package backive
import (
"io/fs"
"testing"
)
func TestDatabase(t *testing.T) {
mockOsStat = func(p string) (fs.FileInfo, error) {
return nil, nil
}
db := new(Database)
mockOsReadFile = func(p string) ([]byte, error) {
return []byte("{}"), nil
}
db.Load()
mockOsWriteFile = func(p string, data []byte, rights fs.FileMode) error {
return nil
}
db.Save()
}

View File

@ -35,7 +35,7 @@ func (d *Device) Mount() error {
cmd.Stdout = log.Writer() cmd.Stdout = log.Writer()
cmd.Stderr = log.Writer() cmd.Stderr = log.Writer()
log.Printf("Command to execute: %s", cmd.String()) log.Printf("Command to execute: %s", cmd.String())
err := mock_cmd_Run(cmd) err := mockCmdRun(cmd)
if err != nil { if err != nil {
log.Printf("Mounting failed with error %v", err) log.Printf("Mounting failed with error %v", err)
return err return err
@ -49,7 +49,7 @@ func (d *Device) Unmount() error {
if d.isMounted { if d.isMounted {
log.Printf("Unmounting %s", d.Name) log.Printf("Unmounting %s", d.Name)
sync := exec.Command("sync") sync := exec.Command("sync")
syncErr := mock_cmd_Run(sync) syncErr := mockCmdRun(sync)
if syncErr != nil { if syncErr != nil {
log.Println(syncErr) log.Println(syncErr)
return syncErr return syncErr
@ -59,7 +59,7 @@ func (d *Device) Unmount() error {
path.Join(config.Settings.SystemMountPoint, d.Name), path.Join(config.Settings.SystemMountPoint, d.Name),
) )
log.Printf("About to run: %s", cmd.String()) log.Printf("About to run: %s", cmd.String())
err := mock_cmd_Run(cmd) err := mockCmdRun(cmd)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
return err return err

33
device_test.go Normal file
View File

@ -0,0 +1,33 @@
package backive
import (
"os/exec"
"testing"
)
func TestDevice(t *testing.T) {
testDevice := new(Device)
testDevice.Name = "Testdevice"
testDevice.UUID = "123-456-789-abc-def"
mockCmdRun = func(c *exec.Cmd) error {
return nil
}
err := testDevice.Mount()
if err != nil {
t.Log("Should not fail, is mocked.")
t.Fail()
}
if !testDevice.IsMounted() {
t.Log("Should return true.")
t.Fail()
}
err = testDevice.Unmount()
if err != nil {
t.Log("Should not fail, is mocked.")
t.Fail()
}
if testDevice.IsMounted() {
t.Log("Should return false.")
t.Fail()
}
}

View File

@ -14,10 +14,12 @@ type EventHandler struct {
ls net.Listener ls net.Listener
//done <-chan struct{} //done <-chan struct{}
callbacks []func(map[string]string) callbacks []func(map[string]string)
stop chan bool
} }
// Init initializes the unix socket. // Init initializes the unix socket.
func (eh *EventHandler) Init(socketPath string) { func (eh *EventHandler) Init(socketPath string) {
eh.stop = make(chan bool)
log.Println("Initializing EventHandler...") log.Println("Initializing EventHandler...")
var err error var err error
dir, _ := path.Split(socketPath) dir, _ := path.Split(socketPath)
@ -29,12 +31,27 @@ func (eh *EventHandler) Init(socketPath string) {
eh.callbacks = make([]func(map[string]string), 3) eh.callbacks = make([]func(map[string]string), 3)
} }
func (eh *EventHandler) Stop() {
log.Println("Closing EventHandler")
eh.stop <- true
err := eh.ls.Close()
if err != nil {
log.Println("Error closing the listener")
}
log.Println("Closed EventHandler")
}
// Listen starts the event loop. // Listen starts the event loop.
func (eh *EventHandler) Listen() { func (eh *EventHandler) Listen() {
log.Println("Running eventloop") log.Println("Running eventloop")
func() { func() {
for { for {
eh.process() select {
case <-eh.stop:
return
default:
eh.process()
}
} }
}() }()
} }
@ -49,8 +66,14 @@ func (eh *EventHandler) process() {
client, err := eh.ls.Accept() client, err := eh.ls.Accept()
log.Println("Accepted client") log.Println("Accepted client")
if err != nil { if err != nil {
log.Fatal(err) select {
case <-eh.stop:
return
default:
log.Fatal(err)
}
} }
defer client.Close()
data := make([]byte, 2048) data := make([]byte, 2048)
for { for {
buf := make([]byte, 512) buf := make([]byte, 512)
@ -67,15 +90,15 @@ func (eh *EventHandler) process() {
//log.Println(sdata) //log.Println(sdata)
var message map[string]interface{} var message map[string]interface{}
errjson := json.Unmarshal([]byte(sdata), &message) errjson := json.Unmarshal([]byte(sdata), &message)
if errjson != nil {
log.Fatal(errjson)
}
var env = map[string]string{} var env = map[string]string{}
if message["request"] == "udev" { if message["request"] == "udev" {
for k, v := range message["data"].(map[string]interface{}) { for k, v := range message["data"].(map[string]interface{}) {
env[k] = v.(string) env[k] = v.(string)
} }
} }
if errjson != nil {
log.Fatal(errjson)
}
for _, v := range eh.callbacks { for _, v := range eh.callbacks {
if v != nil { if v != nil {
v(env) v(env)

81
events_test.go Normal file
View File

@ -0,0 +1,81 @@
package backive
import (
"encoding/json"
"log"
"net"
"os"
"testing"
"time"
)
func TestEventhandler(t *testing.T) {
t.Skip("Do not get it to work...")
eh := new(EventHandler)
eh.Init("./backive.socket")
defer func() {
eh.Stop()
err := os.Remove("./backive.socket")
if err != nil {
t.Log(err)
}
}()
t.Log("Initialized test")
go eh.Listen()
t.Log("eh is listening")
var hasBeenCalled = make(chan bool)
eh.RegisterCallback(
func(m map[string]string) {
hasBeenCalled <- true
},
)
t.Log("registered callback")
beenCalled := false
var counter = 0
env := map[string]string{}
env["test"] = "test"
message := map[string]interface{}{}
message["request"] = "udev"
message["data"] = env
for {
select {
case data := <-hasBeenCalled:
t.Log("receiving message")
beenCalled = data
if !beenCalled {
t.Fail()
}
t.Log("received message")
eh.Stop()
return
default:
t.Logf("Waiting for callback %d", counter)
time.Sleep(time.Millisecond)
if counter == 2 {
sendDataToSocket("./backive.socket", message)
t.Log("sent message")
}
if counter < 10 {
counter++
} else {
t.Log("Stopping with Fail")
eh.Stop()
t.Fail()
break
}
}
}
}
func sendDataToSocket(socket string, message map[string]interface{}) {
c, err := net.Dial("unix", socket)
if err != nil {
log.Fatalln("Could not instantiate unix socket. Aborting")
}
jsonstr, err := json.Marshal(message)
if err != nil {
log.Fatalln("Could not convert to json. Aborting")
}
c.Write(jsonstr)
defer c.Close()
}

View File

@ -5,12 +5,15 @@ import (
"os" "os"
) )
var mockOsStat = os.Stat
var mockOsMkdirAll = os.MkdirAll
// CreateDirectoryIfNotExists Checks for a directory string and creates the directory if it does not exist, must be a absolute path. // CreateDirectoryIfNotExists Checks for a directory string and creates the directory if it does not exist, must be a absolute path.
func CreateDirectoryIfNotExists(dir string) { func CreateDirectoryIfNotExists(dir string) {
if _, err := os.Stat(dir); err == nil { if _, err := mockOsStat(dir); err == nil {
//ignore //ignore
} else if os.IsNotExist(err) { } else if os.IsNotExist(err) {
os.MkdirAll(dir, 0755) mockOsMkdirAll(dir, 0755)
} else { } else {
log.Fatal(err) log.Fatal(err)
} }