Skip to content

Commit 062f515

Browse files
Add smoke tests (#22)
* Ignore more files in Docker context * Add scripts to run tests * Run smoke tests in CI * Add smoke tests
1 parent ab66d87 commit 062f515

13 files changed

+1691
-1
lines changed

.dockerignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,6 @@ node_modules
77
.gitattributes
88
.dockerignore
99
Dockerfile
10+
test/
11+
bin/
12+
!bin/run.sh

.github/workflows/ci.js.yml

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
- name: Lint code
2525
run: yarn lint
2626

27-
ci:
27+
unit_tests:
2828
runs-on: ubuntu-latest
2929

3030
strategy:
@@ -40,3 +40,27 @@ jobs:
4040

4141
- name: Install project dependencies and run tests
4242
run: yarn install --frozen-lockfile
43+
44+
smoke_tests:
45+
runs-on: ubuntu-22.04
46+
steps:
47+
- name: Checkout code
48+
uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b
49+
50+
- name: Set up Docker Buildx
51+
uses: docker/setup-buildx-action@4c0219f9ac95b02789c1075625400b2acbff50b1
52+
with:
53+
install: true
54+
55+
- name: Build Docker image and store in cache
56+
uses: docker/build-push-action@2eb1c1961a95fc15694676618e422e8ba1d63825
57+
with:
58+
context: .
59+
push: false
60+
load: true
61+
tags: exercism/typescript-representer
62+
cache-from: type=gha
63+
cache-to: type=gha,mode=max
64+
65+
- name: Run Tests in Docker
66+
run: bin/run-tests-in-docker.sh

bin/run-in-docker.sh

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#!/usr/bin/env sh
2+
3+
# Synopsis:
4+
# Run the representer on a solution using the representer Docker image.
5+
# The representer Docker image is built automatically.
6+
7+
# Arguments:
8+
# $1: exercise slug
9+
# $2: absolute path to solution folder
10+
# $3: absolute path to output directory
11+
12+
# Output:
13+
# Writes the test results to a results.json file in the passed-in output directory.
14+
# The test results are formatted according to the specifications at https://github.com/exercism/docs/blob/main/building/tooling/representers/interface.md
15+
16+
# Example:
17+
# ./bin/run-in-docker.sh two-fer /absolute/path/to/two-fer/solution/folder/ /absolute/path/to/output/directory/
18+
19+
# If any required arguments is missing, print the usage and exit
20+
if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ]; then
21+
echo "usage: ./bin/run-in-docker.sh exercise-slug /absolute/path/to/solution/folder/ /absolute/path/to/output/directory/"
22+
exit 1
23+
fi
24+
25+
slug="$1"
26+
input_dir="${2%/}"
27+
output_dir="${3%/}"
28+
29+
# Create the output directory if it doesn't exist
30+
mkdir -p "${output_dir}"
31+
32+
# Build the Docker image
33+
docker build --rm -t exercism/typescript-representer .
34+
35+
# Run the Docker image using the settings mimicking the production environment
36+
docker run \
37+
--rm \
38+
--network none \
39+
--read-only \
40+
--mount type=bind,source="${input_dir}",destination=/solution \
41+
--mount type=bind,source="${output_dir}",destination=/output \
42+
--mount type=tmpfs,destination=/tmp \
43+
exercism/typescript-representer "${slug}" /solution /output

