feat: order/delay in service files, enable cmd, --all on unit commands

- install/uninstall/start/stop/enable take <name> or --all; *all kept as shortcuts
- add enable (enable at boot + start); startall no longer enables
- order/delay resolved by config.ResolveOrder and written into systemd,
  OpenRC and runit service files (After=/sleep), so they apply at boot
- install --all stops and disables units before removing their files
- update regenerates all installed, enabled units and removes disabled ones
- edit creates the config dir; docs and man page updated
- tests: fake Init for cmd, ResolveOrder, backend ordering output
This commit is contained in:
2026-10-12 21:31:41 +02:00
parent d1d0889eb3
commit 91811b4fa1
28 changed files with 1394 additions and 503 deletions
+42
View File
@@ -5,6 +5,7 @@ import (
"path/filepath"
"strings"
"testing"
"time"
"github.com/warkanum/unitdore/config"
)
@@ -437,3 +438,44 @@ func TestGenerate_ExecutableMissingPath(t *testing.T) {
t.Error("Generate() should error when executable is empty")
}
}
func TestGenerate_OrderAndDelay(t *testing.T) {
u := config.Unit{Name: "web", Runtime: "podman", Enabled: true, After: []string{"db", "cache"}, StartDelay: 1500 * time.Millisecond}
content, err := Generate(u, "p-", "")
if err != nil {
t.Fatal(err)
}
for _, want := range []string{
"After=network.target unitdore-p-db.service unitdore-p-cache.service\n",
"ExecStartPre=/usr/bin/env sleep 2\n",
"TimeoutStartSec=92\n",
} {
if !strings.Contains(content, want) {
t.Errorf("missing %q in:\n%s", want, content)
}
}
}
func TestGenerate_UserUnitOrder(t *testing.T) {
u := config.Unit{Name: "web", Runtime: "podman", User: "hein", Enabled: true, After: []string{"db"}}
content, err := Generate(u, "", "")
if err != nil {
t.Fatal(err)
}
if !strings.Contains(content, "After=default.target unitdore-db.service\n") {
t.Errorf("user unit missing ordering:\n%s", content)
}
if strings.Contains(content, "ExecStartPre") {
t.Errorf("no delay expected:\n%s", content)
}
}
func TestGenerate_NoOrderNoExtras(t *testing.T) {
content, err := Generate(config.Unit{Name: "a", Runtime: "podman", Enabled: true}, "", "")
if err != nil {
t.Fatal(err)
}
if strings.Contains(content, "ExecStartPre") || strings.Contains(content, "TimeoutStartSec") || !strings.Contains(content, "After=network.target\n") {
t.Errorf("unexpected ordering output:\n%s", content)
}
}