关于如何使用TestContainers对12种不同的JVM进行测试的动手教程

发布于:2021-01-14 10:07:31

0

594

0

TestContainers JVM 测试

JobRunr是一个开放源代码库,通过使用RDBMS或NoSQL数据库等持久性存储,可以轻松地在JVM上执行后台处理。本教程将向您展示如何使用TestContainers对12种不同的JVM进行测试。

  • JobRunr是一个利用Java 8 lambda安排即发即忘,延迟和重复性作业的库,它分析Java应用程序的生成字节码,以找出要在后台运行的lambda。由于它允许以分布式方式处理后台作业,因此它使用了RDBMS或NoSQL数据库之类的持久性存储。

  • 如今,有多家Java虚拟机供应商-OpenJDK,Oracle JDK,Oracle提供的GraalVM,Adopt-OpenJ9和Zulu等。

  • 然后有各种各样的数据库,例如Postgres,Oracle XE,Microsoft SQL Server MySql和MariaDB-甚至没有提到像MongoDB和Redis这样的NoSQL存储。

  • 由于JobRunr使用字节码分析来执行其工作(双关语意),所以我认为进行测试必须在每个不同的JVM实例上编译并执行不同的工作lambda的测试非常重要。

为此,我首先创建了以下测试,该测试包含使用JobRunr使用不同方法排队后台作业的单元测试:

package org.jobrunr.tests.e2e;

 

import org.jobrunr.configuration.JobRunr;

import org.jobrunr.jobs.lambdas.JobLambda;

import org.jobrunr.scheduling.BackgroundJob;

import org.jobrunr.storage.SimpleStorageProvider;

import org.jobrunr.tests.e2e.services.TestService;

import org.jobrunr.utils.mapper.gson.GsonJsonMapper;

import org.junit.jupiter.api.AfterEach;

import org.junit.jupiter.api.BeforeEach;

import org.junit.jupiter.api.Test;

 

import java.util.UUID;

import java.util.concurrent.TimeUnit;

 

import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson;

import static org.awaitility.Awaitility.await;

import static org.jobrunr.tests.fromhost.HttpClient.getJson;

 

public class E2EJDKTest {

 

    private TestService testService;

 

    @BeforeEach

    public void startJobRunr() {

        testService = new TestService();

 

        JobRunr

                .configure()

                .useStorageProvider(new SimpleStorageProvider().withJsonMapper(new GsonJsonMapper()))

                .useJobActivator(this::jobActivator)

                .useDashboard()

                .useDefaultBackgroundJobServer()

                .initialize();

    }

 

    @AfterEach

    public void stopJobRunr() {

        JobRunr

                .destroy();

    }

 

    @Test

    void usingLambdaWithIoCLookupUsingInstance() {

        BackgroundJob.enqueue(() -> testService.doWork(UUID.randomUUID()));

 

        await()

                .atMost(30, TimeUnit.SECONDS)

                .untilAsserted(() -> assertThatJson(getSucceededJobs()).inPath("$.items[0].jobHistory[2].state").asString().contains("SUCCEEDED"));

    }

 

    @Test

    void usingLambdaWithIoCLookupWithoutInstance() {

        BackgroundJob.<TestService>enqueue(x -> x.doWork(UUID.randomUUID()));

 

        await()

                .atMost(30, TimeUnit.SECONDS)

                .untilAsserted(() -> assertThatJson(getSucceededJobs()).inPath("$.items[0].jobHistory[2].state").asString().contains("SUCCEEDED"));

    }

 

    @Test

    void usingMethodReference() {

        BackgroundJob.enqueue((JobLambda)testService::doWork);

 

        await()

                .atMost(30, TimeUnit.SECONDS)

                .untilAsserted(() -> assertThatJson(getSucceededJobs()).inPath("$.items[0].jobHistory[2].state").asString().contains("SUCCEEDED"));

    }

 

    @Test

