в настоящее время я тестирую MyService
, который зависит от AccountService
. Для этого я использую @Testcontainers
Я столкнулся с проблемой, что AccountService
не может подключиться к базе данных на моем Mac, и я не могу понять, почему, поскольку база данных доступна, и я могу подключиться к ней вручную. Я попытался подключить MyService (не в контейнере, из IntelliJ) к БД, и он отлично работает.
Я предполагаю, что проблема с конфигурацией контейнера докера для AccountService из-за этой ошибки: (см. трассировку стека ниже)
Connection refused: localhost/127.0.0.1:52801
где вы, надеюсь, можете помочь мне решить эту проблему.
Мой тестовый код
@Testcontainers
@SpringBootTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@AutoConfigureWebTestClient
@EnableAutoConfiguration
class MyServiceIntegrationTest {
private static final String ACCOUNT_SERVICE = "account-service:0.0.1";
private static final int ACCOUNT_SERVICE_INTERNAL_PORT = 8099;
private static final String ACCOUNT_SERVICE_DATABASE_NAME = "account-db";
private static final String DATABASE_USERNAME = "admin";
private static final String DATABASE_PASSWORD = "password";
@Container
public static PostgreSQLContainer<?> accountServiceDb = new PostgreSQLContainer<>("postgres:latest")
.withDatabaseName(ACCOUNT_SERVICE_DATABASE_NAME)
.withUsername(DATABASE_USERNAME)
.withPassword(DATABASE_PASSWORD);
static GenericContainer<?> accountServiceContainer;
@BeforeAll
static void setup() {
try (final Network network = Network.newNetwork()) {
final var accountServiceEnv = Map.of(
"R2DBC_URL", "r2dbc:postgresql://"
+ accountServiceDb.getHost() + ":"
+ accountServiceDb.getFirstMappedPort()
+ "/"
+ accountServiceDb.getDatabaseName(),
"DB_USERNAME", DATABASE_USERNAME,
"DB_PASSWORD", DATABASE_PASSWORD
);
accountServiceContainer = new GenericContainer<>(DockerImageName.parse(ACCOUNT_SERVICE))
.withNetwork(network)
.withNetworkAliases(ACCOUNT_SERVICE)
.withEnv(accountServiceEnv)
.withExposedPorts(ACCOUNT_SERVICE_INTERNAL_PORT);
accountServiceDb.withNetwork(network);
accountServiceContainer.start();
}
}
@Test
void intTest(){
// todo
}
}
Трассировка стека из AccountService
2023-02-22 09:16:27 2023-02-22 09:16:27.503 INFO 1 --- [ main] c.c.b.Account.AccountServiceApplication : Starting AccountServiceApplication using Java 17.0.5 on 358da35fc9e0 with PID 1 (/service.jar started by root in /)
2023-02-22 09:16:27 2023-02-22 09:16:27.517 INFO 1 --- [ main] c.c.b.Account.AccountServiceApplication : No active profile set, falling back to 1 default profile: "default"
2023-02-22 09:16:30 2023-02-22 09:16:30.833 INFO 1 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data R2DBC repositories in DEFAULT mode.
2023-02-22 09:16:30 2023-02-22 09:16:30.885 INFO 1 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 33 ms. Found 0 R2DBC repository interfaces.
2023-02-22 09:16:31 2023-02-22 09:16:31.567 INFO 1 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data R2DBC repositories in DEFAULT mode.
2023-02-22 09:16:32 2023-02-22 09:16:32.436 INFO 1 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 868 ms. Found 2 R2DBC repository interfaces.
2023-02-22 09:16:38 2023-02-22 09:16:38.398 ERROR 1 --- [tor-tcp-epoll-1] c.c.b.s.services.AccountBackendService : Error by DB creation
2023-02-22 09:16:38
2023-02-22 09:16:38 io.r2dbc.postgresql.PostgresqlConnectionFactory$PostgresConnectionException: Cannot connect to localhost/<unresolved>:52801
2023-02-22 09:16:38 at io.r2dbc.postgresql.PostgresqlConnectionFactory.cannotConnect(PostgresqlConnectionFactory.java:218) ~[r2dbc-postgresql-0.8.13.RELEASE.jar!/:0.8.13.RELEASE]
2023-02-22 09:16:38 at reactor.core.publisher.Mono.lambda$onErrorMap$31(Mono.java:3811) ~[reactor-core-3.4.26.jar!/:3.4.26]
2023-02-22 09:16:38 at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:94) ~[reactor-core-3.4.26.jar!/:3.4.26]
2023-02-22 09:16:38 at
SHORTENED
io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.87.Final.jar!/:4.1.87.Final]
2023-02-22 09:16:38 at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]
2023-02-22 09:16:38 Caused by: io.netty.channel.AbstractChannel$AnnotatedConnectException: finishConnect(..) failed: Connection refused: localhost/127.0.0.1:52801
2023-02-22 09:16:38 Caused by: java.net.ConnectException: finishConnect(..) failed: Connection refused
2023-02-22 09:16:38 at io.netty.channel.unix.Errors.newConnectException0(Errors.java:155) ~[netty-transport-native-unix-common-4.1.87.Final.jar!/:4.1.87.Final]
2023-02-22 09:16:38 at io.netty.channel.unix.Errors.handleConnectErrno(Errors.java:128) ~[netty-transport-native-unix-common-4.1.87.Final.jar!/:4.1.87.Final]
2023-02-22 09:16:38 at io.netty.channel.unix.Socket.finishConnect(Socket.java:359) ~[netty-transport-native-unix-common-4.1.87.Final.jar!/:4.1.87.Final]
2023-02-22 09:16:38 at io.netty.channel.epoll.AbstractEpollChannel$AbstractEpollUnsafe.doFinishConnect(AbstractEpollChannel.java:710) ~[netty-transport-classes-epoll-4.1.87.Final.jar!/:4.1.87.Final]
2023-02-22 09:16:38 at io.netty.channel.epoll.AbstractEpollChannel$AbstractEpollUnsafe.finishConnect(AbstractEpollChannel.java:687) ~[netty-transport-classes-epoll-4.1.87.Final.jar!/:4.1.87.Final]
2023-02-22 09:16:38 at io.netty.channel.epoll.AbstractEpollChannel$AbstractEpollUnsafe.epollOutReady(AbstractEpollChannel.java:567) ~[netty-transport-classes-epoll-4.1.87.Final.jar!/:4.1.87.Final]
2023-02-22 09:16:38 at io.netty.channel.epoll.EpollEventLoop.processReady(EpollEventLoop.java:489) ~[netty-transport-classes-epoll-4.1.87.Final.jar!/:4.1.87.Final]
2023-02-22 09:16:38 at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:397) ~[netty-transport-classes-epoll-4.1.87.Final.jar!/:4.1.87.Final]
2023-02-22 09:16:38 at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) ~[netty-common-4.1.87.Final.jar!/:4.1.87.Final]
2023-02-22 09:16:38 at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.87.Final.jar!/:4.1.87.Final]
2023-02-22 09:16:38 at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.87.Final.jar!/:4.1.87.Final]
2023-02-22 09:16:38 at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]
2023-02-22 09:16:38
2023-02-22 09:16:38 2023-02-22 09:16:38.416 ERROR 1 --- [tor-tcp-epoll-1] reactor.core.publisher.Operators : Operator called default onErrorDropped
Dockerfile службы AccountService
FROM secret/copenjdk17:17
EXPOSE 8080
EXPOSE 9090
# JMX port:
EXPOSE 9998
# Java Debug port:
EXPOSE 5004
COPY /build/libs/account-service-0.0.1.jar service.jar
STOPSIGNAL SIGINT
Заранее большое спасибо!
Вы пытаетесь соединить два контейнера друг с другом, и это не работает? В этом случае вам следует использовать сети.
Также вы имеете в виду обслуживание счета и службу хранения. Эти службы одинаковы или это просто ошибка копирования и вставки?
ошибка копирования, да. Хорошо, я рассмотрю ваше предложение сети.
Можете ли вы использовать базу данных в памяти, такую как H2, или фиктивную реализацию промежуточного сервиса вместо тестовых контейнеров здесь? Эта настройка выглядит почти так, как будто вы пытаетесь использовать Testcontainers для запуска всего стека приложений, и вам может быть лучше запустить приложение в обычном режиме с помощью Docker Compose или аналогичного, а затем запустить отдельный интеграционный тест.
@MichałKrzywański Я добавил сеть в оба контейнера. К сожалению, я получаю ту же ошибку
Вы также изменили хост базы данных в своей службе, чтобы он стал alias
контейнера базы данных в этой сети?
В вашем коде есть несколько неправильных вещей:
Вы должны использовать сопоставленный порт, если хотите подключиться из localhost
Проверьте приведенный ниже код с комментариями, которые должны указать вам правильное направление:
@Testcontainers
@SpringBootTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@AutoConfigureWebTestClient
@EnableAutoConfiguration
class MyServiceIntegrationTest {
private static final String ACCOUNT_SERVICE = "account-service:0.0.1";
private static final int ACCOUNT_SERVICE_INTERNAL_PORT = 8099;
private static final String ACCOUNT_SERVICE_DATABASE_NAME = "account-db";
private static final String DATABASE_USERNAME = "admin";
private static final String DATABASE_PASSWORD = "password";
//create network
private static final Network network = Network.newNetwork();
private static final String ACCOUNT_SERVICE_DB = "account-service-db";
@Container
public static PostgreSQLContainer<?> accountServiceDb = new PostgreSQLContainer<>("postgres:latest")
.withDatabaseName(ACCOUNT_SERVICE_DATABASE_NAME)
.withUsername(DATABASE_USERNAME)
.withPassword(DATABASE_PASSWORD)
//connect postgres db to network
.withNetwork(network)
//give the postgres DNS name
.withNetworkAliases(ACCOUNT_SERVICE_DB);
static GenericContainer<?> accountServiceContainer;
@BeforeAll
static void setup() {
final Network network = Network.newNetwork();
final var accountServiceEnv = Map.of(
"R2DBC_URL", "r2dbc:postgresql://"
//use db container DNS alias as host over common network
+ ACCOUNT_SERVICE_DB + ":"
//here we use default postgres exposed port and not host port
+ "5432"
+ "/"
+ accountServiceDb.getDatabaseName(),
"DB_USERNAME", DATABASE_USERNAME,
"DB_PASSWORD", DATABASE_PASSWORD
);
accountServiceContainer = new GenericContainer<>(DockerImageName.parse(ACCOUNT_SERVICE))
.withNetwork(network)
.withNetworkAliases(ACCOUNT_SERVICE)
.withEnv(accountServiceEnv)
.withExposedPorts(ACCOUNT_SERVICE_INTERNAL_PORT);
accountServiceDb.withNetwork(network);
accountServiceContainer.start();
}
@Test
void intTest() {
// todo
}
Не очень хорошо знаком с Testcontainers, но как работает контейнер postgres? Привязаны ли порты к хосту? Например, docker run -p 52801:$port .. или у вас установлен postgres на хосте?