rats

RAdix iniT Suite
git clone https://git.daat.foo/repos/rats.git
Log | Files | Refs | README | LICENSE

commit 29d95a2fadb3dbeb4955ebed3d0a2c8165beb770
parent e08f498d65f64eb6e7701fe318c8a55580ab22c6
Author: cowmonk <cowmonk@based.pt>
Date:   Mon, 24 Aug 2026 19:32:48 -0700

serva/svc tests

added test suite to ensure serva/svc basic functionality

Diffstat:
M.gitignore | 4++++
MREADME | 4++++
Atests/Makefile | 26++++++++++++++++++++++++++
Atests/run.sh | 144+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atests/ssv/boot/crashme/run | 3+++
Atests/ssv/default/depender/need/sleeper | 0
Atests/ssv/default/depender/run | 3+++
Atests/ssv/default/oneshot.marker | 0
Atests/ssv/default/oneshot/once | 0
Atests/ssv/default/oneshot/run | 4++++
Atests/ssv/default/sleeper/run | 4++++
11 files changed, 192 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -7,3 +7,7 @@ svc.o slog slog.o util.o + +tests/serva-test +tests/serva.log +tests/svc-test diff --git a/README b/README @@ -212,6 +212,10 @@ Source Layout config.mk build configuration Makefile posix (should work with any *competent* make impl) + tests/ + run.sh run this to test init suite (currently only serva/svc) + Makefile build serva/svc test binaries + ssv/* dummy ssv files/ rc.* optional example configurations bin/* optional scripts to use along with RATS diff --git a/tests/Makefile b/tests/Makefile @@ -0,0 +1,26 @@ +# tests/Makefile: build serva/svc against a sandboxed ssv dir + socket +.POSIX: + +include ../config.mk + +TOP = .. +CC ?= cc + +all: serva-test svc-test + +serva-test: $(TOP)/serva.c $(TOP)/util.o + $(CC) $(CFLAGS) -DSVC_DIR='"$(CURDIR)/ssv"' \ + -DSOCK_PATH='"$(CURDIR)/serva.sock"' \ + $(LDFLAGS) -o $@ $(TOP)/serva.c $(TOP)/util.o + +svc-test: $(TOP)/svc.c $(TOP)/util.o + $(CC) $(CFLAGS) -DSOCK_PATH='"$(CURDIR)/serva.sock"' \ + $(LDFLAGS) -o $@ $(TOP)/svc.c $(TOP)/util.o + +$(TOP)/util.o: $(TOP)/util.c $(TOP)/util.h + cd $(TOP) && $(MAKE) util.o + +clean: + rm -f serva-test svc-test serva.log + +.PHONY: all clean run-tests diff --git a/tests/run.sh b/tests/run.sh @@ -0,0 +1,144 @@ +#!/bin/sh +# tests/run.sh: integration test for serva + svc +# +# Boots a sandboxed serva against ./ssv and drives it with svc-test. +# No root needed: everything lives under tests/. + +set -u +cd "$(dirname "$0")" + +SOCK="$PWD/serva.sock" +SERVA=./serva-test +SVC=./svc-test +LOG=serva.log +PASS=0 +FAIL=0 + +say() { printf '%s\n' "$*"; } +ok() { PASS=$((PASS + 1)); say "ok - $1"; } +bad() { FAIL=$((FAIL + 1)); say "FAIL - $1"; } + +cleanup() { + [ -n "${SERVA_PID:-}" ] && kill "$SERVA_PID" 2>/dev/null + wait 2>/dev/null + rm -f "$SOCK" +} +trap cleanup EXIT + +# --- setup sandbox ----------------------------------------------------------- +rm -rf ssv +mkdir -p ssv/boot/crashme ssv/default/sleeper ssv/default/oneshot ssv/default/depender/need + +cat > ssv/boot/crashme/run <<'EOF' +#!/bin/sh +echo "crashme starting" +exit 42 +EOF + +cat > ssv/default/sleeper/run <<'EOF' +#!/bin/sh +echo "sleeper starting" +trap 'exit 0' TERM +while :; do sleep 1; done +EOF + +cat > ssv/default/oneshot/run <<'EOF' +#!/bin/sh +echo "oneshot ran" +touch "$PWD.marker" 2>/dev/null || true +exit 0 +EOF +touch ssv/default/oneshot/once + +cat > ssv/default/depender/run <<'EOF' +#!/bin/sh +trap 'exit 0' TERM +while :; do sleep 1; done +EOF +touch ssv/default/depender/need/sleeper + +chmod +x ssv/*/*/run + +# --- build + launch ---------------------------------------------------------- +make -s all || { say "build failed"; exit 1; } + +"$SERVA" >"$LOG" 2>&1 & +SERVA_PID=$! + +for i in 1 2 3 4 5 6 7 8 9 10; do + [ -S "$SOCK" ] && break + sleep 0.2 +done +[ -S "$SOCK" ] || { bad "serva socket never appeared"; exit 1; } +sleep 1 # let services start (and crashme crash once) + +# --- tests ------------------------------------------------------------------- +out=$("$SVC" -s) +case $out in +*default/sleeper*RUN*) ok "svc -s lists sleeper as RUN" ;; +*) bad "svc -s should show sleeper RUN, got: $out" ;; +esac + +out=$("$SVC" -s sleeper) +case $out in +*sleeper*RUN*runs=1*) ok "svc -s <name> shows single service with runs=1" ;; +*) bad "svc -s sleeper unexpected: $out" ;; +esac + +out=$("$SVC" -s crashme) +case $out in +*exit=42*) ok "svc -s crashme records exit code 42" ;; +*) bad "svc -s crashme missing exit=42: $out" ;; +esac + +out=$("$SVC" -s crashme) +runs=$(printf '%s' "$out" | sed -n 's/.*runs=\([0-9]*\).*/\1/p') +[ "${runs:-0}" -ge 2 ] && ok "crashme restarted with backoff (runs=$runs)" \ + || bad "crashme should have restarted, runs=${runs:-?}" + +out=$("$SVC" -s depender) +case $out in +*RUN*) ok "depender started once sleeper was running" ;; +*) bad "depender should be RUN after dep met: $out" ;; +esac + +out=$("$SVC" -s oneshot) +case $out in +*DONE*) ok "oneshot reports DONE after exit" ;; +*) bad "oneshot should be DONE: $out" ;; +esac + +out=$("$SVC" -d sleeper 2>&1) && sleep 0.5 && out=$("$SVC" -s sleeper) +case $out in +*DOWN*) ok "svc -d brings sleeper down" ;; +*) bad "sleeper should be DOWN after svc -d: $out" ;; +esac + +out=$("$SVC" -s depender) +case $out in +*WAIT*) ok "depender cascades to WAIT when sleeper stops" ;; +*) bad "depender should be WAIT after sleeper down: $out" ;; +esac + +"$SVC" -u sleeper >/dev/null && sleep 0.5 +out=$("$SVC" -s depender) +case $out in +*RUN*) ok "depender restarts when dep comes back" ;; +*) bad "depender should be RUN again: $out" ;; +esac + +out=$("$SVC" -s nosuchsvc 2>&1) +case $out in +*ERR*) ok "svc -s on unknown service returns ERR" ;; +*) bad "expected ERR for unknown service: $out" ;; +esac + +out=$("$SVC" -r sleeper 2>&1) && sleep 0.5 +runs=$("$SVC" -s sleeper | sed -n 's/.*runs=\([0-9]*\).*/\1/p') +[ "${runs:-0}" -ge 2 ] && ok "svc -r restarts sleeper (runs=$runs)" \ + || bad "svc -r did not restart sleeper: runs=${runs:-?}" + +# --- summary ----------------------------------------------------------------- +say "" +say "passed: $PASS failed: $FAIL" +[ "$FAIL" -eq 0 ] diff --git a/tests/ssv/boot/crashme/run b/tests/ssv/boot/crashme/run @@ -0,0 +1,3 @@ +#!/bin/sh +echo "crashme starting" +exit 42 diff --git a/tests/ssv/default/depender/need/sleeper b/tests/ssv/default/depender/need/sleeper diff --git a/tests/ssv/default/depender/run b/tests/ssv/default/depender/run @@ -0,0 +1,3 @@ +#!/bin/sh +trap 'exit 0' TERM +while :; do sleep 1; done diff --git a/tests/ssv/default/oneshot.marker b/tests/ssv/default/oneshot.marker diff --git a/tests/ssv/default/oneshot/once b/tests/ssv/default/oneshot/once diff --git a/tests/ssv/default/oneshot/run b/tests/ssv/default/oneshot/run @@ -0,0 +1,4 @@ +#!/bin/sh +echo "oneshot ran" +touch "$PWD.marker" 2>/dev/null || true +exit 0 diff --git a/tests/ssv/default/sleeper/run b/tests/ssv/default/sleeper/run @@ -0,0 +1,4 @@ +#!/bin/sh +echo "sleeper starting" +trap 'exit 0' TERM +while :; do sleep 1; done