Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement a basic Roc test runner #4

Merged
merged 22 commits into from
Aug 22, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
41fd0fe
Implement a basic Roc test runner
ageron Aug 21, 2024
f4ba82c
Switch Dockerfile to debian:bookworm instead of latest
ageron Aug 21, 2024
a58488c
Fix excessive level in .gitignore tests/ filter
ageron Aug 21, 2024
57e2b4c
Tweak tests/success/expected_results.json to get it to be pushed to g…
ageron Aug 21, 2024
e98920d
Revert tweak to tests/success/expected_results.json
ageron Aug 21, 2024
0e65b64
Switch to Ubuntu 24.04
ageron Aug 21, 2024
c519e17
Set TMPDIR to point to ${{ runner.temp }}
ageron Aug 21, 2024
6f9d86c
Since `runner.temp` seems R/O, creating TMPDIR in `github.workspace` …
ageron Aug 21, 2024
4dacd75
Debugging Github Actions
ageron Aug 21, 2024
d8d1128
Still debugging the TMPDIR issue
ageron Aug 21, 2024
fe65169
Debugging RUNNER_TEMP and GITHUB_WORKSPACE vars
ageron Aug 21, 2024
9d1c84b
Is /tmp actually writable?
ageron Aug 21, 2024
f276ff3
Try forcing TMPDIR=/tmp since /tmp is writable
ageron Aug 21, 2024
45b3412
Still debugging, trying to add debug symbols
ageron Aug 21, 2024
99dc755
Try testing on macOS 14 instead of ubuntu-24.04
ageron Aug 22, 2024
eacd31a
Back to ubuntu-24.04
ageron Aug 22, 2024
31e3378
Test /tmp permissions further
ageron Aug 22, 2024
821f518
Debugging: use Roc compiled from source in debug mode
ageron Aug 22, 2024
dce360e
Use volume mount for /tmp
ErikSchierboom Aug 22, 2024
5cd2f1d
Use Roc version based on latest ccode
ageron Aug 22, 2024
9bc4ef7
Adapt to latest Roc outputs
ageron Aug 22, 2024
55693ed
Merge all-fail and partial-fail expected_results.json
ageron Aug 22, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@
FROM alpine:3.18
FROM debian:latest

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we pin this to a specific Debian version? If feasible, it might be better to use an Alpine image to reduce the overall image size. That'll save Exercism money since we're deploying 71+ different Docker images to each test runner machine in the cloud.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can definitely pin this to debian:bookworm instead. However, I tried using alpine, but Roc failed, probably because I need to install some libraries. I'll start with debian:bookworm, and I'll switch to alpine asap.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If Alpine doesn't work out, that's fine. It's just a nice starting point for reducing file size, but I don't believe all tracks can use Alpine images due to some limitations in what's available.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trying to solve the DlOpen error (see above), I've switched to Ubuntu 22.24. Still works fine on my machine but fails in Github CI. I think it might be a permission issue on the /tmp folder (see this SO answer).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I know about Docker or Github CI can fit in a thimble, but Erik can probably help you out further. He's pretty handy. :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked into migrating to Alpine, but Roc is currently built on glibc whereas Alpine uses musl. There's an ongoing effort to make Roc support musl, so we should be able to migrate to Alpine once that work is completed.

RUN apt-get update --fix-missing
RUN apt-get upgrade --yes

# install packages required to run the tests
RUN apk add --no-cache jq coreutils
RUN apt-get install --yes wget jq coreutils libc-dev binutils \
&& apt clean \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /opt/test-runner
COPY bin/download-basic-cli.roc bin/download-basic-cli.roc

# download & install roc and the basic-cli platform
RUN wget -q -O roc.tar.gz https://github.com/roc-lang/roc/releases/download/nightly/roc_nightly-linux_x86_64-latest.tar.gz \
&& mkdir /usr/lib/roc \
&& tar -xvz -f roc.tar.gz --directory /usr/lib/roc --strip-components=1 \
&& rm roc.tar.gz \
&& /usr/lib/roc/roc test bin/download-basic-cli.roc
ENV PATH="$PATH:/usr/lib/roc"

COPY . .
ENTRYPOINT ["/opt/test-runner/bin/run.sh"]
8 changes: 8 additions & 0 deletions bin/download-basic-cli.roc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.12.0/Lb8EgiejTUzbggO2HVVuPJFkwvvsfW6LojkLR20kTVE.tar.br" }

import pf.Task exposing [Task]

expect Bool.true

main =
Task.ok {}
16 changes: 10 additions & 6 deletions bin/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,7 @@ echo "${slug}: testing..."

# Run the tests for the provided implementation file and redirect stdout and
# stderr to capture it
test_output=$(false)
# TODO: substitute "false" with the actual command to run the test:
# test_output=$(command_to_run_tests 2>&1)
test_output=$(roc test "${solution_dir%/}/${slug}-test.roc" 2>&1)

# Write the results.json file based on the exit code of the command that was
# just executed that tested the implementation file
Expand All @@ -45,16 +43,22 @@ else
# OPTIONAL: Sanitize the output
# In some cases, the test output might be overly verbose, in which case stripping
# the unneeded information can be very helpful to the student
# sanitized_test_output=$(printf "${test_output}" | sed -n '/Test results:/,$p')
sanitized_test_output=$(printf "${test_output}\n" | sed 's/ passed in [0-9]\+ ms./ passed./g')

