Files
sub2api-cn-relay-manager/internal/app/app_test.go
2026-05-12 22:44:30 +08:00

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
}