mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-26 13:33:27 -04:00
246 lines
8.6 KiB
Lua
246 lines
8.6 KiB
Lua
return function(game)
|
|
local U = dofile("tests/drivers/util.lua")
|
|
local PORT = tonumber(os.getenv("POKEPORT_C1_RELAY_PORT") or "") or 18411
|
|
local SERVER = os.getenv("POKESERVER_DIR") or "../pokeserver"
|
|
local failures = 0
|
|
|
|
local function check(cond, msg)
|
|
if cond then
|
|
U.log("ok ", msg)
|
|
else
|
|
failures = failures + 1
|
|
U.log("FAIL", msg)
|
|
end
|
|
end
|
|
|
|
local pidFile = "/tmp/pokeserver_c1_" .. PORT .. ".pid"
|
|
local function stopServer()
|
|
local handle = io.open(pidFile, "r")
|
|
if handle then
|
|
local pid = handle:read("*l")
|
|
handle:close()
|
|
if pid and pid:match("^%d+$") then
|
|
os.execute("kill " .. pid .. " >/dev/null 2>&1")
|
|
end
|
|
end
|
|
os.remove(pidFile)
|
|
end
|
|
|
|
local function finish()
|
|
stopServer()
|
|
U.log(failures == 0 and "online c1 pin relay passed"
|
|
or (failures .. " online c1 pin relay check(s) failed"))
|
|
love.event.quit(failures == 0 and 0 or 1)
|
|
while true do coroutine.yield() end
|
|
end
|
|
|
|
local probe = io.open(SERVER .. "/server.js", "r")
|
|
if not probe then
|
|
U.log("FAIL", SERVER .. "/server.js is not checked out")
|
|
love.event.quit(1)
|
|
return
|
|
end
|
|
probe:close()
|
|
|
|
os.execute(("(cd %q && PORT=%d HTTP_PORT=%d SYNC_ENABLED=0 CARTS_ENABLED=0 "
|
|
.. "STATS_ENABLED=0 GIFTS_ENABLED=0 CART_MIRROR_ENABLED=0 node server.js "
|
|
.. ">/tmp/pokeserver_c1_%d.log 2>&1 & echo $! > %q)")
|
|
:format(SERVER, PORT, PORT + 1, PORT, pidFile))
|
|
|
|
local Net = require("src.link.Net")
|
|
local function reachable()
|
|
local net = Net.new()
|
|
if not net:connectTCP("127.0.0.1:" .. PORT) then return false end
|
|
for _ = 1, 30 do
|
|
net:update()
|
|
if net.closed then
|
|
pcall(function() net:close() end)
|
|
return false
|
|
end
|
|
if not net.connecting then
|
|
pcall(function() net:close() end)
|
|
return true
|
|
end
|
|
end
|
|
pcall(function() net:close() end)
|
|
return false
|
|
end
|
|
|
|
local up = false
|
|
local startedAt = love.timer.getTime()
|
|
while love.timer.getTime() - startedAt < 20 do
|
|
up = reachable()
|
|
if up then break end
|
|
U.wait(2)
|
|
end
|
|
check(up, "the spawned pokeserver answered on 127.0.0.1:" .. PORT)
|
|
if not up then return finish() end
|
|
|
|
local function freshClient()
|
|
package.loaded["src.online.Client"] = nil
|
|
local C = require("src.online.Client")
|
|
C.reset()
|
|
C.configure({ relayAddress = "127.0.0.1:" .. PORT })
|
|
return C
|
|
end
|
|
|
|
local Host = freshClient()
|
|
local Guest = freshClient()
|
|
local OnlinePanel = require("src.import.OnlinePanel")
|
|
OnlinePanel._hooked = nil
|
|
OnlinePanel._events = {}
|
|
|
|
local Version = require("src.core.Version")
|
|
local PROFILE = {
|
|
engine = 1, version = "red", engineVersion = Version.engine,
|
|
apiVersion = Version.modApi, fingerprint = "c1-pin", rulesetId = "gen1_faithful",
|
|
kind = "vanilla", rule = { partySize = 1 },
|
|
}
|
|
|
|
local imp = { ready = { red = true }, activeSlot = {}, slots = {}, pulse = 0,
|
|
_pages = {}, _uiActions = {}, _actAt = {} }
|
|
local st = OnlinePanel.state(imp)
|
|
st.version, st.slotId, st.setupDone = "red", "slot1", true
|
|
st.team = { { where = "party", index = 1 } }
|
|
st.profiles["red|vanilla|-"] = { profile = PROFILE }
|
|
local SAVE = { party = { { species = "PIKACHU", level = 20, moves = {} } } }
|
|
st.slotRead = { key = "red|slot1|-",
|
|
data = { generation = 1, party = SAVE.party, save = SAVE } }
|
|
|
|
local function pump(n)
|
|
for _ = 1, n or 1 do
|
|
Host.update(1 / 60)
|
|
Guest.update(1 / 60)
|
|
OnlinePanel.update(imp, 1 / 60)
|
|
coroutine.yield()
|
|
end
|
|
end
|
|
|
|
local function waitFor(fn, frames, what)
|
|
for _ = 1, frames or 600 do
|
|
if fn() then return true end
|
|
pump(1)
|
|
end
|
|
check(false, "timed out waiting for " .. tostring(what))
|
|
return false
|
|
end
|
|
|
|
Host.connect({ name = "HOST#001", profiles = { PROFILE } })
|
|
Guest.connect({ name = "GUEST#002", profiles = { PROFILE } })
|
|
if not waitFor(function()
|
|
return Host.state() == "online" and Guest.state() == "online"
|
|
end, 600, "both clients online") then
|
|
U.log("host", Host.state(), tostring(Host.error()),
|
|
"guest", Guest.state(), tostring(Guest.error()))
|
|
return finish()
|
|
end
|
|
|
|
local made = Host.createRoom({ intent = "battle", profile = PROFILE,
|
|
playing = true, maxSpectators = 4, private = true, pin = "0427",
|
|
seats = 2, auto = false })
|
|
waitFor(function() return made.done end, 600, "the private room")
|
|
local hostRoom = Host.room()
|
|
check(hostRoom ~= nil and hostRoom.locked == true, "the host's room is locked")
|
|
local roomId = hostRoom and hostRoom.room
|
|
check(type(roomId) == "string" and roomId:match("^r%x+$") ~= nil,
|
|
"and has an opaque id, no code")
|
|
|
|
local row
|
|
waitFor(function()
|
|
OnlinePanel.invalidate(imp, "lobby")
|
|
OnlinePanel.refresh(imp)
|
|
for _, r in ipairs(OnlinePanel.cache(imp).rooms) do
|
|
if r.room == roomId then row = r end
|
|
end
|
|
return row ~= nil
|
|
end, 600, "the locked room in the Play list")
|
|
check(row and row.locked == true, "the Play list shows it with a lock")
|
|
check(row and row.code == nil, "and no code")
|
|
|
|
OnlinePanel.startJoin(imp, OnlinePanel.targetFor(row, "player"))
|
|
check(OnlinePanel.pinModal(imp) ~= nil, "Join opens the PIN modal")
|
|
OnlinePanel.fieldType(imp, OnlinePanel.PIN_FIELD, "1111")
|
|
check(OnlinePanel.pinSubmit(imp), "a wrong PIN is sent")
|
|
waitFor(function() return OnlinePanel.pinModal(imp) ~= nil end, 600,
|
|
"the wrong PIN answer")
|
|
local mo = OnlinePanel.pinModal(imp)
|
|
check(mo and mo.error and mo.error:find("didn't match", 1, true) ~= nil,
|
|
"the relay's bad_pin reopens the modal: " .. tostring(mo and mo.error))
|
|
check(Guest.room() == nil, "and the guest is not seated")
|
|
|
|
for _ = 1, 4 do OnlinePanel.pinBack(imp) end
|
|
OnlinePanel.fieldType(imp, OnlinePanel.PIN_FIELD, "0427")
|
|
check(OnlinePanel.pinSubmit(imp), "the right PIN is sent")
|
|
waitFor(function() local r = Guest.room() return r and r.room == roomId end,
|
|
600, "the guest to take the seat")
|
|
check(Guest.room() and Guest.room().room == roomId,
|
|
"the right PIN seats the guest")
|
|
check(OnlinePanel.screen(imp) == "room", "on the Room screen")
|
|
|
|
Guest.leaveRoom()
|
|
pump(30)
|
|
OnlinePanel.home(imp)
|
|
|
|
local tokenMsg
|
|
Host.on("invite_token", function(msg) tokenMsg = msg end)
|
|
Host.inviteToken(roomId)
|
|
waitFor(function() return tokenMsg ~= nil end, 600, "an invite token")
|
|
local token = tokenMsg and tokenMsg.token
|
|
check(type(token) == "string" and #token == 32, "the relay mints a token")
|
|
if token then
|
|
check(OnlinePanel.deepLink(imp, { invite = token }, "player"),
|
|
"a Discord join hands the token to the panel")
|
|
waitFor(function() local r = Guest.room() return r and r.room == roomId end,
|
|
600, "the token join")
|
|
check(Guest.room() and Guest.room().room == roomId,
|
|
"the token seats the guest with no PIN")
|
|
Guest.leaveRoom()
|
|
pump(30)
|
|
end
|
|
OnlinePanel.home(imp)
|
|
|
|
local guestId = Guest.you() and Guest.you().id
|
|
if type(Host.invite) == "function" and guestId then
|
|
Host.leaveRoom()
|
|
pump(30)
|
|
Host.invite(guestId, "battle_single", {}, PROFILE)
|
|
waitFor(function() return OnlinePanel.toast(imp) ~= nil end, 600,
|
|
"the invite toast")
|
|
local toast = OnlinePanel.toast(imp)
|
|
check(toast ~= nil, "an invite shows a toast")
|
|
check(toast and OnlinePanel.inviteLine(toast):find("HOST#001", 1, true) ~= nil,
|
|
"naming the sender")
|
|
OnlinePanel.toastAction(imp, "accept")
|
|
waitFor(function() return Guest.room() ~= nil end, 600, "the invite room")
|
|
local r = Guest.room()
|
|
check(r ~= nil and r.origin == "invite", "accepting lands in an invite room")
|
|
check(r ~= nil and r.listed ~= true, "which is not listed")
|
|
waitFor(function() return Host.room() ~= nil end, 600, "the inviter in the invite room")
|
|
Guest.leaveRoom()
|
|
Host.leaveRoom()
|
|
local quietFrom = love.timer.getTime()
|
|
while love.timer.getTime() - quietFrom < 1 do pump(1) end
|
|
end
|
|
|
|
local tourMade = Host.createTournament({ profile = PROFILE,
|
|
rule = { partySize = 1 }, playing = false, shotClock = 6,
|
|
maxSpectators = 8, public = false })
|
|
waitFor(function() return tourMade.done end, 600, "the private tournament")
|
|
local tour = Host.tournament()
|
|
local code = tour and tour.code
|
|
check(type(code) == "string" and #code == 6,
|
|
"a private tournament keeps a six-character code: " .. tostring(code)
|
|
.. " " .. tostring(tourMade.error or tourMade.reason))
|
|
if code then
|
|
st.tourCode = code:lower()
|
|
OnlinePanel.joinTournament(imp, { code = st.tourCode }, "spectator")
|
|
waitFor(function() return Guest.tournament() ~= nil end, 600,
|
|
"joining by the private code")
|
|
check(Guest.tournament() ~= nil, "the code lets a guest in")
|
|
end
|
|
|
|
Host.disconnect()
|
|
Guest.disconnect()
|
|
return finish()
|
|
end
|