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