github.com/epsagon/epsagon-go@v1.39.0/wrappers/net/http/handler_wrapper_test.go (about) 1 package epsagonhttp 2 3 import ( 4 "bytes" 5 "context" 6 "encoding/json" 7 "io/ioutil" 8 "net/http" 9 "net/http/httptest" 10 11 "github.com/epsagon/epsagon-go/epsagon" 12 "github.com/epsagon/epsagon-go/protocol" 13 "github.com/epsagon/epsagon-go/tracer" 14 . "github.com/onsi/ginkgo" 15 . "github.com/onsi/gomega" 16 ) 17 18 var _ = Describe("http_wrapper", func() { 19 Describe("WrapHandleFunc", func() { 20 var ( 21 events []*protocol.Event 22 exceptions []*protocol.Exception 23 request *http.Request 24 responseWriter *httptest.ResponseRecorder 25 called bool 26 config *epsagon.Config 27 ) 28 BeforeEach(func() { 29 called = false 30 config = &epsagon.Config{Config: tracer.Config{ 31 Disable: true, 32 TestMode: true, 33 }} 34 events = make([]*protocol.Event, 0) 35 exceptions = make([]*protocol.Exception, 0) 36 tracer.GlobalTracer = &tracer.MockedEpsagonTracer{ 37 Events: &events, 38 Exceptions: &exceptions, 39 Labels: make(map[string]interface{}), 40 Config: &config.Config, 41 } 42 body := []byte("hello") 43 request = httptest.NewRequest("POST", "https://www.help.com", ioutil.NopCloser(bytes.NewReader(body))) 44 responseWriter = httptest.NewRecorder() 45 }) 46 Context("Happy Flows", func() { 47 It("calls the wrapped function", func() { 48 wrapper := WrapHandleFunc( 49 config, 50 func(rw http.ResponseWriter, req *http.Request) { 51 called = true 52 }, 53 ) 54 wrapper(responseWriter, request) 55 Expect(called).To(Equal(true)) 56 }) 57 It("passes the tracer through request context", func() { 58 wrapper := WrapHandleFunc( 59 config, 60 func(rw http.ResponseWriter, req *http.Request) { 61 called = true 62 tracer := epsagon.ExtractTracer([]context.Context{req.Context()}) 63 tracer.AddLabel("test", "ok") 64 }, 65 ) 66 wrapper(responseWriter, request) 67 Expect(called).To(Equal(true)) 68 Expect( 69 tracer.GlobalTracer.(*tracer.MockedEpsagonTracer).Labels["test"], 70 ).To(Equal("ok")) 71 }) 72 It("Creates a runner and trigger events for handler invocation", func() { 73 wrapper := WrapHandleFunc( 74 config, 75 func(rw http.ResponseWriter, req *http.Request) { 76 called = true 77 }, 78 "test-handler", 79 ) 80 wrapper(responseWriter, request) 81 Expect(len(events)).To(Equal(2)) 82 var runnerEvent *protocol.Event 83 for _, event := range events { 84 if event.Origin == "runner" { 85 runnerEvent = event 86 } 87 } 88 Expect(runnerEvent).NotTo(Equal(nil)) 89 Expect(runnerEvent.Resource.Type).To(Equal("go-function")) 90 Expect(runnerEvent.Resource.Name).To(Equal("test-handler")) 91 }) 92 It("Adds correct trigger event", func() { 93 body := []byte("hello world") 94 request = httptest.NewRequest( 95 "POST", 96 "https://www.help.com/test?hello=world&good=bye", 97 ioutil.NopCloser(bytes.NewReader(body))) 98 wrapper := WrapHandleFunc( 99 config, 100 func(rw http.ResponseWriter, req *http.Request) { 101 called = true 102 internalHandlerBody, err := ioutil.ReadAll(req.Body) 103 if err != nil { 104 Expect(true).To(Equal(false)) 105 } 106 Expect(internalHandlerBody).To(Equal(body)) 107 resp, err := json.Marshal(map[string]string{"hello": "world"}) 108 if err != nil { 109 Expect(true).To(Equal(false)) 110 } 111 rw.Header().Add("Content-Type", "application/json; charset=utf-8") 112 _, err = rw.Write(resp) 113 if err != nil { 114 Expect(true).To(Equal(false)) 115 } 116 117 }, 118 "test-handler", 119 ) 120 wrapper(responseWriter, request) 121 Expect(len(events)).To(Equal(2)) 122 var triggerEvent *protocol.Event 123 for _, event := range events { 124 if event.Origin == "trigger" { 125 triggerEvent = event 126 } 127 } 128 Expect(triggerEvent).NotTo(Equal(nil)) 129 Expect(triggerEvent.Resource.Name).To(Equal("www.help.com")) 130 Expect(triggerEvent.Resource.Type).To(Equal("http")) 131 Expect(triggerEvent.Resource.Operation).To(Equal("POST")) 132 expectedQuery, _ := json.Marshal(map[string][]string{ 133 "hello": {"world"}, "good": {"bye"}}) 134 Expect(triggerEvent.Resource.Metadata["query_string_parameters"]).To( 135 Equal(string(expectedQuery))) 136 Expect(triggerEvent.Resource.Metadata["path"]).To( 137 Equal("/test")) 138 Expect(triggerEvent.Resource.Metadata["request_body"]).To( 139 Equal(string(body))) 140 Expect(triggerEvent.Resource.Metadata["response_body"]).To( 141 Equal("{\"hello\":\"world\"}")) 142 Expect(triggerEvent.Resource.Metadata["response_headers"]).To( 143 Equal("{\"Content-Type\":\"application/json; charset=utf-8\"}")) 144 Expect(triggerEvent.Resource.Metadata["status_code"]).To( 145 Equal("200")) 146 }) 147 It("Doesn't collect body and headers if MetadataOnly", func() { 148 config.MetadataOnly = true 149 body := []byte("hello world") 150 request = httptest.NewRequest( 151 "POST", 152 "https://www.help.com/test?hello=world&good=bye", 153 ioutil.NopCloser(bytes.NewReader(body))) 154 wrapper := WrapHandleFunc( 155 config, 156 func(rw http.ResponseWriter, req *http.Request) { 157 called = true 158 internalHandlerBody, err := ioutil.ReadAll(req.Body) 159 if err != nil { 160 Expect(true).To(Equal(false)) 161 } 162 Expect(internalHandlerBody).To(Equal(body)) 163 resp, err := json.Marshal(map[string]string{"hello": "world"}) 164 if err != nil { 165 Expect(true).To(Equal(false)) 166 } 167 rw.Header().Add("Content-Type", "application/json; charset=utf-8") 168 _, err = rw.Write(resp) 169 if err != nil { 170 Expect(true).To(Equal(false)) 171 } 172 173 }, 174 "test-handler", 175 ) 176 wrapper(responseWriter, request) 177 Expect(len(events)).To(Equal(2)) 178 var triggerEvent *protocol.Event 179 for _, event := range events { 180 if event.Origin == "trigger" { 181 triggerEvent = event 182 } 183 } 184 Expect(triggerEvent).NotTo(Equal(nil)) 185 Expect(triggerEvent.Resource.Metadata["request_body"]).To( 186 Equal("")) 187 Expect(triggerEvent.Resource.Metadata["response_body"]).To( 188 Equal("")) 189 Expect(triggerEvent.Resource.Metadata["response_headers"]).To( 190 Equal("")) 191 Expect(triggerEvent.Resource.Metadata["query_string_parameters"]).To( 192 Equal("")) 193 }) 194 }) 195 Context("Error Flows", func() { 196 It("Adds Exception if handler explodes", func() { 197 errorMessage := "boom" 198 Expect(func() { 199 wrapper := WrapHandleFunc( 200 config, 201 func(rw http.ResponseWriter, req *http.Request) { 202 called = true 203 panic(errorMessage) 204 }, 205 "test-handler", 206 ) 207 wrapper(responseWriter, request) 208 }).To( 209 PanicWith(epsagon.MatchUserError(errorMessage))) 210 Expect(called).To(Equal(true)) 211 Expect(len(events)).To(Equal(2)) 212 var runnerEvent, triggerEvent *protocol.Event 213 for _, event := range events { 214 if event.Origin == "runner" { 215 runnerEvent = event 216 } 217 if event.Origin == "trigger" { 218 triggerEvent = event 219 } 220 } 221 Expect(runnerEvent.Exception).NotTo(Equal(nil)) 222 Expect(triggerEvent.Exception).NotTo(Equal(nil)) 223 Expect(triggerEvent.Resource.Metadata["status_code"]).To( 224 Equal("500")) 225 }) 226 }) 227 }) 228 })