DEV Community

Cover image for Using Podman to run Testcontainers in a Quarkus project
Yassine Benabbas for Technology at Worldline

Posted on • Updated on

Using Podman to run Testcontainers in a Quarkus project

In the area of container engines, podman seems to be a relevant alternative to docker, at least during the development phase on a Windows or macOS machine. Indeed, both podman and podman-desktop, it's desktop UI, do not require a paid licence. Which is not the case anymore for Docker-Desktop under certain conditions (it's still free for individual developers, education, open source communities, and small businesses). In addition to that, podman is daemonless and can run in rootless mode.

This article shows how to use podman as a container engine instead of Docker and Docker-Desktop on Windows and macOS. We'll see how to install this tool and how to configure it to run tests that rely on Testcontainers. So let's get started with the prerequisites.

Prerequisites

Even though you can use the official installers, I suggest to use package managers moving forward.

Start and configure podman

Open a terminal and run these commands:

  • podman machine init, which initializes a new VM. You just need to run it once.
  • podman machine start, which starts the VM. You need to re-run it after each reboot.
  • Podman-desktop allows to configure the podman machine to auto-start. You can start if from the apps menu.

Podman desktop app

Podman desktop auto-start settings

  • Now we are ready to launch containers. Run podman run hello which launches a basic container.
  • The last thing we need to configure is to set this environment variable to TESTCONTAINERS_RYUK_DISABLED to true

The next section demonstrates that we can use Testcontainers through a sample project.

Sample Quarkus project that uses Testcontainers

Let's create with an app with Quarkus which consists of a REST API that backs its data on a postgreSQL database.

Quarkus provides zero-confguration databases for development and test modes (called DEV SERVICES FOR DATABASES). It relies on a containerization tool, such as docker or podman, for some databases. Since we have podman installed and configured, we are ready to go.

In order to create a starter project, open code.quarkus.io and choose JDBC Driver - PostgreSQL extension and any other extensions that you'd like to use for you project.

In the following, I have selected the following extensions just for fun 😁.

  • YAML Configuration
  • JDBC Driver - PostgreSQL
  • Hibernate ORM with Panache
  • Hibernate ORM with Panache and Kotlin
  • Kotlin
  • RESTEasy Reactive
  • RESTEasy Reactive Kotlin Serialization

I also selected Gradle with Kotlin SDL build tool, but you can use any available one.

Once the applications information and extensions are selected, generate and download the zip archive. After that, unzip that archive and open a terminal on the root folder of the project (the one contains pom.xml, build.gradle or build.gradle.kts).

Next, run the tests using .\gradlew.bat test (if you are using powershell). You should see the following output:

********************************************************************************
Ryuk has been disabled. This can cause unexpected behavior in your environment.
********************************************************************************
2022-11-27 00:16:55,210 INFO  [org.tes.DockerClientFactory] (build-57) Checking the system...
2022-11-27 00:16:55,212 INFO  [org.tes.DockerClientFactory] (build-57) ?? Docker server version should be at least 1.6.0
2022-11-27 00:16:55,241 INFO  [org.tes.uti.ImageNameSubstitutor] (build-57) Image name substitution will be performed by: DefaultImageNameSubstitutor (composite of 'ConfigurationFileImageNameSubstitutor' and 'PrefixingImageNameSubstitutor')
2022-11-27 00:16:55,284 INFO  [doc.io/postgres:14]] (build-57) Pulling docker image: docker.io/postgres:14. Please be patient; this may take some time but only needs to be done once.
...
BUILD SUCCESSFUL in 21s
9 actionable tasks: 1 executed, 8 up-to-date
Enter fullscreen mode Exit fullscreen mode

The tests were executed successfully. The output proves that a container image has been downloaded and started. We can deduce that Podman was successfully able to interact with Testcontaiers, which is the library that is responsible for testing with containers.

Let's analyse this output. The following line means that the environment variable that we set earlier was detected.

Ryuk has been disabled. This can cause unexpected behavior in your environment.

This line means that postgreSQL container image docker.io/postgres:14 is being downloaded.

2022-11-27 00:16:55,284 INFO [doc.io/postgres:14]] (build-57) Pulling docker image: docker.io/postgres:14. Please be patient; this may take some time but only needs to be done once.

Finally, we can check with podman the presence of a postgreSQL image. Open a terminal and run podman images, you should see an output similar to this one.

REPOSITORY                  TAG         IMAGE ID      CREATED      SIZE
docker.io/library/postgres  14          c920f82d2df2  11 days ago  384 MB
Enter fullscreen mode Exit fullscreen mode

Indeed, the postgres image is present. We have used containers with Podman. Horaaay !

Testing with an entity

Even though we validated that podman works with testcontainers, we did not really use the database yet. Thus, for the sake of completion, let's create a Panache entity as well as a repository, and update our REST resource and tests to use this entity.

Here is the code on the app side:

@Entity
@Serializable
class Greeting : PanacheEntity() {
    lateinit var message: String
}

@ApplicationScoped
class GreetingRepository : PanacheRepository<Greeting> {
    fun findByPrefix(prefix: String) = list("message like ?1", "$prefix%")
}

@Path("/")
class GreetingResource {

    @Inject
    lateinit var greetingRepository: GreetingRepository

    @GET
    @Path("/greetings/{prefix}")
    @Produces(MediaType.APPLICATION_JSON)
    fun greetings(@PathParam("prefix") prefix: String) = greetingRepository.findByPrefix(prefix).orEmpty()
}
Enter fullscreen mode Exit fullscreen mode

The library used for entity mangement is called Panache and allows to use the repository pattern with Hibernate.

⚠ We added @Serializable on the entity so that it can be parsed into and from JSON. However, the Quarkus project generator did not add an important plugin that makes serialization work with Kotlin. Please add this plugin to build.gradle.kts in order to enable this feature: id("org.jetbrains.kotlin.plugin.serialization") version "1.7.21"

The plugin part should look like this:

plugins {
    kotlin("jvm") version "1.7.21"
    kotlin("plugin.allopen") version "1.7.21"
// add this line
    id("org.jetbrains.kotlin.plugin.serialization") version "1.7.21"
    id("io.quarkus")
}
Enter fullscreen mode Exit fullscreen mode

This is the test code. The method prepareData adds initial data to the database and testHelloEndpoint tests the above endpoint. The library that is used for testing the REST API is called rest-assured and provides a nice DSL (Domain Specific Language) with functions such as given and when.

@QuarkusTest
class GreetingResourceTest {

    @Inject
    lateinit var greetingRepository: GreetingRepository

    @Transactional
    @BeforeEach
    fun prepareData() {
        greetingRepository.deleteAll()
        val greeting = Greeting()
        greeting.message = "hello world"
        greetingRepository.persist(greeting)
        greetingRepository.flush()
    }

    @Test
    fun testHelloEndpoint() {
        given()
            .`when`().get("/greetings/hello")
            .then()
            .statusCode(HttpStatus.SC_OK)
            .body("$.size()", equalTo(1))
            .body("message", hasItem("hello world"))
    }

}
Enter fullscreen mode Exit fullscreen mode

As stated earlier, no database configuration is needed, thanks to Quarkus' Dev Services. We just need to run .\gradlew.bat test to run the tests and ./gradlew quarkusDev to run the development server.

Conclusion

This article showed how to use podman as a container tool on a Quarkus + testcontainers project. The most important setting that make Podman and Testcontainers interact with each other is setting the environment variable TESTCONTAINERS_RYUK_DISABLED to true.

Happy coding

Top comments (0)