github.com/haraldrudell/parl@v0.4.176/phttp/http_test.go (about) 1 /* 2 © 2021–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/) 3 ISC License 4 */ 5 6 package phttp 7 8 import ( 9 "fmt" 10 "net/http" 11 "net/netip" 12 "sync/atomic" 13 "testing" 14 15 "github.com/haraldrudell/parl" 16 "github.com/haraldrudell/parl/perrors" 17 "github.com/haraldrudell/parl/pnet" 18 ) 19 20 func TestNewHttp(t *testing.T) { 21 var nearSocketInvalid0 = netip.AddrPort{} 22 var expAddr1 = ":http" 23 var nearSocket0 = netip.MustParseAddrPort("1.2.3.4:0") 24 var expAddr2 = "1.2.3.4:http" 25 var nearSocket6 = netip.MustParseAddrPort("[::1]:1024") 26 var expAddr3 = "[::1]:1024" 27 28 // HandleFunc() Listen() SendErr() Shutdown() WaitForUp() 29 var pnetHttp *Http 30 31 // nearSocket invalid 0 32 pnetHttp = NewHttp(nearSocketInvalid0, pnet.NetworkDefault) 33 // addr: ":http" network: tcp 34 t.Logf("addr: %q network: %s", pnetHttp.Server.Addr, pnetHttp.Network) 35 if pnetHttp.Network != pnet.NetworkTCP { 36 t.Errorf("New1 bad network %s exp %s", pnetHttp.Network, pnet.NetworkTCP) 37 } 38 if pnetHttp.Server.Addr != expAddr1 { 39 t.Errorf("New1 bad addr %q exp %q", pnetHttp.Server.Addr, expAddr1) 40 } 41 42 // port 0 43 pnetHttp = NewHttp(nearSocket0, pnet.NetworkTCP) 44 if pnetHttp.Network != pnet.NetworkTCP { 45 t.Errorf("New bad network %s exp %s", pnetHttp.Network, pnet.NetworkTCP) 46 } 47 if pnetHttp.Server.Addr != expAddr2 { 48 t.Errorf("New1 bad addr %q exp %q", pnetHttp.Server.Addr, expAddr1) 49 } 50 51 // IPv6 52 pnetHttp = NewHttp(nearSocket6, pnet.NetworkTCP) 53 if pnetHttp.Network != pnet.NetworkTCP { 54 t.Errorf("New bad network %s exp %s", pnetHttp.Network, pnet.NetworkTCP) 55 } 56 if pnetHttp.Server.Addr != expAddr3 { 57 t.Errorf("New1 bad addr %q exp %q", pnetHttp.Server.Addr, expAddr1) 58 } 59 } 60 61 func TestHttp(t *testing.T) { 62 var nearSocket netip.AddrPort 63 var network pnet.Network 64 // "/" matches everything 65 var URIPattern = "/" 66 67 var protocol = "http://" 68 var handler *sHandler 69 var near, respS string 70 var resp *http.Response 71 var err error 72 var statusCode int 73 var goResult = parl.NewGoResult() 74 75 // HandleFunc() Listen() SendErr() Shutdown() WaitForUp() 76 var pnetHttp *Http = NewHttp(nearSocket, network) 77 handler = newShandler() 78 pnetHttp.HandleFunc(URIPattern, handler.Handle) 79 defer pnetHttp.Shutdown() 80 81 t.Log("invoking Listen") 82 go errChListener(pnetHttp.Listen(), goResult) 83 84 t.Log("waiting for ListenAwaitable") 85 <-pnetHttp.ListenAwaitable.Ch() 86 if !pnetHttp.Near.IsValid() { 87 t.Fatalf("FATAL: pnetHttp.Near invalid") 88 } 89 near = pnetHttp.Near.String() 90 t.Logf("Near: %s", near) 91 92 t.Log("issuing http.GET") 93 resp, err = http.Get(protocol + near) 94 if resp != nil { 95 statusCode = resp.StatusCode 96 respS = fmt.Sprintf("status code: %d", statusCode) 97 } else { 98 respS = "resp nil" 99 } 100 101 t.Logf("%s err: %s", respS, perrors.Short(err)) 102 if err != nil { 103 t.Errorf("http.Get err %s", perrors.Short(err)) 104 } 105 // status code should be 204 106 if resp != nil { 107 if resp.StatusCode != http.StatusNoContent { 108 t.Errorf("http.Get status code %d exp %d", resp.StatusCode, http.StatusNoContent) 109 } 110 if e := resp.Body.Close(); e != nil { 111 panic(e) 112 } 113 } 114 115 // handle count should be 1 116 if c := int(handler.Rqs.Load()); c != 1 { 117 t.Errorf("bad handle count: %d exp 1", c) 118 } 119 120 t.Logf("Shutting down server") 121 pnetHttp.Shutdown() 122 123 // wait for error reader to exit 124 goResult.ReceiveError(nil) 125 126 if !pnetHttp.ErrCh.IsClosed() { 127 t.Error("ErrCh not closed") 128 } 129 if !pnetHttp.EndListenAwaitable.IsClosed() { 130 t.Error("EndListenAwaitable not closed") 131 } 132 } 133 134 // errChListener is goroutine consuming http error channel 135 func errChListener(errCh <-chan error, g parl.GoResult) { 136 var err error 137 defer g.SendError(&err) 138 139 for err = range errCh { 140 parl.Log(perrors.Long(err)) 141 panic(err) 142 } 143 } 144 145 // sHandler counts incoming requests 146 type sHandler struct{ Rqs atomic.Uint64 } 147 148 // newShandler returns a request counter 149 func newShandler() (s *sHandler) { return &sHandler{} } 150 151 // Handle is the http-server handler function 152 func (s *sHandler) Handle(w http.ResponseWriter, r *http.Request) { 153 s.Rqs.Add(1) 154 w.WriteHeader(http.StatusNoContent) 155 }