bin/run-tests-in-docker.sh

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/usr/bin/env sh
2+
3+
# Synopsis:
4+
# Test the representer Docker image by running it against a predefined set of
5+
# solutions with an expected output.
6+
# The representer Docker image is built automatically.
7+
8+
# Output:
9+
# Outputs the diff of the expected representation and mapping against the
10+
# actual representation and mapping generated by the representer.
11+
12+
# Example:
13+
# ./bin/run-tests-in-docker.sh
14+
15+
# Build the Docker image
16+
docker build --rm -t exercism/typescript-representer .
17+
18+
# Run the Docker image using the settings mimicking the production environment
19+
docker run \
20+
--rm \
21+
--network none \
22+
--read-only \
23+
--mount type=bind,source="${PWD}/test",destination=/opt/representer/test \
24+
--mount type=tmpfs,destination=/tmp \
25+
--volume "${PWD}/bin/run-tests.sh:/opt/representer/bin/run-tests.sh" \
26+
--workdir /opt/representer \
27+
--entrypoint /opt/representer/bin/run-tests.sh \
28+
exercism/typescript-representer

bin/run-tests.sh

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#!/usr/bin/env sh
2+
3+
# Synopsis:
4+
# Test the representer by running it against a predefined set of solutions
5+
# with an expected output.
6+
7+
# Output:
8+
# Outputs the diff of the expected representation and mapping against the
9+
# actual representation and mapping generated by the representer.
10+
11+
# Example:
12+
# ./bin/run-tests.sh
13+
14+
exit_code=0
15+
16+
# We need to copy the fixtures to a temp directory as the user
17+
# running within the Docker container does not have permissions
18+
# to run the sed command on the fixtures directory
19+
fixtures_dir="test/fixtures"
20+
tmp_fixtures_dir="/tmp/test/fixtures"
21+
rm -rf "${tmp_fixtures_dir}"
22+
mkdir -p "${tmp_fixtures_dir}"
23+
cp -R ${fixtures_dir}/* "${tmp_fixtures_dir}"
24+
25+
# Iterate over all test directories
26+
for test_file in $(find "${tmp_fixtures_dir}" -name expected_mapping.json); do
27+
slug=$(echo "${test_file:${#tmp_fixtures_dir}+1}" | cut -d / -f 1)
28+
test_dir=$(dirname "${test_file}")
29+
test_dir_name=$(basename "${test_dir}")
30+
test_dir_path=$(realpath "${test_dir}")
31+
32+
bin/run.sh "${slug}" "${test_dir_path}" "${test_dir_path}"
33+
34+
for file in representation.txt mapping.json; do
35+
expected_file="expected_${file}"
36+
echo "${test_dir_name}: comparing ${file} to ${expected_file}"
37+
38+
if ! diff "${test_dir_path}/${file}" "${test_dir_path}/${expected_file}"; then
39+
exit_code=1
40+
fi
41+
done
42+
done
43+
44+
exit ${exit_code}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"IDENTIFIER_0": "Clock",
3+
"IDENTIFIER_1": "hour",
4+
"IDENTIFIER_2": "minute",
5+
"IDENTIFIER_3": "reset",
6+
"IDENTIFIER_4": "totalMinutes",
7+
"IDENTIFIER_5": "adjustTime",
8+
"IDENTIFIER_6": "getHour",
9+
"IDENTIFIER_7": "getMinute",
10+
"IDENTIFIER_8": "formatNumber",
11+
"IDENTIFIER_9": "numberToFormat",
12+
"IDENTIFIER_10": "numberString",
13+
"IDENTIFIER_11": "length",
14+
"IDENTIFIER_12": "plus",
15+
"IDENTIFIER_13": "minutes",
16+
"IDENTIFIER_14": "minus",
17+
"IDENTIFIER_15": "equals",
18+
"IDENTIFIER_16": "clock",
19+
"IDENTIFIER_17": "delta",
20+
"IDENTIFIER_18": "minutesPerDay",
21+
"IDENTIFIER_19": "minutesPerHour",
22+
"IDENTIFIER_20": "hoursPerDay",
23+
"IDENTIFIER_21": "Math",
24+
"IDENTIFIER_22": "abs",
25+
"IDENTIFIER_23": "currentMinutes",
26+
"IDENTIFIER_24": "newMinutes",
27+
"IDENTIFIER_25": "floor"
28+
}

0 commit comments

Comments
 (0)