Compare commits

..

18 Commits
v0.1.1 ... main

Author SHA1 Message Date
Marcel M. Otte
abb90bb172
Merge pull request #7 from qwc/dependabot/go_modules/golang.org/x/text-0.3.8
Some checks failed
Go / build (push) Has been cancelled
Bump golang.org/x/text from 0.3.7 to 0.3.8
2024-10-29 10:48:25 +01:00
dependabot[bot]
99047a576f
Bump golang.org/x/text from 0.3.7 to 0.3.8
Bumps [golang.org/x/text](https://github.com/golang/text) from 0.3.7 to 0.3.8.
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.3.7...v0.3.8)

---
updated-dependencies:
- dependency-name: golang.org/x/text
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-17 08:58:36 +00:00
b8f92c68ba Fix code to pass tests 2022-02-13 00:26:16 +01:00
5b092b1988 Added a possibility to have scripts with arguments 2022-02-13 00:20:45 +01:00
7cd0cee610 Add the udev and systemd stubs 2022-01-31 23:33:39 +01:00
Marcel M. Otte
b059ed3f01
Update README.md 2022-01-31 22:52:24 +01:00
e102e976ab Add some more tests for coverage 2022-01-31 22:18:21 +01:00
87109b6bf0 Create map if it does not exist 2022-01-30 00:26:14 +01:00
fe83c16934 Do coverage aswell 2022-01-30 00:20:35 +01:00
4a264091a9 forgot Comment 2022-01-30 00:18:08 +01:00
9c5feeb672 A bunch of tests and mocking 2022-01-30 00:16:59 +01:00
8ca9615541 Mocking exec.Cmd.Run() and new tests 2022-01-10 23:03:14 +01:00
5b14065b29 Test stup for testing PrepareRun 2022-01-08 11:14:38 +01:00
8c054a66d3 Adding more tests and fixed viper finding the /etc config file 2022-01-08 11:13:05 +01:00
5602907eb0 Add first unit test 2022-01-07 23:41:31 +01:00
e5e7f7326a Introducing a better interface
Goal is to distinguish between udev input only and a gui for
notifications.
2022-01-07 12:09:10 +01:00
Marcel M. Otte
dfff4af38f
Update go-release.yml 2022-01-07 11:33:42 +01:00
Marcel M. Otte
164db58156
Create go-release.yml 2022-01-07 11:28:40 +01:00
23 changed files with 549 additions and 61 deletions

31
.github/workflows/go-release.yml vendored Normal file
View File

@ -0,0 +1,31 @@
name: Go
on:
release
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.17
- name: Install GoReleaser
uses: goreleaser/goreleaser-action@v2.7.0
with:
install-only: true
- name: Go-linter
# You may pin to the exact commit or the version.
# uses: Jerome1337/golint-action@c5d17206a0a436bbf1edb91e314ed084f7c57589
uses: Jerome1337/golint-action@v1.0.2
#with:
# Path used by golint command
# golint-path: # optional, default is ./...
- name: Build
run: goreleaser
- name: Test
run: go test -v ./...

View File

@ -31,5 +31,5 @@ jobs:
- name: Build - name: Build
run: goreleaser build --snapshot --rm-dist run: goreleaser build --snapshot --rm-dist
- name: Test - name: Test
run: go test -v ./... run: go test -v -cover

View File

@ -30,4 +30,4 @@ What I currently see as optional:
# Current state # Current state
In the very beginning... Working daemon and udev binary. Ready for first basic usage and testing in "production".

View File

