github.com/instana/go-sensor@v1.62.2-0.20240520081010-4919868049e1/delayed_spans_test.go (about)

     1  // (c) Copyright IBM Corp. 2022
     2  
     3  package instana
     4  
     5  import (
     6  	"context"
     7  	"fmt"
     8  	"net/http"
     9  	"net/http/httptest"
    10  	"sync"
    11  	"sync/atomic"
    12  	"testing"
    13  
    14  	"github.com/instana/go-sensor/acceptor"
    15  	"github.com/instana/go-sensor/autoprofile"
    16  	"github.com/stretchr/testify/assert"
    17  )
    18  
    19  func TestAppendALotDelayedSpans(t *testing.T) {
    20  	ds := &delayedSpans{
    21  		spans: make(chan *spanS, maxDelayedSpans),
    22  	}
    23  
    24  	i := 0
    25  	for i <= 2*maxDelayedSpans {
    26  		ds.append(&spanS{})
    27  		i++
    28  	}
    29  
    30  	assert.Len(t, ds.spans, maxDelayedSpans)
    31  }
    32  
    33  func resetDelayedSpans() {
    34  	delayed = &delayedSpans{
    35  		spans: make(chan *spanS, maxDelayedSpans),
    36  	}
    37  }
    38  
    39  func TestPartiallyFlushDelayedSpans(t *testing.T) {
    40  	defer resetDelayedSpans()
    41  
    42  	recorder := NewTestRecorder()
    43  	s := NewSensorWithTracer(NewTracerWithEverything(&Options{
    44  		Service: "go-sensor-test",
    45  		Tracer: TracerOptions{
    46  			Secrets: DefaultSecretsMatcher(),
    47  		},
    48  	}, recorder))
    49  	defer ShutdownSensor()
    50  
    51  	generateSomeTraffic(s, maxDelayedSpans)
    52  
    53  	assert.Len(t, delayed.spans, maxDelayedSpans)
    54  
    55  	notReadyAfter := maxDelayedSpans / 10
    56  	sensor.agent = &eventuallyNotReadyClient{
    57  		notReadyAfter: uint64(notReadyAfter),
    58  	}
    59  
    60  	delayed.flush()
    61  
    62  	assert.Len(t, delayed.spans, maxDelayedSpans-notReadyAfter)
    63  }
    64  
    65  func TestFlushDelayedSpans(t *testing.T) {
    66  	defer resetDelayedSpans()
    67  
    68  	recorder := NewTestRecorder()
    69  	s := NewSensorWithTracer(NewTracerWithEverything(&Options{
    70  		Service: "go-sensor-test",
    71  		Tracer: TracerOptions{
    72  			Secrets: DefaultSecretsMatcher(),
    73  		},
    74  	}, recorder))
    75  	defer ShutdownSensor()
    76  
    77  	generateSomeTraffic(s, maxDelayedSpans)
    78  
    79  	assert.Len(t, delayed.spans, maxDelayedSpans)
    80  
    81  	sensor.agent = alwaysReadyClient{}
    82  
    83  	delayed.flush()
    84  
    85  	assert.Len(t, delayed.spans, 0)
    86  }
    87  
    88  func TestParallelFlushDelayedSpans(t *testing.T) {
    89  	defer resetDelayedSpans()
    90  
    91  	m, _ := NamedMatcher(ContainsIgnoreCaseMatcher, []string{"q", "secret"})
    92  
    93  	recorder := NewTestRecorder()
    94  	s := NewSensorWithTracer(NewTracerWithEverything(&Options{
    95  		Service: "go-sensor-test",
    96  		Tracer: TracerOptions{
    97  			Secrets: m,
    98  		},
    99  	}, recorder))
   100  	defer ShutdownSensor()
   101  
   102  	generateSomeTraffic(s, maxDelayedSpans*2)
   103  
   104  	assert.Len(t, delayed.spans, maxDelayedSpans)
   105  
   106  	workers := 15
   107  	worker := 0
   108  	wg := sync.WaitGroup{}
   109  	wg.Add(workers)
   110  
   111  	sensor.agent = alwaysReadyClient{}
   112  
   113  	for worker < workers {
   114  		go func() {
   115  			delayed.flush()
   116  			wg.Done()
   117  		}()
   118  		worker++
   119  	}
   120  
   121  	wg.Wait()
   122  
   123  	recordedSpans := recorder.GetQueuedSpans()
   124  	assert.Equal(t, maxDelayedSpans, len(recordedSpans))
   125  
   126  	for _, v := range recordedSpans {
   127  		if v, ok := v.Data.(HTTPSpanData); ok {
   128  			assert.Equal(t, "q=%3Credacted%3E&secret=%3Credacted%3E", v.Tags.Params)
   129  		} else {
   130  			assert.Fail(t, "wrong span type")
   131  		}
   132  	}
   133  }
   134  
   135  type eventuallyNotReadyClient struct {
   136  	notReadyAfter uint64
   137  	ops           uint64
   138  }
   139  
   140  func (e *eventuallyNotReadyClient) Ready() bool {
   141  	n := atomic.AddUint64(&e.ops, 1)
   142  	return n <= e.notReadyAfter
   143  }
   144  
   145  func (*eventuallyNotReadyClient) SendMetrics(data acceptor.Metrics) error           { return nil }
   146  func (*eventuallyNotReadyClient) SendEvent(event *EventData) error                  { return nil }
   147  func (*eventuallyNotReadyClient) SendSpans(spans []Span) error                      { return nil }
   148  func (*eventuallyNotReadyClient) SendProfiles(profiles []autoprofile.Profile) error { return nil }
   149  func (*eventuallyNotReadyClient) Flush(context.Context) error                       { return nil }
   150  
   151  func generateSomeTraffic(s TracerLogger, amount int) {
   152  	h := TracingNamedHandlerFunc(s, "action", "/{action}", func(w http.ResponseWriter, req *http.Request) {
   153  		fmt.Fprintln(w, "Ok")
   154  	})
   155  
   156  	req := httptest.NewRequest(http.MethodGet, "/test?q=term&secret=mypassword", nil)
   157  
   158  	rec := httptest.NewRecorder()
   159  
   160  	for i := 0; i < amount; i++ {
   161  		h.ServeHTTP(rec, req)
   162  	}
   163  }