    void usingMethodReferenceWithoutInstance() {

        BackgroundJob.<TestService>enqueue(TestService::doWork);

 

        await()

                .atMost(30, TimeUnit.SECONDS)

                .untilAsserted(() -> assertThatJson(getSucceededJobs()).inPath("$.items[0].jobHistory[2].state").asString().contains("SUCCEEDED"));

    }

 

    private String getSucceededJobs() {

        return getJson("http://localhost:8000/api/jobs/default/succeeded");

    }

 

    private <T> T jobActivator(Class<T> clazz) {

        return (T) testService;

    }

}

该测试使作业入队,然后查询其余的API以查看该作业是否成功。

为了针对12个不同的JVM运行该测试,我随后使用了Richard North的TestContainers:

package org.jobrunr.tests.e2e;

 

import org.jobrunr.configuration.JobRunr;

import org.jobrunr.jobs.lambdas.JobLambda;

import org.jobrunr.scheduling.BackgroundJob;

import org.jobrunr.storage.SimpleStorageProvider;

import org.jobrunr.tests.e2e.services.TestService;

import org.jobrunr.utils.mapper.gson.GsonJsonMapper;

import org.junit.jupiter.api.AfterEach;

import org.junit.jupiter.api.BeforeEach;

import org.junit.jupiter.api.Test;

 

import java.util.UUID;

import java.util.concurrent.TimeUnit;

 

import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson;

import static org.awaitility.Awaitility.await;

import static org.jobrunr.tests.fromhost.HttpClient.getJson;

 

public class E2EJDKTest {

 

    private TestService testService;

 

    @BeforeEach

    public void startJobRunr() {

        testService = new TestService();

 

        JobRunr

                .configure()

                .useStorageProvider(new SimpleStorageProvider().withJsonMapper(new GsonJsonMapper()))

                .useJobActivator(this::jobActivator)

                .useDashboard()

                .useDefaultBackgroundJobServer()

                .initialize();

    }

 

    @AfterEach

    public void stopJobRunr() {

        JobRunr

                .destroy();

    }

 

    @Test

    void usingLambdaWithIoCLookupUsingInstance() {

        BackgroundJob.enqueue(() -> testService.doWork(UUID.randomUUID()));

 

        await()

                .atMost(30, TimeUnit.SECONDS)

                .untilAsserted(() -> assertThatJson(getSucceededJobs()).inPath("$.items[0].jobHistory[2].state").asString().contains("SUCCEEDED"));

    }

 

    @Test

    void usingLambdaWithIoCLookupWithoutInstance() {

        BackgroundJob.<TestService>enqueue(x -> x.doWork(UUID.randomUUID()));

 

        await()

                .atMost(30, TimeUnit.SECONDS)

                .untilAsserted(() -> assertThatJson(getSucceededJobs()).inPath("$.items[0].jobHistory[2].state").asString().contains("SUCCEEDED"));

    }

 

    @Test

    void usingMethodReference() {

        BackgroundJob.enqueue((JobLambda)testService::doWork);

 

        await()

                .atMost(30, TimeUnit.SECONDS)

                .untilAsserted(() -> assertThatJson(getSucceededJobs()).inPath("$.items[0].jobHistory[2].state").asString().contains("SUCCEEDED"));

    }

 

    @Test

    void usingMethodReferenceWithoutInstance() {

        BackgroundJob.<TestService>enqueue(TestService::doWork);

 

        await()

                .atMost(30, TimeUnit.SECONDS)

                .untilAsserted(() -> assertThatJson(getSucceededJobs()).inPath("$.items[0].jobHistory[2].state").asString().contains("SUCCEEDED"));

    }

 

    private String getSucceededJobs() {

        return getJson("http://localhost:8000/api/jobs/default/succeeded");

    }

 

    private <T> T jobActivator(Class<T> clazz) {

        return (T) testService;

    }

}

在这里,使用可传递的基础映像动态构建Docker映像。添加了一个称为的特殊环境变量JDK_TEST,并将gradle包装器安装在docker映像内(这在我的本地系统和CI服务器上有所不同)。接下来,将当前gradle模块复制到容器中,并./gradlew运行build命令。最后,容器等待日志消息“ BUILD SUCCESFULF”,否则它将立即停止。

