From 7ba17cff18912c64771f82d2d68a5480109460d1 Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Sat, 23 Sep 2023 20:24:57 -0400 Subject: [PATCH 1/8] Reflow actions completely Add a "test" action instead of a "citra" action. It might still be useful to have the citra action for examples later on but it's pretty simple to reimplement. --- .github/actions/citra/action.yml | 12 --------- .github/actions/setup/action.yml | 11 ++------ .github/actions/test/action.yml | 33 ++++++++++++++++++++++++ .github/workflows/ci.yml | 43 +++++++++++++------------------- 4 files changed, 52 insertions(+), 47 deletions(-) delete mode 100644 .github/actions/citra/action.yml create mode 100644 .github/actions/test/action.yml diff --git a/.github/actions/citra/action.yml b/.github/actions/citra/action.yml deleted file mode 100644 index 18441f0..0000000 --- a/.github/actions/citra/action.yml +++ /dev/null @@ -1,12 +0,0 @@ -name: 'Run 3DS Executable' -description: 'Run a given 3DS executable with citra and GDB' -inputs: - executable: - description: > - The 3DS executable(s) to run. Globs and space separated lists allowed. - required: true -runs: - using: docker - image: ../../../Dockerfile - args: - - ${{ inputs.executable }} diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 95629df..b5a7f37 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -10,14 +10,6 @@ inputs: runs: using: composite steps: - # https://github.com/nektos/act/issues/917#issuecomment-1074421318 - - if: ${{ env.ACT }} - shell: bash - name: Hack container for local development - run: | - curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - - sudo apt-get install -y nodejs - - name: Setup default Rust toolchain # Use this helper action so we get matcher support # https://github.com/actions-rust-lang/setup-rust-toolchain/pull/15 @@ -25,6 +17,7 @@ runs: with: components: clippy, rustfmt, rust-src toolchain: ${{ inputs.toolchain }} + rustflags: "" - name: Set up Rust cache uses: Swatinem/rust-cache@v2 @@ -38,7 +31,7 @@ runs: - name: Install cargo-3ds shell: bash # TODO: replace with crates.io version once published - run: cargo install --git https://github.com/rust3ds/cargo-3ds --branch feature/verbose-flag + run: cargo install --locked --git https://github.com/rust3ds/cargo-3ds - name: Set PATH to include devkitARM shell: bash diff --git a/.github/actions/test/action.yml b/.github/actions/test/action.yml new file mode 100644 index 0000000..b4d6f2f --- /dev/null +++ b/.github/actions/test/action.yml @@ -0,0 +1,33 @@ +name: Cargo 3DS Test +description: > + Run `cargo 3ds test` executables using Citra. Note that to use this action, + you must mount `/var/run/docker.sock:/var/run/docker.sock` and `/tmp:/tmp` into + the container so that the runner image can be built and doctest artifacts can + be found, respectively. + +inputs: + args: + description: > + Extra arguments to pass to `cargo 3ds test` + required: false + default: '' + +runs: + using: composite + steps: + - name: Build test-runner image + uses: docker/build-push-action@v2 + with: + tags: test-runner-3ds:latest + push: false + + - shell: bash + env: + # Set a custom runner for `cargo test` commands to use + CARGO_TARGET_ARMV6K_NINTENDO_3DS_RUNNER: |- + docker run --rm \ + -v /tmp:/tmp \ + -v ${{ github.workspace }}/target:/app/target \ + -v ${{ github.workspace }}:${{ github.workspace }} \ + test-runner-3ds:latest + run: cargo 3ds test ${{ inputs.args }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 04d0614..aa7ee03 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,10 +9,6 @@ on: - main workflow_dispatch: -env: - # actions-rust-lang/setup-rust-toolchain sets some default RUSTFLAGS, which we don't want to use - RUSTFLAGS: "" - jobs: lint: strategy: @@ -34,8 +30,7 @@ jobs: run: cargo fmt --all --verbose -- --check - name: Run clippy - # We have to build the test crate here since it's not included in build-std by default - run: cargo 3ds clippy -Zbuild-std=std,test --color=always --verbose --all-targets + run: cargo 3ds clippy --color=always --verbose --all-targets test: strategy: @@ -47,7 +42,6 @@ jobs: continue-on-error: ${{ matrix.toolchain == 'nightly' }} runs-on: ubuntu-latest - container: devkitpro/devkitarm steps: - name: Checkout branch uses: actions/checkout@v3 @@ -56,29 +50,26 @@ jobs: with: toolchain: ${{ matrix.toolchain }} - - name: Build lib tests - run: cargo 3ds test --no-run --lib - - - name: Build integration tests - run: cargo 3ds test --no-run --test integration - - - name: Build doc tests - run: cargo 3ds test --no-run --doc - - - name: Run lib + integration tests - uses: ./.github/actions/citra + - name: Build and run tests (unit + integration) + uses: ./.github/actions/test + + - name: Build and run doc tests + # Let's still run doc tests even if lib/integration tests fail: + if: ${{ !cancelled() }} + env: + # This ensures the citra logs and video output gets put in a directory + # where we can upload as artifacts + RUSTDOCFLAGS: " --persist-doctests target/armv6k-nintendo-3ds/debug/doctests" + uses: ./.github/actions/test with: - executable: ./target/armv6k-nintendo-3ds/debug/deps/*.elf - - # TODO: run doc tests. We might be able to do something with e.g. - # cargo's "runner" configuration, but it seems we also need a test - # runtime and stuff for that to work. + args: --doc - name: Upload citra logs and capture videos uses: actions/upload-artifact@v3 - if: success() || failure() + # We always want to upload artifacts regardless of previous success/failure + if: ${{ !cancelled() }} with: name: citra-logs-${{ matrix.toolchain }} path: | - target/armv6k-nintendo-3ds/debug/deps/*.txt - target/armv6k-nintendo-3ds/debug/deps/*.webm + target/armv6k-nintendo-3ds/debug/**/*.txt + target/armv6k-nintendo-3ds/debug/**/*.webm From 5c29862e2df17800c82df1e4417904760ae66bae Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Sat, 23 Sep 2023 20:53:19 -0400 Subject: [PATCH 2/8] Fix ENV from devkitarm image in dockerfile Also try to fix citra download even though I don't know what's wrong yet. --- .github/actions/setup/action.yml | 3 ++- .github/actions/test/action.yml | 36 ++++++++++++++++++++------------ .github/workflows/ci.yml | 9 +++++++- Dockerfile | 17 ++++++++------- docker/download_citra.sh | 2 +- 5 files changed, 44 insertions(+), 23 deletions(-) diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index b5a7f37..0352153 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -17,12 +17,13 @@ runs: with: components: clippy, rustfmt, rust-src toolchain: ${{ inputs.toolchain }} + cache: "false" # We set up our own cache manually in the next step rustflags: "" - name: Set up Rust cache uses: Swatinem/rust-cache@v2 with: - shared-key: rust3ds + cache-on-failure: "true" - name: Install build tools for host shell: bash diff --git a/.github/actions/test/action.yml b/.github/actions/test/action.yml index b4d6f2f..98dffea 100644 --- a/.github/actions/test/action.yml +++ b/.github/actions/test/action.yml @@ -7,27 +7,37 @@ description: > inputs: args: - description: > - Extra arguments to pass to `cargo 3ds test` + description: Extra arguments to pass to `cargo 3ds test` required: false default: '' + runner-image: + description: The name of the container image to build for running tests in + required: false + default: test-runner-3ds + runs: using: composite steps: + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Build test-runner image - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v4 with: - tags: test-runner-3ds:latest + tags: ${{ inputs.runner-image }}:latest push: false - shell: bash - env: - # Set a custom runner for `cargo test` commands to use - CARGO_TARGET_ARMV6K_NINTENDO_3DS_RUNNER: |- - docker run --rm \ - -v /tmp:/tmp \ - -v ${{ github.workspace }}/target:/app/target \ - -v ${{ github.workspace }}:${{ github.workspace }} \ - test-runner-3ds:latest - run: cargo 3ds test ${{ inputs.args }} + # Set a custom runner for `cargo test` commands to use. + # Use ${GITHUB_WORKSPACE} due to + # https://github.com/actions/runner/issues/2058, which also means + # we have to export this instead of using the env: key + run: | + export CARGO_TARGET_ARMV6K_NINTENDO_3DS_RUNNER="docker run --rm + -v /tmp:/tmp + -v ${GITHUB_WORKSPACE}/target:/app/target + -v ${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE} + ${{ inputs.runner-image }}:latest" + env + cargo 3ds -v test ${{ inputs.args }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aa7ee03..5016854 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,6 +42,11 @@ jobs: continue-on-error: ${{ matrix.toolchain == 'nightly' }} runs-on: ubuntu-latest + container: + image: devkitpro/devkitarm + volumes: + - '/var/run/docker.sock:/var/run/docker.sock' + steps: - name: Checkout branch uses: actions/checkout@v3 @@ -52,6 +57,8 @@ jobs: - name: Build and run tests (unit + integration) uses: ./.github/actions/test + with: + args: -- -v - name: Build and run doc tests # Let's still run doc tests even if lib/integration tests fail: @@ -62,7 +69,7 @@ jobs: RUSTDOCFLAGS: " --persist-doctests target/armv6k-nintendo-3ds/debug/doctests" uses: ./.github/actions/test with: - args: --doc + args: --doc -- -v - name: Upload citra logs and capture videos uses: actions/upload-artifact@v3 diff --git a/Dockerfile b/Dockerfile index f183e67..1e81737 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,14 +1,12 @@ FROM buildpack-deps:latest as builder -ARG CITRA_CHANNEL=nightly -ARG CITRA_RELEASE=1962 - WORKDIR /tmp COPY ./docker/download_citra.sh /usr/local/bin/download_citra RUN apt-get update -y && apt-get install -y jq -RUN download_citra ${CITRA_CHANNEL} ${CITRA_RELEASE} -FROM devkitpro/devkitarm:latest as devkitarm +ARG CITRA_CHANNEL=nightly +ARG CITRA_RELEASE=1995 +RUN download_citra ${CITRA_CHANNEL} ${CITRA_RELEASE} FROM ubuntu:latest @@ -21,8 +19,13 @@ RUN --mount=type=cache,sharing=locked,target=/var/cache/apt \ libavfilter7 \ xvfb -COPY --from=devkitarm /opt/devkitpro /opt/devkitpro -ENV PATH=/opt/devkitpro/devkitARM/bin:${PATH} +COPY --from=devkitpro/devkitarm:latest /opt/devkitpro /opt/devkitpro +# There's no way to copy ENV values from other stages properly: +# https://github.com/moby/moby/issues/37345 +# Luckily in this case we know exactly what the values should be: +ENV DEVKITPRO=/opt/devkitpro +ENV DEVKITARM=${DEVKITPRO}/devkitARM +ENV PATH=${DEVKITARM}/bin:${PATH} COPY --from=builder /tmp/citra.AppImage /usr/local/bin/citra COPY ./docker/sdl2-config.ini /app/ diff --git a/docker/download_citra.sh b/docker/download_citra.sh index ec6699c..fd12cea 100755 --- a/docker/download_citra.sh +++ b/docker/download_citra.sh @@ -9,7 +9,7 @@ RELEASE_API="https://api.github.com/repos/citra-emu/citra-${CITRA_CHANNEL}/relea curl "${RELEASE_API}" | jq --raw-output '.assets[].browser_download_url' | - grep -E 'citra-linux-.*.tar.gz' | + grep -E 'citra-linux-.*[.]tar.gz' | xargs wget -O citra-linux.tar.gz tar --strip-components 1 -xvf citra-linux.tar.gz From 0f7be6f691f271874f626ac11d17de2a16a00fc0 Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Sun, 24 Sep 2023 01:04:36 -0400 Subject: [PATCH 3/8] Overhaul the test-runner entrypoint for one file Make sure docker is installed in our custom action --- .github/actions/test/action.yml | 8 ++- docker/entrypoint.sh | 96 +++++++++++++++++++-------------- 2 files changed, 62 insertions(+), 42 deletions(-) diff --git a/.github/actions/test/action.yml b/.github/actions/test/action.yml index 98dffea..d28d518 100644 --- a/.github/actions/test/action.yml +++ b/.github/actions/test/action.yml @@ -27,8 +27,14 @@ runs: with: tags: ${{ inputs.runner-image }}:latest push: false + load: true - - shell: bash + - name: Ensure docker is installed in the container + shell: bash + run: apt-get update -y && apt-get install docker.io -y + + - name: Run cargo 3ds test + shell: bash # Set a custom runner for `cargo test` commands to use. # Use ${GITHUB_WORKSPACE} due to # https://github.com/actions/runner/issues/2058, which also means diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index a64e91d..e36af9f 100755 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -1,50 +1,64 @@ #!/bin/bash -# Clean up child processes on exit: https://stackoverflow.com/a/2173421/14436105 -trap "pkill -P $$" EXIT INT TERM - -mkdir -p ~/.config/citra-emu -cp /app/sdl2-config.ini ~/.config/citra-emu -# For some reason, log file is only written when this dir already exists, -# but it is only created after the first run of citra (our only run, in the container) -mkdir -p ~/.local/share/citra-emu/ - -ERRS=0 -# shellcheck disable=SC2068 -for EXE in $@; do - VIDEO_OUT="$(dirname "$EXE")/$(basename "$EXE" .elf)_capture.webm" - - # colored logs would be nice, but we can always just grab the plaintext log file - xvfb-run citra \ - --appimage-extract-and-run \ - --dump-video="$VIDEO_OUT" \ - "$EXE" \ - &>/dev/null & - PID=$! - - # Citra takes a little while to start up, so wait a little before we try to connect - sleep 3 - - arm-none-eabi-gdb --silent --batch-silent --command /app/test-runner.gdb "$EXE" - STATUS=$? - if [ $STATUS -ne 0 ]; then - echo >&2 "FAILED (exit status $STATUS): $EXE" - ERRS=$(( ERRS + 1 )) - fi +set -x - kill -INT $PID &>/dev/null - sleep 1 - if kill -0 $PID &>/dev/null; then - kill -KILL $PID &>/dev/null +function cleanup_jobs() { + # shellcheck disable=SC2317 # Unreachable because it's only used in trap + if [ -n "$(jobs -p)" ]; then + sleep 5 & + wait -n + # shellcheck disable=SC2046 # We want to expand jobs here and for `wait` + kill -9 $(jobs -p) + # shellcheck disable=SC2046 + wait $(jobs -p) &>/dev/null fi +} + +trap cleanup_jobs EXIT + +EXE_ELF=$1 +EXE_3DSX="$(dirname "$EXE")/$(basename "$EXE" .elf).3dsx" + +EXE_TO_RUN="$EXE_ELF" +if [ -f "$EXE_3DSX" ]; then + echo >&2 "Found $(basename "$EXE_3DSX"), it will be run instead of $(basename "$EXE_ELF")" + EXE_TO_RUN="$EXE_3DSX" +fi + +VIDEO_OUT="$(dirname "$EXE_ELF")/$(basename "$EXE_ELF" .elf)_capture.webm" + +CITRA_LOG_DIR=~/.local/share/citra-emu/log +CITRA_OUT="$CITRA_LOG_DIR/citra_output.txt" + +xvfb-run --auto-servernum \ + citra \ + --appimage-extract-and-run \ + --dump-video="$VIDEO_OUT" \ + "$EXE_TO_RUN" \ + &>"$CITRA_OUT" & +CITRA_PID=$! + +# Citra takes a little while to start up, so wait a little before we try to connect +sleep 5 + +arm-none-eabi-gdb --silent --batch-silent --command /app/test-runner.gdb "$EXE_ELF" +STATUS=$? + +kill $CITRA_PID +cleanup_jobs + +CITRA_LOG="$CITRA_LOG_DIR/citra_log.txt" - CITRA_LOG=~/.local/share/citra-emu/log/citra_log.txt - CITRA_LOG_OUT="$(dirname "$EXE")/$(basename "$EXE" .elf)_citra_log.txt" - if test -f "$CITRA_LOG"; then - cp "$CITRA_LOG" "$CITRA_LOG_OUT" +for f in "$CITRA_LOG" "$CITRA_OUT"; do + OUT="$(dirname "$EXE_ELF")/$(basename "$EXE_ELF" .elf)_$(basename "$f")" + if test -f "$f"; then + cp "$f" "$OUT" + if [ $STATUS -ne 0 ]; then + echo >&2 "$(basename $f) copied to $OUT" + fi else - echo "WARNING: citra log not found" + echo >&2 "WARNING: $(basename "$f") not found" fi done -exit $ERRS +exit $STATUS From 224865854e44ca5fe87146c360e049fc1d23dd4b Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Sun, 24 Sep 2023 13:08:19 -0400 Subject: [PATCH 4/8] Move actions to top-level for nicer call syntax For external repos this will be a lot simpler --- .github/workflows/ci.yml | 15 +++++++------ Dockerfile | 21 +++++++++++++++++-- README.md | 4 +++- .../actions/test => run-tests}/action.yml | 11 +++++----- {.github/actions/setup => setup}/action.yml | 0 5 files changed, 37 insertions(+), 14 deletions(-) rename {.github/actions/test => run-tests}/action.yml (82%) rename {.github/actions/setup => setup}/action.yml (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5016854..7f9cf4a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,7 @@ jobs: - name: Checkout branch uses: actions/checkout@v2 - - uses: ./.github/actions/setup + - uses: ./actions/setup with: toolchain: ${{ matrix.toolchain }} @@ -45,18 +45,20 @@ jobs: container: image: devkitpro/devkitarm volumes: + # So the test action can `docker run` the runner: - '/var/run/docker.sock:/var/run/docker.sock' - + # So the built test artifacts end up on the host, not just inside the action container + - '/tmp:/tmp' steps: - name: Checkout branch uses: actions/checkout@v3 - - uses: ./.github/actions/setup + - uses: ./setup with: toolchain: ${{ matrix.toolchain }} - name: Build and run tests (unit + integration) - uses: ./.github/actions/test + uses: ./run-tests with: args: -- -v @@ -67,9 +69,10 @@ jobs: # This ensures the citra logs and video output gets put in a directory # where we can upload as artifacts RUSTDOCFLAGS: " --persist-doctests target/armv6k-nintendo-3ds/debug/doctests" - uses: ./.github/actions/test + uses: ./run-tests with: - args: --doc -- -v + # TODO(#4): run them suckers + args: --doc --no-run -- -v - name: Upload citra logs and capture videos uses: actions/upload-artifact@v3 diff --git a/Dockerfile b/Dockerfile index 1e81737..c250038 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,6 +8,15 @@ ARG CITRA_CHANNEL=nightly ARG CITRA_RELEASE=1995 RUN download_citra ${CITRA_CHANNEL} ${CITRA_RELEASE} +FROM devkitpro/devkitarm as devkitarm + +# For some reason, citra isn't always happy when you try to run it for the first time, +# so we build a simple dummy program to force it to create its directory structure +RUN cd /opt/devkitpro/examples/3ds/graphics/printing/hello-world && \ + echo 'int main(int, char**) {}' > source/main.c && \ + make && \ + mv hello-world.3dsx /tmp/ + FROM ubuntu:latest RUN --mount=type=cache,sharing=locked,target=/var/cache/apt \ @@ -19,7 +28,7 @@ RUN --mount=type=cache,sharing=locked,target=/var/cache/apt \ libavfilter7 \ xvfb -COPY --from=devkitpro/devkitarm:latest /opt/devkitpro /opt/devkitpro +COPY --from=devkitarm /opt/devkitpro /opt/devkitpro # There's no way to copy ENV values from other stages properly: # https://github.com/moby/moby/issues/37345 # Luckily in this case we know exactly what the values should be: @@ -28,7 +37,15 @@ ENV DEVKITARM=${DEVKITPRO}/devkitARM ENV PATH=${DEVKITARM}/bin:${PATH} COPY --from=builder /tmp/citra.AppImage /usr/local/bin/citra -COPY ./docker/sdl2-config.ini /app/ +COPY --from=devkitarm /tmp/hello-world.3dsx /tmp/ +# We run citra once before copying our config file, so it should create its +# necessary directory structure and run once with defaults +RUN xvfb-run citra --appimage-extract-and-run /tmp/hello-world.3dsx; \ + rm -f /tmp/hello-world.3dsx +# Initial run seems to miss this one directory so just make it manually +RUN mkdir -p /root/.local/share/citra-emu/log + +COPY ./docker/sdl2-config.ini /root/.config/citra-emu/ COPY ./docker/test-runner.gdb /app/ COPY ./docker/entrypoint.sh /app/ diff --git a/README.md b/README.md index 6141473..956e201 100644 --- a/README.md +++ b/README.md @@ -13,4 +13,6 @@ A set of tools for running automated Rust tests against Citra (3DS emulator). * `.github/actions/citra`: action for running test executables with Citra in workflows - +## Usage + + diff --git a/.github/actions/test/action.yml b/run-tests/action.yml similarity index 82% rename from .github/actions/test/action.yml rename to run-tests/action.yml index d28d518..b957bb4 100644 --- a/.github/actions/test/action.yml +++ b/run-tests/action.yml @@ -40,10 +40,11 @@ runs: # https://github.com/actions/runner/issues/2058, which also means # we have to export this instead of using the env: key run: | - export CARGO_TARGET_ARMV6K_NINTENDO_3DS_RUNNER="docker run --rm - -v /tmp:/tmp - -v ${GITHUB_WORKSPACE}/target:/app/target - -v ${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE} - ${{ inputs.runner-image }}:latest" + export CARGO_TARGET_ARMV6K_NINTENDO_3DS_RUNNER=" + docker run --rm + -v /tmp:/tmp + -v ${{ github.workspace }}/target:/app/target + -v ${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE} + ${{ inputs.runner-image }}:latest" env cargo 3ds -v test ${{ inputs.args }} diff --git a/.github/actions/setup/action.yml b/setup/action.yml similarity index 100% rename from .github/actions/setup/action.yml rename to setup/action.yml From 057496e4a2df1be4a3c4bc11118faccf3f3d3dd0 Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Sun, 24 Sep 2023 13:27:37 -0400 Subject: [PATCH 5/8] Big restructure for crate and actions Move the runner-specific docker stuff into that action directory, and move the runner crate into a subdirectory for simpler top-level structure. --- .github/workflows/ci.yml | 2 ++ .dockerignore => run-tests/.dockerignore | 0 Dockerfile => run-tests/Dockerfile | 0 run-tests/action.yml | 7 +++++++ {docker => run-tests/docker}/download_citra.sh | 0 {docker => run-tests/docker}/entrypoint.sh | 0 {docker => run-tests/docker}/sdl2-config.ini | 0 {docker => run-tests/docker}/test-runner.gdb | 0 Cargo.toml => test-runner/Cargo.toml | 7 +++++++ {src => test-runner/src}/console.rs | 0 {src => test-runner/src}/gdb.rs | 0 {src => test-runner/src}/lib.rs | 0 {src => test-runner/src}/socket.rs | 0 {tests => test-runner/tests}/integration.rs | 0 14 files changed, 16 insertions(+) rename .dockerignore => run-tests/.dockerignore (100%) rename Dockerfile => run-tests/Dockerfile (100%) rename {docker => run-tests/docker}/download_citra.sh (100%) rename {docker => run-tests/docker}/entrypoint.sh (100%) rename {docker => run-tests/docker}/sdl2-config.ini (100%) rename {docker => run-tests/docker}/test-runner.gdb (100%) rename Cargo.toml => test-runner/Cargo.toml (54%) rename {src => test-runner/src}/console.rs (100%) rename {src => test-runner/src}/gdb.rs (100%) rename {src => test-runner/src}/lib.rs (100%) rename {src => test-runner/src}/socket.rs (100%) rename {tests => test-runner/tests}/integration.rs (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7f9cf4a..adcb03c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -60,6 +60,7 @@ jobs: - name: Build and run tests (unit + integration) uses: ./run-tests with: + working-directory: test-runner args: -- -v - name: Build and run doc tests @@ -71,6 +72,7 @@ jobs: RUSTDOCFLAGS: " --persist-doctests target/armv6k-nintendo-3ds/debug/doctests" uses: ./run-tests with: + working-directory: test-runner # TODO(#4): run them suckers args: --doc --no-run -- -v diff --git a/.dockerignore b/run-tests/.dockerignore similarity index 100% rename from .dockerignore rename to run-tests/.dockerignore diff --git a/Dockerfile b/run-tests/Dockerfile similarity index 100% rename from Dockerfile rename to run-tests/Dockerfile diff --git a/run-tests/action.yml b/run-tests/action.yml index b957bb4..08c46e4 100644 --- a/run-tests/action.yml +++ b/run-tests/action.yml @@ -16,6 +16,11 @@ inputs: required: false default: test-runner-3ds + working-directory: + description: Change to this directory before running tests. Defaults to $GITHUB_WORKSPACE + required: false + default: ${GITHUB_WORKSPACE} + runs: using: composite steps: @@ -25,6 +30,7 @@ runs: - name: Build test-runner image uses: docker/build-push-action@v4 with: + contest: ${{ github.action_path }} tags: ${{ inputs.runner-image }}:latest push: false load: true @@ -40,6 +46,7 @@ runs: # https://github.com/actions/runner/issues/2058, which also means # we have to export this instead of using the env: key run: | + cd ${{ inputs.working-directory }} export CARGO_TARGET_ARMV6K_NINTENDO_3DS_RUNNER=" docker run --rm -v /tmp:/tmp diff --git a/docker/download_citra.sh b/run-tests/docker/download_citra.sh similarity index 100% rename from docker/download_citra.sh rename to run-tests/docker/download_citra.sh diff --git a/docker/entrypoint.sh b/run-tests/docker/entrypoint.sh similarity index 100% rename from docker/entrypoint.sh rename to run-tests/docker/entrypoint.sh diff --git a/docker/sdl2-config.ini b/run-tests/docker/sdl2-config.ini similarity index 100% rename from docker/sdl2-config.ini rename to run-tests/docker/sdl2-config.ini diff --git a/docker/test-runner.gdb b/run-tests/docker/test-runner.gdb similarity index 100% rename from docker/test-runner.gdb rename to run-tests/docker/test-runner.gdb diff --git a/Cargo.toml b/test-runner/Cargo.toml similarity index 54% rename from Cargo.toml rename to test-runner/Cargo.toml index 6d49699..eddd1c3 100644 --- a/Cargo.toml +++ b/test-runner/Cargo.toml @@ -12,3 +12,10 @@ socket = [] ctru-rs = { git = "https://github.com/rust3ds/ctru-rs" } ctru-sys = { git = "https://github.com/rust3ds/ctru-rs" } libc = "0.2.147" + +[patch."https://github.com/ian-h-chamberlain/test-runner-3ds"] +test-runner = { path = "." } + +# Future-proofing for a rename + org move: +[patch."https://github.com/rust3ds/test-runner"] +test-runner = { path = "." } diff --git a/src/console.rs b/test-runner/src/console.rs similarity index 100% rename from src/console.rs rename to test-runner/src/console.rs diff --git a/src/gdb.rs b/test-runner/src/gdb.rs similarity index 100% rename from src/gdb.rs rename to test-runner/src/gdb.rs diff --git a/src/lib.rs b/test-runner/src/lib.rs similarity index 100% rename from src/lib.rs rename to test-runner/src/lib.rs diff --git a/src/socket.rs b/test-runner/src/socket.rs similarity index 100% rename from src/socket.rs rename to test-runner/src/socket.rs diff --git a/tests/integration.rs b/test-runner/tests/integration.rs similarity index 100% rename from tests/integration.rs rename to test-runner/tests/integration.rs From 986b47711e0e91f55695072bf3e3c809b37203b3 Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Sun, 24 Sep 2023 13:30:52 -0400 Subject: [PATCH 6/8] Minor docker cleanup --- run-tests/Dockerfile | 2 +- run-tests/docker/entrypoint.sh | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/run-tests/Dockerfile b/run-tests/Dockerfile index c250038..aa95b1d 100644 --- a/run-tests/Dockerfile +++ b/run-tests/Dockerfile @@ -8,7 +8,7 @@ ARG CITRA_CHANNEL=nightly ARG CITRA_RELEASE=1995 RUN download_citra ${CITRA_CHANNEL} ${CITRA_RELEASE} -FROM devkitpro/devkitarm as devkitarm +FROM devkitpro/devkitarm:latest as devkitarm # For some reason, citra isn't always happy when you try to run it for the first time, # so we build a simple dummy program to force it to create its directory structure diff --git a/run-tests/docker/entrypoint.sh b/run-tests/docker/entrypoint.sh index e36af9f..3e2ecbf 100755 --- a/run-tests/docker/entrypoint.sh +++ b/run-tests/docker/entrypoint.sh @@ -1,6 +1,10 @@ #!/bin/bash -set -x +# Uncomment for debugging the action itself. Maybe consider a job summary or +# grouping the output, to keep this stuff visible but make it simpler to use: +# https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions + +# set -x function cleanup_jobs() { # shellcheck disable=SC2317 # Unreachable because it's only used in trap From 2f70af3297c850bf86c6345ec61970087b0af707 Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Sun, 24 Sep 2023 13:32:22 -0400 Subject: [PATCH 7/8] Update to latest checkout action to hide warnings --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index adcb03c..0056bda 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: container: devkitpro/devkitarm steps: - name: Checkout branch - uses: actions/checkout@v2 + uses: actions/checkout@v4 - uses: ./actions/setup with: @@ -51,7 +51,7 @@ jobs: - '/tmp:/tmp' steps: - name: Checkout branch - uses: actions/checkout@v3 + uses: actions/checkout@v4 - uses: ./setup with: From a90f7d591f02e2efb77d73b9a80ba2939a9bdddd Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Sun, 24 Sep 2023 13:42:36 -0400 Subject: [PATCH 8/8] Update README with usage examples Also fix typo + cleanup YAML --- .github/workflows/ci.yml | 30 ++++++++++---------- README.md | 59 ++++++++++++++++++++++++++++++++++++---- run-tests/action.yml | 10 +++++-- setup/action.yml | 4 +-- 4 files changed, 77 insertions(+), 26 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0056bda..f117c0c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,14 +22,16 @@ jobs: - name: Checkout branch uses: actions/checkout@v4 - - uses: ./actions/setup + - uses: ./setup with: toolchain: ${{ matrix.toolchain }} - name: Check formatting + working-directory: test-runner run: cargo fmt --all --verbose -- --check - name: Run clippy + working-directory: test-runner run: cargo 3ds clippy --color=always --verbose --all-targets test: @@ -47,8 +49,6 @@ jobs: volumes: # So the test action can `docker run` the runner: - '/var/run/docker.sock:/var/run/docker.sock' - # So the built test artifacts end up on the host, not just inside the action container - - '/tmp:/tmp' steps: - name: Checkout branch uses: actions/checkout@v4 @@ -63,18 +63,18 @@ jobs: working-directory: test-runner args: -- -v - - name: Build and run doc tests - # Let's still run doc tests even if lib/integration tests fail: - if: ${{ !cancelled() }} - env: - # This ensures the citra logs and video output gets put in a directory - # where we can upload as artifacts - RUSTDOCFLAGS: " --persist-doctests target/armv6k-nintendo-3ds/debug/doctests" - uses: ./run-tests - with: - working-directory: test-runner - # TODO(#4): run them suckers - args: --doc --no-run -- -v + # TODO(#4): run these suckers + # - name: Build and run doc tests + # # Let's still run doc tests even if lib/integration tests fail: + # if: ${{ !cancelled() }} + # env: + # # This ensures the citra logs and video output gets put in a directory + # # where we can upload as artifacts + # RUSTDOCFLAGS: " --persist-doctests ${{ env.GITHUB_WORKSPACE }}/target/armv6k-nintendo-3ds/debug/doctests" + # uses: ./run-tests + # with: + # working-directory: test-runner + # args: --doc -- -v - name: Upload citra logs and capture videos uses: actions/upload-artifact@v3 diff --git a/README.md b/README.md index 956e201..67018b1 100644 --- a/README.md +++ b/README.md @@ -6,13 +6,60 @@ A set of tools for running automated Rust tests against Citra (3DS emulator). ## Components * `test-runner`: a Rust crate for writing tests for 3DS homebrew -* `Dockerfile`: builds a container for running test executables with Citra. * GitHub Actions: - * `.github/actions/setup`: action for setting up the Rust 3DS toolchain in - workflows - * `.github/actions/citra`: action for running test executables with Citra in - workflows + * `setup`: action for setting up the Rust 3DS toolchain in workflows + * `run-tests`: action for running test executables with Citra in workflows ## Usage - +First the test runner to your crate: + +```sh +cargo add --dev test-runner --git https://github.com/ian-h-chamberlain/test-runner-3ds +``` + +In `lib.rs` and any integration test files: + +```rs +#![feature(custom_test_frameworks)] +#![test_runner(test_runner::run_gdb)] +``` + +Then use the `setup` and `run-tests` actions in your github workflow. This +example shows the default value for each of the inputs: + +```yml +jobs: + test: + runs-on: ubuntu-latest + container: + image: devkitpro/devkitarm + volumes: + # This is required so the test action can `docker run` the runner: + - '/var/run/docker.sock:/var/run/docker.sock' + # This is required so doctest artifacts are accessible to the action: + - '/tmp:/tmp' + + steps: + - name: Checkout branch + uses: actions/checkout@v4 + + - name: Setup Rust3DS toolchain + uses: ian-h-chamberlain/test-runner-3ds/setup@v1 + with: + # Optionally use a more specific nightly toolchain here if desired + toolchain: nightly + + - name: Build and run tests + uses: ian-h-chamberlain/test-runner-3ds/run-tests@v1 + with: + # Optionally add arguments to pass to `cargo 3ds test` + args: '' + # Optionally set the name of the built test-runner docker image + runner-image: test-runner-3ds + # Optionally change to a given directory before running tests. Note + # that this should use the environment variable ${GITHUB_WORKSPACE} + # rather than ${{ github.workspace }} to avoid the issue described in + # https://github.com/actions/runner/issues/2058 + working-directory: ${GITHUB_WORKSPACE} +``` diff --git a/run-tests/action.yml b/run-tests/action.yml index 08c46e4..c9255dd 100644 --- a/run-tests/action.yml +++ b/run-tests/action.yml @@ -30,7 +30,7 @@ runs: - name: Build test-runner image uses: docker/build-push-action@v4 with: - contest: ${{ github.action_path }} + context: ${{ github.action_path }} tags: ${{ inputs.runner-image }}:latest push: false load: true @@ -49,9 +49,13 @@ runs: cd ${{ inputs.working-directory }} export CARGO_TARGET_ARMV6K_NINTENDO_3DS_RUNNER=" docker run --rm - -v /tmp:/tmp + -v ${{ runner.temp }}:${{ runner.temp }} -v ${{ github.workspace }}/target:/app/target - -v ${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE} + -v ${{ github.workspace }}:${GITHUB_WORKSPACE} ${{ inputs.runner-image }}:latest" env cargo 3ds -v test ${{ inputs.args }} + env: + # Ensure that doctests get built into a path which is mounted on the host + # as well as in this container (via the bind mount in the RUNNER command) + TMPDIR: ${{ runner.temp }} diff --git a/setup/action.yml b/setup/action.yml index 0352153..60167b7 100644 --- a/setup/action.yml +++ b/setup/action.yml @@ -17,13 +17,13 @@ runs: with: components: clippy, rustfmt, rust-src toolchain: ${{ inputs.toolchain }} - cache: "false" # We set up our own cache manually in the next step + cache: false # We set up our own cache manually in the next step rustflags: "" - name: Set up Rust cache uses: Swatinem/rust-cache@v2 with: - cache-on-failure: "true" + cache-on-failure: true - name: Install build tools for host shell: bash