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  }