发布于:2021-01-14 10:07:31
0
653
0
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”。
作者介绍