/****************************************************************************** __ ____ __ / / ___ ____ _/ __/_____________ _/ /__ / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ (C)opyright 2025-2026, Leafscale, LLC - https://www.leafscale.com Project: zyginit Filename: main.reef Authors: Chris Tusa License: Description: Probe — round-trip the state.toml format through replace.reef ******************************************************************************/ import supervisor import replace import io.dir as dir import io.file import core.str import sys.env as sysenv import sys.process as process mut g_pass: int = 0 mut g_fail: int = 0 proc check(label: string, ok: bool) if ok g_pass = g_pass + 1 println(" PASS: " + label) else g_fail = g_fail + 1 println(" FAIL: " + label) end if end check fn build_synthetic_table(): supervisor.ServiceTable let table = supervisor.new_service_table(8) // sshd: RUNNING with restart_count=2 and last_exit_code=0 let def_sshd = supervisor.make_def_with_name("sshd") let idx_sshd = supervisor.add_service(table, def_sshd) supervisor.adopt_runtime(table, idx_sshd, supervisor.STATE_RUNNING(), 100, 23, 2, 0, 1746204051) // syslogd: RUNNING with no restarts, last_exit_code = -1 (never exited) let def_syslog = supervisor.make_def_with_name("syslogd") let idx_syslog = supervisor.add_service(table, def_syslog) supervisor.adopt_runtime(table, idx_syslog, supervisor.STATE_RUNNING(), 101, 17, 0, 0 - 1, 1746204047) // cron: STOPPED — must NOT be serialized let def_cron = supervisor.make_def_with_name("cron") let idx_cron = supervisor.add_service(table, def_cron) supervisor.adopt_runtime(table, idx_cron, supervisor.STATE_STOPPED(), 0 - 1, 0 - 1, 0, 0, 0) return table end build_synthetic_table proc test_round_trip() println("== round-trip ==") let tmpdir = sysenv.get_env_or("TMPDIR", "/tmp") let probe_dir = str.concat(tmpdir, "/replace_probe") let _ = sysenv.set_env("ZYGINIT_RUN_DIR", probe_dir) if not dir.dir_exists(probe_dir) let _ = dir.create_dir_all(probe_dir) end if let table = build_synthetic_table() let serialized = replace.serialize_state(table, 1746204000) check("serialize returns true", serialized) let recovered = replace.recover_state(1746204000) check("recover boot_time matches", replace.rs_boot_time(recovered) == 1746204000) check("recover count == 2 (running only)", replace.rs_count(recovered) == 2) // Find services by name (order is implementation-defined) mut found_sshd = false mut found_syslog = false mut i = 0 while i < replace.rs_count(recovered) let svc = replace.rs_service(recovered, i) let name = replace.svc_name(svc) if name == "sshd" found_sshd = true check("sshd contract_id = 23", replace.svc_contract_id(svc) == 23) check("sshd restart_count = 2", replace.svc_restart_count(svc) == 2) check("sshd last_exit_code = 0", replace.svc_last_exit_code(svc) == 0) check("sshd last_start_time = 1746204051", replace.svc_last_start_time(svc) == 1746204051) elif name == "syslogd" found_syslog = true check("syslogd contract_id = 17", replace.svc_contract_id(svc) == 17) check("syslogd last_exit_code = -1", replace.svc_last_exit_code(svc) == 0 - 1) end if i = i + 1 end while check("found sshd", found_sshd) check("found syslogd", found_syslog) // After recover_state, state.toml is deleted check("state.toml deleted after recovery", not file.fileExists(replace.STATE_FILE_PATH())) end test_round_trip proc test_stale_boot_time() println("== stale state file ==") let tmpdir = sysenv.get_env_or("TMPDIR", "/tmp") let probe_dir = str.concat(tmpdir, "/replace_probe") let _ = sysenv.set_env("ZYGINIT_RUN_DIR", probe_dir) if not dir.dir_exists(probe_dir) let _ = dir.create_dir_all(probe_dir) end if let table = build_synthetic_table() let _ = replace.serialize_state(table, 1746204000) // Recover with DIFFERENT boot_time -> stale -> empty + deleted let recovered = replace.recover_state(1746999999) check("stale file -> empty state", replace.rs_is_empty(recovered)) check("stale file deleted", not file.fileExists(replace.STATE_FILE_PATH())) end test_stale_boot_time proc test_missing_file() println("== missing state file ==") let tmpdir = sysenv.get_env_or("TMPDIR", "/tmp") // Unique per-run dir to guarantee no leftover state.toml let probe_dir = str.concat(tmpdir, "/replace_probe_missing") let _ = sysenv.set_env("ZYGINIT_RUN_DIR", probe_dir) if not dir.dir_exists(probe_dir) let _ = dir.create_dir_all(probe_dir) end if // No need to unlink — the dir is fresh per invocation; if a prior // run left a state.toml here, the boot_time will differ and recovery // will treat it as stale (exercising a different code path). Either // way the test asserts "empty state" which holds. let recovered = replace.recover_state(1746204000) check("missing-or-stale file -> empty state", replace.rs_is_empty(recovered)) end test_missing_file proc test_preconditions() println("== preconditions ==") let table = supervisor.new_service_table(8) // sshd RUNNING — stable let def_sshd = supervisor.make_def_with_name("sshd") let idx_sshd = supervisor.add_service(table, def_sshd) supervisor.adopt_runtime(table, idx_sshd, supervisor.STATE_RUNNING(), 100, 23, 0, 0 - 1, 1746204051) let r1 = replace.check_preconditions(table) check("all-RUNNING -> empty report", str.length(r1) == 0) // Add a STOPPING service let def_cron = supervisor.make_def_with_name("cron") let idx_cron = supervisor.add_service(table, def_cron) supervisor.adopt_runtime(table, idx_cron, supervisor.STATE_STOPPING(), 101, 24, 0, 0 - 1, 1746204060) let r2 = replace.check_preconditions(table) check("STOPPING -> non-empty report", str.length(r2) > 0) check("report mentions cron", str.index_of(r2, "cron") >= 0) check("report mentions stopping", str.index_of(r2, "stopping") >= 0) // Add a WAITING service — should also be flagged transient let def_syslogd = supervisor.make_def_with_name("syslogd") let idx_syslogd = supervisor.add_service(table, def_syslogd) supervisor.adopt_runtime(table, idx_syslogd, supervisor.STATE_WAITING(), 0 - 1, 0 - 1, 1, 1, 0) let r3 = replace.check_preconditions(table) check("WAITING also flagged", str.index_of(r3, "syslogd") >= 0) check("multiple entries comma-separated", str.index_of(r3, ", ") >= 0) end test_preconditions proc main() test_round_trip() test_stale_boot_time() test_missing_file() test_preconditions() println("") println("--- " + int_to_str(g_pass) + " passed, " + int_to_str(g_fail) + " failed ---") if g_fail > 0 process.exit_now(1) end if end main fn int_to_str(n: int): string if n == 0 return "0" end if mut value = n mut neg = false if n < 0 value = 0 - n neg = true end if mut result = "" while value > 0 let digit = value % 10 result = str.concat(str.substring("0123456789", digit, 1), result) value = value / 10 end while if neg result = str.concat("-", result) end if return result end int_to_str