192 lines
9.1 KiB
Python
192 lines
9.1 KiB
Python
# A bunch of tests to verify MultiServer and custom webhost server work as expected.
|
|
# This spawns processes and may modify your local AP, so this is not run as part of unit testing.
|
|
# Run with `python test/hosting` instead,
|
|
import logging
|
|
import traceback
|
|
from tempfile import TemporaryDirectory
|
|
from time import sleep
|
|
from typing import Any
|
|
|
|
from test.hosting.client import Client
|
|
from test.hosting.generate import generate_local
|
|
from test.hosting.serve import ServeGame, LocalServeGame, WebHostServeGame
|
|
from test.hosting.webhost import (create_room, get_app, get_multidata_for_room, set_multidata_for_room, start_room,
|
|
stop_autohost, upload_multidata)
|
|
from test.hosting.world import copy as copy_world, delete as delete_world
|
|
|
|
failure = False
|
|
fail_fast = True
|
|
|
|
|
|
def assert_true(condition: Any, msg: str = "") -> None:
|
|
global failure
|
|
if not condition:
|
|
failure = True
|
|
msg = f": {msg}" if msg else ""
|
|
raise AssertionError(f"Assertion failed{msg}")
|
|
|
|
|
|
def assert_equal(first: Any, second: Any, msg: str = "") -> None:
|
|
global failure
|
|
if first != second:
|
|
failure = True
|
|
msg = f": {msg}" if msg else ""
|
|
raise AssertionError(f"Assertion failed: {first} == {second}{msg}")
|
|
|
|
|
|
if fail_fast:
|
|
expect_true = assert_true
|
|
expect_equal = assert_equal
|
|
else:
|
|
def expect_true(condition: Any, msg: str = "") -> None:
|
|
global failure
|
|
if not condition:
|
|
failure = True
|
|
tb = "".join(traceback.format_stack()[:-1])
|
|
msg = f": {msg}" if msg else ""
|
|
logging.error(f"Expectation failed{msg}\n{tb}")
|
|
|
|
def expect_equal(first: Any, second: Any, msg: str = "") -> None:
|
|
global failure
|
|
if first != second:
|
|
failure = True
|
|
tb = "".join(traceback.format_stack()[:-1])
|
|
msg = f": {msg}" if msg else ""
|
|
logging.error(f"Expectation failed {first} == {second}{msg}\n{tb}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import warnings
|
|
warnings.simplefilter("ignore", ResourceWarning)
|
|
warnings.simplefilter("ignore", UserWarning)
|
|
|
|
spacer = '=' * 80
|
|
|
|
with TemporaryDirectory() as tempdir:
|
|
multis = [["Clique"], ["Temp World"], ["Clique", "Temp World"]]
|
|
p1_games = []
|
|
data_paths = []
|
|
rooms = []
|
|
|
|
copy_world("Clique", "Temp World")
|
|
try:
|
|
for n, games in enumerate(multis, 1):
|
|
print(f"Generating [{n}] {', '.join(games)}")
|
|
multidata = generate_local(games, tempdir)
|
|
print(f"Generated [{n}] {', '.join(games)} as {multidata}\n")
|
|
p1_games.append(games[0])
|
|
data_paths.append(multidata)
|
|
finally:
|
|
delete_world("Temp World")
|
|
|
|
webapp = get_app(tempdir)
|
|
webhost_client = webapp.test_client()
|
|
for n, multidata in enumerate(data_paths, 1):
|
|
seed = upload_multidata(webhost_client, multidata)
|
|
room = create_room(webhost_client, seed)
|
|
print(f"Uploaded [{n}] {multidata} as {room}\n")
|
|
rooms.append(room)
|
|
|
|
print("Starting autohost")
|
|
from WebHostLib.autolauncher import autohost
|
|
try:
|
|
autohost(webapp.config)
|
|
|
|
host: ServeGame
|
|
for n, (multidata, room, game, multi_games) in enumerate(zip(data_paths, rooms, p1_games, multis), 1):
|
|
involved_games = {"Archipelago"} | set(multi_games)
|
|
for collected_items in range(3):
|
|
print(f"\nTesting [{n}] {game} in {multidata} on MultiServer with {collected_items} items collected")
|
|
with LocalServeGame(multidata) as host:
|
|
with Client(host.address, game, "Player1") as client:
|
|
local_data_packages = client.games_packages
|
|
local_collected_items = len(client.checked_locations)
|
|
if collected_items < 2: # Clique only has 2 Locations
|
|
client.collect_any()
|
|
# TODO: Ctrl+C test here as well
|
|
|
|
for game_name in sorted(involved_games):
|
|
expect_true(game_name in local_data_packages,
|
|
f"{game_name} missing from MultiServer datap ackage")
|
|
expect_true("item_name_groups" not in local_data_packages.get(game_name, {}),
|
|
f"item_name_groups are not supposed to be in MultiServer data for {game_name}")
|
|
expect_true("location_name_groups" not in local_data_packages.get(game_name, {}),
|
|
f"location_name_groups are not supposed to be in MultiServer data for {game_name}")
|
|
for game_name in local_data_packages:
|
|
expect_true(game_name in involved_games,
|
|
f"Received unexpected extra data package for {game_name} from MultiServer")
|
|
assert_equal(local_collected_items, collected_items,
|
|
"MultiServer did not load or save correctly")
|
|
|
|
print(f"\nTesting [{n}] {game} in {multidata} on customserver with {collected_items} items collected")
|
|
prev_host_adr: str
|
|
with WebHostServeGame(webhost_client, room) as host:
|
|
prev_host_adr = host.address
|
|
with Client(host.address, game, "Player1") as client:
|
|
web_data_packages = client.games_packages
|
|
web_collected_items = len(client.checked_locations)
|
|
if collected_items < 2: # Clique only has 2 Locations
|
|
client.collect_any()
|
|
if collected_items == 1:
|
|
sleep(1) # wait for the server to collect the item
|
|
stop_autohost(True) # simulate Ctrl+C
|
|
sleep(3)
|
|
autohost(webapp.config) # this will spin the room right up again
|
|
sleep(1) # make log less annoying
|
|
# if saving failed, the next iteration will fail below
|
|
|
|
# verify server shut down
|
|
try:
|
|
with Client(prev_host_adr, game, "Player1") as client:
|
|
assert_true(False, "Server did not shut down")
|
|
except ConnectionError:
|
|
pass
|
|
|
|
for game_name in sorted(involved_games):
|
|
expect_true(game_name in web_data_packages,
|
|
f"{game_name} missing from customserver data package")
|
|
expect_true("item_name_groups" not in web_data_packages.get(game_name, {}),
|
|
f"item_name_groups are not supposed to be in customserver data for {game_name}")
|
|
expect_true("location_name_groups" not in web_data_packages.get(game_name, {}),
|
|
f"location_name_groups are not supposed to be in customserver data for {game_name}")
|
|
for game_name in web_data_packages:
|
|
expect_true(game_name in involved_games,
|
|
f"Received unexpected extra data package for {game_name} from customserver")
|
|
assert_equal(web_collected_items, collected_items,
|
|
"customserver did not load or save correctly during/after "
|
|
+ ("Ctrl+C" if collected_items == 2 else "/exit"))
|
|
|
|
# compare customserver to MultiServer
|
|
expect_equal(local_data_packages, web_data_packages,
|
|
"customserver datapackage differs from MultiServer")
|
|
|
|
sleep(5.5) # make sure all tasks actually stopped
|
|
|
|
# raise an exception in customserver and verify the save doesn't get destroyed
|
|
# local variables room is the last room's id here
|
|
old_data = get_multidata_for_room(webhost_client, room)
|
|
print(f"Destroying multidata for {room}")
|
|
set_multidata_for_room(webhost_client, room, bytes([0]))
|
|
try:
|
|
start_room(webhost_client, room, timeout=7)
|
|
except TimeoutError:
|
|
pass
|
|
else:
|
|
assert_true(False, "Room started with destroyed multidata")
|
|
print(f"Restoring multidata for {room}")
|
|
set_multidata_for_room(webhost_client, room, old_data)
|
|
with WebHostServeGame(webhost_client, room) as host:
|
|
with Client(host.address, game, "Player1") as client:
|
|
assert_equal(len(client.checked_locations), 2,
|
|
"Save was destroyed during exception in customserver")
|
|
print("Save file is not busted 🥳")
|
|
|
|
finally:
|
|
print("Stopping autohost")
|
|
stop_autohost(False)
|
|
|
|
if failure:
|
|
print("Some tests failed")
|
|
exit(1)
|
|
exit(0)
|