local failures = 0 local function expect(condition, message) if not condition then failures = failures + 1 io.stderr:write("FAIL: " .. message .. "\n") end end local globalData = {} local transmitted = 0 ModData = { getOrCreate = function(name) globalData[name] = globalData[name] or {} return globalData[name] end, transmit = function() transmitted = transmitted + 1 end } function isServer() return true end TowBarMod = {} dofile("42.20/media/lua/shared/TowBar/Persistence.lua") local function vehicle(sqlId) return { getSqlId = function() return sqlId end } end local towing, towed = vehicle(101), vehicle(202) expect(TowBarMod.Persistence.savePair("towbar", towing, towed, "trailer", "trailerfront"), "valid SQL pair must save") local pair = TowBarMod.Persistence.getPair("towbar", towing, towed) expect(pair and pair.towingSqlId == 101 and pair.towedSqlId == 202, "saved pair must use stable SQL IDs") expect(pair and pair.attachmentA == "trailer" and pair.attachmentB == "trailerfront", "saved pair must retain attachments") expect(TowBarMod.Persistence.savePair("wrecker", towing, towed, "towbarWreckerHookHigh", "trailer", 2), "wrecker pair must save") local wreckerPair = TowBarMod.Persistence.getPair("wrecker", towing, towed) expect(wreckerPair and wreckerPair.heightLevel == 2, "wrecker pair must retain hook height") local seen = 0 TowBarMod.Persistence.forEachPair("towbar", function(record) if record.towingSqlId == 101 and record.towedSqlId == 202 then seen = seen + 1 end end) expect(seen == 1, "registry iteration must return the saved pair exactly once") expect(TowBarMod.Persistence.removePair("towbar", towing, towed), "saved pair must be removable") expect(TowBarMod.Persistence.getPair("towbar", towing, towed) == nil, "removed pair must stay absent") expect(transmitted >= 3, "server registry changes must transmit") expect(not TowBarMod.Persistence.savePair("towbar", vehicle(-1), towed, "trailer", "trailerfront"), "unsaved vehicles must not create unstable records") local state, action = TowBarMod.Persistence.advanceRecoveryState(nil, 1000, false, false, 2000, 5000) expect(action == "restore", "first missing-link observation must start one restore") state, action = TowBarMod.Persistence.advanceRecoveryState(state, 1500, false, false, 2000, 5000) expect(action == "wait", "an in-flight restore must not be duplicated") state, action = TowBarMod.Persistence.advanceRecoveryState(state, 3000, true, false, 2000, 5000) expect(action == "adopt" and state.confirmed, "a restored link must be adopted") state, action = TowBarMod.Persistence.advanceRecoveryState(state, 3100, false, false, 2000, 5000) expect(action == "wait", "one missing sample must not destroy an adopted link") state, action = TowBarMod.Persistence.advanceRecoveryState(state, 8099, false, false, 2000, 5000) expect(action == "wait", "cleanup must wait for the complete break grace period") state, action = TowBarMod.Persistence.advanceRecoveryState(state, 8100, false, false, 2000, 5000) expect(action == "break", "a continuously missing confirmed link must eventually break") state = TowBarMod.Persistence.notePeerAvailability({ confirmed = true }, false) expect(state.peerMissing, "an unloaded peer must be remembered") state = TowBarMod.Persistence.notePeerAvailability(state, true) expect(state.confirmed == false, "a reloaded pair must re-enter recovery instead of break cleanup") expect(state.peerMissing == nil, "the peer-missing marker must clear after both vehicles load") state, action = TowBarMod.Persistence.advanceRecoveryState(state, 9000, false, false, 2000, 5000) expect(action == "restore", "a reloaded pair must rebuild its constraint") if failures > 0 then os.exit(1) end print("PASS: persistent pair registry behavior")