Fix tests to pass on linux

master
bel 2020-03-13 03:40:53 +00:00
parent 45c58cf0af
commit 710c5e5fbb
6 changed files with 185 additions and 3 deletions

23
TODO.md Normal file
View File

@ -0,0 +1,23 @@
# Frontend
1. UI to view
1. running job
1. jobs
1. job definition
1. next runtime
1. last runtime
1. last output
1. UI to mutate
1. submit job
1. delete job
1. pause jobs
1. interrupt job
1. JS
1. ajax for json calls
# Backend
1. load from file
1. interrupt running jobs
1. temporarily disable jobs
1. json API

View File

@ -17,6 +17,7 @@ var (
StoreUser string
StorePass string
Root string
Config string
)
func init() {
@ -36,6 +37,7 @@ func Refresh() {
as.Append(args.STRING, "storeuser", "storage username", "")
as.Append(args.STRING, "storepass", "storage password", "")
as.Append(args.STRING, "root", "root for static files", "./public")
as.Append(args.STRING, "config", "cron config to load;; non-persisting", "")
if err := as.Parse(); err != nil {
panic(err)
}
@ -47,6 +49,11 @@ func Refresh() {
StoreUser = as.Get("storeuser").GetString()
StorePass = as.Get("storepass").GetString()
Root = as.Get("root").GetString()
Config = as.Get("config").GetString()
if Config != "" {
StoreType = "map"
}
if db, err := storage.New(storage.TypeFromString(StoreType), StoreAddr, StoreUser, StorePass); err != nil {
panic(err)

View File

@ -3,6 +3,7 @@ package logger
import (
"bytes"
"errors"
"fmt"
"io/ioutil"
"local/logb"
"os"
@ -29,8 +30,8 @@ func TestInterface(t *testing.T) {
os.Stderr = was
}()
logger.Info("hello from %v", "me")
logger.Error(errors.New("bad"), "error from %v", "me")
logger.Info(fmt.Sprintf("hello from %v", "me"))
logger.Error(errors.New("bad"), fmt.Sprintf("error from %v", "me"))
if !bytes.Contains(w.Bytes(), []byte(`error from me`)) {
t.Errorf("%s", w.Bytes())

View File

@ -3,6 +3,7 @@ package scheduler
import (
"bytes"
"encoding/gob"
"fmt"
"local/firestormy/logger"
"os/exec"
@ -41,7 +42,7 @@ func newBashJob(schedule, sh string) (*Job, error) {
if err != nil {
panic(err)
}
logger.New().Info("executed %s: %s", sh, out)
logger.New().Info(fmt.Sprintf("executed %s: %s", sh, out))
},
}, nil
}

View File

@ -1,9 +1,14 @@
package scheduler
import (
"bytes"
"errors"
"fmt"
"io/ioutil"
"local/firestormy/config"
"local/firestormy/logger"
"regexp"
"strings"
"time"
cron "github.com/robfig/cron/v3"
@ -30,6 +35,61 @@ func New() *Scheduler {
}
}
func NewFromFile(config string) (*Scheduler, error) {
f, err := ioutil.ReadFile(config)
if err != nil {
return nil, err
}
s := New()
for _, line := range bytes.Split(f, []byte("\n")) {
line = cleanLine(line)
if len(line) == 0 {
continue
}
schedule, command := splitScheduleCommand(line)
if len(schedule) == 0 || len(command) == 0 {
continue
}
job, err := NewJob(Bash, schedule, command)
if err != nil {
logger.New().Error(err, "cannot fully parse file: new job error", config, ", sched", schedule, ", comm", command)
continue
}
if err := s.Add(job); err != nil {
logger.New().Error(err, "cannot fully parse file: add job error", config)
continue
}
}
jobs, _ := s.List()
if len(jobs) == 0 {
return nil, errors.New("no jobs parsed from file " + config)
}
return s, nil
}
func cleanLine(b []byte) []byte {
b = bytes.Trim(b, "\t \n")
if len(b) == 0 {
return nil
}
if b[0] == '#' {
return nil
}
return b
}
func splitScheduleCommand(b []byte) (string, string) {
re := regexp.MustCompile(`^((\d+|\*\/\d+|(\d,)*\d+|\*) [ ]*){5}`)
schedule := string(re.Find(b))
if len(schedule) == 0 {
return "", ""
}
command := strings.TrimPrefix(string(b), schedule)
schedule = strings.TrimSpace(schedule)
command = strings.TrimSpace(command)
return schedule, command
}
func (s *Scheduler) Start() error {
jobs, err := s.List()
if err != nil {

View File

@ -2,8 +2,10 @@ package scheduler
import (
"bytes"
"io/ioutil"
"local/firestormy/config"
"local/storage"
"os"
"testing"
)
@ -59,3 +61,91 @@ func TestSchedulerStartStop(t *testing.T) {
t.Errorf("%v: %s", n, b.Bytes())
}
}
func TestSchedulerFromFile(t *testing.T) {
was := config.Store
defer func() {
config.Store = was
}()
cases := map[string]struct {
content string
want int
}{
"just a job": {
content: `10 */12 * * * /bin/bash -c "hostname"`,
want: 1,
},
"all wild": {
content: `* * * * * /bin/bash -c "hostname"`,
want: 1,
},
"all single numbers": {
content: `1 1 1 1 1 /bin/bash -c "hostname"`,
want: 1,
},
"all double numbers": {
content: `10 10 10 10 2 /bin/bash -c "hostname"`,
want: 1,
},
"all /\\d+": {
content: `*/11 */2 */3 */4 */1 /bin/bash -c "hostname"`,
want: 1,
},
"2 jobs with 1 comment no whitespace leading": {
content: `# this is my comment
10 */12 * * * /bin/bash -c "hostname"
10 */12 * * * /bin/bash -c "hostname"
`,
want: 2,
},
"2 jobs with 1 comment whitespace leading": {
content: ` # this is my comment
10 */12 * * * /bin/bash -c "hostname"
10 */12 * * * /bin/bash -c "hostname"
`,
want: 2,
},
"2 jobs with crazy whitespace between cron spec": {
content: ` # this is my comment
10 */12 * * * /bin/bash -c "hostname"
10 */12 * * * /bin/bash -c "hostname"
`,
want: 2,
},
"2 jobs with 2 comemnts and 2 empty lines": {
content: ` # this is my comment
# this is a second comment
10 */12 * * * /bin/bash -c "hostname"
10 */12 * * * /bin/bash -c "hostname"
`,
want: 2,
},
}
for name, c := range cases {
t.Run(name, func(t *testing.T) {
config.Store, _ = storage.New(storage.MAP)
f, err := ioutil.TempFile(os.TempDir(), "testSchedulerFromFile")
if err != nil {
t.Fatal(err)
}
defer os.Remove(f.Name())
f.Write([]byte(c.content))
f.Close()
s, err := NewFromFile(f.Name())
if err != nil {
t.Fatal(err)
}
jobs, err := s.List()
if err != nil {
t.Fatal(err)
}
if len(jobs) != c.want {
t.Fatalf("want %v, got %v jobs", c.want, jobs)
}
})
}
}