Skip to content

M3.3 — Devices and device pools

What you'll learn

  • The ITargetDevice abstraction and its per-platform implementations.
  • What a device pool is and why shared hardware needs reservation.
  • How "same test, different device" maps onto the role layout from M3.2.

How it applies (QA)

Console and mobile coverage is gated by physical hardware, not by test logic. The devkit pool is a shared, contended, flaky resource, and a large share of "Gauntlet failures" on consoles are actually device problems — a kit that's offline, stuck in a bad state, or reserved by someone else. Telling a device failure from a test failure is a core QA-owner skill.

Concepts

ITargetDevice and its implementations

ITargetDevice (tier 1) abstracts "a thing a build can be installed on and launched." Each platform has a concrete implementation (tier 2):

TargetDeviceWindows, TargetDeviceMac, TargetDevicePS4, TargetDeviceXboxOne, TargetDeviceSwitch, TargetDeviceIOS, TargetDeviceAndroid, and so on across the platforms Unreal supports.

Each implements the same operations behind the interface: install a build, launch it, query its state, copy artifacts back, reboot/clean. A test written against ITargetDevice runs on any of them — the implementation hides "how do you copy a build to a Switch devkit" vs. "how do you launch a local Windows process."

Local vs. remote vs. devkit

  • Local (TargetDeviceWindows/Mac on the host) — fastest; no reservation, no copy over the network. Default when -device is omitted.
  • Remote PC — another machine addressed by IP/name; needs the build copied and the process launched remotely.
  • Console devkit / mobile device — special hardware that runs development builds. Slowest path: reserve it, copy/install the cooked build, launch, pull artifacts back, clean up.

The further from local, the more failure modes that have nothing to do with your test: network, reservation, devkit firmware, storage full, a previous run left it dirty.

Device pools and reservation

Studios share a finite set of devkits across many people and many CI jobs. A device pool is the managed set of available devices; a run reserves the device(s) it needs, uses them, and releases them. Reservation prevents two jobs from launching on the same kit at once (which corrupts both).

Implications for a test owner:

  • A run can queue waiting for a free device — "slow nightly" is sometimes contention, not a slow test.
  • A reservation that isn't released (crashed job, killed process) leaks a device out of the pool until reclaimed.
  • "No devices available" is a pool/capacity failure, not a test failure.

Devices × roles

M3.2's role layout places each role on a device. The device axis is orthogonal to the role axis:

  • 1 server + 2 clients, all local → three processes on one PC.
  • 1 server + 2 clients, each on its own kit → three reservations from the pool.

Scaling a test from "cheap, local, every commit" to "real hardware, nightly" is mostly moving roles from local devices onto pooled devices — same roles, different ITargetDevice targets.

Pitfall: blaming the test for a dirty device

A kit left in a bad state by a previous run (full storage, a zombie process holding a port, an OS update pending) fails the next run for reasons the next test never caused. Before deep-diving a one-off console failure, check the device's health and whether a clean/reboot makes it pass. Reproducibility across devices is the tell: fails on one kit, passes on others → suspect the kit.

Worked example — reading a device-shaped failure

A nightly console job log:

LogGauntlet: Reserving device from pool 'PS5-Pool' ...
LogGauntlet: Error: No devices available in pool 'PS5-Pool' after 600s

This never reached a build install, never launched the game, never ran a line of test logic. It's a capacity/reservation failure: the pool was exhausted (other jobs, or leaked reservations) for the whole wait window. The action is on the pool (capacity, stuck reservations), not the test or the build. Re-running the test unchanged will fail identically until the pool frees up.

Exercise 1 — Test fault or device fault?

Classify each as test/build or device/pool:

  1. "No devices available in pool after 600s."
  2. The game booted on the kit, reached the menu, then the verdict went red on a missing marker.
  3. Install failed: "not enough free space on device."
  4. Passes on kits 1–3, fails only on kit 4 with a launch timeout.
  5. A detected crash with a dump in the role's /Saved.

Exercise 2 — Scale the layout

You have a green local 1-server/2-client test. To run it with each client on a separate PS5 kit and the server on a Win64 host, what changes — and what doesn't? Answer in terms of roles vs. devices.

Self-check — answers

Exercise 1: 1 device/pool (capacity), 2 test/build (verdict logic), 3 device/pool (kit storage), 4 device/pool (kit-specific; passes elsewhere), 5 test/build (a real crash in the run).

Exercise 2: What changes: the device each role targets — clients move from TargetDeviceWindows (local) to TargetDevicePS4/PS5 kits drawn from the pool (adding reservation, build copy, and per-device failure modes), and the build matrix now needs cooked PS5 client builds. What doesn't change: the roles themselves (still 1 server + 2 clients), the launch order, and the pass condition — that's the payoff of the device/role separation.

Done when

  • [ ] You can explain what ITargetDevice abstracts and name several implementations.
  • [ ] You can describe a device pool and why reservation exists.
  • [ ] You can separate a device/pool failure from a test/build failure from a log line.
  • [ ] You can scale a role layout from local to pooled devices and say what changes.

Next: M3.4 — Builds and build sources.