Skip to content

Commit 0ff7c19

Browse files
committed
Update Golang test app to generate telemetry data
1 parent dce238e commit 0ff7c19

File tree

2 files changed

+116
-11
lines changed

2 files changed

+116
-11
lines changed

tests/test-e2e-apps/golang/Dockerfile

+26-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,30 @@
1-
FROM golang:1.23-alpine as builder
1+
# Stage 1: Build the Go application
2+
FROM golang:1.23.0-alpine AS builder
23

4+
# Set the working directory inside the container for the build stage.
5+
WORKDIR /app
6+
7+
# Copy the Go source file into the working directory inside the container.
38
COPY main.go .
4-
RUN CGO_ENABLED=0 GOOS=linux GO111MODULE=on go build -o app main.go
59

10+
# Build the Go application.
11+
# - CGO_ENABLED=0: Disables CGO, which is necessary to build a statically linked binary
12+
# that can run in a minimal 'scratch' image without external C libraries.
13+
# - GOOS=linux: Explicitly sets the target operating system to Linux, which is standard for containers.
14+
# -o /app/rolldice: Specifies the output path and name for the compiled executable inside this builder stage.
15+
# main.go: The source file to compile.
16+
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o /app/rolldice main.go
17+
18+
# Stage 2: Create the final minimal production image
619
FROM scratch
7-
COPY --from=builder /go/app .
8-
ENTRYPOINT ["./app"]
20+
21+
# Set the working directory for the final image.
22+
WORKDIR /
23+
24+
# Copy only the compiled binary from the 'builder' stage (/app/rolldice)
25+
# into the root directory of the final 'scratch' image.
26+
COPY --from=builder /app/rolldice /rolldice
27+
28+
# Set the command to run when the container starts.
29+
# This executes the compiled Go binary we copied into the image.
30+
ENTRYPOINT ["/rolldice"]

tests/test-e2e-apps/golang/main.go

+90-7
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,106 @@
44
package main
55

66
import (
7+
"crypto/rand"
78
"fmt"
9+
"log"
10+
"math/big"
811
"net/http"
12+
"os"
13+
"strconv"
914
"time"
1015
)
1116

17+
// getRandomNumber generates a random integer between min and max (inclusive).
18+
func getRandomNumber(min, max int) (int, error) {
19+
if min > max {
20+
return 0, fmt.Errorf("min (%d) cannot be greater than max (%d)", min, max)
21+
}
22+
23+
// Calculate the range size.
24+
rangeSize := big.NewInt(int64(max - min + 1))
25+
26+
// Generate a random number n, where 0 <= n < rangeSize.
27+
n, err := rand.Int(rand.Reader, rangeSize)
28+
if err != nil {
29+
// Return an error if random number generation fails
30+
return 0, fmt.Errorf("failed to generate random number: %w", err)
31+
}
32+
33+
// Convert the big.Int result back to a regular int.
34+
// Add min to shift the range from [0, rangeSize) to [min, max].
35+
// n.Int64() is safe here because rangeSize fits in int64 if max-min+1 does.
36+
result := int(n.Int64()) + min
37+
return result, nil
38+
}
39+
40+
// rollDiceHandler handles requests to the /rolldice endpoint.
41+
func rollDiceHandler(w http.ResponseWriter, r *http.Request) {
42+
// Ensure we only handle GET requests for this endpoint
43+
if r.Method != http.MethodGet {
44+
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
45+
return
46+
}
47+
48+
// Generate a random number between 1 and 6
49+
diceRoll, err := getRandomNumber(1, 6)
50+
if err != nil {
51+
// Log the error and return an internal server error if generation failed
52+
log.Printf("Error generating random number: %v", err)
53+
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
54+
return
55+
}
56+
57+
// Convert the integer result to a string
58+
responseString := strconv.Itoa(diceRoll)
59+
60+
// Set the content type header to text/plain
61+
w.Header().Set("Content-Type", "text/plain")
62+
63+
// Write the string response back to the client
64+
_, writeErr := fmt.Fprint(w, responseString)
65+
if writeErr != nil {
66+
// Log the error if writing the response failed (response may be partially sent)
67+
log.Printf("Error writing response: %v", writeErr)
68+
// Attempt to send an error, though headers might already be sent
69+
// http.Error(w, "Internal Server Error", http.StatusInternalServerError) // Avoid sending second error
70+
}
71+
log.Printf("Rolled a %d for request from %s", diceRoll, r.RemoteAddr) // Optional: Log the roll
72+
}
73+
1274
func main() {
13-
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
14-
fmt.Println("Hi")
15-
})
75+
// Get the port from the environment variable, default to "8095" if not set
76+
port := os.Getenv("PORT")
77+
if port == "" {
78+
port = "8095"
79+
}
80+
81+
// Register the handler function for the "/rolldice" path with the DefaultServeMux.
82+
http.HandleFunc("/rolldice", rollDiceHandler)
83+
84+
// Construct the server address string (e.g., ":8095")
85+
serverAddr := ":" + port
1686

87+
// Configure the HTTP server with timeouts
1788
server := &http.Server{
18-
Addr: ":8080",
19-
ReadHeaderTimeout: 3 * time.Second,
89+
Addr: serverAddr,
90+
// Use DefaultServeMux by leaving Handler nil, which includes our /rolldice handler
91+
Handler: nil,
92+
ReadTimeout: 10 * time.Second, // Max time to read entire request, including body
93+
WriteTimeout: 10 * time.Second, // Max time to write response
94+
IdleTimeout: 60 * time.Second, // Max time for connections using TCP Keep-Alive
2095
}
2196

97+
// Print a message indicating the server is starting
98+
log.Printf("Listening for requests on http://localhost:%s", port)
99+
100+
// Start the configured HTTP server.
101+
// This ListenAndServe is now called on our configured server instance.
22102
err := server.ListenAndServe()
23-
if err != nil {
24-
panic(err)
103+
if err != nil && err != http.ErrServerClosed {
104+
// Log any fatal errors encountered during server startup, ignore ErrServerClosed
105+
log.Fatalf("Server failed to start or unexpectedly closed: %v", err)
106+
} else if err == http.ErrServerClosed {
107+
log.Println("Server shut down gracefully")
25108
}
26109
}

0 commit comments

Comments
 (0)