github.com/ActiveState/cli@v0.0.0-20240508170324-6801f60cd051/test/pseudo/cmd/internal/serve/serve.go (about) 1 package serve 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "io" 8 "net" 9 "net/http" 10 "time" 11 ) 12 13 type Serve struct { 14 h *http.Server 15 errs chan error 16 } 17 18 func New() *Serve { 19 return &Serve{ 20 h: &http.Server{ 21 Handler: NewEndpoints(), 22 }, 23 } 24 } 25 26 func (s *Serve) Run() (string, error) { 27 emsg := "serve run: %w" 28 29 l, err := net.Listen("tcp", "127.0.0.1:0") 30 if err != nil { 31 return "", fmt.Errorf(emsg, err) 32 } 33 34 if s.errs == nil { 35 s.errs = make(chan error) 36 } 37 38 go func() { 39 defer close(s.errs) 40 s.errs <- s.h.Serve(l) 41 }() 42 43 return l.Addr().String(), nil 44 } 45 46 func (s *Serve) Close() error { 47 ctx, cancel := context.WithTimeout(context.Background(), time.Second*3) 48 defer cancel() 49 50 if err := s.h.Shutdown(ctx); err != nil { 51 return err 52 } 53 54 if err := <-s.errs; err != nil && !errors.Is(err, http.ErrServerClosed) { 55 return err 56 } 57 58 return nil 59 } 60 61 var handleInfoPath = "/info" 62 63 type Endpoints struct { 64 h http.Handler 65 } 66 67 func NewEndpoints() *Endpoints { 68 m := http.NewServeMux() 69 m.HandleFunc(handleInfoPath, handleInfo) 70 71 return &Endpoints{ 72 h: m, 73 } 74 } 75 76 func (es *Endpoints) ServeHTTP(w http.ResponseWriter, r *http.Request) { 77 es.h.ServeHTTP(w, r) 78 } 79 80 func handleInfo(w http.ResponseWriter, r *http.Request) { 81 fmt.Fprintln(w, "DATA") 82 } 83 84 type Client struct { 85 addr string 86 c *http.Client 87 } 88 89 func NewClient(addr string) *Client { 90 return &Client{ 91 addr: addr, 92 c: &http.Client{}, 93 } 94 } 95 96 func (c *Client) GetInfo() (string, error) { 97 r, err := c.c.Get("http://" + c.addr + handleInfoPath) 98 if err != nil { 99 return "", err 100 } 101 defer r.Body.Close() 102 103 body, err := io.ReadAll(r.Body) 104 if err != nil { 105 return "", err 106 } 107 108 return string(body), nil 109 }