@Override
    protected void waitUntilReady() {
        final String containerName = waitStrategyTarget.getContainerInfo().getName();

        final Integer livenessCheckPort = livenessPort
            .map(waitStrategyTarget::getMappedPort)
            .orElseGet(() -> {
                final Set<Integer> livenessCheckPorts = getLivenessCheckPorts();
                if (livenessCheckPorts == null || livenessCheckPorts.isEmpty()) {
                    log.warn("{}: No exposed ports or mapped ports - cannot wait for status", containerName);
                    return -1;
                }
                return livenessCheckPorts.iterator().next();
            });

        if (null == livenessCheckPort || -1 == livenessCheckPort) {
            return;
        }
        final URI rawUri = buildLivenessUri(livenessCheckPort);
        final String uri = rawUri.toString();

        try {
            // Un-map the port for logging
            int originalPort = waitStrategyTarget
                .getExposedPorts()
                .stream()
                .filter(exposedPort -> rawUri.getPort() == waitStrategyTarget.getMappedPort(exposedPort))
                .findFirst()
                .orElseThrow(() -> new IllegalStateException("Target port " + rawUri.getPort() + " is not exposed"));
            log.info(
                "{}: Waiting for {} seconds for URL: {} (where port {} maps to container port {})",
                containerName,
                startupTimeout.getSeconds(),
                uri,
                rawUri.getPort(),
                originalPort
            );
        } catch (RuntimeException e) {
            // do not allow a failure in logging to prevent progress, but log for diagnosis
            log.warn("Unexpected error occurred - will proceed to try to wait anyway", e);
        }

        // try to connect to the URL
        try {
            retryUntilSuccess(
                (int) startupTimeout.getSeconds(),
                TimeUnit.SECONDS,
                () -> {
                    getRateLimiter()
                        .doWhenReady(() -> {
                            try {
                                final HttpURLConnection connection = openConnection(uri);
                                connection.setReadTimeout(Math.toIntExact(readTimeout.toMillis()));

                                // authenticate
                                if (!Strings.isNullOrEmpty(username)) {
                                    connection.setRequestProperty(
                                        HEADER_AUTHORIZATION,
                                        buildAuthString(username, password)
                                    );
                                    connection.setUseCaches(false);
                                }

                                // Add user configured headers
                                this.headers.forEach(connection::setRequestProperty);
                                connection.setRequestMethod(method);
                                connection.connect();

                                log.trace("Get response code {}", connection.getResponseCode());

                                // Choose the statusCodePredicate strategy depending on what we defined.
                                Predicate<Integer> predicate;
                                if (statusCodes.isEmpty() && statusCodePredicate == null) {
                                    // We have no status code and no predicate so we expect a 200 OK response code
                                    predicate = responseCode -> HttpURLConnection.HTTP_OK == responseCode;
                                } else if (!statusCodes.isEmpty() && statusCodePredicate == null) {
                                    // We use the default status predicate checker when we only have status codes
                                    predicate = responseCode -> statusCodes.contains(responseCode);
                                } else if (statusCodes.isEmpty()) {
                                    // We only have a predicate
                                    predicate = statusCodePredicate;
                                } else {
                                    // We have both predicate and status code
                                    predicate =
                                        statusCodePredicate.or(responseCode -> statusCodes.contains(responseCode));
                                }
                                if (!predicate.test(connection.getResponseCode())) {
                                    throw new RuntimeException(
                                        String.format("HTTP response code was: %s", connection.getResponseCode())
                                    );
                                }

                                if (responsePredicate != null) {
                                    String responseBody = getResponseBody(connection);

                                    log.trace("Get response {}", responseBody);

                                    if (!responsePredicate.test(responseBody)) {
                                        throw new RuntimeException(
                                            String.format("Response: %s did not match predicate", responseBody)
                                        );
                                    }
                                }
                            } catch (IOException e) {
                                throw new RuntimeException(e);
                            }
                        });
                    return true;
                }
            );
        } catch (TimeoutException e) {
            throw new ContainerLaunchException(
                String.format(
                    "Timed out waiting for URL to be accessible (%s should return HTTP %s)",
                    uri,
                    statusCodes.isEmpty() ? HttpURLConnection.HTTP_OK : statusCodes
                ),
                e
            );
        }
    }
Waits for the response to pass the given predicate
@param responsePredicate The predicate to test the response against
@return this
core/src/main/java/org/testcontainers/containers/wait/strategy/HttpWaitStrategy.java