129 lines
2.8 KiB
Go
129 lines
2.8 KiB
Go
package app
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"io"
|
|
"net"
|
|
"net/http"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestServeExposesHealthz(t *testing.T) {
|
|
server := NewServer("127.0.0.1:0", nil)
|
|
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
|
if err != nil {
|
|
t.Fatalf("net.Listen() error = %v", err)
|
|
}
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
errCh := make(chan error, 1)
|
|
go func() {
|
|
errCh <- server.Serve(ctx, listener)
|
|
}()
|
|
|
|
response := waitForHealthz(t, "http://"+listener.Addr().String()+"/healthz")
|
|
defer response.Body.Close()
|
|
|
|
body, err := io.ReadAll(response.Body)
|
|
if err != nil {
|
|
t.Fatalf("ReadAll() error = %v", err)
|
|
}
|
|
|
|
if string(body) != "ok" {
|
|
t.Fatalf("healthz body = %q, want %q", string(body), "ok")
|
|
}
|
|
|
|
cancel()
|
|
|
|
if err := <-errCh; err != nil {
|
|
t.Fatalf("Serve() error = %v, want nil", err)
|
|
}
|
|
}
|
|
|
|
func TestRunReturnsAfterContextCancellation(t *testing.T) {
|
|
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
|
if err != nil {
|
|
t.Fatalf("net.Listen() error = %v", err)
|
|
}
|
|
|
|
server := NewServer("127.0.0.1:0", func(string, string) (net.Listener, error) {
|
|
return listener, nil
|
|
})
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
errCh := make(chan error, 1)
|
|
go func() {
|
|
errCh <- server.Run(ctx)
|
|
}()
|
|
|
|
response := waitForHealthz(t, "http://"+listener.Addr().String()+"/healthz")
|
|
response.Body.Close()
|
|
|
|
cancel()
|
|
|
|
select {
|
|
case err := <-errCh:
|
|
if err != nil {
|
|
t.Fatalf("Run() error = %v, want nil", err)
|
|
}
|
|
case <-time.After(2 * time.Second):
|
|
t.Fatal("Run() did not return after context cancellation")
|
|
}
|
|
}
|
|
|
|
func TestRunReturnsListenError(t *testing.T) {
|
|
wantErr := errors.New("listen failed")
|
|
server := NewServer("127.0.0.1:0", func(string, string) (net.Listener, error) {
|
|
return nil, wantErr
|
|
})
|
|
|
|
err := server.Run(context.Background())
|
|
if !errors.Is(err, wantErr) {
|
|
t.Fatalf("Run() error = %v, want %v", err, wantErr)
|
|
}
|
|
}
|
|
|
|
func TestServeReturnsListenerError(t *testing.T) {
|
|
server := NewServer("127.0.0.1:0", nil)
|
|
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
|
if err != nil {
|
|
t.Fatalf("net.Listen() error = %v", err)
|
|
}
|
|
|
|
if err := listener.Close(); err != nil {
|
|
t.Fatalf("listener.Close() error = %v", err)
|
|
}
|
|
|
|
err = server.Serve(context.Background(), listener)
|
|
if err == nil {
|
|
t.Fatal("Serve() error = nil, want listener startup error")
|
|
}
|
|
}
|
|
|
|
func waitForHealthz(t *testing.T, url string) *http.Response {
|
|
t.Helper()
|
|
|
|
client := &http.Client{Timeout: 100 * time.Millisecond}
|
|
deadline := time.Now().Add(2 * time.Second)
|
|
|
|
for time.Now().Before(deadline) {
|
|
response, err := client.Get(url)
|
|
if err == nil && response.StatusCode == http.StatusOK {
|
|
return response
|
|
}
|
|
|
|
if response != nil {
|
|
response.Body.Close()
|
|
}
|
|
|
|
time.Sleep(20 * time.Millisecond)
|
|
}
|
|
|
|
t.Fatalf("health endpoint %q was not reachable before deadline", url)
|
|
return nil
|
|
}
|