testcontainers-java
testcontainers-java copied to clipboard
Using a postgres image with mounted `/data` fails on LogWaitStrategy
Testcontainer: version: 1.14.3
Postgres: version: 5.6-alpine output:
PostgreSQL Database directory appears to contain a database; Skipping initialization
LOG: database system was interrupted; last known up at 2020-10-13 08:45:54 UTC
LOG: database system was not properly shut down; automatic recovery in progress
LOG: redo starts at 0/14F0430
LOG: invalid record length at 0/3356CD0: wanted 24, got 0
LOG: redo done at 0/3356CA8
LOG: last completed transaction was at log time 2020-10-13 08:46:42.609873+00
LOG: MultiXact member wraparound protections are now enabled
LOG: database system is ready to accept connections
LOG: autovacuum launcher started
Expected behavior:
- Container started successfully
Exception:
org.testcontainers.containers.ContainerLaunchException: Timed out waiting for log output matching '.*database system is ready to accept connections.*\s'
at org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy.waitUntilReady(LogMessageWaitStrategy.java:31)
Issue:
Because the image skep the initialization and the code on PostgresSQLContainer:56 is registering the LogMessageWaitStrategy to match the line ".*database system is ready to accept connections.*\\s" twice withTimes(2), the container readiness check fails.
I'm curious why the regex here is looking for a trailing whitespace character? I use the following for a postgres container and it works like a charm:
new LogMessageWaitStrategy().withRegEx(".*database system is ready to accept connections.*")
Note that I use WaitAllStrategy and also include the HostPortWaitStrategy, or connections will fail due to some race condition between observing the log line and the port being mapped.
I think the current LogMessageWaitStrategy is a bit difficult to work with, because it's looking for log lines that entirely match the expression, instead of just trying to find any match, such as with Pattern.compile(regex).matcher(logLine).find(). Using that approach wouldn't require the expression to be wrapped with .*, and could negate concerns around line terminators mentioned in the LogMessageWaitStrategy:
Predicate<OutputFrame> waitPredicate = outputFrame ->
// (?s) enables line terminator matching (equivalent to Pattern.DOTALL)
outputFrame.getUtf8String().matches("(?s)" + regEx);
I'm happy to PR such a change if it makes sense.
encountered this too
@jerryleooo Unfortunately that issue still exists. Happy to support if someone wants to have a look at it. Last time we (i.e. @TomCools) tried it, we were not able to find a consistent wait strategy implementation for both conditions, no data and pre-existing data: https://github.com/testcontainers/testcontainers-java/pull/5501
That being said, AFAIK @TomCools still implemented a workaround internally in the past, maybe he can share it again to unblock you.
@jerryleooo and @kiview. I'd have to go looking for the code that fixes this for both data/no-data cases. As you mentioned, it didn't work out back then.
In the meantime, my workaround is to just use a custom waiter if I know that the database is populated: https://github.com/TomCools/modern-testing-patterns/blob/5dde521e709a1273696f581e08ee743194245a23/testcontainers/src/test/java/be/tomcools/moderntestingpatterns/testcontainers/additional/updatecontainer/ExampleTestUsingContainerWithData.java#L32