Skip to content

Test Deck

Jared Wright edited this page Aug 10, 2026 · 1 revision

DC Test Deck

A web frontend for test runs, built to be handed to testers: log in with a game GM account, pick a dungeon, and a full five-bot party runs it while you watch live. No service control, no shell access — just testing.

It ships inside the module, at modules/mod-dungeon-clear/testdeck/. This page is the tour; testdeck/README.md in the repo is the operational reference and goes further on troubleshooting, configuration keys and the API.

What's in it

Panel What it does
Launch Dungeon grid. Start a single run, an N-run campaign ("plan"), or a hand-picked roster of real characters. Difficulty, bot level, comp seed and the gear ceiling are all on the one form.
Live Every active run: party HP/mana chips, boss progress, a full status timeline, stop buttons. Plan progress bars.
Roster Browse real characters (class colours, talent spec, instance budget), fill the five positional slots — tank / heal / dps ×3 — and save named rosters.
History Finished runs with the post-mortem (party, boss kills, deaths, status timeline) and campaign summaries. Rerun relaunches a run with its own dungeon, difficulty, level, gear ceiling and comp seed — same party, new run id.
Logs Live tail of the server's *.log files.

The three launch modes map onto three questions:

  • Quick run — one run, now. The loop for "did my change help?"
  • Plan — the same run N times, for a success rate rather than an anecdote.
  • Roster — a hand-picked party of real characters instead of pool bots.

Requirements

Test Deck runs on the machine your worldserver runs on — Linux, macOS or Windows. It needs:

  • Python 3.9+ (on Windows, tick "Add python.exe to PATH" in the installer).
  • A MySQL client (mysql / mysql.exe) — how it reads the game databases.
  • SOAP enabled on the worldserver — how it issues .dc test … commands.

No Node.js: the UI ships pre-built in dist/.

Quick start

1. Turn on SOAP in worldserver.conf and restart the worldserver:

SOAP.Enabled = 1
SOAP.IP      = "127.0.0.1"
SOAP.Port    = 7878

2. Create the bridge account on the worldserver console. SOAP requires administrator level:

account create tdbridge <a long random password>
account set gmlevel tdbridge 3 -1

3. Start it, from modules/mod-dungeon-clear/testdeck:

Windows double-click testdeck.bat
Linux / macOS ./testdeck.sh
either, by hand python3 launch.py

The first run creates a private Python environment, installs what it needs, asks a handful of questions (mostly confirming what it already worked out), writes testdeck.toml, then serves the deck and opens your browser at it. Later runs skip straight to serving. It prints both the local URL and the LAN one — testers elsewhere on the network need nothing installed, just that second address in a browser.

4. Log in with any game account that has gmlevel >= 1. There is no separate Test Deck password.

Then pick a dungeon, leave every option alone, and press Start run.

The three accounts

Easy to conflate, so:

What it is Who creates it
tdbridge The account SOAP authenticates as. No character, never enters the world. Needs gmlevel 3 — the core refuses SOAP below administrator. You, in quick-start step 2.
Dcdriver The test driver character the module logs in headlessly to stand in as the issuing GM, because a console launch has no player behind it. Nothing the deck starts works without it. The module, on first need. See Test Runs.
tester accounts Ordinary game accounts with gmlevel >= 1, used to log into the deck. You: account create alice <pw> then account set gmlevel alice 1 -1.

On a host that has never launched anything, Dcdriver is simply absent and the first launch may report that it is logging in. The deck handles that by queueing the run as a one-run plan, which waits the driver out server-side.

Creating tester accounts

From the worldserver console (or via SOAP):

account create alice <password>
account set gmlevel alice 1 -1

Verify one end to end with python3 -m testdeck check-auth alice.

gmlevel 1 can log in, launch pool runs and plans, and draft characters on its own account. Anything that affects someone else — clearing shared run and plan history, deleting or overwriting another tester's saved roster, or running characters that belong to another account — needs [auth] admin_gmlevel (default 3). That last one matters: a roster run logs a character in, teleports it and re-gears it.

Revoking access is account set gmlevel <user> 0 -1, and it takes effect within about a minute — authorization re-reads the account's GM level and ban state from the auth database on every request rather than trusting the cookie.

When something is wrong

python3 -m testdeck check       # every problem this host has, in one list

check names the config key behind each finding, and prints the two directories that most findings come down to:

  server    C:\WoW\SingleCraft  (worldserver working directory)
  log_dir   C:\WoW\SingleCraft\logs
  sidecars  C:\WoW\SingleCraft  (found)

server_root is the setting that decides the most. It is the directory the worldserver runs in, not necessarily where the binary sits — the module writes its dc_* files there by relative name, so the Launch, Live and History panels all read out of it, and LogsDir / DataDir in worldserver.conf are relative to it too. Set [paths] server_root explicitly if the server is started from somewhere the binary is not: a service with its own working directory, or a launcher script that cds first. Most "No dungeon catalogue yet" and "Live stays empty" reports are this one setting.

The repo README has the full symptom-to-cause table.

Security model

Test Deck is a LAN tool. Defence in depth, outermost first: a Host header check ([server] allowed_hosts), a source-address allowlist ([server] allowed_nets), GM-account login against the auth database's SRP6 salt and verifier (per-IP and per-username throttled, generic failure messages), a signed HttpOnly session cookie, and a CSRF header on every mutation. Command strings are built server-side from validated fields only — nothing typed in the browser is ever spliced into a console command. Every start and stop is audit-logged with the account name.

Two things to get right:

  • Reach the deck by address (what the startup banner prints) and you need no extra config. If testers use a hostname — a reverse proxy, a DNS or hosts entry — list it in [server] allowed_hosts. That check is what stops a hostile page a tester visits from pointing a name it controls at your server and driving it from their browser.
  • [paths] data_dir holds the session secret and is kept at mode 0700. A readable copy of that file is enough to forge an admin session.

Do not expose it to the internet without a TLS reverse proxy in front. The session cookie rides plain HTTP on a LAN, which is what [auth] session_hours (default 12) is really sizing: how long a sniffed one stays useful.

Alternatives to SOAP

SOAP is the recommended transport and the only one that exists on Windows — it works no matter how the worldserver is launched and needs no privileges. Two POSIX-only alternatives exist for hosts that would rather not enable it: screen (set screen_session) and tmux (set tmux_target). If the session belongs to another user, set use_sudo = true and install the snippet python3 -m testdeck sudoers prints.

Keep the bridge password out of the config file with TESTDECK_SOAP_PASS if you prefer.

Running it as a service

Nothing about the launcher is required — any supervisor that runs python3 -m testdeck serve works. ac-testdeck.service.in is a systemd unit to fill in; on Windows, Task Scheduler with "Run whether user is logged on or not" pointed at testdeck.bat does the same job.

Configuration and development

testdeck.example.toml documents every setting. The config file is looked for in this order: --config PATH, $TESTDECK_CONFIG, ./testdeck.toml, the checkout's own testdeck.toml, ~/.config/testdeck.toml, /etc/testdeck.toml. Missing config is never fatal — the server boots on derived defaults and says what is wrong in its own banner, because a server that refuses to start cannot tell you why it refuses to start.

For UI work: cd web && npm install && npm run dev (hot reload, /api proxied to 127.0.0.1:8790); npm run build writes ../dist, and the result is committed. Tests are bash t/run_tests.sh — no root, no live worldserver, no database needed. The HTTP API is documented in testdeck/docs/api.md.

Clone this wiki locally