| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 |
- --[[
- tests/probes_config.lua — regression tests for the three testbed bugs:
- 1. probes.all() must accept per-WAN tcp targets (tables or
- "host:port" strings) instead of dereferencing a nil global.
- 2. config.load() must find UCI wan sections named wan_a / wan_b
- (hyphens are not valid UCI identifiers) and map them onto the
- internal wan-a / wan-b ids.
- 3. main.lua --dry-run: covered by the daemon dry-run smoke check
- ("(DRY RUN)" banner + "exited after 1 cycles").
- Pure-Lua, no root, no network (exec is not invoked by these paths
- except via injected stubs / disabled probes).
- ]]
- package.path = package.path .. ";./src/?.lua"
- local probes = require("balancerlite.probes")
- local config = require("balancerlite.config")
- 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
- -- -----------------------------------------------------------------
- -- TEST 1: probes.all with per-WAN tcp targets (the drive_cycle crash)
- -- -----------------------------------------------------------------
- print("\n[1] probes.all per-WAN tcp targets")
- do
- -- All probe types disabled except TCP; use a dead local port so
- -- nc fails fast (connect refused, no network dependency).
- local P = probes.new({
- tcp_targets = {}, -- global list intentionally empty
- tcp_enabled = true,
- icmp_enabled = false,
- dns_enabled = false,
- wg_enabled = false,
- tcp_timeout = 1,
- })
- -- Table form
- local r = probes.all(P, "lo", { { host = "127.0.0.1", port = 1 } }, nil)
- check("returns 1 result", #r == 1, "got " .. tostring(#r))
- check("probe is tcp", r[1] and r[1].name == "tcp")
- check("no crash on empty global list", true)
- -- String form
- local P2 = probes.new({
- tcp_targets = {},
- tcp_enabled = true,
- icmp_enabled = false,
- dns_enabled = false,
- wg_enabled = false,
- tcp_timeout = 1,
- })
- local r2 = probes.all(P2, "lo", { "127.0.0.1:1" }, nil)
- check("string form returns 1 result", #r2 == 1, "got " .. tostring(#r2))
- check("string form probe is tcp", r2[1] and r2[1].name == "tcp")
- -- nil override → falls back to global list
- local P3 = probes.new({
- tcp_targets = { { host = "127.0.0.1", port = 1 } },
- tcp_enabled = true,
- icmp_enabled = false,
- dns_enabled = false,
- wg_enabled = false,
- tcp_timeout = 1,
- })
- local r3 = probes.all(P3, "lo", nil, nil)
- check("nil override uses global", #r3 == 1, "got " .. tostring(#r3))
- -- Empty per-WAN list → no tcp probes at all
- local P4 = probes.new({
- tcp_targets = { { host = "127.0.0.1", port = 1 } },
- tcp_enabled = true,
- icmp_enabled = false,
- dns_enabled = false,
- wg_enabled = false,
- })
- local r4 = probes.all(P4, "lo", {}, nil)
- check("empty override yields no results", #r4 == 0, "got " .. tostring(#r4))
- end
- -- -----------------------------------------------------------------
- -- TEST 2: config.load maps UCI wan_a/wan_b sections to wan-a/wan-b
- -- -----------------------------------------------------------------
- print("\n[2] config.load wan section naming")
- do
- local dir = "/tmp/bl_pcfg_" .. tostring(os.time()) .. "_" ..
- tostring(math.random(1000000))
- os.execute("mkdir -p " .. dir)
- local p = dir .. "/balancerlite"
- local f = io.open(p, "w")
- f:write([[
- config general 'general'
- option host 'unit-test'
- config health 'health'
- option probe_interval '1s'
- config wan 'wan_a'
- option interface 'eth10'
- option address '192.0.2.10/24'
- option gateway '192.0.2.1'
- option preference '90'
- config wan 'wan_b'
- option interface 'eth11'
- option address '198.51.100.10/24'
- option gateway '198.51.100.1'
- option preference '10'
- ]])
- f:close()
- local cfg, err = config.load(p)
- check("config loads", cfg ~= nil, tostring(err))
- check("two wans parsed", cfg and #cfg.wans == 2,
- cfg and tostring(#cfg.wans))
- check("wan-a interface from wan_a section",
- cfg and cfg.wans[1].interface == "eth10",
- cfg and tostring(cfg.wans[1].interface))
- check("wan-a address from wan_a section",
- cfg and cfg.wans[1].address == "192.0.2.10/24",
- cfg and tostring(cfg.wans[1].address))
- check("wan-a gateway from wan_a section",
- cfg and cfg.wans[1].gateway == "192.0.2.1",
- cfg and tostring(cfg.wans[1].gateway))
- check("wan-a preference from wan_a section",
- cfg and cfg.wans[1].preference == 90,
- cfg and tostring(cfg.wans[1].preference))
- check("wan-b interface from wan_b section",
- cfg and cfg.wans[2].interface == "eth11",
- cfg and tostring(cfg.wans[2].interface))
- check("wan-b gateway from wan_b section",
- cfg and cfg.wans[2].gateway == "198.51.100.1",
- cfg and tostring(cfg.wans[2].gateway))
- os.execute("rm -rf " .. dir)
- end
- -- -----------------------------------------------------------------
- -- TEST 3: config.load still accepts hyphenated wan-a/wan-b sections
- -- (back-compat)
- -- -----------------------------------------------------------------
- print("\n[3] config.load hyphenated sections (back-compat)")
- do
- local dir = "/tmp/bl_pcfg2_" .. tostring(os.time()) .. "_" ..
- tostring(math.random(1000000))
- os.execute("mkdir -p " .. dir)
- local p = dir .. "/balancerlite"
- local f = io.open(p, "w")
- f:write([[
- config wan 'wan-a'
- option interface 'eth20'
- option gateway '10.20.0.1'
- config wan 'wan-b'
- option interface 'eth21'
- option gateway '10.21.0.1'
- ]])
- f:close()
- local cfg, err = config.load(p)
- check("config loads", cfg ~= nil, tostring(err))
- check("wan-a interface from wan-a section",
- cfg and cfg.wans[1].interface == "eth20",
- cfg and tostring(cfg.wans[1].interface))
- check("wan-b interface from wan-b section",
- cfg and cfg.wans[2].interface == "eth21",
- cfg and tostring(cfg.wans[2].interface))
- os.execute("rm -rf " .. dir)
- end
- -- -----------------------------------------------------------------
- -- TEST 4: no wan sections at all → defaults, no crash
- -- -----------------------------------------------------------------
- print("\n[4] config.load zero wan sections")
- do
- local dir = "/tmp/bl_pcfg3_" .. tostring(os.time()) .. "_" ..
- tostring(math.random(1000000))
- os.execute("mkdir -p " .. dir)
- local p = dir .. "/balancerlite"
- local f = io.open(p, "w")
- f:write([[
- config general 'general'
- option host 'nowan'
- ]])
- f:close()
- local cfg, err = config.load(p)
- check("config loads", cfg ~= nil, tostring(err))
- check("two wans defaulted", cfg and #cfg.wans == 2)
- check("default iface eth0", cfg and cfg.wans[1].interface == "eth0",
- cfg and tostring(cfg.wans[1].interface))
- os.execute("rm -rf " .. dir)
- end
- -- -----------------------------------------------------------------
- -- Done
- -- -----------------------------------------------------------------
- print(string.format("\n=== probes_config: %d/%d passed ===",
- passed, passed + failed))
- if failed > 0 then os.exit(1) end
|