Files
DroidDeck/tools/tests/test_steam_compat_environment.py

113 lines
6.0 KiB
Python

import json
import os
from pathlib import Path
import subprocess
import tempfile
import unittest
BIN = Path(__file__).resolve().parents[1] / 'linuxfs/overlay/usr/local/bin'
class SteamCompatEnvironmentTest(unittest.TestCase):
def test_library_launch_preserves_guest_environment_without_steam_client_libraries(self):
source = (BIN / 'droiddeck-session').read_text()
setup = source[source.index(' _bl_compat_env='):source.index(' export SDL_VIDEO_X11_DGAMOUSE=')]
launch = next(line for line in source.splitlines()
if 'droiddeck-steam-compat "$steam_root"' in line)
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
helper = root / 'droiddeck-steam-compat'
helper.write_text('#!/usr/bin/env python3\nimport json, os, sys\n'
'json.dump({"env": dict(os.environ), "args": sys.argv[1:]}, '
'open(os.environ["BRIDGE_CAPTURE"], "w"))\n')
helper.chmod(0o755)
for inherited in ({}, {'LD_LIBRARY_PATH': '/guest/driver:/guest/libs'},
{'LD_LIBRARY_PATH': '', 'STEAM_RUNTIME': ''},
{'LD_LIBRARY_PATH': '/custom path/lib', 'STEAM_RUNTIME': '0'}):
with self.subTest(inherited=inherited):
env = dict(os.environ, PATH=str(root) + os.pathsep + os.environ['PATH'],
BRIDGE_CAPTURE=str(root / 'captured.json'),
VK_ICD_FILENAMES='/guest/driver/turnip.json', steam_root='/steam')
for key in ('LD_LIBRARY_PATH', 'STEAM_RUNTIME'):
env.pop(key, None)
env.update(inherited)
result = subprocess.run(['bash', '-c', setup + '\n' + launch + '\nwait $!\n'
'printf "%s\\n" "$STEAM_RUNTIME" "$LD_LIBRARY_PATH"'],
env=env, capture_output=True, text=True, timeout=10)
self.assertEqual(result.returncode, 0, result.stderr)
bridge = json.loads((root / 'captured.json').read_text())
self.assertEqual(bridge['args'], ['/steam'])
for key in ('LD_LIBRARY_PATH', 'STEAM_RUNTIME', 'VK_ICD_FILENAMES'):
self.assertEqual(bridge['env'].get(key), env.get(key), key)
client_path = '/steam/steamrtarm64:/steam/steamrtarm64/panorama'
if inherited.get('LD_LIBRARY_PATH'):
client_path += ':' + inherited['LD_LIBRARY_PATH']
self.assertEqual(result.stdout.splitlines(), ['1', client_path])
def test_session_exit_stops_the_library_helper(self):
source = (BIN / 'droiddeck-session').read_text()
launch = next(line for line in source.splitlines()
if 'droiddeck-steam-compat "$steam_root"' in line)
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
pid = root / 'pid'
helper = root / 'droiddeck-steam-compat'
helper.write_text('#!/bin/sh\necho $$ > "$PID_FILE"\nexec sleep 30\n')
helper.chmod(0o755)
env = dict(os.environ, PATH=str(root) + os.pathsep + os.environ['PATH'],
PID_FILE=str(pid), steam_root='/steam', steam_x64='0')
subprocess.run(['bash', '-c', '_bl_compat_env=(env)\n' + launch + '\n'
'until [ -s "$PID_FILE" ]; do sleep 0.05; done\n'
'kill $(jobs -p)\nwait'],
env=env, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=10)
helper_pid = int(pid.read_text())
try:
os.kill(helper_pid, 0)
except ProcessLookupError:
return
os.kill(helper_pid, 9)
self.fail('droiddeck-steam-compat outlived the session')
def test_the_x86_64_client_gets_only_the_file_dialog_bridge(self):
source = (BIN / 'droiddeck-session').read_text()
start = source.index(' if [ "$steam_x64" = 1 ]; then\n { droiddeck-steam-compat --files-only')
block = source[start:source.index(' fi\n', start) + len(' fi\n')]
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
helper = root / 'droiddeck-steam-compat'
helper.write_text('#!/bin/sh\necho "$@" >> "$ARGS_FILE"\n')
helper.chmod(0o755)
for x64, expected in (('1', '--files-only /steam'), ('0', '/steam')):
with self.subTest(x64=x64):
args = root / ('args-' + x64)
env = dict(os.environ, PATH=str(root) + os.pathsep + os.environ['PATH'],
ARGS_FILE=str(args), steam_root='/steam', steam_x64=x64)
subprocess.run(['bash', '-c', '_bl_compat_env=(env)\n' + block + 'wait\n'], env=env, timeout=10, check=True)
self.assertEqual(args.read_text().split('\n')[0], expected)
def test_files_only_mode_installs_only_the_file_dialog_hook(self):
import runpy
compat = runpy.run_path(str(BIN / 'droiddeck-steam-compat'))
calls = []
class Page:
def __init__(self, port, path):
self.ws = None
def evaluate(self, expression):
calls.append(('evaluate', expression[:40]))
return True
def call(self, method, params):
calls.append((method, params['name']))
helper = compat['Helper']('/steam', 1234, files_only=True)
helper.attach.__globals__.update(shared_context=lambda port: '/devtools/page/1', Page=Page)
self.assertTrue(helper.attach())
bindings = [name for method, name in calls if method == 'Runtime.addBinding']
self.assertEqual(bindings, [compat['FILE_BINDING']])
self.assertIn(('evaluate', compat['FILE_JS'][:40]), calls)
if __name__ == '__main__':
unittest.main()