Add test and crontab checker.

pull/113/head
xyb 2018-12-02 16:04:15 +08:00
parent a18f5ac3fc
commit 18717c0e78
2 changed files with 59 additions and 29 deletions

View File

@ -4,14 +4,13 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"math/rand"
"os/exec" "os/exec"
"strings" "strings"
"time" "time"
"math/rand"
"github.com/shunfei/cronsun" "github.com/shunfei/cronsun"
cron2 "github.com/shunfei/cronsun/node/cron"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -33,47 +32,41 @@ var ImportCmd = &cobra.Command{
Use: "import", Use: "import",
Short: `it will load the job from the crontab, but you must to confirm you can execute 'crontab -l'`, Short: `it will load the job from the crontab, but you must to confirm you can execute 'crontab -l'`,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
ea := NewExitAction()
var nodeInclude []string var nodeInclude []string
if len(importNodes) > 0 { if len(importNodes) > 0 {
nodeInclude = strings.Split(importNodes, spliter) nodeInclude = strings.Split(importNodes, spliter)
} }
crons := loadCrons() ea := NewExitAction()
crons, err := loadCrons()
if err != nil {
ea.Exit("load crontab failed,err:%s", err.Error())
}
total := len(crons) total := len(crons)
var successCount int var successCount int
ea.After = func() { ea.After = func() {
fmt.Printf("total:%d,success:%d,failed:%d\n", total, successCount, total-successCount) fmt.Printf("total:%d,success:%d,failed:%d\n", total, successCount, total-successCount)
cmd.Help() if err := cmd.Help(); err != nil {
return
}
} }
rand.Seed(time.Now().Unix()) rand.Seed(time.Now().Unix())
for _, cron := range crons { for _, cron := range crons {
job := cronsun.Job{} job := cronsun.Job{}
job.ID = cronsun.NextID() job.ID = cronsun.NextID()
job.Command = cron.cmd job.Command = cron.cmd
jr := &cronsun.JobRule{ jr := &cronsun.JobRule{
Timer: "* " + cron.timer, Timer: "* " + cron.timer,
} }
jr.NodeIDs = nodeInclude jr.NodeIDs = nodeInclude
job.Name = fmt.Sprintf("crontab-%d", rand.Intn(1000)) job.Name = fmt.Sprintf("crontab-%d", rand.Intn(1000))
job.Group = "crontab" job.Group = "crontab"
job.Rules = append(job.Rules, jr) job.Rules = append(job.Rules, jr)
// 默认先暂停 // 默认先暂停
job.Pause = true job.Pause = true
if err := job.Check(); err != nil { if err := job.Check(); err != nil {
ea.Exit("job check error:%s", err.Error()) ea.Exit("job check error:%s", err.Error())
} }
b, err := json.Marshal(job) b, err := json.Marshal(job)
if err != nil { if err != nil {
ea.Exit("json marshal error:%s", err.Error()) ea.Exit("json marshal error:%s", err.Error())
@ -83,31 +76,46 @@ var ImportCmd = &cobra.Command{
if err != nil { if err != nil {
ea.Exit("etcd put error:%s", err.Error()) ea.Exit("etcd put error:%s", err.Error())
} }
successCount++ successCount++
fmt.Printf("crontab-%s %s has import to the cronsun, the job id is:%s\n", cron.timer, cron.cmd, job.ID) fmt.Printf("crontab-%s %s has import to the cronsun, the job id is:%s\n", cron.timer, cron.cmd, job.ID)
} }
fmt.Printf("import fininsh,success:%d\n", successCount) fmt.Printf("import fininsh,succes:%d\n", successCount)
}, },
} }
func loadCrons() []cron { func checkCrons(crons []string) (invalid []string) {
var crons []cron for _, item := range crons {
item = strings.TrimSpace(item)
cmd := exec.Command("crontab", "-l") if item != "" && !strings.HasPrefix(item, "#") {
expr := strings.Fields(item)
expr = expr[:5]
_, err := cron2.ParseStandard(strings.Join(expr, " "))
if err != nil {
invalid = append(invalid, item)
}
}
}
return
}
func loadCrons() (crons []cron, err error) {
var b bytes.Buffer var b bytes.Buffer
cmd := exec.Command("crontab", "-l")
cmd.Stdout = &b cmd.Stdout = &b
cmd.Stderr = &b cmd.Stderr = &b
err = cmd.Run()
err := cmd.Run()
if err != nil { if err != nil {
fmt.Println(err) return
} }
result := strings.Split(b.String(), "\n") result := strings.Split(b.String(), "\n")
invalid := checkCrons(result)
if len(invalid) > 0 {
title := fmt.Sprintf("There are %d invalid cron expression,please check them at first.\n", len(invalid))
err = fmt.Errorf(title + strings.Join(invalid, "\n"))
return
}
for _, item := range result { for _, item := range result {
item = strings.TrimSpace(item) item = strings.TrimSpace(item)
@ -118,6 +126,5 @@ func loadCrons() []cron {
crons = append(crons, cron{timer, cmd}) crons = append(crons, cron{timer, cmd})
} }
} }
return
return crons
} }

View File

@ -0,0 +1,23 @@
package cmd
import (
"strings"
"testing"
)
func TestCheckCrons(t *testing.T) {
crontab := `
*/1 * * * * /usr/bine/echo hello
* * * * * /usr/bin/ls
* & * * * /usr/bin/php -v
* * * * /usr/bin/go run main.go
`
invalidCrons := checkCrons(strings.Split(crontab, "\n"))
if len(invalidCrons) != 2 {
t.Error("should have 2 cron expression,but get none.")
}
if invalidCrons[0] != "* & * * * /usr/bin/php -v" ||
invalidCrons[1] != "* * * * /usr/bin/go run main.go" {
t.Error("invalid cron expression should * & * * * /usr/bin/php -v and * * * * /usr/bin/go run main.go.")
}
}