diff --git a/tests/containers.py b/tests/containers.py
index 6dd75ade3a69af1e79492243b8c0b102669ce4ae..a82b1c94fe05b80775c01b937cf6aee218635dbb 100755
--- a/tests/containers.py
+++ b/tests/containers.py
@@ -21,7 +21,9 @@ ideally contains at least:
     on the host system
 * scout/files:
     The Platform merged-/usr from the SteamLinuxRuntime depot
-* scout_sysroot:
+* soldier/files:
+    The Platform merged-/usr from the SteamLinuxRuntime depot
+* scout_sysroot, soldier_sysroot:
     An SDK sysroot like the one recommended for the Docker container
 
 and run (for example) 'meson test -v -C _build' as usual.
@@ -312,7 +314,7 @@ class TestContainers(BaseTest):
         # need into that directory.
         os.makedirs(os.path.join(cls.artifacts, 'tmp'), exist_ok=True)
 
-        for f in ('testutils.py', 'inside-scout.py'):
+        for f in ('testutils.py', 'inside-runtime.py'):
             shutil.copy2(
                 os.path.join(cls.G_TEST_SRCDIR, f),
                 os.path.join(cls.artifacts, 'tmp', f),
@@ -359,18 +361,60 @@ class TestContainers(BaseTest):
     def _test_scout(
         self,
         test_name: str,
-        scout: str,
+        runtime: str,
+        *,
+        copy: bool = False,
+        gc: bool = True,
+        locales: bool = False,
+        only_prepare: bool = False
+    ) -> None:
+        self._test_container(
+            test_name,
+            runtime,
+            copy=copy,
+            gc=gc,
+            is_scout=True,
+            locales=locales,
+            only_prepare=only_prepare,
+        )
+
+    def _test_soldier(
+        self,
+        test_name: str,
+        runtime: str,
+        *,
+        copy: bool = False,
+        gc: bool = True,
+        locales: bool = False,
+        only_prepare: bool = False
+    ) -> None:
+        self._test_container(
+            test_name,
+            runtime,
+            copy=copy,
+            gc=gc,
+            is_soldier=True,
+            locales=locales,
+            only_prepare=only_prepare,
+        )
+
+    def _test_container(
+        self,
+        test_name: str,
+        runtime: str,
         *,
         copy: bool = False,
         gc: bool = True,
+        is_scout: bool = False,
+        is_soldier: bool = False,
         locales: bool = False,
         only_prepare: bool = False
     ) -> None:
         if self.bwrap is None and not only_prepare:
             self.skipTest('Unable to run bwrap (in a container?)')
 
-        if not os.path.isdir(scout):
-            self.skipTest('{} not found'.format(scout))
+        if not os.path.isdir(runtime):
+            self.skipTest('{} not found'.format(runtime))
 
         artifacts = os.path.join(
             self.artifacts,
@@ -380,7 +424,7 @@ class TestContainers(BaseTest):
 
         argv = [
             self.pv_wrap,
-            '--runtime', scout,
+            '--runtime', runtime,
             '--verbose',
         ]
 
@@ -397,17 +441,28 @@ class TestContainers(BaseTest):
                 if not gc:
                     argv.append('--no-gc-runtimes')
 
+            if is_scout:
+                python = 'python3.5'
+            else:
+                python = 'python3'
+
             if only_prepare:
                 argv.append('--only-prepare')
             else:
                 argv.extend([
                     '--',
                     'env',
-                    'TEST_INSIDE_SCOUT_ARTIFACTS=' + artifacts,
-                    'TEST_INSIDE_SCOUT_IS_COPY=' + ('1' if copy else ''),
-                    'TEST_INSIDE_SCOUT_LOCALES=' + ('1' if locales else ''),
-                    'python3.5',
-                    os.path.join(self.artifacts, 'tmp', 'inside-scout.py'),
+                    'TEST_INSIDE_RUNTIME_ARTIFACTS=' + artifacts,
+                    'TEST_INSIDE_RUNTIME_IS_COPY=' + ('1' if copy else ''),
+                    'TEST_INSIDE_RUNTIME_IS_SCOUT=' + (
+                        '1' if is_scout else ''
+                    ),
+                    'TEST_INSIDE_RUNTIME_IS_SOLDIER=' + (
+                        '1' if is_soldier else ''
+                    ),
+                    'TEST_INSIDE_RUNTIME_LOCALES=' + ('1' if locales else ''),
+                    python,
+                    os.path.join(self.artifacts, 'tmp', 'inside-runtime.py'),
                 ])
 
             # Create directories representing previous runs of
@@ -444,7 +499,7 @@ class TestContainers(BaseTest):
 
                 # Put this in a subtest so that if it fails, we still get
                 # to inspect the copied sysroot
-                with self.subTest('run', copy=copy, scout=scout):
+                with self.subTest('run', copy=copy, runtime=runtime):
                     completed = self.run_subprocess(
                         argv,
                         cwd=self.artifacts,
@@ -486,7 +541,8 @@ class TestContainers(BaseTest):
                     self._assert_mutable_sysroot(
                         tree,
                         artifacts,
-                        is_scout=True,
+                        is_scout=is_scout,
+                        is_soldier=is_soldier,
                     )
 
     def _assert_mutable_sysroot(
@@ -494,7 +550,8 @@ class TestContainers(BaseTest):
         tree: str,
         artifacts: str,
         *,
-        is_scout: bool = True
+        is_scout: bool = False,
+        is_soldier: bool = False
     ) -> None:
         with open(
             os.path.join(artifacts, 'contents.txt'),
@@ -851,6 +908,42 @@ class TestContainers(BaseTest):
         with self.subTest('transient'):
             self._test_scout('scout', scout)
 
+    def test_soldier_sysroot(self) -> None:
+        soldier = os.path.join(self.containers_dir, 'soldier_sysroot')
+
+        if os.path.isdir(os.path.join(soldier, 'files')):
+            soldier = os.path.join(soldier, 'files')
+
+        with self.subTest('only-prepare'):
+            self._test_soldier(
+                'soldier_sysroot_prep', soldier,
+                copy=True, only_prepare=True,
+            )
+
+        with self.subTest('copy'):
+            self._test_soldier(
+                'soldier_sysroot_copy', soldier, copy=True, gc=False,
+            )
+
+        with self.subTest('transient'):
+            self._test_soldier('soldier_sysroot', soldier, locales=True)
+
+    def test_soldier_usr(self) -> None:
+        soldier = os.path.join(self.containers_dir, 'soldier', 'files')
+
+        with self.subTest('only-prepare'):
+            self._test_soldier(
+                'soldier_prep', soldier, copy=True, only_prepare=True,
+            )
+
+        with self.subTest('copy'):
+            self._test_soldier(
+                'soldier_copy', soldier, copy=True, locales=True,
+            )
+
+        with self.subTest('transient'):
+            self._test_soldier('soldier', soldier)
+
 
 if __name__ == '__main__':
     assert sys.version_info >= (3, 4), \
diff --git a/tests/inside-scout.py b/tests/inside-runtime.py
similarity index 76%
rename from tests/inside-scout.py
rename to tests/inside-runtime.py
index 58e402ff8b7cc4cf3b9e6298412b52f5a2127ce2..3b8674bf7cb5ae0e1d4d9915176f2c779996bb36 100755
--- a/tests/inside-scout.py
+++ b/tests/inside-runtime.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python3.5
+#!/usr/bin/python3
 # Copyright 2020 Collabora Ltd.
 #
 # SPDX-License-Identifier: MIT
@@ -21,11 +21,11 @@ from testutils import (
 )
 
 """
-Test script intended to be run inside a SteamRT 1 'scout' container,
+Test script intended to be run inside a SteamRT container
 to assert that everything is as it should be.
 """
 
-logger = logging.getLogger('test-inside-scout')
+logger = logging.getLogger('test-inside-runtime')
 
 
 class HostInfo:
@@ -70,12 +70,12 @@ class HostInfo:
                 break
 
 
-class TestInsideScout(BaseTest):
+class TestInsideRuntime(BaseTest):
     def setUp(self) -> None:
         super().setUp()
         self.host = HostInfo()
 
-        artifacts = os.getenv('TEST_INSIDE_SCOUT_ARTIFACTS')
+        artifacts = os.getenv('TEST_INSIDE_RUNTIME_ARTIFACTS')
 
         if artifacts is not None:
             self.artifacts = Path(artifacts)
@@ -135,9 +135,16 @@ class TestInsideScout(BaseTest):
                     assert len(tokens) == 1, tokens
                     data[key] = tokens[0]
 
-            self.assertEqual(data.get('VERSION_ID'), '1')
-            self.assertEqual(data.get('ID'), 'steamrt')
-            self.assertEqual(data.get('ID_LIKE'), 'ubuntu')
+            if os.environ.get('TEST_INSIDE_RUNTIME_IS_SCOUT'):
+                self.assertEqual(data.get('VERSION_ID'), '1')
+                self.assertEqual(data.get('ID'), 'steamrt')
+                self.assertEqual(data.get('ID_LIKE'), 'ubuntu')
+
+            elif os.environ.get('TEST_INSIDE_RUNTIME_IS_SOLDIER'):
+                self.assertEqual(data.get('VERSION_ID'), '2')
+                self.assertEqual(data.get('ID'), 'steamrt')
+                self.assertEqual(data.get('ID_LIKE'), 'debian')
+
             self.assertIsNotNone(data.get('BUILD_ID'))
 
     def test_environ(self) -> None:
@@ -148,7 +155,7 @@ class TestInsideScout(BaseTest):
         # No actual *tests* here just yet - we just log what's there.
 
     def test_overrides(self) -> None:
-        if os.getenv('TEST_INSIDE_SCOUT_IS_COPY'):
+        if os.getenv('TEST_INSIDE_RUNTIME_IS_COPY'):
             target = os.readlink('/overrides')
             self.assertEqual(target, 'usr/lib/pressure-vessel/overrides')
 
@@ -156,76 +163,64 @@ class TestInsideScout(BaseTest):
         self.assertTrue(Path('/overrides/lib').is_dir())
 
     def test_glibc(self) -> None:
-        """
-        Assert that we took the glibc version from the host OS.
-
-        We assume this will always be true for scout, because scout
-        is based on Ubuntu 12.04, the oldest operating system we support;
-        and in cases where our glibc is the same version as the glibc of
-        the host OS, we prefer the host.
-        """
-        overrides = Path('/overrides').resolve()
-
         glibc = ctypes.cdll.LoadLibrary('libc.so.6')
         gnu_get_libc_version = glibc.gnu_get_libc_version
         gnu_get_libc_version.restype = ctypes.c_char_p
         glibc_version = gnu_get_libc_version().decode('ascii')
         logger.info('glibc version in use: %s', glibc_version)
         major, minor, *rest = glibc_version.split('.')
-        self.assertGreaterEqual((int(major), int(minor)), (2, 15))
-
-        # This assumes that uname -m matches the multiarch tuple
-        # closely enough. On x86_64 it does, and on i386 we have
-        # symlinks /overrides/lib/i[456]86-linux-gnu.
-        host_glibc = ctypes.cdll.LoadLibrary(
-            '/{}/lib/{}-linux-gnu/libc.so.6'.format(
-                overrides,
-                os.uname().machine,
-            ),
-        )
-        gnu_get_libc_version = host_glibc.gnu_get_libc_version
-        gnu_get_libc_version.restype = ctypes.c_char_p
-        host_glibc_version = gnu_get_libc_version().decode('ascii')
-        logger.info('host glibc version: %s', host_glibc_version)
-        self.assertEqual(host_glibc_version, glibc_version)
 
-        if (
-            'HOST_LD_LINUX_SO_REALPATH' in os.environ
-            and Path('/usr/lib/i386-linux-gnu').is_dir()
-        ):
-            host_path = os.environ['HOST_LD_LINUX_SO_REALPATH']
-            expected = self.host.path / host_path.lstrip('/')
-            expected_stat = expected.stat()
-            logger.info('host ld-linux.so.2: %s', host_path)
-
-            for really in (
-                '/lib/ld-linux.so.2',
-                '/lib/i386-linux-gnu/ld-linux.so.2',
-                '/lib/i386-linux-gnu/ld-2.15.so',
+        if os.environ.get('TEST_INSIDE_RUNTIME_IS_SCOUT'):
+            # Assert that we took the glibc version from the host OS.
+            #
+            # We assume this will always be true for scout, because scout
+            # is based on Ubuntu 12.04, the oldest operating system we support;
+            # and in cases where our glibc is the same version as the glibc of
+            # the host OS, we prefer the host.
+
+            if (
+                'HOST_LD_LINUX_SO_REALPATH' in os.environ
+                and Path('/usr/lib/i386-linux-gnu').is_dir()
             ):
-                really_stat = Path(really).stat()
-                # Either it's a symlink to the same file, or the same file
-                # was mounted over it
-                self.assertEqual(really_stat.st_dev, expected_stat.st_dev)
-                self.assertEqual(really_stat.st_ino, expected_stat.st_ino)
-
-        if (
-            'HOST_LD_LINUX_X86_64_SO_REALPATH' in os.environ
-            and Path('/usr/lib/x86_64-linux-gnu').is_dir()
-        ):
-            host_path = os.environ['HOST_LD_LINUX_X86_64_SO_REALPATH']
-            expected = self.host.path / host_path.lstrip('/')
-            expected_stat = expected.stat()
-            logger.info('host ld-linux-x86-64.so.2: %s', host_path)
-
-            for really in (
-                '/lib64/ld-linux-x86-64.so.2',
-                '/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2',
-                '/lib/x86_64-linux-gnu/ld-2.15.so',
+                host_path = os.environ['HOST_LD_LINUX_SO_REALPATH']
+                expected = self.host.path / host_path.lstrip('/')
+                expected_stat = expected.stat()
+                logger.info('host ld-linux.so.2: %s', host_path)
+
+                for really in (
+                    '/lib/ld-linux.so.2',
+                    '/lib/i386-linux-gnu/ld-linux.so.2',
+                    '/lib/i386-linux-gnu/ld-2.15.so',
+                ):
+                    really_stat = Path(really).stat()
+                    # Either it's a symlink to the same file, or the same file
+                    # was mounted over it
+                    self.assertEqual(really_stat.st_dev, expected_stat.st_dev)
+                    self.assertEqual(really_stat.st_ino, expected_stat.st_ino)
+
+            if (
+                'HOST_LD_LINUX_X86_64_SO_REALPATH' in os.environ
+                and Path('/usr/lib/x86_64-linux-gnu').is_dir()
             ):
-                really_stat = Path(really).stat()
-                self.assertEqual(really_stat.st_dev, expected_stat.st_dev)
-                self.assertEqual(really_stat.st_ino, expected_stat.st_ino)
+                host_path = os.environ['HOST_LD_LINUX_X86_64_SO_REALPATH']
+                expected = self.host.path / host_path.lstrip('/')
+                expected_stat = expected.stat()
+                logger.info('host ld-linux-x86-64.so.2: %s', host_path)
+
+                for really in (
+                    '/lib64/ld-linux-x86-64.so.2',
+                    '/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2',
+                    '/lib/x86_64-linux-gnu/ld-2.15.so',
+                ):
+                    really_stat = Path(really).stat()
+                    self.assertEqual(really_stat.st_dev, expected_stat.st_dev)
+                    self.assertEqual(really_stat.st_ino, expected_stat.st_ino)
+
+        elif os.environ.get('TEST_INSIDE_RUNTIME_IS_SOLDIER'):
+            # We don't know whether it's soldier's glibc 2.28 or something
+            # newer from the host, but it should definitely be at least
+            # soldier's version
+            self.assertGreaterEqual((int(major), int(minor)), (2, 28))
 
     def test_srsi(self) -> None:
         overrides = Path('/overrides').resolve()
@@ -324,10 +319,21 @@ class TestInsideScout(BaseTest):
             self.assertIn('name', parsed['os-release'])
             self.assertIn('pretty_name', parsed['os-release'])
             self.assertIn('version_id', parsed['os-release'])
-            self.assertEqual('1', parsed['os-release']['version_id'])
-            self.assertEqual('scout', parsed['os-release']['version_codename'])
             self.assertIn('build_id', parsed['os-release'])
 
+            if os.environ.get('TEST_INSIDE_RUNTIME_IS_SCOUT'):
+                self.assertEqual('1', parsed['os-release']['version_id'])
+                self.assertEqual(
+                    'scout',
+                    parsed['os-release']['version_codename'],
+                )
+            elif os.environ.get('TEST_INSIDE_RUNTIME_IS_SOLDIER'):
+                self.assertEqual('2', parsed['os-release']['version_id'])
+                self.assertEqual(
+                    'soldier',
+                    parsed['os-release']['version_codename'],
+                )
+
         with self.catch(
             'container info',
             diagnostic=parsed.get('container'),
@@ -342,7 +348,7 @@ class TestInsideScout(BaseTest):
                 host_parsed['os-release'],
             )
 
-            if os.environ.get('TEST_INSIDE_SCOUT_LOCALES'):
+            if os.environ.get('TEST_INSIDE_RUNTIME_LOCALES'):
                 for locale, host_details in host_parsed.get(
                     'locales', {}
                 ).items():
@@ -414,37 +420,53 @@ class TestInsideScout(BaseTest):
                     )
                     self.assertEqual([], details.get('issues', []))
 
-            for soname in (
-                'libBrokenLocale.so.1',
-                'libanl.so.1',
-                'libc.so.6',
-                'libcrypt.so.1',
-                'libdl.so.2',
-                'libm.so.6',
-                'libnsl.so.1',
-                'libpthread.so.0',
-                'libresolv.so.2',
-                'librt.so.1',
-                'libutil.so.1',
-            ):
-                # These are from glibc, which is depended on by Mesa, and
-                # is at least as new as scout's version in every supported
-                # version of the Steam Runtime.
-                self.assertEqual(
-                    arch_info['library-details'][soname]['path'],
-                    '{}/lib/{}/{}'.format(overrides, multiarch, soname),
-                )
+            if os.environ.get('TEST_INSIDE_RUNTIME_IS_SCOUT'):
+                for soname in (
+                    'libBrokenLocale.so.1',
+                    'libanl.so.1',
+                    'libc.so.6',
+                    'libcrypt.so.1',
+                    'libdl.so.2',
+                    'libm.so.6',
+                    'libnsl.so.1',
+                    'libpthread.so.0',
+                    'libresolv.so.2',
+                    'librt.so.1',
+                    'libutil.so.1',
+                ):
+                    # These are from glibc, which is depended on by Mesa, and
+                    # is at least as new as scout's version in every supported
+                    # version of the Steam Runtime.
+                    self.assertEqual(
+                        arch_info['library-details'][soname]['path'],
+                        '{}/lib/{}/{}'.format(overrides, multiarch, soname),
+                    )
 
-            for soname in (
-                'libSDL-1.2.so.0',
-                'libfltk.so.1.1',
-            ):
+            if os.environ.get('TEST_INSIDE_RUNTIME_IS_SCOUT'):
+                not_graphics_drivers = [
+                    'libSDL-1.2.so.0',
+                    'libfltk.so.1.1',
+                ]
+            elif os.environ.get('TEST_INSIDE_RUNTIME_IS_SOLDIER'):
+                not_graphics_drivers = [
+                    'libfltk.so.1.1',
+                    'libgdk-3.so.0',
+                    'libSDL2-2.0.so.0',
+                ]
+            else:
+                not_graphics_drivers = []
+
+            for soname in not_graphics_drivers:
                 # These libraries are definitely not part of the graphics
                 # driver stack
-                self.assertEqual(
-                    arch_info['library-details'][soname]['path'],
-                    '/usr/lib/{}/{}'.format(multiarch, soname),
-                )
+                if (
+                    arch_info['library-details'][soname]['path']
+                    != '/lib/{}/{}'.format(multiarch, soname)
+                ):
+                    self.assertEqual(
+                        arch_info['library-details'][soname]['path'],
+                        '/usr/lib/{}/{}'.format(multiarch, soname),
+                    )
 
             if host_info:
                 expect_symlinks = {
@@ -583,7 +605,7 @@ class TestInsideScout(BaseTest):
             with self.subTest(read_only_place):
                 if (
                     read_only_place.startswith('/overrides')
-                    and not os.getenv('TEST_INSIDE_SCOUT_IS_COPY')
+                    and not os.getenv('TEST_INSIDE_RUNTIME_IS_COPY')
                 ):
                     # If we aren't working from a temporary copy of the
                     # runtime, /overrides is on a tmpfs