Solution to the take-home assignment of an interview process I took part in 2022. Description of the assignment can be found here.
The test plan can be found here.
Despite having worked in the past with some of the languages in use at your company (Java, Python, and C#), I chose to write the tests in Golang (Go) because it is the language I use on a daily basis since 2020. For this challenge, Go has been used together with a testing framework called Ginkgo and its matcher library Gomega.
The tests are written in a BDD-like flavor: each test case description is wrapped into its own It function. I think this approach eases reading the test. To further ease the process, I intentionally left some duplicated code among the tests (so the reader can identify quickly what each test does).
suites contains the entry point of the program and the test cases.
internal contains the components the tests delegate tasks to (i.e. encoding, HTTP client, hash calculation etc.)
The test cases 1, 2, 3, 9, 10, 11 and 12 of the test plan have been automated.
You have two options for running the tests: Docker or Golang and Java. For the latter, you also need the Ginkgo binary. You can install it with the command:
go install -mod=mod github.com/onsi/ginkgo/v2/ginkgo
The repo contains two Dockerfiles and a docker-compose:
- server copies the
.jar
along with two files in a Debian distribution with openjdk 18 pre-installed - tests builds the tests binary and copies it together with the config file in a light distribution (Linux Alpine)
- compose builds the two custom images and spawns the containers. The tests container is started only when the server container is healthy (i.e. the .
jar
is running)
To run the tests, run the following command in the terminal:
make dev
The docker-compose will be launched in foreground (you must press "ctrl+c" or "cmd+c" to regain control of the window). In this instance, I prefer this approach to running the command in background and then having to run docker-compose logs -f
to see the execution status.
There are two commands more:
make nodev # stop the containers
make devrebuild # rebuild the images
Before running the tests you might want to execute go mod tidy
to download potentially missing dependencies.
make server
: spawns the web server (.jar
)
make tests
: runs the tests with the Ginkgo binary and uses this config file. You can also provide a custom config file to the make target (config.yml
is ignored by git). Example:
CFG=../config.yml make tests # ".." because the tests are in the "suites" folder
The config file is also used to make some of the tests data-driven.
- trivy has been used to identify vulnerabilities in the Dockerfiles
- hadolint has been used to lint the Dockerfiles
- golangci-lint has been used to lint the Go code
All the work has been done on a 2021 16" Apple Macbook Pro with the following specs:
- M1 Pro processor (10-core CPU and 16-core GPU)
- 32 GB of RAM
- 1 TB SSD
- macOS Monterey 12.4
- Go 1.18.3
- Ginkgo 2.1.4
- JDK 18.0.1.1
-
When supplying a large file (6 GB or more) to the
.jar
, the process exits immediately with the message:java.lang.OutOfMemoryError: Required array size too large
. Running the jar with increased heap size (tested with-Xms10G -Xmx16G
) did not solve the issue. -
When supplying a < 1 KB file to the web server, a call to the endpoint
/piece/:hash/0
returns:{404, "No such route"}
. The app log prints:java.lang.ArrayIndexOutOfBoundsException: Index 1 out of bounds for length 1
. You can reproduce the error by running the following commands:
java -jar problem/merkle-tree-java.jar problem/small
# The command below in a separate terminal window
curl localhost:8080/piece/c4dbc298900101df82899b1b9dd2c9752f3dc59c8d79843c9083210cf882040e/0