Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.Strings;
import org.testcontainers.containers.Container.ExecResult;
import org.testcontainers.containers.ExecInContainerPattern;
import org.testcontainers.containers.wait.strategy.WaitStrategyTarget;
Expand Down Expand Up @@ -56,6 +57,9 @@ public Boolean call() {
int exitCode = result.getExitCode();
if (exitCode != 0 && exitCode != 1) {
log.warn("An exception while executing the internal check: {}", result);
if (Strings.CS.contains(result.getStdout(), "/bin/sh: no such file or directory")) {
log.warn("Unable to find '/bin/sh'. Does your Dockerfile extends scratch base Dockerfile?");
}
}
return exitCode == 0;
} catch (Exception e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@
import org.testcontainers.utility.DockerLoggerFactory;
import org.testcontainers.utility.ImageNameSubstitutor;
import org.testcontainers.utility.LazyFuture;
import org.testcontainers.utility.MountableFile;
import org.testcontainers.utility.ResourceReaper;

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
Expand Down Expand Up @@ -280,4 +282,14 @@ public ImageFromDockerfile withBuildImageCmdModifier(Consumer<BuildImageCmd> mod
this.buildImageCmdModifiers.add(modifier);
return this;
}

/**
* Sets the Dockerfile to be used for this image based on file from classpath.
*
* @param classpathResource
*/
public ImageFromDockerfile withDockerfileFromClasspath(String classpathResource) {
withDockerfile(Paths.get(MountableFile.forClasspathResource(classpathResource).getResolvedPath()));
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package org.testcontainers.containers.wait.internal;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.AppenderBase;
import lombok.Cleanup;
import org.apache.commons.lang3.function.FailableRunnable;
import org.assertj.core.api.ListAssert;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.slf4j.LoggerFactory;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.images.builder.ImageFromDockerfile;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

import static org.assertj.core.api.Assertions.assertThat;

public class InternalCommandPortListeningCheckWithScratchTest {

public static Stream<Arguments> testDockerfileFromScratchProvider() {
return Stream.of(Arguments.of("scratch", false), Arguments.of("alpine", true));
}

@ParameterizedTest(name = "Dockerfile.{0} -> {1}")
@MethodSource("testDockerfileFromScratchProvider")
public void testDockerfileFromScratch(String dockerfileKind, boolean expectedEmpty) throws Throwable {
List<ILoggingEvent> logEvents = runForLogEvents(() -> {
ImageFromDockerfile image = new ImageFromDockerfile("tc-scratch-wait-hostport-strategy")
// based on https://github.com/jeremyhuiskamp/golang-docker-scratch
.withDockerfileFromClasspath("/scratch-wait-strategy-dockerfile/Dockerfile." + dockerfileKind)
.withFileFromClasspath("go.mod", "/scratch-wait-strategy-dockerfile/go.mod")
.withFileFromClasspath("hello-world.go", "/scratch-wait-strategy-dockerfile/hello-world.go");
try (
GenericContainer<?> container = new GenericContainer<>(image)
.withCommand("/hello-world")
.withExposedPorts(8080)
) {
container.start();

// check if ports are correctly published
String response = responseFromUrl(
new URL("http://" + container.getHost() + ":" + container.getFirstMappedPort() + "/helloworld")
);
assertThat(response).isEqualTo("Hello, World!");
}
});

ListAssert<ILoggingEvent> asserting = assertThat(
logEvents
.stream()
.filter(it -> it.getLevel() == Level.WARN)
.filter(it -> it.getFormattedMessage().contains("/bin/sh: no such file or directory"))
.toList()
);
if (expectedEmpty) {
asserting.isEmpty();
} else {
asserting.isNotEmpty();
}
}

private static List<ILoggingEvent> runForLogEvents(FailableRunnable<?> action) throws Throwable {
Logger logger = (Logger) LoggerFactory.getLogger(InternalCommandPortListeningCheck.class);
TestLogAppender testLogAppender = new TestLogAppender();
logger.addAppender(testLogAppender);
testLogAppender.start();
try {
action.run();
return testLogAppender.events;
} finally {
testLogAppender.stop();
}
}

private static String responseFromUrl(URL baseUrl) throws IOException {
URLConnection urlConnection = baseUrl.openConnection();
@Cleanup
BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
return reader.readLine();
}

private static class TestLogAppender extends AppenderBase<ILoggingEvent> {

private final List<ILoggingEvent> events;

private TestLogAppender() {
this.events = new ArrayList<>();
}

@Override
protected void append(ILoggingEvent eventObject) {
events.add(eventObject);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FROM golang:alpine as app-builder
WORKDIR /go/src/app
COPY hello-world.go .
COPY go.mod .
RUN CGO_ENABLED=0 go install -ldflags '-extldflags "-static"'

FROM alpine
COPY --from=app-builder /go/bin/hello-world /hello-world
ENTRYPOINT ["/hello-world"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FROM golang:alpine as app-builder
WORKDIR /go/src/app
COPY hello-world.go .
COPY go.mod .
RUN CGO_ENABLED=0 go install -ldflags '-extldflags "-static"'

FROM scratch
COPY --from=app-builder /go/bin/hello-world /hello-world
ENTRYPOINT ["/hello-world"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/testcontainers/hello-world

go 1.16
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package main;
import (
"fmt"
"log"
"net/http"
)
func main() {
http.HandleFunc("/helloworld", func(w http.ResponseWriter, r *http.Request){
fmt.Fprintf(w, "Hello, World!")
})
fmt.Printf("Server running (port=8080), route: http://localhost:8080/helloworld\n")
if err := http.ListenAndServe(":8080", nil); err != nil {
log.Fatal(err)
}
}
Loading