Reorganize

This commit is contained in:
Matt Borgerson 2022-02-28 13:14:59 -07:00
parent c9516d3abb
commit b9980e8f4c
9 changed files with 160 additions and 104 deletions

5
.gitignore vendored
View File

@ -1,5 +0,0 @@
results
bios.bin
mcpx.bin
xemu.ini
xemu.deb

79
Dockerfile Normal file
View File

@ -0,0 +1,79 @@
#
# Build base test container image
#
FROM ubuntu:20.04 as run-container-base
ENV DEBIAN_FRONTEND=noninteractive
RUN set -xe; \
apt-get -qy update \
&& apt-get -qy install \
python3-pip \
xvfb \
x11-utils \
x11vnc \
xinit \
ffmpeg \
i3 \
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 \
;
#
# Build pyfatx for HDD management
#
FROM ubuntu:20.04 AS pyfatx
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update \
&& apt-get install -qy \
build-essential \
cmake \
git \
python3-pip
RUN git clone --depth=1 https://github.com/mborgerson/fatx \
&& mkdir -p /whl \
&& python3 -m pip wheel -w /whl ./fatx
#
# Build test ISO
#
FROM ghcr.io/xboxdev/nxdk AS test-iso-1
COPY test-xbe /test-xbe
RUN /usr/src/nxdk/docker_entry.sh make -C /test-xbe
#
# Build final test container
#
FROM run-container-base
RUN useradd -ms /bin/bash user
COPY --from=pyfatx /whl /whl
RUN python3 -m pip install --find-links /whl /whl/pyfatx-*.whl
ENV DEBIAN_FRONTEND=noninteractive
ENV SDL_AUDIODRIVER=dummy
# VNC port for debugging
EXPOSE 5900
COPY docker_entry.sh /docker_entry.sh
ENTRYPOINT ["/docker_entry.sh"]
RUN mkdir /work
COPY test.py /work/test.py
COPY xbox_hdd.qcow2 /work/xbox_hdd.qcow2
COPY --from=test-iso-1 /test-xbe/tester.iso /work/tester.iso
WORKDIR /work
CMD ["/usr/bin/python3", "/work/test.py"]

43
README.md Normal file
View File

@ -0,0 +1,43 @@
xemu Automated Testing
======================
Performs a suite of tests against a build of xemu, capturing test results and
footage of the runs. Primarily used for CI testing of xemu.
Containerized Testing
---------------------
This testing system is intended to be able to be run inside a container for
reproducability and for regular testing on cheap cloud VMs.
To build the container image:
docker build -t xemu-test .
This repository also has GitHub actions set up to automatically build and
publish the container image to the GitHub container registry, so you can pull
that image for testing:
docker pull ghcr.io/mborgerson/xemu-test:master
Set up the following dir structure:
- /work/results: Results will be copied here
- /work/private: Directory for ROMs and other files
- /work/private/mcpx.bin
- /work/private/bios.bin
- /work/inputs: Directory containing xemu build to test
- /work/xemu.deb
Then run with something like:
docker run --rm -it \
-v $PWD/results:/work/results \
-v $PWD/private:/work/private \
-v $PWD/inputs:/work/inputs \
-p 5900:5900 \
ghcr.io/mborgerson/xemu-test:master
xemu is running headless when in the container, so if you need to interact with
it you can connect to the container VNC server with:
xtightvncviewer 127.0.0.1

View File

@ -1,4 +1,6 @@
#!/bin/bash #!/bin/bash
exec 2>&1
XVFB_WHD=640x480x24 XVFB_WHD=640x480x24
DISPLAY=:99 DISPLAY=:99
@ -9,15 +11,18 @@ fi
set -e set -e
echo "[*] Installing xemu package" echo "[*] Installing xemu package"
apt-get -qy install /work/xemu.deb apt-get -qy install /work/inputs/xemu.deb
echo "exec i3" >> ~/.xinitrc echo "exec i3" >> ~/.xinitrc
chmod +x ~/.xinitrc chmod +x ~/.xinitrc
mkdir -p ~/.config/i3 mkdir -p ~/.config/i3
echo "border none" >> ~/.config/i3/config cat <<EOF >>~/.config/i3/config
border none
EOF
echo "[*] Starting Xvfb" echo "[*] Starting Xvfb"
xinit -- /usr/bin/Xvfb $DISPLAY -ac -screen 0 "$XVFB_WHD" -nolisten tcp +extension GLX +render -noreset & xinit -- /usr/bin/Xvfb $DISPLAY -ac -screen 0 "$XVFB_WHD" -nolisten tcp +extension GLX +render -noreset & 1>/dev/null 2>&1 &
Xvfb_pid="$!" Xvfb_pid="$!"
echo "[~] Waiting for Xvfb (PID: $Xvfb_pid) to be ready..." echo "[~] Waiting for Xvfb (PID: $Xvfb_pid) to be ready..."
set +e set +e

View File