# OPTIONAL: Manually add colors to the output to help scanning the output for errors
# If the test output does not contain colors to help identify failing (or passing)
# tests, it can be helpful to manually add colors to the output
# colorized_test_output=$(echo "${test_output}" \
# colorized_test_output=$(echo "${sanitized_test_output}" \
# | GREP_COLOR='01;31' grep --color=always -E -e '^(ERROR:.*|.*failed)$|$' \
# | GREP_COLOR='01;32' grep --color=always -E -e '^.*passed$|$')

jq -n --arg output "${test_output}" '{version: 1, status: "fail", message: $output}' > ${results_file}
printf "${sanitized_test_output}" | grep -q -E "── EXPECT (FAILED|PANICKED) in "
if [ $? -eq 0 ]; then
roc_status="fail"
else
roc_status="error"
fi
jq -n --arg output "${sanitized_test_output}" "{version: 1, status: \"$roc_status\", message: \$output}" > ${results_file}
fi

echo "${slug}: done"
9 changes: 9 additions & 0 deletions tests/all-fail/all-fail-test.roc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.12.0/Lb8EgiejTUzbggO2HVVuPJFkwvvsfW6LojkLR20kTVE.tar.br" }

import pf.Task exposing [Task]

expect 2 + 2 == 5
expect "four" == "five"

main =
Task.ok {}
2 changes: 1 addition & 1 deletion tests/all-fail/expected_results.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": 1,
"status": "fail",
"message": "TODO: replace with correct output"
"message": "\u001b[1;36m── EXPECT FAILED in tests/all-fail/all-fail-test.roc ───────────────────────────\u001b[0m\n\nThis expectation failed:\n\n\u001b[1;36m5\u001b[0m\u001b[1;36m│\u001b[0m \u001b[37mexpect 2 + 2 == 5\u001b[0m\n \u001b[1;31m^^^^^^^^^^^^^^^^^\u001b[0m\n\n\n\u001b[1;36m── EXPECT FAILED in tests/all-fail/all-fail-test.roc ───────────────────────────\u001b[0m\n\nThis expectation failed:\n\n\u001b[1;36m6\u001b[0m\u001b[1;36m│\u001b[0m \u001b[37mexpect \"four\" == \"five\"\u001b[0m\n \u001b[1;31m^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\n\n\n\u001b[1;31m2\u001b[0m failed and \u001b[1;32m0\u001b[0m passed."
}
Empty file.
4 changes: 2 additions & 2 deletions tests/empty-file/expected_results.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": 1,
"status": "fail",
"message": "TODO: replace with correct output"
"status": "error",
"message": "\u001b[1;36m── MISSING HEADER in tests/empty-file/empty-file-test.roc ──────────────────────\u001b[0m\n\nI am expecting a header, but got stuck here:\n\n\u001b[1;36m1\u001b[0m\u001b[1;36m│\u001b[0m\n \u001b[1;31m^\u001b[0m\n\nI am expecting a module keyword next, one of \u001b[1;32minterface\u001b[0m, \u001b[1;32mapp\u001b[0m, \u001b[1;32mpackage\u001b[0m\nor \u001b[1;32mplatform\u001b[0m."
}
2 changes: 1 addition & 1 deletion tests/partial-fail/expected_results.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": 1,
"status": "fail",
"message": "TODO: replace with correct output"
"message": "\u001b[1;36m── EXPECT FAILED in tests/partial-fail/partial-fail-test.roc ───────────────────\u001b[0m\n\nThis expectation failed:\n\n\u001b[1;36m6\u001b[0m\u001b[1;36m│\u001b[0m \u001b[37mexpect \"hello\" == \"good bye\"\u001b[0m\n \u001b[1;31m^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\n\n\n\u001b[1;31m1\u001b[0m failed and \u001b[1;32m1\u001b[0m passed."
}
9 changes: 9 additions & 0 deletions tests/partial-fail/partial-fail-test.roc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.12.0/Lb8EgiejTUzbggO2HVVuPJFkwvvsfW6LojkLR20kTVE.tar.br" }

import pf.Task exposing [Task]

expect 2 + 2 == 4
expect "hello" == "good bye"

main =
Task.ok {}
9 changes: 9 additions & 0 deletions tests/success/success-test.roc
ageron marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.12.0/Lb8EgiejTUzbggO2HVVuPJFkwvvsfW6LojkLR20kTVE.tar.br" }

import pf.Task exposing [Task]

expect 2 + 2 == 4
expect "four" == "four"

main =
Task.ok {}
2 changes: 1 addition & 1 deletion tests/syntax-error/expected_results.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": 1,
"status": "error",
"message": "TODO: replace with correct output"
"message": "\u001b[1;36m── NOT END OF FILE in tests/syntax-error/syntax-error-test.roc ─────────────────\u001b[0m\n\nI expected to reach the end of the file, but got stuck here:\n\n\u001b[1;36m3\u001b[0m\u001b[1;36m│\u001b[0m \u001b[37miMpOrT pf.Task exposing [Task]\u001b[0m\n \u001b[1;31m^\u001b[0m"
}
9 changes: 9 additions & 0 deletions tests/syntax-error/syntax-error-test.roc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.12.0/Lb8EgiejTUzbggO2HVVuPJFkwvvsfW6LojkLR20kTVE.tar.br" }

iMpOrT pf.Task exposing [Task]

expect 2 + 2 == 5
expect "four" == "five"

main =
Task.ok {}
Loading