@ -12,16 +12,21 @@ import (
"time" "time"
) )
// Mockings
var mockCmdRun = func(c *exec.Cmd) error {
return c.Run()
}
// Backup contains all necessary information for executing a configured backup. // Backup contains all necessary information for executing a configured backup.
type Backup struct { type Backup struct {
Name string `mapstructure:",omitempty"` Name string `mapstructure:",omitempty"`
TargetDevice string `mapstructure:"targetDevice"` TargetDevice string `mapstructure:"targetDevice"`
TargetPath string `mapstructure:"targetPath"` TargetPath string `mapstructure:"targetPath"`
SourcePath string `mapstructure:"sourcePath"` SourcePath string `mapstructure:"sourcePath"`
ScriptPath string `mapstructure:"scriptPath"` ScriptPath interface{} `mapstructure:"scriptPath"`
Frequency int `mapstructure:"frequency"` Frequency int `mapstructure:"frequency"`
ExeUser string `mapstructure:"user,omitempty"` ExeUser string `mapstructure:"user,omitempty"`
Label string `mapstructure:"label,omitempty"` Label string `mapstructure:"label,omitempty"`
logger *log.Logger logger *log.Logger
} }
@ -47,7 +52,7 @@ func (b *Backup) CanRun() error {
return fmt.Errorf("the setting targetPath MUST exist within a backup configuration") return fmt.Errorf("the setting targetPath MUST exist within a backup configuration")
} }
// script must exist, having only script means this is handled in the script // script must exist, having only script means this is handled in the script
if b.ScriptPath == "" { if b.ScriptPath == nil {
return fmt.Errorf("the setting scriptPath must exist within a backup configuration") return fmt.Errorf("the setting scriptPath must exist within a backup configuration")
} }
if !b.ShouldRun() { if !b.ShouldRun() {
@ -65,10 +70,9 @@ func (b *Backup) PrepareRun() error {
) )
CreateDirectoryIfNotExists(backupPath) CreateDirectoryIfNotExists(backupPath)
// configure extra logger // configure extra logger
logname := "/var/log/backive/backive.log" logdir := config.Settings.LogLocation
logdir, _ := path.Split(logname)
CreateDirectoryIfNotExists(logdir) CreateDirectoryIfNotExists(logdir)
logname = path.Join(logdir, b.Name) + ".log" logname := path.Join(logdir, b.Name) + ".log"
logfile, err := os.OpenFile(logname, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0666) logfile, err := os.OpenFile(logname, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0666)
if err != nil { if err != nil {
log.Println("Error creating logfile!") log.Println("Error creating logfile!")
@ -77,11 +81,12 @@ 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 := exec.Command("chown", "-R", b.ExeUser, backupPath) cmd := exec.Command("chown", "-R", b.ExeUser, backupPath)
err = cmd.Run() 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
} }
b.logger.Printf("Backup %s prepared.", b.Name)
return nil return nil
} }
@ -93,17 +98,40 @@ func (b *Backup) Run() error {
log.Printf("Device found: %s (%s).", dev.Name, dev.UUID) log.Printf("Device found: %s (%s).", dev.Name, dev.UUID)
} else { } else {
log.Printf("Device %s not found", b.TargetDevice) log.Printf("Device %s not found", b.TargetDevice)
return fmt.Errorf("device %s not found", b.TargetDevice)
} }
if ok && dev.IsMounted() { if ok && dev.IsMounted() {
if !strings.ContainsAny(b.ScriptPath, "/") || strings.HasPrefix(b.ScriptPath, ".") { var scriptWArgs []string
switch slice := b.ScriptPath.(type) {
case []interface{}:
for _, v := range slice {
scriptWArgs = append(scriptWArgs, v.(string))
}
case []string:
for _, v := range slice {
scriptWArgs = append(scriptWArgs, v)
}
case string:
scriptWArgs = append(scriptWArgs, slice)
default:
log.Print("Fuck, the var is nothing we predicted...")
}
if !strings.ContainsAny(scriptWArgs[0], "/") || strings.HasPrefix(scriptWArgs[0], ".") {
//The scriptPath is a relative path, from the place of the config, so use the config as base //The scriptPath is a relative path, from the place of the config, so use the config as base
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 := exec.Command("/usr/bin/sh", b.ScriptPath) var cmd *exec.Cmd
var args []string
if b.ExeUser != "" { if b.ExeUser != "" {
// setup script environment including user to use // setup script environment including user to use
cmd = exec.Command("sudo", "-E", "-u", b.ExeUser, "/usr/bin/sh", b.ScriptPath) args = []string{"-E", "-u", b.ExeUser, "/usr/bin/sh"}
args = append(args, scriptWArgs...)
cmd = exec.Command("sudo", args...)
} else {
args = []string{}
args = append(args, scriptWArgs...)
cmd = exec.Command("/usr/bin/sh", args...)
} }
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)
@ -122,7 +150,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 := cmd.Run() 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
@ -152,6 +180,9 @@ func (r *Runs) Load(db Database) {
// Save saves the data into the json database // Save saves the data into the json database
func (r *Runs) Save(db Database) { func (r *Runs) Save(db Database) {
if db.data == nil {
db.data = map[string]string{}
}
str, err := json.Marshal(r.data) str, err := json.Marshal(r.data)
if err != nil { if err != nil {
panic(err) panic(err)

172
backup_test.go Normal file
View File

@ -0,0 +1,172 @@
package backive
import (
"fmt"
"os/exec"
"path"
"runtime"
"testing"
)
func getCurrentFilePath() string {
pc, file, line, ok := runtime.Caller(1)
fmt.Printf("pc: %d, file: %s, line: %d, ok: %v\n", pc, file, line, ok)
return file
}
func TestFindBackupsForDevice(t *testing.T) {
var testBackups = Backups{}
testBackups["backup1"] = &Backup{
Name: "backup1",
TargetDevice: "dev1",
}
testBackups["backup2"] = &Backup{
Name: "backup2",
TargetDevice: "dev1",
}
testBackups["backup3"] = &Backup{
Name: "backup3",
TargetDevice: "dev2",
}
var testDevice = Device{
Name: "dev1",
}
bkps, found := testBackups.FindBackupsForDevice(testDevice)
if !found {
t.Log("found has to be true")
t.Fail()
}
if len(bkps) != 2 {
t.Log("Length of the returned backup slice has to be 2")
t.Fail()
}
for _, b := range bkps {
if b.TargetDevice != testDevice.Name {
t.Log("All resulting elements of the returned slice have to have the questioned device as TargetDevice!")
t.Fail()
}
}
}
func TestCanRun(t *testing.T) {
var bkpTargetPathMissing = Backup{
Name: "targetPathMissing",
ScriptPath: "Somethingsomething",
}
err := bkpTargetPathMissing.CanRun()
if err == nil {
t.Log("Missing targetPath has to fail function 'CanRun()'")
t.Fail()
}
var bkpScriptPathMissing = Backup{
Name: "scriptPathMissing",
TargetPath: "somethingsomething",
}
err = bkpScriptPathMissing.CanRun()
if err == nil {
t.Logf("ScriptPath is %v", bkpScriptPathMissing.ScriptPath)
t.Log("Missing scriptPath has to fail function 'CanRun()'")
t.Fail()
}
var bkpFrequencyZero = Backup{
Name: "testFrequencyZero",
TargetPath: "somewhere",
ScriptPath: "somehwere_else",
Frequency: 0,
}
var bkpFrequencySeven = Backup{
Name: "testFrequencySeven",
TargetPath: "somewhere",
ScriptPath: "somewhere_else",
Frequency: 7,
}
database.Load()
runs.Load(database)
runs.RegisterRun(&bkpFrequencyZero)
err = bkpFrequencyZero.CanRun()
if err != nil {
t.Log("Frequency zero can be executed anytime.")
t.Fail()
}
if !bkpFrequencyZero.ShouldRun() {
t.Log("Frequency zero can be executed anytime, should run does not work.")
t.Fail()
}
runs.RegisterRun(&bkpFrequencySeven)
err = bkpFrequencySeven.CanRun()
if err == nil {
t.Log("Frequency 7 must give an error about not having reached the interval")
t.Fail()
}
}
func setupNewTestEnv(subdir string) {
file := getCurrentFilePath()
dir, _ := path.Split(file)
dir = path.Join(dir, "test", "_workarea", subdir)
config.Settings.SystemMountPoint = path.Join(dir, "mnt")
config.Settings.LogLocation = path.Join(dir, "log")
fmt.Printf("SystemMountPoint: %s, LogLocation: %s\n", config.Settings.SystemMountPoint, config.Settings.LogLocation)
}
func TestPrepareRun(t *testing.T) {
setupNewTestEnv("preparerun")
mockCmdRun = func(c *exec.Cmd) error {
return nil
}
var testBkp = Backup{
Name: "testbkp",
TargetDevice: "mytarget",
TargetPath: "mypath",
}
err := testBkp.PrepareRun()
if err != nil {
t.Log("When this fails, something's fishy...")
t.Fail()
}
}
func TestRun(t *testing.T) {
setupNewTestEnv("run")
config.Devices = map[string]*Device{
"mytarget": new(Device),
}
config.Devices["mytarget"].Name = "mytarget"
config.Devices["mytarget"].UUID = "123-456-789-abc-def"
mockCmdRun = func(c *exec.Cmd) error {
return nil
}
var testBkp = Backup{
Name: "testbkp",
TargetDevice: "mytargets",
TargetPath: "mypath",
ScriptPath: "/dev/null",
SourcePath: "/dev/random",
}
err := testBkp.Run()
if err == nil || err.Error() != "device mytargets not found" {
if err != nil {
t.Logf("The error should be 'device mytargets not found', but is '%s'", err.Error())
t.Fail()
}
}
testBkp.TargetDevice = "mytarget"
config.Devices["mytarget"].Mount()
err = testBkp.PrepareRun()
err = testBkp.Run()
if err != nil {
t.Logf("Error which should not occur: %s", err)
t.Fail()
}
mockCmdRun = func(c *exec.Cmd) error {
return nil
}
}

View File

@ -12,7 +12,7 @@ import (
) )
func setupLogging() { func setupLogging() {
logname := "/var/log/backive/backive.log" logname := path.Join(config.Settings.LogLocation, "backive.log")
logdir, _ := path.Split(logname) logdir, _ := path.Split(logname)
backive.CreateDirectoryIfNotExists(logdir) backive.CreateDirectoryIfNotExists(logdir)
logfile, err := os.OpenFile(logname, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0666) logfile, err := os.OpenFile(logname, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0666)
@ -21,6 +21,7 @@ func setupLogging() {
panic("no logfile no info") panic("no logfile no info")
} }
log.SetOutput(logfile) log.SetOutput(logfile)
log.Println("Logging initialized")
} }
// Global variables for backive // Global variables for backive
@ -87,7 +88,6 @@ func defaultCallback(envMap map[string]string) {
} }
func main() { func main() {
setupLogging()
signalChan := make(chan os.Signal, 1) signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, signal.Notify(signalChan,
syscall.SIGHUP, syscall.SIGHUP,
@ -123,6 +123,10 @@ func main() {
code := <-exitChan code := <-exitChan
database.Save() database.Save()
log.Printf("Received exit code (%d), shutting down.", code) log.Printf("Received exit code (%d), shutting down.", code)
err := os.Remove(config.Settings.UnixSocketLocation)
if err != nil {
log.Printf("Removal of %s failed.", config.Settings.UnixSocketLocation)
}
os.Exit(code) os.Exit(code)
}() }()
@ -131,6 +135,7 @@ func main() {
// find and load config // find and load config
database.Load() database.Load()
config.Load() config.Load()
setupLogging()
backive.Init(config, database) backive.Init(config, database)
// init scheduler and check for next needed runs? // init scheduler and check for next needed runs?

View File

@ -34,12 +34,16 @@ func main() {
env[pair[0]] = pair[1] env[pair[0]] = pair[1]
log.Println(e) log.Println(e)
} }
message := map[string]interface{}{}
message["request"] = "udev"
message["data"] = env
c, err := net.Dial("unix", "/var/local/backive/backive.sock") c, err := net.Dial("unix", "/var/local/backive/backive.sock")
if err != nil { if err != nil {
log.Fatalln("Could not instantiate unix socket. Aborting") log.Fatalln("Could not instantiate unix socket. Aborting")
} }
jsonstr, err := json.Marshal(env) jsonstr, err := json.Marshal(message)
if err != nil { if err != nil {
log.Fatalln("Could not convert to json. Aborting") log.Fatalln("Could not convert to json. Aborting")
} }

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"log" "log"
"github.com/fsnotify/fsnotify"
"github.com/spf13/viper" "github.com/spf13/viper"
) )
@ -26,16 +27,27 @@ type Settings struct {
// CreateViper creates a viper instance for usage later // CreateViper creates a viper instance for usage later
func (c *Configuration) CreateViper() { func (c *Configuration) CreateViper() {
vconfig := viper.New() if c.Vconfig == nil {
// vconfig.Debug() vconfig := viper.New()
vconfig.SetConfigName("backive") // vconfig.Debug()
vconfig.SetConfigFile("backive.yml") vconfig.SetConfigName("backive")
//vconfig.SetConfigFile("backive.yaml") // do not set config file explicitly or viper doesnt search for it, and /etc search fails
vconfig.SetConfigType("yaml") //vconfig.SetConfigFile("backive.yml")
vconfig.AddConfigPath("/etc/backive/") // system config //vconfig.SetConfigFile("backive.yaml")
//vconfig.AddConfigPath("$HOME/.backive/") vconfig.SetConfigType("yaml")
vconfig.AddConfigPath(".") //vconfig.AddConfigPath("$HOME/.backive/")
c.Vconfig = vconfig vconfig.AddConfigPath(".") // backup config in local dir
vconfig.AddConfigPath("/etc/backive/") // system config
vconfig.OnConfigChange(func(e fsnotify.Event) {
log.Printf("Event: %s", e)
if e.Op == fsnotify.Write {
log.Printf("Reloading %s", e.Name)
c.Load()
}
})
vconfig.WatchConfig()
c.Vconfig = vconfig
}
} }
// Load loads the configuration from the disk // Load loads the configuration from the disk

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 := cmd.Run() 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 := sync.Run() 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 := cmd.Run() 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

@ -9,24 +9,29 @@ import (
"path" "path"
) )
var mockAccept = func(eh *EventHandler) (net.Conn, error) {
log.Println("Calling eh.ls.Accept()")
return eh.ls.Accept()
}
// EventHandler holds the necessary elements to get an eventhandler setup and working. // EventHandler holds the necessary elements to get an eventhandler setup and working.
type EventHandler struct { type EventHandler struct {
ls net.Listener ls net.Listener
//done <-chan struct{}
callbacks []func(map[string]string) callbacks []func(map[string]string)
} }
// Init initializes the unix socket. // Init initializes the unix socket.
func (eh *EventHandler) Init(socketPath string) { func (eh *EventHandler) Init(socketPath string) error {
log.Println("Initializing EventHandler...") log.Println("Initializing EventHandler...")
var err error var err error
dir, _ := path.Split(socketPath) dir, _ := path.Split(socketPath)
CreateDirectoryIfNotExists(dir) CreateDirectoryIfNotExists(dir)
eh.ls, err = net.Listen("unix", socketPath) eh.ls, err = net.Listen("unix", socketPath)
if err != nil { if err != nil {
panic(err) return err
} }
eh.callbacks = make([]func(map[string]string), 3) eh.callbacks = make([]func(map[string]string), 3)
return nil
} }
// Listen starts the event loop. // Listen starts the event loop.
@ -46,17 +51,21 @@ func (eh *EventHandler) RegisterCallback(cb func(map[string]string)) {
// process processes each and every unix socket event, Unmarshals the json data and calls the list of callbacks. // process processes each and every unix socket event, Unmarshals the json data and calls the list of callbacks.
func (eh *EventHandler) process() { func (eh *EventHandler) process() {
client, err := eh.ls.Accept() client, err := mockAccept(eh)
log.Println("Accepted client") log.Println("Accepted client")
if err != nil { if err != nil {
log.Fatal(err) log.Println(err)
return
} }
defer client.Close()
data := make([]byte, 2048) data := make([]byte, 2048)
for { for {
buf := make([]byte, 512) buf := make([]byte, 512)
nr, err := client.Read(buf) nr, err := client.Read(buf)
log.Printf("Read %d bytes...", nr)
if err != nil && err != io.EOF { if err != nil && err != io.EOF {
log.Fatal(err) log.Println(err)
return
} }
data = append(data, buf[0:nr]...) data = append(data, buf[0:nr]...)
if err == io.EOF { if err == io.EOF {
@ -64,14 +73,23 @@ func (eh *EventHandler) process() {
} }
} }
sdata := string(bytes.Trim(data, "\x00")) sdata := string(bytes.Trim(data, "\x00"))
//log.Println(sdata) var message map[string]interface{}
env := map[string]string{} log.Printf("Reading JSON: %s", sdata)
errjson := json.Unmarshal([]byte(sdata), &env) errjson := json.Unmarshal([]byte(sdata), &message)
if errjson != nil { if errjson != nil {
log.Fatal(errjson) log.Println(errjson)
return
}
log.Println("Calling callbacks")
var env = map[string]string{}
if message["request"] == "udev" {
for k, v := range message["data"].(map[string]interface{}) {
env[k] = v.(string)
}
} }
for _, v := range eh.callbacks { for _, v := range eh.callbacks {
if v != nil { if v != nil {
log.Println("Calling callback")
v(env) v(env)
} }
} }

99
events_test.go Normal file
View File

@ -0,0 +1,99 @@
package backive
import (
"encoding/json"
"fmt"
"io"
"log"
"net"
"os"
"testing"
"time"
)
type ConnStub struct {
}
var counter int
func (c ConnStub) Read(b []byte) (int, error) {
switch {
case counter == 0:
counter++
env := map[string]string{}
env["test"] = "test"
message := map[string]interface{}{}
message["request"] = "udev"
message["data"] = env
data, err := json.Marshal(message)
copy(b, data)
log.Println(string(b))
return len(data), err
case counter == 1:
counter++
return 0, io.EOF
case counter == 2:
counter++
return 0, fmt.Errorf("Some Error for testing")
default:
return 0, io.EOF
}
}
func (c ConnStub) Close() error {
return nil
}
func (c ConnStub) LocalAddr() net.Addr {
return nil
}
func (c ConnStub) RemoteAddr() net.Addr {
return nil
}
func (c ConnStub) SetDeadline(t time.Time) error {
return nil
}
func (c ConnStub) SetReadDeadline(t time.Time) error {
return nil
}
func (c ConnStub) SetWriteDeadline(t time.Time) error {
return nil
}
func (c ConnStub) Write(b []byte) (int, error) {
return 0, nil
}
var hasBeenCalled = false
func TestEventhandler(t *testing.T) {
eh := new(EventHandler)
err := eh.Init("./backive.socket")
if err != nil {
t.Fail()
}
defer func() {
err := os.Remove("./backive.socket")
if err != nil {
t.Log(err)
}
}()
t.Log("Initialized test")
//var hasBeenCalled = make(chan bool)
eh.RegisterCallback(
func(m map[string]string) {
t.Log("Callback got called")
hasBeenCalled = true
},
)
t.Log("registered callback")
mockAccept = func(eh *EventHandler) (net.Conn, error) {
t.Log("Mocked Accept() has been called.")
mycon := ConnStub{}
return mycon, nil
}
eh.process()
//beenCalled := <-hasBeenCalled
if !hasBeenCalled {
t.Log("Got false, need true.")
t.Fail()
}
}

10
go.mod
View File

@ -2,10 +2,12 @@ module github.com/qwc/backive
go 1.17 go 1.17
require github.com/spf13/viper v1.9.0 require (
github.com/fsnotify/fsnotify v1.5.1
github.com/spf13/viper v1.9.0
)
require ( require (
github.com/fsnotify/fsnotify v1.5.1 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect
github.com/kr/text v0.2.0 // indirect github.com/kr/text v0.2.0 // indirect
github.com/magiconair/properties v1.8.5 // indirect github.com/magiconair/properties v1.8.5 // indirect
@ -16,8 +18,8 @@ require (
github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.2.0 // indirect github.com/subosito/gotenv v1.2.0 // indirect
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac // indirect golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect
golang.org/x/text v0.3.7 // indirect golang.org/x/text v0.3.8 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/ini.v1 v1.63.2 // indirect gopkg.in/ini.v1 v1.63.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect

15
go.sum
View File

@ -256,6 +256,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
@ -279,6 +280,7 @@ golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@ -314,6 +316,7 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -351,6 +354,7 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -377,6 +381,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -432,9 +437,11 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac h1:oN6lz7iLW/YC7un8pq+9bOLyXrprv2+DKfkJY+2LJJw= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -443,8 +450,9 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@ -502,6 +510,7 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

9
systemd/backive.service Normal file
View File

@ -0,0 +1,9 @@
[Unit]
Description=Backive
[Service]
Nice=19
IOSchedulingClass=2
IOSchedulingPriority=7
WorkingDirectory=/the/path/of/backive
ExecStart=backive

0
test/_scripts/.keep Normal file
View File

View File

1
udev/99-backive.rules Normal file
View File

@ -0,0 +1 @@
KERNEL=="sd*", RUN+="/path/to/backive_udev"

View File

@ -1,17 +1,21 @@
package backive package backive
import ( import (
"log"
"os" "os"
) )
var mockOsStat = os.Stat
var mockOsMkdirAll = os.MkdirAll
var mockOsIsNotExist = os.IsNotExist
// 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) error {
if _, err := os.Stat(dir); err == nil { if _, err := mockOsStat(dir); err == nil {
//ignore //ignore
} else if os.IsNotExist(err) { } else if mockOsIsNotExist(err) {
os.MkdirAll(dir, 0755) return mockOsMkdirAll(dir, 0755)
} else { } else {
log.Fatal(err) return err
} }
return nil
} }

32
utils_test.go Normal file
View File

@ -0,0 +1,32 @@
package backive
import (
"fmt"
"io/fs"
"os"
"testing"
)
var creatingDir = false
func TestCreateDirectoryIfNotExists(t *testing.T) {
mockOsMkdirAll = func(dir string, mode os.FileMode) error {
t.Log("Creating directories")
creatingDir = true
return nil
}
mockOsStat = os.Stat
CreateDirectoryIfNotExists("/somewhere/which.does/not/exist")
if !creatingDir {
t.Log("Should have called MkdirAll")
t.Fail()
}
mockOsStat = func(dir string) (fs.FileInfo, error) {
return nil, fmt.Errorf("Just some error for testing")
}
err := CreateDirectoryIfNotExists("asdfasdfasdf")
if err == nil {
t.Log("Should have an error here")
t.Fail()
}
}