| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175 |
- --[[
- tests/smoke.lua — End-to-end smoke test
- Boots the daemon in dry-run mode with a fake UCI config; runs 2 cycles,
- verifies status.json + control.json round-trip via the ctl module.
- ]]
- package.path = package.path .. ";/usr/lib/lua/5.1/?.lua;./src/?.lua"
- local config = require("balancerlite.config")
- local ctl = require("balancerlite.ctl")
- local passed = 0
- local failed = 0
- local function check(name, ok, detail)
- if ok then
- passed = passed + 1
- print(" PASS " .. name)
- else
- failed = failed + 1
- print(" FAIL " .. name .. (detail and (" " .. detail) or ""))
- end
- end
- -- -----------------------------------------------------------------
- -- Setup: write a minimal UCI config to a temp dir.
- -- -----------------------------------------------------------------
- local dir = "/tmp/bl_smoke_" .. tostring(os.time()) .. "_" ..
- tostring(math.random(1000000))
- os.execute("mkdir -p " .. dir)
- local cfg_path = dir .. "/balancerlite"
- local f = io.open(cfg_path, "w")
- f:write([[
- config general 'general'
- option host 'smoke-test'
- option dry_run '1'
- option log_level 'info'
- config health 'health'
- option probe_interval '1s'
- option window_size '5'
- option down_threshold '2'
- option up_threshold '3'
- option icmp_timeout '1s'
- option tcp_timeout '2s'
- option dns_timeout '2s'
- option dns_probe_domain 'example.com'
- option icmp_enabled '0'
- option tcp_enabled '0'
- option dns_enabled '0'
- config wan 'wan_a'
- option interface 'lo'
- option address '127.0.0.1/32'
- option gateway '127.0.0.1'
- config wan 'wan_b'
- option interface 'lo'
- option address '127.0.0.1/32'
- option gateway '127.0.0.1'
- config routing 'routing'
- option table_a '100'
- option table_b '101'
- option mark_active_a '0x1'
- option mark_active_b '0x2'
- config wireguard 'wg'
- option enabled '0'
- option interface 'wg0'
- config notifier 'notifier'
- option webhook_url ''
- option webhook_secret ''
- option batch_window '0s'
- option max_attempts '1'
- option initial_backoff '1s'
- option max_backoff '1s'
- option outbox_capacity '100'
- option cb_threshold '5'
- option cb_cooldown '60s'
- config flap 'flap'
- option switch_count '3'
- option window '60s'
- option recovery_grace '60s'
- config features 'features'
- option hot_reload '0'
- option trace_ids '0'
- config store 'store'
- option state_dir ']] .. dir .. [['
- option retention_days '30'
- ]])
- f:close()
- -- -----------------------------------------------------------------
- -- TEST 1: config loads
- -- -----------------------------------------------------------------
- print("\n[1] config load")
- local cfg, err = config.load(cfg_path)
- check("config loads", cfg ~= nil, tostring(err))
- check("dry_run=true", cfg.general.dry_run == true)
- check("host=smoke-test", cfg.general.host == "smoke-test")
- check("state_dir matches", cfg.store.state_dir == dir)
- check("icmp disabled", cfg.health.icmp_enabled == false)
- check("tcp disabled", cfg.health.tcp_enabled == false)
- -- -----------------------------------------------------------------
- -- TEST 1b: wan section values actually loaded (was silently defaulted)
- -- -----------------------------------------------------------------
- print("\n[1b] wan section values")
- check("wan-a iface=lo", cfg.wans[1].interface == "lo",
- tostring(cfg.wans[1].interface))
- check("wan-a gw=127.0.0.1", cfg.wans[1].gateway == "127.0.0.1",
- tostring(cfg.wans[1].gateway))
- check("wan-b iface=lo", cfg.wans[2].interface == "lo",
- tostring(cfg.wans[2].interface))
- check("wan-b gw=127.0.0.1", cfg.wans[2].gateway == "127.0.0.1",
- tostring(cfg.wans[2].gateway))
- -- -----------------------------------------------------------------
- -- TEST 2: ctl round-trip in our temp dir
- -- -----------------------------------------------------------------
- print("\n[2] ctl round-trip in " .. dir)
- local rc = ctl.cmd_switch(dir, "wan-b")
- check("ctl switch rc=0", rc == 0)
- local req = ctl.read_control(dir)
- check("control file written", req ~= nil and req.kind == "switch" and
- req.target == "wan-b")
- ctl.clear_control(dir)
- check("control file cleared", io.open(dir .. "/control.json", "r") == nil)
- -- status file should NOT exist yet (daemon hasn't been started)
- check("no status yet", io.open(dir .. "/status.json", "r") == nil)
- -- Write a fake status file (as the daemon would)
- local sf = io.open(dir .. "/status.json", "w")
- sf:write('{"daemon":true,"state":"WAN_A_PRIMARY","active_wan":"wan-a",' ..
- '"host":"smoke-test","cycles":3,"updated_ts":' ..
- tostring(os.time()) .. '}\n')
- sf:close()
- local st = ctl.read_status(dir)
- check("status readable", st ~= nil and st.daemon == true)
- check("status.state=WAN_A_PRIMARY", st.state == "WAN_A_PRIMARY")
- check("status.active_wan=wan-a", st.active_wan == "wan-a")
- local rendered = ctl.render_status(st)
- check("rendered contains WAN_A_PRIMARY",
- rendered:match("WAN_A_PRIMARY"))
- check("rendered contains 'alive'", rendered:match("alive"))
- -- -----------------------------------------------------------------
- -- TEST 3: ctl cmd_status returns rc=0 when status file exists
- -- -----------------------------------------------------------------
- print("\n[3] cmd_status with status file")
- local rc2 = ctl.cmd_status(dir)
- check("rc=0", rc2 == 0)
- -- -----------------------------------------------------------------
- -- TEST 4: ctl cmd_events with no events
- -- -----------------------------------------------------------------
- print("\n[4] cmd_events with empty store")
- local rc3 = ctl.cmd_events(dir, 10)
- check("rc=0", rc3 == 0)
- -- -----------------------------------------------------------------
- -- Cleanup
- -- -----------------------------------------------------------------
- os.execute("rm -rf " .. dir)
- print(string.format("\n=== smoke: %d/%d passed ===", passed, passed + failed))
- if failed > 0 then os.exit(1) end
|