WIP: unit test done, need further test

This commit is contained in:
Suyono 2025-05-25 09:12:39 +10:00
parent 6e84adbf16
commit 61d735bbad
11 changed files with 130 additions and 47 deletions

View File

@ -46,7 +46,7 @@ func main() {
_ = file.Close()
}()
if err = wingmate.NewLog(file); err == nil {
if err = wingmate.NewLog(file, wingmate.Time|wingmate.Caller); err == nil {
wingmate.Log().Info().Msg(logMessage)
}
}

View File

@ -53,7 +53,7 @@ func TestRead(t *testing.T) {
_ = f.Close()
}
_ = wingmate.NewLog(os.Stderr)
_ = wingmate.NewLog(os.Stderr, wingmate.Caller|wingmate.Time)
tests := []testEntry{
{
name: "positive",

View File

@ -20,7 +20,7 @@ func TestCrontab(t *testing.T) {
wantErr bool
}
_ = wingmate.NewLog(os.Stderr)
_ = wingmate.NewLog(os.Stderr, wingmate.Caller|wingmate.Time)
tests := []testEntry{
{
name: "positive",

View File

@ -18,7 +18,7 @@ func TestYaml(t *testing.T) {
wantErr bool
}
_ = wingmate.NewLog(os.Stderr)
_ = wingmate.NewLog(os.Stderr, wingmate.Caller|wingmate.Time)
tests := []testEntry{
{
name: "positive",

View File

@ -35,10 +35,7 @@ cron:
goto fail
}
cmd = exec.Command(cron.Command(), cron.Arguments()...)
cmd.Env = os.Environ()
if cron.EnvLen() > 0 {
cmd.Env = append(cmd.Env, cron.Environ()...)
}
cmd.Env = cron.PatchEnv(os.Environ())
if len(cron.WorkingDir()) > 0 {
cmd.Dir = cron.WorkingDir()

View File

@ -27,6 +27,7 @@ type Task interface {
Arguments() []string
EnvLen() int
Environ() []string
PatchEnv([]string) []string
Setsid() bool
UserGroup() UserGroup
WorkingDir() string

View File

@ -40,10 +40,7 @@ service:
goto fail
}
cmd = exec.Command(task.Command(), task.Arguments()...)
cmd.Env = os.Environ()
if task.EnvLen() > 0 {
cmd.Env = append(cmd.Env, task.Environ()...)
}
cmd.Env = task.PatchEnv(os.Environ())
if len(task.WorkingDir()) > 0 {
cmd.Dir = task.WorkingDir()

View File

@ -19,14 +19,14 @@ func (i *Init) sighandler(wg *sync.WaitGroup, trigger chan<- any, selfExit <-cha
isOpen := true
c := make(chan os.Signal, 1)
signal.Notify(c, unix.SIGINT, unix.SIGTERM, unix.SIGCHLD)
signal.Notify(c, unix.SIGINT, unix.SIGTERM, unix.SIGQUIT, unix.SIGCHLD)
signal:
for {
select {
case s := <-c:
switch s {
case unix.SIGTERM, unix.SIGINT:
case unix.SIGTERM, unix.SIGINT, unix.SIGQUIT:
if isOpen {
wingmate.Log().Info().Msg("initiating shutdown...")
close(trigger)

View File

@ -249,6 +249,10 @@ func (c *CronTask) Environ() []string {
return retval
}
func (c *CronTask) PatchEnv(env []string) []string {
return patchEnv(env, c.environ)
}
func (c *CronTask) Setsid() bool {
return c.setsid
}
@ -264,7 +268,7 @@ func (c *CronTask) WorkingDir() string {
func (c *CronTask) Status() wminit.TaskStatus {
//TODO: implement me!
panic("not implemented")
return nil
// return nil
}
func (c *CronTask) TimeToRun(now time.Time) bool {

View File

@ -13,7 +13,10 @@ import (
)
var (
envRef = regexp.MustCompile(`\$([a-zA-Z][a-zA-Z0-9]*)`)
envCapture = regexp.MustCompile(`\$+[a-zA-Z_][a-zA-Z0-9_]*|\$+{[a-zA-Z_][a-zA-Z0-9_]*}`)
envEsc = regexp.MustCompile(`^\$\$+[^\$]+$`) // escaped, starts with two or more $ character
envRef = regexp.MustCompile(`^\$([^\$]+)$`) // capture the variable name
envRefExplicit = regexp.MustCompile(`^\${([^\$]+)}$`) // capture the variable name - explicit
)
type config interface {
@ -75,7 +78,7 @@ func (ts *Tasks) Crones() []wminit.CronTask {
func (ts *Tasks) Get(name string) (wminit.Task, error) {
//TODO: implement me!
panic("not implemented")
return nil, nil
// return nil, nil
}
type ServiceTask struct {
@ -311,32 +314,7 @@ func (t *ServiceTask) Environ() []string {
}
func (t *ServiceTask) PatchEnv(env []string) []string {
tMap := make(map[string]string)
for _, e := range env {
key, value, ok := strings.Cut(e, "=")
if !ok {
wingmate.Log().Warn().Msgf("removing invalid environment:", e)
continue
}
tMap[key] = value
}
for _, e := range t.environ {
key, value, ok := strings.Cut(e, "=")
if !ok {
wingmate.Log().Warn().Msgf("removing invalid environment:", e)
continue
}
if strings.ContainsAny(key, "$") {
continue
}
//envRef.FindAllString()
_ = value
}
return nil
return patchEnv(env, t.environ)
}
func (t *ServiceTask) Setsid() bool {
@ -358,19 +336,19 @@ func (t *ServiceTask) WorkingDir() string {
func (t *ServiceTask) Status() wminit.TaskStatus {
//TODO: implement me!
panic("not implemented")
return nil
// return nil
}
func (t *ServiceTask) AutoStart() bool {
//TODO: implement me!
panic("not implemented")
return false
// return false
}
func (t *ServiceTask) AutoRestart() bool {
//TODO: implement me!
panic("not implemented")
return false
// return false
}
func (t *ServiceTask) StartSecs() uint {
@ -407,3 +385,60 @@ func validate(validators ...func() error) error {
}
return nil
}
func patchEnv(existing, new []string) []string {
tMap := make(map[string]string)
for _, e := range existing {
key, value, ok := strings.Cut(e, "=")
if !ok {
wingmate.Log().Warn().Msgf("removing invalid environment:", e)
continue
}
tMap[key] = value
}
for _, e := range new {
key, value, ok := strings.Cut(e, "=")
if !ok {
wingmate.Log().Warn().Msgf("removing invalid environment:", e)
continue
}
if strings.ContainsAny(key, "$") {
wingmate.Log().Error().Err(fmt.Errorf("variable name contains $")).Msgf("removing invalid environment:", e)
continue
}
value = envCapture.ReplaceAllStringFunc(value, func(rep string) string {
if envEsc.MatchString(rep) {
return rep
}
if envName := envRefExplicit.FindStringSubmatch(rep); envName != nil && envName[1] != "" {
exVal, ok := tMap[envName[1]]
if !ok {
return ""
}
return exVal
}
if envName := envRef.FindStringSubmatch(rep); envName != nil && envName[1] != "" {
exVal, ok := tMap[envName[1]]
if !ok {
return ""
}
return exVal
}
return rep
})
tMap[key] = value
}
outEnv := make([]string, 0, len(existing))
for key, val := range tMap {
outEnv = append(outEnv, fmt.Sprintf("%s=%s", key, val))
}
return outEnv
}

View File

@ -1,9 +1,12 @@
package task
import (
"os"
"testing"
"gitea.suyono.dev/suyono/wingmate"
wminit "gitea.suyono.dev/suyono/wingmate/init"
"github.com/stretchr/testify/assert"
"testing"
)
func TestServicesV0(t *testing.T) {
@ -77,3 +80,49 @@ func TestTasks_List(t *testing.T) {
assert.ElementsMatch(t, testNames, tnames)
}
func TestServiceTaskPatchEnv(t *testing.T) {
type testEntry struct {
name string
systemEnv []string
serviceEnv []string
expected []string
}
_ = wingmate.NewLog(os.Stderr, wingmate.Caller|wingmate.Time)
tests := []testEntry{
{
name: "normal",
systemEnv: []string{"PATH=/bin:/usr/bin:/usr/local/bin"},
serviceEnv: []string{
"SPARK_HOME=/opt/spark",
"PATH=$SPARK_HOME/bin:$PATH",
},
expected: []string{
"SPARK_HOME=/opt/spark",
"PATH=/opt/spark/bin:/bin:/usr/bin:/usr/local/bin",
},
},
{
name: "explicit",
systemEnv: []string{"PART=hello "},
serviceEnv: []string{"GREET=${PART}world"},
expected: []string{"PART=hello ", "GREET=hello world"},
},
}
for _, tt := range tests {
t.Run(tt.name+" - service", func(t *testing.T) {
st := NewServiceTask(tt.name)
st.SetEnv(tt.serviceEnv...)
result := st.PatchEnv(tt.systemEnv)
assert.ElementsMatch(t, result, tt.expected)
})
t.Run(tt.name+" - cron", func(t *testing.T) {
st := NewCronTask(tt.name)
st.SetEnv(tt.serviceEnv...)
result := st.PatchEnv(tt.systemEnv)
assert.ElementsMatch(t, result, tt.expected)
})
}
}