@ -1,48 +0,0 @@
FROM ubuntu:20.04
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive \
apt-get install -qy \
build-essential cmake git python3-pip
RUN git clone --depth=1 https://github.com/mborgerson/fatx \
&& cd fatx \
&& mkdir -p /whl \
&& python3 -m pip wheel -w /whl .
FROM ubuntu:20.04
RUN set -xe; \
apt-get -qy update \
&& DEBIAN_FRONTEND=noninteractive \
apt-get -qy install \
python3-pip \
xvfb \
x11-utils \
x11vnc \
xinit \
ffmpeg \
i3 \
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 /whl /whl
RUN python3 -m pip install --find-links /whl /whl/pyfatx-*.whl
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"]

5
test-xbe/.gitignore vendored
View File

@ -1,5 +0,0 @@
bin
*.d
*.exe
*.obj
*.iso

View File

@ -1,4 +1,5 @@
#include <hal/debug.h> #include <hal/debug.h>
#include <hal/video.h> #include <hal/video.h>
#include <windows.h> #include <windows.h>
#include <nxdk/mount.h> #include <nxdk/mount.h>
@ -9,7 +10,10 @@ int main(void)
{ {
XVideoSetMode(640, 480, 32, REFRESH_DEFAULT); XVideoSetMode(640, 480, 32, REFRESH_DEFAULT);
debugPrint("Hello nxdk!\n"); for (int i = 0; i < 10; i++) {
debugPrint("Hello nxdk!\n");
Sleep(500);
}
BOOL ret = nxMountDrive('C', "\\Device\\Harddisk0\\Partition2\\"); BOOL ret = nxMountDrive('C', "\\Device\\Harddisk0\\Partition2\\");
if (!ret) { if (!ret) {
@ -28,6 +32,7 @@ int main(void)
fwrite(buf, strlen(buf), 1, f); fwrite(buf, strlen(buf), 1, f);
fclose(f); fclose(f);
shutdown: shutdown:
HalInitiateShutdown(); HalInitiateShutdown();
while (1) { while (1) {

31
test_main.py → test.py Normal file → Executable file
View File

@ -11,13 +11,21 @@ logging.basicConfig(level=logging.INFO)
_l = logging.getLogger(__file__) _l = logging.getLogger(__file__)
class Test: class Test:
"""
Test provides a basic framework that:
- Starts FFMPEG to record footage of xemu while it runs
- Launches xemu with an test XBE loaded from a disc image
- Waits for xemu to shutdown or timeout
- Inspect the filesystem for test results
"""
def __init__(self): def __init__(self):
self.flash_path = '/work/private/bios.bin' self.flash_path = '/work/private/bios.bin'
self.mcpx_path = '/work/private/mcpx.bin' self.mcpx_path = '/work/private/mcpx.bin'
self.blank_hdd_path = '/work/xbox_hdd.qcow2' self.blank_hdd_path = '/work/xbox_hdd.qcow2'
self.hdd_path = '/tmp/test.img' self.hdd_path = '/tmp/test.img'
self.mount_path = '/tmp/xemu-hdd-mount' self.mount_path = '/tmp/xemu-hdd-mount'
self.iso_path = '/work/test-xbe/tester.iso' self.iso_path = '/work/tester.iso'
self.results_in_path = os.path.join(self.mount_path, 'results') self.results_in_path = os.path.join(self.mount_path, 'results')
self.results_out_path = '/work/results' self.results_out_path = '/work/results'
self.video_capture_path = os.path.join(self.results_out_path, 'capture.mp4') self.video_capture_path = os.path.join(self.results_out_path, 'capture.mp4')
@ -25,10 +33,11 @@ class Test:
def prepare_roms(self): def prepare_roms(self):
_l.info('Preparing ROM images') _l.info('Preparing ROM images')
# TODO # Nothing to do here yet
def prepare_hdd(self): def prepare_hdd(self):
_l.info('Preparing HDD image') _l.info('Preparing HDD image')
# FIXME: Replace qcow2 with pyfatx disk init
subprocess.run(f'qemu-img convert {self.blank_hdd_path} {self.hdd_path}'.split(), check=True) subprocess.run(f'qemu-img convert {self.blank_hdd_path} {self.hdd_path}'.split(), check=True)
def prepare_config(self): def prepare_config(self):
@ -67,9 +76,8 @@ class Test:
def launch_xemu(self): def launch_xemu(self):
_l.info('Launching xemu...') _l.info('Launching xemu...')
c = (f'timeout {self.timeout} ' c = (f'timeout {self.timeout} '
f'xemu -config_path ./xemu.ini -dvd_path {self.iso_path} ' f'xemu -config_path ./xemu.ini -dvd_path {self.iso_path} -full-screen')
'-full-screen') subprocess.run(c.split(), check=True)
subprocess.run(c.split())
def mount_hdd(self): def mount_hdd(self):
_l.info('Mounting HDD image') _l.info('Mounting HDD image')
@ -102,8 +110,17 @@ class Test:
self.analyze_results() self.analyze_results()
def main(): def main():
test = Test() result = True
test.run() tests = [Test]
for test_cls in tests:
try:
test_cls().run()
print('Test passed!')
except:
_l.exception('Test failed!')
result = False
exit(0 if result else 1)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

35
test.sh
View File

@ -1,35 +0,0 @@
#!/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 \
ghcr.io/mborgerson/xemu-test:master \
python3 test_main.py 2>&1 | tee results/log.txt