要E2EJDKTest在不同的JVM实例中运行,请使用以下测试:

package org.jobrunr.tests.fromhost;

 

import org.junit.jupiter.api.Test;

import org.junit.jupiter.api.condition.DisabledIfEnvironmentVariable;

 

import java.time.Duration;

 

import static org.assertj.core.api.Assertions.assertThat;

 

// why: we create a build of the current gradle module inside docker container for each JDK

// we do not want to run this test within the docker container itself as it would otherwise run recursively

// once inside the docker build, the ENV variable JDK_TEST is set

// the end result is that only the tests inside org.jobrunr.tests.e2e must run (on the correct JDK) and not this test

@DisabledIfEnvironmentVariable(named = "JDK_TEST", matches = "true")

public class JdkTest {

 

    @Test

    public void jdk8OpenJdk() {

        assertThat(buildAndTestOnImage("adoptopenjdk:8-jdk-hotspot")).contains("BUILD SUCCESSFUL");

    }

 

    @Test

    public void jdk8OpenJ9() {

        assertThat(buildAndTestOnImage("adoptopenjdk:8-jdk-openj9")).contains("BUILD SUCCESSFUL");

    }

 

    @Test

    public void jdk8Zulu() {

        assertThat(buildAndTestOnImage("azul/zulu-openjdk:8")).contains("BUILD SUCCESSFUL");

    }

 

    @Test

    public void jdk8GraalVM() {

        assertThat(buildAndTestOnImage("oracle/graalvm-ce:20.1.0-java8")).contains("BUILD SUCCESSFUL");

    }

 

    @Test

    public void jdk8Ibm() {

        assertThat(buildAndTestOnImage("ibmcom/ibmjava:8-sdk-alpine")).contains("BUILD SUCCESSFUL");

    }

 

    @Test

    public void jdk11OpenJdk() {

        assertThat(buildAndTestOnImage("adoptopenjdk:11-jdk-hotspot")).contains("BUILD SUCCESSFUL");

    }

 

    @Test

    public void jdk11OpenJ9() {

        assertThat(buildAndTestOnImage("adoptopenjdk:11-jdk-openj9")).contains("BUILD SUCCESSFUL");

    }

 

    @Test

    public void jdk11Zulu() {

        assertThat(buildAndTestOnImage("azul/zulu-openjdk:11")).contains("BUILD SUCCESSFUL");

    }

 

    @Test

    public void jdk11GraalVM() {

        assertThat(buildAndTestOnImage("oracle/graalvm-ce:20.1.0-java11")).contains("BUILD SUCCESSFUL");

    }

 

    @Test

    public void jdk14OpenJdk() {

        assertThat(buildAndTestOnImage("adoptopenjdk:14-jdk-hotspot")).contains("BUILD SUCCESSFUL");

    }

 

    @Test

    public void jdk14OpenJ9() {

        assertThat(buildAndTestOnImage("adoptopenjdk:14-jdk-openj9")).contains("BUILD SUCCESSFUL");

    }

 

    @Test

    public void jdk14Zulu() {

        assertThat(buildAndTestOnImage("azul/zulu-openjdk:14")).contains("BUILD SUCCESSFUL");

    }

 

    private String buildAndTestOnImage(String dockerfile) {

        final BuildAndTestContainer buildAndTestContainer = new BuildAndTestContainer(dockerfile);

        buildAndTestContainer

                .withStartupTimeout(Duration.ofMinutes(10))

                .start();

        return buildAndTestContainer.getLogs();

    }

}

因此,对于每个不同的JVM,将源代码复制到该JVM内,然后完成运行的构建E2EJDKTest。这样可以确保代码已编译并且测试在该JVM中执行。为了确认一切都很好,请求了容器的日志,并使用出色的AssertJ库进行了声明,以确保容器日志包含“ BUILD SUCCESSFUL”。