package main import ( "context" "errors" "sync" "testing" ) func TestMain_RunSuccess(t *testing.T) { origRun := apiRunFn origFatal := apiFatalFn t.Cleanup(func() { apiRunFn = origRun apiFatalFn = origFatal }) runCalled := false fatalCalled := false apiRunFn = func() error { runCalled = true return nil } apiFatalFn = func(v ...any) { fatalCalled = true } main() if !runCalled { t.Fatalf("expected main to call run function") } if fatalCalled { t.Fatalf("did not expect fatal function on successful run") } } func TestMain_RunErrorCallsFatal(t *testing.T) { origRun := apiRunFn origFatal := apiFatalFn t.Cleanup(func() { apiRunFn = origRun apiFatalFn = origFatal }) errBoom := errors.New("boom") fatalCalled := false var fatalArgs []any apiRunFn = func() error { return errBoom } apiFatalFn = func(v ...any) { fatalCalled = true fatalArgs = v } main() if !fatalCalled { t.Fatalf("expected fatal function to be called on run error") } if len(fatalArgs) != 1 || fatalArgs[0] != errBoom { t.Fatalf("unexpected fatal args: %#v", fatalArgs) } } func TestServeAPI_StartError(t *testing.T) { errBoom := errors.New("boom") srv := &stubAPIServer{startErr: errBoom} err := serveAPI(context.Background(), srv, ":8080") if !errors.Is(err, errBoom) { t.Fatalf("expected %v, got %v", errBoom, err) } if srv.shutdownCalled { t.Fatalf("did not expect shutdown to be called on start error") } } func TestServeAPI_ShutsDownOnContextCancel(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) srv := &stubAPIServer{ started: make(chan struct{}), releaseStart: make(chan struct{}), } errCh := make(chan error, 1) go func() { errCh <- serveAPI(ctx, srv, ":8080") }() <-srv.started cancel() if err := <-errCh; err != nil { t.Fatalf("expected nil error, got %v", err) } if !srv.shutdownCalled { t.Fatalf("expected shutdown to be called") } } func TestServeAPI_ReturnsShutdownError(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) errBoom := errors.New("shutdown failed") srv := &stubAPIServer{ started: make(chan struct{}), releaseStart: make(chan struct{}), shutdownErr: errBoom, } errCh := make(chan error, 1) go func() { errCh <- serveAPI(ctx, srv, ":8080") }() <-srv.started cancel() if err := <-errCh; !errors.Is(err, errBoom) { t.Fatalf("expected %v, got %v", errBoom, err) } } type stubAPIServer struct { startErr error shutdownErr error started chan struct{} releaseStart chan struct{} shutdownCalled bool releaseOnce sync.Once } func (s *stubAPIServer) Start(string) error { if s.started != nil { close(s.started) } if s.releaseStart != nil { <-s.releaseStart } return s.startErr } func (s *stubAPIServer) Shutdown(context.Context) error { s.shutdownCalled = true if s.releaseStart != nil { s.releaseOnce.Do(func() { close(s.releaseStart) }) } return s.shutdownErr }