As part of the Precognito github project (details soon to be set forth — yes it has some machine learning), I’ve been setting up the github project to use CircleCI. One of the goals of the project is to adopt best of breed technology and build a completely serverless log analysis platform that runs in your VPC — in the free tier ;) It is using Quarkus (because my twitter friends cannot stop talking about it), CircleCI and serverless cloud technologies.
I hit a few barriers along the way, some of which are my own lack of understanding or misconceptions about how to get the ‘new’ stuff working. I’ve tried to capture each item below.
TestContainers and DynamoDB local for testing
If you haven’t looked at or learned about TestContainers then you are missing out ;). It is definitely something to have in your arsenal. While fixtured APIs are ideal (and fast) there will come a time where you need Dockerized services to integration test against. I say integration test, because using Docker in testing is slow, but kind of fully featured. Below is a list of issues I hit.
- TestContainers uses docker commands and requires ‘authorized configuration’ otherwise you get a nasty error like: ‘docker-credential-desktop’ not found. This is because .docker/config.json is telling it to ‘auth’ itself. Remove the line “credsStore” : “desktop” — but be aware of why the line exists and if you should indeed remove it!
- TestContainers provides a dynalite localised dynamodb instance (a dynamodb alternative). However, it is simply a wrapper over the TestContainers GenericContainer. Quarkus advocate the semi-experimental dynamodb2 client driver. The dynalite tescontainer provides a client builder for the old version, so instead adopted my own — see here. I could then switch between different docker images to see which one suited my needs. I ended up using the aws/dynamo-local it seemed to work better with the new v2 client drivers.
- To speed up testing you don’t want to start/stop Docker all the time. Using a Junit5/Juniper @BeforeAll helps, however, the standard approach is to declare required resources as static variables. Due to Quarkus CDI injection, it was somehow classloading the unit-test static fields (wha??). This made non-related unit tests spin up testcontainers — I could see it in the log output — and was like WTF? To work around this problem, rather than following what TestContainers advocate (see here) I simply create it in the @BeforeAll static function — as shown here.
Test Containers and CircleCI
Upon checking-in I soon realized that TestContainers would not work with the default CircleCI dockerized executor. This would mean running docker within docker == FAIL! I had to switch to the ‘Machine’ executor. This means updating .circleci/config to not only specify the execution type, but also the maven build steps. The config file is here. I will eventually get time to setup and build the GraalVM native image. I followed these docs on building Quarkus on CircleCI.
Quarkus and application profiles
Application profiles are a really nice feature of Quarkus. It means I can run unit or integration tests in the IDE, commandline or CI build and have a specific behavior — I might want to use fixtures for super fast local builds, and docker images for CI integration builds. By default, Quarkus supports test, dev and production profiles. The config values are held in an application.properties file. The test/resources files only need to contain test values, however, the shipped properties file will specify other profiles. I use this profiling to control when fixtures are loaded, to this I set up a microprofile convertor config to allow the various classes to be specified so the CDI injection loads the right thing! The only gotcha here was that I needed my application runtime to sometimes know when profile is being run. Im still not 100% certain that its the right approach. You will see here that the AWSStorageConvertor can return a fixture when in test mode.
There is a fairly basic web-interface so feel free to grab it download. It is possible to run it locally with ‘maven quarkus:dev’ — in which case it uses fixtured cloud services!
All the best!