diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..31e0fce --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +helloworld diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..ec4f390 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,11 @@ +FROM golang:alpine3.12 AS builder +WORKDIR /go/src/github.com/testcontainers/helloworld +COPY go.mod go.sum ./ +RUN go mod download +COPY . ./ +RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags '-extldflags "-static"' -o /helloworld . + +FROM scratch +COPY static /static +COPY --from=builder /helloworld /helloworld +ENTRYPOINT ["/helloworld"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7582fdf --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2020 Richard North + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..5f152ec --- /dev/null +++ b/README.md @@ -0,0 +1,37 @@ +# Testcontainers Helloworld Docker Image + +This is a Docker image for use by Testcontainers' own self-test suites. It is not intended for use outside of the Testcontainers project. + +It features a small HTTP server with the following characteristics: + +* It serves content on two ports (8080 and 8081) to enable testing that multiple Docker container ports can be exposed. +* It serves an HTML root page, with a few basic elements, to enable verification that browser-based test tools can access the container. +* It serves a non-HTML endpoint at `/ping`, to enable plain HTTP testing. +* It serves a UUID unique to this running instance of the container, at `/uuid`, to enable testing of multiple container instances or testing of stop/start behaviour. +* It implements a configurable delay at startup before each port's server is started, to enable testing of startup wait strategies (TCP or HTTP-based). Setting the environment variable `DELAY_START_MSEC` to a non-zero number will: + * wait for the defined duration + * start the port 8080 server + * wait again for the same duration + * start the port 8081 server +* It emits a basic log message after starting which can be used to test log-based wait strategies. + +## Example usage + +``` +$ docker run -p 8080:8080 -p 8081:8081 -e DELAY_START_MSEC=2000 testcontainers/helloworld + +2020/09/26 08:50:55 DELAY_START_MSEC: 2000 +2020/09/26 08:50:55 Sleeping for 2000 ms +2020/09/26 08:50:57 Starting server on port 8080 +2020/09/26 08:50:57 Sleeping for 2000 ms +2020/09/26 08:50:59 Starting server on port 8081 +2020/09/26 08:50:59 Ready, listening on 8080 and 8081 +``` + +## License + +See [LICENSE](./LICENSE). + +## Copyright + +Copyright (c) 2020 Richard North and other authors. \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..298d74a --- /dev/null +++ b/go.mod @@ -0,0 +1,8 @@ +module github.com/testcontainers/helloworld + +go 1.15 + +require ( + github.com/google/uuid v1.1.2 + github.com/gorilla/handlers v1.5.1 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..2c192ef --- /dev/null +++ b/go.sum @@ -0,0 +1,6 @@ +github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= +github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= +github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= diff --git a/internal/server/server.go b/internal/server/server.go new file mode 100644 index 0000000..74c6a8a --- /dev/null +++ b/internal/server/server.go @@ -0,0 +1,51 @@ +package server + +import ( + "fmt" + "log" + "net/http" + "os" + "time" + + "github.com/google/uuid" + "github.com/gorilla/handlers" + "github.com/testcontainers/helloworld/internal/util" +) + +// StartServing starts serving content on ports 8080 and 8081 +func StartServing() { + + // We will delay, if configured to do so with an environment variable + delayStart := util.GetEnvInt("DELAY_START_MSEC", 0) + log.Printf("DELAY_START_MSEC: %d\n", delayStart) + + // Create a UUID for this container instance + instanceUUID := uuid.New().String() + + // start both servers, with delay before each + startServerOnPort(8080, instanceUUID, delayStart) + startServerOnPort(8081, instanceUUID, delayStart) +} + +func startServerOnPort(port int, instanceUUID string, delayStart int) { + fs := http.FileServer(http.Dir("./static")) + + server := http.NewServeMux() + server.Handle("/", fs) + server.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "PONG") + }) + server.HandleFunc("/uuid", func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, instanceUUID) + }) + + // Delay before the server starts + log.Printf("Sleeping for %d ms", delayStart) + time.Sleep(time.Duration(delayStart) * time.Millisecond) + + log.Printf("Starting server on port %d", port) + portName := fmt.Sprintf(":%d", port) + go func() { + log.Fatal(http.ListenAndServe(portName, handlers.LoggingHandler(os.Stdout, server))) + }() +} diff --git a/internal/util/util.go b/internal/util/util.go new file mode 100644 index 0000000..5213032 --- /dev/null +++ b/internal/util/util.go @@ -0,0 +1,19 @@ +package util + +import ( + "log" + "os" + "strconv" +) + +func GetEnvInt(key string, fallback int) int { + if valueString, ok := os.LookupEnv(key); ok { + value, err := strconv.Atoi(valueString) + if err != nil { + log.Fatalf("Environment variable %s could not be parsed as an integer. Found value: %s. Will use default value: %d\n", key, valueString, fallback) + return fallback + } + return value + } + return fallback +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..413230b --- /dev/null +++ b/main.go @@ -0,0 +1,19 @@ +package main + +import ( + "log" + + "github.com/testcontainers/helloworld/internal/server" +) + +func main() { + // Use a channel to wait indefinitely once running + finish := make(chan bool) + + server.StartServing() + + log.Println("Ready, listening on 8080 and 8081") + + // Wait + <-finish +} diff --git a/static/favicon.ico b/static/favicon.ico new file mode 100644 index 0000000..0042823 Binary files /dev/null and b/static/favicon.ico differ diff --git a/static/index.html b/static/index.html new file mode 100644 index 0000000..a972908 --- /dev/null +++ b/static/index.html @@ -0,0 +1,37 @@ + + + + + + Hello world + + + + +

Hello world

+Testcontainers logo +

+ This is a test server used for Testcontainers' own self-tests. Find out more about this image on GitHub. +

+

+ Find out more about Testcontainers at www.testcontainers.org. +

+

+ Hit /ping for a simple test response. +

+

+ Hit /uuid for a UUID that is unique to this running instance of the container. +

+ + diff --git a/static/logo.png b/static/logo.png new file mode 100644 index 0000000..696e03a Binary files /dev/null and b/static/logo.png differ