我正在尝试为基于 RESTful(服务)Java 的应用程序创建一个全面的集成测试套件,该应用程序在 Tomcat(7.x) 中运行并依赖于 Postgresql (9.x) 实例。此外,我希望能够将这个套件作为一个独立的进程运行,如果可能的话,通过使用 Maven 故障安全插件,仅从 Maven 3.x 运行。这样,测试就可以在 3 个主要平台(Mac OSX、Linux 和 Windows)上运行。
根据我所了解到的情况,我相信实现这一目标的关键是执行以下步骤(按顺序):
- 在预集成测试阶段以某种方式启动 postgresql DB 的“嵌入式”版本(和模式设置)Maven生命周期 http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html,让 postgres-db-process 在后台运行
- 启动加载我的服务应用程序的 Java 容器:我正在使用 Jetty 9.1.5 插件
- 在集成测试阶段从 Failsafe 插件运行我的(基于 JUnit 的)测试
- 在 Maven 的集成后测试阶段关闭我的 Jetty 容器
- 最后,有一些机制shutdown先前在生命周期的集成测试阶段启动的(后台)postgres-db-process(终止/清理此进程)
在我当前的实现中,成功完成步骤 1 - 3。在第 2 步中,它使用了 exec-maven-plugin,该插件调用一个 Java 类,该类使用postgresql 嵌入式 Java 组件 https://github.com/yandex-qatools/postgresql-embedded。
POM.xml 的摘录:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<id>Run Postgres DB start/schema setup</id>
<phase>pre-integration-test</phase>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>com.some.package.test.utils.DbSetup</mainClass>
<arguments>
<argument>setup</argument>
</arguments>
</configuration>
</plugin>
以下是使用 postgresql-embedded 启动 postgresql 实例的 DBSetup 类的摘录:
try {
DownloadConfigBuilder downloadConfigBuilder = new DownloadConfigBuilder();
downloadConfigBuilder.defaultsForCommand(Command.Postgres);
downloadConfigBuilder.proxyFactory(new HttpProxyFactory(PROXY_ADDRESS, DEFAULT_PROXY_PORT));
IRuntimeConfig runtimeConfig = new RuntimeConfigBuilder()
.defaults(Command.Postgres)
.artifactStore(new ArtifactStoreBuilder()
.defaults(Command.Postgres)
.download(downloadConfigBuilder)).build();
PostgresStarter<PostgresExecutable, PostgresProcess> runtime = PostgresStarter.getInstance(runtimeConfig);
final PostgresConfig config = new PostgresConfig(Version.V9_2_4, new AbstractPostgresConfig.Net(
"localhost", 5432
), new AbstractPostgresConfig.Storage(dbName), new AbstractPostgresConfig.Timeout(),
new AbstractPostgresConfig.Credentials(username, password));
config.getAdditionalInitDbParams().addAll(Arrays.asList(
"-E", "UTF-8",
"--locale=en_US.UTF-8",
"--lc-collate=en_US.UTF-8",
"--lc-ctype=en_US.UTF-8"
));
exec = runtime.prepare(config);
process = exec.start();
System.out.println("embedded Postgres started");
Thread.sleep(1200L);
} catch (IOException e) {
System.out.println("Something Went Wrong initializing embedded Postgres: " + e);
e.printStackTrace();
}
catch (InterruptedException e) {
System.out.println("Something Went Wrong Pausing this thread " + e);
e.printStackTrace();
}
请注意,我不是在打电话process.stop();
在启动 Postgres 实例的方法中。所以,我目前没有办法shutdown数据库进程。一旦我退出这门课DbSetup
,所有对该现有流程的引用都将丢失。并且 Postgres 进程永远不会关闭。事实上,jetty 容器似乎也不会关闭,并且整个 Maven 作业挂起,所以我必须手动终止它(摘自我的 Maven 控制台输出):
[INFO] --- exec-maven-plugin:1.2.1:java (Run Postgres DB start/schema setup) @ BLAHBLAH ---
***START of Postgres DB Setup Process ***
Extract /Users/myUserName/.embedpostgresql/postgresql-9.2.4-1-osx-binaries.zip START
...................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................Extract /Users/myUserName/.embedpostgresql/postgresql-9.2.4-1-osx-binaries.zip DONE
INFO:20161021 12:58:00: de.flapdoodle.embed.process.runtime.Executable de.flapdoodle.embed.process.runtime.Executable start AbstractPostgresConfig{storage=Storage{dbDir=/var/folders/8g/69wh31fn7nx3q81phwfdpld00000gn/T/postgresql-embed-66cfc41f-0e16-439f-a24b-6e5b6dbc683d/db-content-3bc4b9cc-dd21-43a7-9058-285767f5c53d, dbName='BLAH', isTmpDir=true}, network=Net{host='localhost', port=5432}, timeout=Timeout{startupTimeout=15000}, credentials=Credentials{BLAH, BLAH}, args=[], additionalInitDbParams=[-E, UTF-8, --locale=en_US.UTF-8, --lc-collate=en_US.UTF-8, --lc-ctype=en_US.UTF-8]}
INFO:20161021 12:58:01: de.flapdoodle.embed.process.runtime.Executable de.flapdoodle.embed.process.runtime.Executable start AbstractPostgresConfig{storage=Storage{dbDir=/var/folders/8g/69wh31fn7nx3q81phwfdpld00000gn/T/postgresql-embed-66cfc41f-0e16-439f-a24b-6e5b6dbc683d/db-content-3bc4b9cc-dd21-43a7-9058-285767f5c53d, dbName='BLAH', isTmpDir=true}, network=Net{host='localhost', port=5432}, timeout=Timeout{startupTimeout=15000}, credentials=Credentials{BLAH, BLAH}, args=[BLAH], additionalInitDbParams=[]}
INFO:20161021 12:58:04: de.flapdoodle.embed.process.runtime.Executable de.flapdoodle.embed.process.runtime.Executable start AbstractPostgresConfig{storage=Storage{dbDir=/var/folders/8g/69wh31fn7nx3q81phwfdpld00000gn/T/postgresql-embed-66cfc41f-0e16-439f-a24b-6e5b6dbc683d/db-content-3bc4b9cc-dd21-43a7-9058-285767f5c53d, dbName='BLAH', isTmpDir=true}, network=Net{host='localhost', port=5432}, timeout=Timeout{startupTimeout=15000}, credentials=Credentials{BLAH, BLAH}, args=[], additionalInitDbParams=[-E, UTF-8, --locale=en_US.UTF-8, --lc-collate=en_US.UTF-8, --lc-ctype=en_US.UTF-8]}
embedded Postgres started
***END of Postgres DB Setup Process ***
...
[INFO] --- jetty-maven-plugin:9.1.2.v20140210:run-war (start-jetty) @ BLAH ---
[INFO] Configuring Jetty for project: BlahProject
[INFO] Context path = /
[INFO] Tmp directory = some/path/to/my/webapp/target/tmp
[INFO] Web defaults = org/eclipse/jetty/webapp/webdefault.xml
[INFO] Web overrides = none
[INFO] jetty-9.1.2.v20140210
[INFO] Scanned 1 container path jars, 133 WEB-INF/lib jars, 1 WEB-INF/classes dirs in 1887ms for context o.e.j.m.p.JettyWebAppContext@444942b0{/,file:/some/path/to/my/webapp/,STARTING}{/some/path/to/my/Application-2.3.33+46be96b464dc5b57b2e2e04ce31718a01360e5fb.war}
[INFO] Initializing Spring root WebApplicationContext
INFO:20161021 12:58:27: org.springframework.web.context.ContextLoader org.springframework.web.context.ContextLoader Root WebApplicationContext: initialization started
INFO:20161021 12:58:27: org.springframework.web.context.support.XmlWebApplicationContext org.springframework.context.support.AbstractApplicationContext Refreshing Root WebApplicationContext: startup date [Fri Oct 21 12:58:27 EDT 2016]; root of context hierarchy
INFO:20161021 12:58:27: org.springframework.beans.factory.xml.XmlBeanDefinitionReader org.springframework.beans.factory.xml.XmlBeanDefinitionReader Loading XML bean definitions from class path resource [spring/app-config.xml]
INFO:20161021 12:58:27: org.springframework.beans.factory.xml.XmlBeanDefinitionReader org.springframework.beans.factory.xml.XmlBeanDefinitionReader Loading XML bean definitions from class path resource [spring/db-config.xml]
INFO:20161021 12:58:28: org.springframework.beans.factory.support.DefaultListableBeanFactory org.springframework.beans.factory.support.DefaultListableBeanFactory Overriding bean definition for bean 'endpointLTERepository': replacing [Root bean: class [org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null] with [Root bean: class [org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null]
[INFO] Started ServerConnector@3a8f9130{HTTP/1.1}{0.0.0.0:8080}
[INFO] Started Jetty Server
/Maven 控制台输出结束
我认识到 postgresql 嵌入式组件旨在在同一单元测试中启动和关闭 Postgres 数据库实例。我正在尝试找到一种使用它的方法,它比最初预期的用例更进一步。本质上,我想要一个postgresql 嵌入式服务某种可以从 Maven 插件启动的东西,然后可以用来关闭该 postgres 进程。
关于如何创建/构建这样的服务和/或插件有什么建议吗?