github.com/epsagon/epsagon-go@v1.39.0/tracer/tracer_test.go (about) 1 package tracer_test 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "io" 8 "io/ioutil" 9 "log" 10 "net/http" 11 "net/http/httptest" 12 "os" 13 "strings" 14 15 "testing" 16 "time" 17 18 "github.com/epsagon/epsagon-go/epsagon" 19 "github.com/epsagon/epsagon-go/protocol" 20 "github.com/epsagon/epsagon-go/tracer" 21 . "github.com/onsi/ginkgo" 22 . "github.com/onsi/gomega" 23 ) 24 25 func TestEpsagonTracer(t *testing.T) { 26 RegisterFailHandler(Fail) 27 RunSpecs(t, "Epsagon Core Suite") 28 } 29 30 var _ = Describe("epsagonTracer suite", func() { 31 Describe("Run/Stop", func() { 32 }) 33 Describe("AddEvent", func() { 34 }) 35 Describe("AddException", func() { 36 }) 37 Describe("sendTraces", func() { 38 }) 39 }) 40 41 func runWithTracer(endpoint string, operations func()) { 42 tracer.GlobalTracer = nil 43 tracer.CreateGlobalTracer(&tracer.Config{ 44 CollectorURL: endpoint, 45 Token: "1", 46 }) 47 tracer.GlobalTracer.Start() 48 defer tracer.StopGlobalTracer() 49 operations() 50 } 51 52 // testWithTracer runs a test with 53 func testWithTracer(timeout *time.Duration, operations func()) *protocol.Trace { 54 traceChannel := make(chan *protocol.Trace) 55 fakeCollectorServer := httptest.NewServer(http.HandlerFunc( 56 func(res http.ResponseWriter, req *http.Request) { 57 buf, err := ioutil.ReadAll(req.Body) 58 if err != nil { 59 traceChannel <- nil 60 return 61 } 62 var receivedTrace protocol.Trace 63 err = json.Unmarshal(buf, &receivedTrace) 64 if err != nil { 65 traceChannel <- nil 66 return 67 } 68 traceChannel <- &receivedTrace 69 res.Write([]byte("")) 70 }, 71 )) 72 go runWithTracer(fakeCollectorServer.URL, operations) 73 if timeout == nil { 74 defaultTimeout := time.Second * 10 75 timeout = &defaultTimeout 76 } 77 timer := time.NewTimer(*timeout) 78 select { 79 case <-timer.C: 80 fakeCollectorServer.Close() 81 return nil 82 case trace := <-traceChannel: 83 fakeCollectorServer.Close() 84 return trace 85 } 86 } 87 88 type stubHTTPClient struct { 89 httpClient *http.Client 90 PostError error 91 } 92 93 func (s stubHTTPClient) Post(url, contentType string, body io.Reader) (resp *http.Response, err error) { 94 if s.PostError != nil { 95 return nil, s.PostError 96 } 97 return s.httpClient.Post(url, contentType, body) 98 } 99 100 func Test_handleSendTracesResponse(t *testing.T) { 101 tests := []struct { 102 name string 103 apiResponse string 104 apiStatusCode int 105 httpClient stubHTTPClient 106 expectedLog string 107 }{ 108 { 109 name: "No Log", 110 apiResponse: `{"test":"valid"}`, 111 apiStatusCode: http.StatusOK, 112 httpClient: stubHTTPClient{ 113 httpClient: &http.Client{Timeout: time.Duration(time.Second)}, 114 }, 115 expectedLog: "", 116 }, 117 { 118 name: "Error With No Response", 119 httpClient: stubHTTPClient{ 120 httpClient: &http.Client{Timeout: time.Duration(time.Second)}, 121 PostError: fmt.Errorf("Post http://not-valid-blackole.local.test: dial tcp: lookup not-valid-blackole.local.test: no such host"), 122 }, 123 expectedLog: fmt.Sprintf("Error while sending traces \nPost http://not-valid-blackole.local.test: dial tcp: lookup not-valid-blackole.local.test: no such host"), 124 }, 125 { 126 name: "Error With 5XX Response", 127 apiResponse: `{"error":"failed to send traces"}`, 128 httpClient: stubHTTPClient{ 129 httpClient: &http.Client{Timeout: time.Duration(time.Second)}, 130 }, 131 apiStatusCode: http.StatusInternalServerError, 132 expectedLog: fmt.Sprintf("Error while sending traces \n{\"error\":\"failed to send traces\"}"), 133 }, 134 } 135 for _, test := range tests { 136 t.Run(test.name, func(t *testing.T) { 137 //Read the logs to a buffer 138 buf := bytes.Buffer{} 139 log.SetOutput(&buf) 140 defer func() { 141 log.SetOutput(os.Stderr) 142 }() 143 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 144 w.WriteHeader(test.apiStatusCode) 145 w.Write([]byte(test.apiResponse)) 146 })) 147 defer server.Close() 148 resp, err := test.httpClient.Post(server.URL, "application/json", nil) 149 tracer.HandleSendTracesResponse(resp, err) 150 151 if !strings.Contains(buf.String(), test.expectedLog) { 152 t.Errorf("Unexpected log: expected %s got %s", test.expectedLog, buf.String()) 153 } 154 155 }) 156 } 157 } 158 159 func Test_AddLabel_sanity(t *testing.T) { 160 defaultTimeout := time.Second * 5 161 timeout := &defaultTimeout 162 trace := testWithTracer(timeout, func() { epsagon.Label("test_key", "test_value") }) 163 Expect(trace).ToNot(BeNil()) 164 } 165 166 func Test_AddError_sanity(t *testing.T) { 167 defaultTimeout := time.Second * 5 168 timeout := &defaultTimeout 169 trace := testWithTracer(timeout, func() { epsagon.Error("some error") }) 170 Expect(trace).ToNot(BeNil()) 171 } 172 173 func Test_AddTypeError(t *testing.T) { 174 defaultTimeout := time.Second * 5 175 timeout := &defaultTimeout 176 trace := testWithTracer(timeout, func() { epsagon.TypeError("some error", "test error type") }) 177 Expect(trace).ToNot(BeNil()) 178 } 179 180 func Test_MaxTraceSize_sanity(t *testing.T) { 181 defer os.Unsetenv(tracer.MaxTraceSizeEnvVar) 182 os.Setenv(tracer.MaxTraceSizeEnvVar, "2048") 183 defaultTimeout := time.Second * 5 184 timeout := &defaultTimeout 185 trace := testWithTracer(timeout, func() { epsagon.Label("1", "2") }) 186 Expect(trace).ToNot(BeNil()) 187 os.Setenv(tracer.MaxTraceSizeEnvVar, "64") 188 trace = testWithTracer(timeout, func() { epsagon.Label("1", "2") }) 189 Expect(trace).To(BeNil()) 190 }