mirror of
https://github.com/xemu-project/xemu-test.git
synced 2024-11-23 09:59:38 +00:00
Basic testing
This commit is contained in:
parent
dbdbc1424a
commit
06452f4d88
46
.github/workflows/build_docker_image.yml
vendored
Normal file
46
.github/workflows/build_docker_image.yml
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
name: Build Docker image
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: master
|
||||
paths:
|
||||
- 'test-container/**'
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
jobs:
|
||||
main:
|
||||
name: Build and Publish Image
|
||||
if: github.repository_owner == 'mborgerson'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- name: Clone Tree
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Extract image metadata (tags, labels)
|
||||
id: meta
|
||||
uses: docker/metadata-action@v3
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v1
|
||||
if: github.event_name != 'pull_request'
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build and push image
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: test-container
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
results
|
||||
bios.bin
|
||||
mcpx.bin
|
||||
xemu.ini
|
||||
xemu.deb
|
49
test-container/Dockerfile
Normal file
49
test-container/Dockerfile
Normal file
@ -0,0 +1,49 @@
|
||||
FROM ubuntu:20.04
|
||||
RUN apt-get update \
|
||||
&& DEBIAN_FRONTEND=noninteractive apt-get install -qy fuse build-essential pkg-config libfuse-dev cmake git
|
||||
RUN mkdir -p /usr/src \
|
||||
&& git clone https://github.com/mborgerson/fatx.git /usr/src/fatx
|
||||
WORKDIR /usr/src/fatx
|
||||
RUN mkdir build \
|
||||
&& cd build \
|
||||
&& cmake .. \
|
||||
&& make DESTDIR=/fatx install
|
||||
|
||||
FROM ubuntu:20.04
|
||||
RUN set -xe; \
|
||||
apt-get -qy update \
|
||||
&& DEBIAN_FRONTEND=noninteractive \
|
||||
apt-get -qy install \
|
||||
xvfb \
|
||||
x11-utils \
|
||||
x11vnc \
|
||||
xinit \
|
||||
ffmpeg \
|
||||
i3 \
|
||||
fuse \
|
||||
qemu-utils \
|
||||
libc6 \
|
||||
libepoxy0 \
|
||||
libgcc-s1 \
|
||||
libglib2.0-0 \
|
||||
libgtk-3-0 \
|
||||
libpcap0.8 \
|
||||
libpixman-1-0 \
|
||||
libpulse0 \
|
||||
libsamplerate0 \
|
||||
libsdl2-2.0-0 \
|
||||
libssl1.1 \
|
||||
libstdc++6 \
|
||||
zlib1g \
|
||||
cpu-checker \
|
||||
;
|
||||
|
||||
COPY --from=0 /fatx /fatx
|
||||
RUN cp -ruT /fatx / && rm -rf /fatx
|
||||
|
||||
ENV SDL_AUDIODRIVER=disk
|
||||
ENV SDL_DISKAUDIOFILE=/dev/null
|
||||
EXPOSE 5900
|
||||
|
||||
COPY ./docker_entry.sh /usr/local/bin/docker_entry.sh
|
||||
ENTRYPOINT ["/usr/local/bin/docker_entry.sh"]
|
34
test-container/docker_entry.sh
Executable file
34
test-container/docker_entry.sh
Executable file
@ -0,0 +1,34 @@
|
||||
#!/bin/bash
|
||||
XVFB_WHD=640x480x24
|
||||
DISPLAY=:99
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "No launch command provided"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -e
|
||||
echo "[*] Installing xemu package"
|
||||
apt-get -qy install /work/xemu.deb
|
||||
|
||||
echo "exec i3" >> ~/.xinitrc
|
||||
chmod +x ~/.xinitrc
|
||||
mkdir -p ~/.config/i3
|
||||
echo "border none" >> ~/.config/i3/config
|
||||
|
||||
echo "[*] Starting Xvfb"
|
||||
xinit -- /usr/bin/Xvfb $DISPLAY -ac -screen 0 "$XVFB_WHD" -nolisten tcp +extension GLX +render -noreset &
|
||||
Xvfb_pid="$!"
|
||||
echo "[~] Waiting for Xvfb (PID: $Xvfb_pid) to be ready..."
|
||||
set +e
|
||||
while ! xdpyinfo -display "${DISPLAY}" 1>/dev/null 2>&1; do
|
||||
sleep 0.1
|
||||
done
|
||||
set -e
|
||||
export DISPLAY
|
||||
|
||||
echo "[*] Starting VNC server"
|
||||
x11vnc -forever 1>/dev/null 2>&1 &
|
||||
|
||||
echo "[*] Running target command"
|
||||
exec "$@"
|
5
test-xbe/.gitignore
vendored
Normal file
5
test-xbe/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
bin
|
||||
*.d
|
||||
*.exe
|
||||
*.obj
|
||||
*.iso
|
6
test-xbe/Makefile
Normal file
6
test-xbe/Makefile
Normal file
@ -0,0 +1,6 @@
|
||||
XBE_TITLE = tester
|
||||
GEN_XISO = $(XBE_TITLE).iso
|
||||
SRCS = $(CURDIR)/main.c
|
||||
NXDK_DIR ?= $(CURDIR)/../..
|
||||
|
||||
include $(NXDK_DIR)/Makefile
|
38
test-xbe/main.c
Normal file
38
test-xbe/main.c
Normal file
@ -0,0 +1,38 @@
|
||||
#include <hal/debug.h>
|
||||
#include <hal/video.h>
|
||||
#include <windows.h>
|
||||
#include <nxdk/mount.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
XVideoSetMode(640, 480, 32, REFRESH_DEFAULT);
|
||||
|
||||
debugPrint("Hello nxdk!\n");
|
||||
|
||||
BOOL ret = nxMountDrive('C', "\\Device\\Harddisk0\\Partition2\\");
|
||||
if (!ret) {
|
||||
debugPrint("Failed to mount C: drive!\n");
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
CreateDirectoryA("C:\\results", NULL);
|
||||
|
||||
FILE *f = fopen("C:\\results\\results.txt", "w");
|
||||
if (!f) {
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
const char *buf = "Success";
|
||||
fwrite(buf, strlen(buf), 1, f);
|
||||
fclose(f);
|
||||
|
||||
shutdown:
|
||||
HalInitiateShutdown();
|
||||
while (1) {
|
||||
Sleep(2000);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
36
test.sh
Executable file
36
test.sh
Executable file
@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
set -o pipefail
|
||||
|
||||
SUPPORT_DIR=private
|
||||
SUPPORT_ARCHIVE=${SUPPORT_DIR}.zip
|
||||
SUPPORT_ARCHIVE_ENC=${SUPPORT_ARCHIVE}.enc
|
||||
SUPPORT_URL=${SUPPORT_URL:-http://localhost:8080/${SUPPORT_ARCHIVE_ENC}}
|
||||
|
||||
if [[ ! -d ${SUPPORT_DIR} ]]; then
|
||||
if [[ ! -e ${SUPPORT_ARCHIVE} ]]; then
|
||||
if [[ ! -e ${SUPPORT_ARCHIVE_ENC} ]]; then
|
||||
echo "[*] Downloading ${SUPPORT_ARCHIVE_ENC}"
|
||||
wget -O ${SUPPORT_ARCHIVE_ENC} ${SUPPORT_URL} 1>/dev/null 2>&1
|
||||
fi
|
||||
echo "[*] Decrypting ${SUPPORT_ARCHIVE}"
|
||||
gpg --quiet --batch --yes --decrypt --passphrase="$SUPPORT_PASSPHRASE" \
|
||||
--output ./${SUPPORT_ARCHIVE} ${SUPPORT_ARCHIVE_ENC}
|
||||
fi
|
||||
|
||||
unzip ${SUPPORT_ARCHIVE}
|
||||
fi
|
||||
|
||||
echo "[*] Building test executable"
|
||||
docker run --rm -v $PWD/test-xbe:/work -w /work ghcr.io/xboxdev/nxdk make
|
||||
|
||||
echo "[*] Pulling test container"
|
||||
docker pull ghcr.io/mborgerson/xemu-test:master
|
||||
|
||||
echo "[*] Running tests"
|
||||
rm -rf results
|
||||
mkdir results
|
||||
docker run --rm -p 5900:5900 -v $PWD:/work -w /work --device /dev/fuse \
|
||||
--privileged \
|
||||
ghcr.io/mborgerson/xemu-test:master \
|
||||
python3 test_main.py 2>&1 | tee results/log.txt
|
109
test_main.py
Normal file
109
test_main.py
Normal file
@ -0,0 +1,109 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import subprocess
|
||||
import shutil
|
||||
import logging
|
||||
import os
|
||||
import signal
|
||||
import time
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
_l = logging.getLogger(__file__)
|
||||
|
||||
class Test:
|
||||
def __init__(self):
|
||||
self.flash_path = '/work/private/bios.bin'
|
||||
self.mcpx_path = '/work/private/mcpx.bin'
|
||||
self.blank_hdd_path = '/work/xbox_hdd.qcow2'
|
||||
self.hdd_path = '/tmp/test.img'
|
||||
self.mount_path = '/tmp/xemu-hdd-mount'
|
||||
self.iso_path = '/work/test-xbe/tester.iso'
|
||||
self.results_in_path = os.path.join(self.mount_path, 'results')
|
||||
self.results_out_path = '/work/results'
|
||||
self.video_capture_path = os.path.join(self.results_out_path, 'capture.mp4')
|
||||
self.timeout = 60
|
||||
|
||||
def prepare_roms(self):
|
||||
_l.info('Preparing ROM images')
|
||||
# TODO
|
||||
|
||||
def prepare_hdd(self):
|
||||
_l.info('Preparing HDD image')
|
||||
subprocess.run(f'qemu-img convert {self.blank_hdd_path} {self.hdd_path}'.split(), check=True)
|
||||
|
||||
def prepare_config(self):
|
||||
config = ('[system]\n'
|
||||
f'flash_path = {self.flash_path}\n'
|
||||
f'bootrom_path = {self.mcpx_path}\n'
|
||||
f'hdd_path = {self.hdd_path}\n'
|
||||
'shortanim = true\n'
|
||||
)
|
||||
_l.info('Prepared config file:\n%s', config)
|
||||
with open('xemu.ini', 'w') as f:
|
||||
f.write(config)
|
||||
|
||||
def launch_ffmpeg(self):
|
||||
_l.info('Launching FFMPEG (capturing to %s)', self.video_capture_path)
|
||||
c = ('/usr/bin/ffmpeg -loglevel error '
|
||||
f'-video_size 640x480 -f x11grab -i {os.getenv("DISPLAY")} '
|
||||
f'-c:v libx264 -preset fast -profile:v baseline -pix_fmt yuv420p '
|
||||
f'{self.video_capture_path} -y')
|
||||
self.ffmpeg = subprocess.Popen(c.split())
|
||||
|
||||
def terminate_ffmpeg(self):
|
||||
_l.info('Shutting down FFMPEG')
|
||||
self.ffmpeg.send_signal(signal.SIGINT)
|
||||
for _ in range(10):
|
||||
self.ffmpeg.poll()
|
||||
if self.ffmpeg.returncode is not None:
|
||||
_l.info('FFMPEG exited %d', self.ffmpeg.returncode)
|
||||
break
|
||||
time.sleep(0.1)
|
||||
self.ffmpeg.poll()
|
||||
if self.ffmpeg.returncode is None:
|
||||
_l.warning('Terminating FFMPEG')
|
||||
self.ffmpeg.terminate()
|
||||
|
||||
def launch_xemu(self):
|
||||
_l.info('Launching xemu...')
|
||||
c = (f'timeout {self.timeout} '
|
||||
f'xemu -config_path ./xemu.ini -dvd_path {self.iso_path} '
|
||||
'-full-screen')
|
||||
subprocess.run(c.split())
|
||||
|
||||
def mount_hdd(self):
|
||||
_l.info('Mounting HDD image')
|
||||
os.makedirs(self.mount_path, exist_ok=True)
|
||||
subprocess.run(f'fatxfs {self.hdd_path} {self.mount_path}'.split(), check=True)
|
||||
|
||||
def copy_results(self):
|
||||
_l.info('Copying test results...')
|
||||
shutil.copytree(self.results_in_path, self.results_out_path, dirs_exist_ok=True)
|
||||
|
||||
def unmount_hdd(self):
|
||||
_l.info('Unmounting HDD image')
|
||||
subprocess.run(f'fusermount -u {self.mount_path}'.split())
|
||||
|
||||
def analyze_results(self):
|
||||
with open(os.path.join(self.results_out_path, 'results.txt')) as f:
|
||||
assert(f.read().strip() == 'Success')
|
||||
|
||||
def run(self):
|
||||
os.makedirs(self.results_out_path, exist_ok=True)
|
||||
self.prepare_roms()
|
||||
self.prepare_hdd()
|
||||
self.prepare_config()
|
||||
self.launch_ffmpeg()
|
||||
self.launch_xemu()
|
||||
self.terminate_ffmpeg()
|
||||
self.mount_hdd()
|
||||
self.copy_results()
|
||||
self.unmount_hdd()
|
||||
self.analyze_results()
|
||||
|
||||
def main():
|
||||
test = Test()
|
||||
test.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
BIN
xbox_hdd.qcow2
Normal file
BIN
xbox_hdd.qcow2
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user