无法连接到测试容器 Neo4J 实例?
Can't connect to a testcontainer Neo4J instance?
这是我的测试class:
@Testcontainers
@ReactiveDataNeo4jTest
internal class RepositoryIT {
@Container
private val container = KNeo4jContainer.instance
@Test
fun `should answer with One`() {
val boltUrl = container.getBoltUrl()
GraphDatabase.driver(
boltUrl,
AuthTokens.basic("neo4j", "123456"))
.use { driver ->
driver.session().use { session ->
val res = session.run("OPTIONAL MATCH(n) RETURN 1 AS value")
val one = res.single().get("value").asInt()
assertThat(one).isEqualTo(2)
}
}
}
}
object KNeo4jContainer {
val instance by lazy {
startNeo4jContainer()
}
private fun startNeo4jContainer(): Neo4jContainer<*> =
Neo4jContainer<Nothing>("neo4j:4.1.0").apply {
withEnv("NEO4J_AUTH", "neo4j/123456")
withExposedPorts(7687)
withExposedPorts(7473)
withExposedPorts(7474)
start()
}
}
当我检查 docker ps -a
时,它似乎已经开始了
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
-------------- ----------------------------------- ------------------------ -------------------- ------------------- --------------------------------------------------------------------------- ----------------------------------------------------------
102b11fa5c7c neo4j:4.1.0 "/sbin/tini -g -- /d…" About a minute ago Up About a minute 0.0.0.0:32791->7473/tcp, 0.0.0.0:32790->7474/tcp, 0.0.0.0:32789->7687/tcp pensive_williams
92fac72190e0 testcontainersofficial/ryuk:0.3.0 "/app" About a minute ago Up About a minute 0.0.0.0:32788->8080/tcp testcontainers-ryuk-ecc3bfaf-44ba-482d-ae5f-ddba9a70182f
但是我连接不上:
org.neo4j.driver.exceptions.ServiceUnavailableException: Unable to
connect to localhost:7687, ensure the database is running and that
there is a working network connection to it.
我可以 运行 通过 docker-compose up
:
对以相同配置启动的容器进行测试
version: "3.1"
services:
neo4j:
image: neo4j:4.1.0
ports:
# Http
- "7474:7474"
# Https
- "7473:7473"
# Bolt
- "7687:7687"
environment:
# initial password reset
"NEO4J_AUTH": "neo4j/secret"
但我认为这只是为了在开发测试时不必启动新容器。
我做错了什么?
编辑
在启动代码中设置管理员密码为空后,将 AuthTokens 更改为 AuthTokens.none() - 仍然没有成功。
编辑
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.3.RELEASE</version>
<relativePath/>
</parent>
<!-- groupId, artifactId, version, name and description ommitted -->
<properties>
<java.version>11</java.version>
<kotlin.version>1.3.72</kotlin.version>
<neo4j.test.port>7687</neo4j.test.port>
<neo4j.test.auth>neo4j/secret</neo4j.test.auth>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-kotlin</artifactId>
</dependency>
<dependency>
<groupId>io.projectreactor.kotlin</groupId>
<artifactId>reactor-kotlin-extensions</artifactId>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-coroutines-reactor</artifactId>
</dependency>
<dependency>
<groupId>org.neo4j.springframework.data</groupId>
<artifactId>spring-data-neo4j-rx-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency><dependency>
<groupId>org.neo4j.springframework.data</groupId>
<artifactId>spring-data-neo4j-rx-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.neo4j.driver</groupId>
<artifactId>neo4j-java-driver</artifactId>
<version>4.1.1</version>
</dependency>
<dependency>
<groupId>org.neo4j.springframework.data</groupId>
<artifactId>spring-data-neo4j-rx-spring-boot-test-autoconfigure</artifactId>
<version>1.1.1</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.neo4j.test</groupId>
<artifactId>neo4j-harness</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.4.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.4.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.4.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>1.14.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>1.14.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>neo4j</artifactId>
<version>1.14.3</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<configuration>
<args>
<arg>-Xjsr305=strict</arg>
</args>
<compilerPlugins>
<plugin>spring</plugin>
</compilerPlugins>
</configuration>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-allopen</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.33.0</version>
<configuration>
<images>
<image>
<name>neo4j:4.1.0</name>
<alias>neo4j</alias>
<run>
<env>
<NEO4J_AUTH>${neo4j.test.auth}</NEO4J_AUTH>
</env>
<ports>
<port>${neo4j.test.port}:3306</port>
</ports>
<wait>
<!-- time based waiting is the only option, because TCP-based or log-based polling are not reliable.
see https://github.com/fabric8io/docker-maven-plugin/issues/328
Alternatively we can wait log- or tcp-based and try to connect for a while in the test code -->
<time>8000</time>
</wait>
</run>
</image>
</images>
</configuration>
<executions>
<execution>
<id>start</id>
<phase>pre-integration-test</phase>
<goals>
<goal>start</goal>
</goals>
</execution>
<execution>
<id>stop</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<includes>
<include>**/*IT.*</include>
</includes>
<systemPropertyVariables>
<neo4j.port>${neo4j.test.port}</neo4j.port>
<neo4j.auth>${neo4j.test.auth}</neo4j.auth>
</systemPropertyVariables>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M4</version>
<configuration>
<excludes>
<exclude>**/*IT.*</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
解决方案
private fun startNeo4jContainer(): Neo4jContainer<*> {
val container = Neo4jContainer<Nothing>("neo4j:4.1.0").apply {
withAdminPassword(null)
start()
}
return container
}
发生这种情况是因为在 Windows 中,默认地址 0.0.0.0 未转换为本地主机。
我无法重现,但添加这些环境变量应该可以完成工作:
version: "3.1"
services:
neo4j:
image: neo4j:4.1.0
ports:
# Http
- "7474:7474"
# Https
- "7473:7473"
# Bolt
- "7687:7687"
environment:
# initial password reset
- NEO4J_AUTH=neo4j/secret
- NEO4J_dbms_connector_https_advertised__address=localhost:7473
- NEO4J_dbms_connector_http_advertised__address=localhost:7474
- NEO4J_dbms_connector_bolt_advertised__address=localhost:7687
这与 https://www.testcontainers.org/features/networking/
的工作方式略有不同
From the host's perspective Testcontainers actually exposes this on a
random free port. This is by design, to avoid port collisions that may
arise with locally running software or in between parallel test runs.
以及 https://www.testcontainers.org/modules/databases/jdbc/
的底部
Now, in your test code (or a suitable setup method), you can obtain
details necessary to connect to this database:
mysql.getJdbcUrl()
provides a JDBC URL your code can connect to
mysql.getUsername()
provides the username your code should pass to the driver
mysql.getPassword()
provides the password your code should pass to the driver
考虑使用 Neo4jContainer#withAdminPassword
设置密码而不是设置环境变量。
这是我的测试class:
@Testcontainers
@ReactiveDataNeo4jTest
internal class RepositoryIT {
@Container
private val container = KNeo4jContainer.instance
@Test
fun `should answer with One`() {
val boltUrl = container.getBoltUrl()
GraphDatabase.driver(
boltUrl,
AuthTokens.basic("neo4j", "123456"))
.use { driver ->
driver.session().use { session ->
val res = session.run("OPTIONAL MATCH(n) RETURN 1 AS value")
val one = res.single().get("value").asInt()
assertThat(one).isEqualTo(2)
}
}
}
}
object KNeo4jContainer {
val instance by lazy {
startNeo4jContainer()
}
private fun startNeo4jContainer(): Neo4jContainer<*> =
Neo4jContainer<Nothing>("neo4j:4.1.0").apply {
withEnv("NEO4J_AUTH", "neo4j/123456")
withExposedPorts(7687)
withExposedPorts(7473)
withExposedPorts(7474)
start()
}
}
当我检查 docker ps -a
时,它似乎已经开始了
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
-------------- ----------------------------------- ------------------------ -------------------- ------------------- --------------------------------------------------------------------------- ----------------------------------------------------------
102b11fa5c7c neo4j:4.1.0 "/sbin/tini -g -- /d…" About a minute ago Up About a minute 0.0.0.0:32791->7473/tcp, 0.0.0.0:32790->7474/tcp, 0.0.0.0:32789->7687/tcp pensive_williams
92fac72190e0 testcontainersofficial/ryuk:0.3.0 "/app" About a minute ago Up About a minute 0.0.0.0:32788->8080/tcp testcontainers-ryuk-ecc3bfaf-44ba-482d-ae5f-ddba9a70182f
但是我连接不上:
org.neo4j.driver.exceptions.ServiceUnavailableException: Unable to connect to localhost:7687, ensure the database is running and that there is a working network connection to it.
我可以 运行 通过 docker-compose up
:
version: "3.1"
services:
neo4j:
image: neo4j:4.1.0
ports:
# Http
- "7474:7474"
# Https
- "7473:7473"
# Bolt
- "7687:7687"
environment:
# initial password reset
"NEO4J_AUTH": "neo4j/secret"
但我认为这只是为了在开发测试时不必启动新容器。
我做错了什么?
编辑
在启动代码中设置管理员密码为空后,将 AuthTokens 更改为 AuthTokens.none() - 仍然没有成功。
编辑
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.3.RELEASE</version>
<relativePath/>
</parent>
<!-- groupId, artifactId, version, name and description ommitted -->
<properties>
<java.version>11</java.version>
<kotlin.version>1.3.72</kotlin.version>
<neo4j.test.port>7687</neo4j.test.port>
<neo4j.test.auth>neo4j/secret</neo4j.test.auth>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-kotlin</artifactId>
</dependency>
<dependency>
<groupId>io.projectreactor.kotlin</groupId>
<artifactId>reactor-kotlin-extensions</artifactId>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-coroutines-reactor</artifactId>
</dependency>
<dependency>
<groupId>org.neo4j.springframework.data</groupId>
<artifactId>spring-data-neo4j-rx-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency><dependency>
<groupId>org.neo4j.springframework.data</groupId>
<artifactId>spring-data-neo4j-rx-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.neo4j.driver</groupId>
<artifactId>neo4j-java-driver</artifactId>
<version>4.1.1</version>
</dependency>
<dependency>
<groupId>org.neo4j.springframework.data</groupId>
<artifactId>spring-data-neo4j-rx-spring-boot-test-autoconfigure</artifactId>
<version>1.1.1</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.neo4j.test</groupId>
<artifactId>neo4j-harness</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.4.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.4.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.4.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>1.14.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>1.14.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>neo4j</artifactId>
<version>1.14.3</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<configuration>
<args>
<arg>-Xjsr305=strict</arg>
</args>
<compilerPlugins>
<plugin>spring</plugin>
</compilerPlugins>
</configuration>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-allopen</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.33.0</version>
<configuration>
<images>
<image>
<name>neo4j:4.1.0</name>
<alias>neo4j</alias>
<run>
<env>
<NEO4J_AUTH>${neo4j.test.auth}</NEO4J_AUTH>
</env>
<ports>
<port>${neo4j.test.port}:3306</port>
</ports>
<wait>
<!-- time based waiting is the only option, because TCP-based or log-based polling are not reliable.
see https://github.com/fabric8io/docker-maven-plugin/issues/328
Alternatively we can wait log- or tcp-based and try to connect for a while in the test code -->
<time>8000</time>
</wait>
</run>
</image>
</images>
</configuration>
<executions>
<execution>
<id>start</id>
<phase>pre-integration-test</phase>
<goals>
<goal>start</goal>
</goals>
</execution>
<execution>
<id>stop</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<includes>
<include>**/*IT.*</include>
</includes>
<systemPropertyVariables>
<neo4j.port>${neo4j.test.port}</neo4j.port>
<neo4j.auth>${neo4j.test.auth}</neo4j.auth>
</systemPropertyVariables>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M4</version>
<configuration>
<excludes>
<exclude>**/*IT.*</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
解决方案
private fun startNeo4jContainer(): Neo4jContainer<*> {
val container = Neo4jContainer<Nothing>("neo4j:4.1.0").apply {
withAdminPassword(null)
start()
}
return container
}
发生这种情况是因为在 Windows 中,默认地址 0.0.0.0 未转换为本地主机。
我无法重现,但添加这些环境变量应该可以完成工作:
version: "3.1"
services:
neo4j:
image: neo4j:4.1.0
ports:
# Http
- "7474:7474"
# Https
- "7473:7473"
# Bolt
- "7687:7687"
environment:
# initial password reset
- NEO4J_AUTH=neo4j/secret
- NEO4J_dbms_connector_https_advertised__address=localhost:7473
- NEO4J_dbms_connector_http_advertised__address=localhost:7474
- NEO4J_dbms_connector_bolt_advertised__address=localhost:7687
这与 https://www.testcontainers.org/features/networking/
的工作方式略有不同From the host's perspective Testcontainers actually exposes this on a random free port. This is by design, to avoid port collisions that may arise with locally running software or in between parallel test runs.
以及 https://www.testcontainers.org/modules/databases/jdbc/
的底部Now, in your test code (or a suitable setup method), you can obtain details necessary to connect to this database:
mysql.getJdbcUrl()
provides a JDBC URL your code can connect tomysql.getUsername()
provides the username your code should pass to the drivermysql.getPassword()
provides the password your code should pass to the driver
考虑使用 Neo4jContainer#withAdminPassword
设置密码而不是设置环境变量。