| 
4 | 4 | package exemplar  | 
5 | 5 | 
 
  | 
6 | 6 | import (  | 
 | 7 | +	"context"  | 
 | 8 | +	"sync"  | 
7 | 9 | 	"testing"  | 
8 | 10 | 	"time"  | 
9 | 11 | 
 
  | 
@@ -144,3 +146,64 @@ func ReservoirTest[N int64 | float64](f factory) func(*testing.T) {  | 
144 | 146 | 		})  | 
145 | 147 | 	}  | 
146 | 148 | }  | 
 | 149 | + | 
 | 150 | +func reservoirConcurrentSafeTest[N int64 | float64](f factory) func(*testing.T) {  | 
 | 151 | +	return func(t *testing.T) {  | 
 | 152 | +		t.Helper()  | 
 | 153 | +		rp, n := f(1)  | 
 | 154 | +		if n < 1 {  | 
 | 155 | +			t.Skip("skipping, reservoir capacity less than 1:", n)  | 
 | 156 | +		}  | 
 | 157 | +		r := rp(*attribute.EmptySet())  | 
 | 158 | + | 
 | 159 | +		var wg sync.WaitGroup  | 
 | 160 | + | 
 | 161 | +		for i := range 5 {  | 
 | 162 | +			wg.Add(1)  | 
 | 163 | +			go func() {  | 
 | 164 | +				ctx, ts, val, attrs := generateOfferInputs[N](t, i+1)  | 
 | 165 | +				r.Offer(ctx, ts, val, attrs)  | 
 | 166 | +				wg.Done()  | 
 | 167 | +			}()  | 
 | 168 | +		}  | 
 | 169 | +		for range 2 {  | 
 | 170 | +			wg.Add(1)  | 
 | 171 | +			var dest []Exemplar  | 
 | 172 | +			r.Collect(&dest)  | 
 | 173 | +			for _, e := range dest {  | 
 | 174 | +				validateExemplar[N](t, e)  | 
 | 175 | +			}  | 
 | 176 | +			wg.Done()  | 
 | 177 | +		}  | 
 | 178 | +		wg.Wait()  | 
 | 179 | +	}  | 
 | 180 | +}  | 
 | 181 | + | 
 | 182 | +func generateOfferInputs[N int64 | float64](t *testing.T, i int) (context.Context, time.Time, Value, []attribute.KeyValue) {  | 
 | 183 | +	sc := trace.NewSpanContext(trace.SpanContextConfig{  | 
 | 184 | +		TraceID:    trace.TraceID([16]byte{byte(i)}),  | 
 | 185 | +		SpanID:     trace.SpanID([8]byte{byte(i)}),  | 
 | 186 | +		TraceFlags: trace.FlagsSampled,  | 
 | 187 | +	})  | 
 | 188 | +	ctx := trace.ContextWithSpanContext(t.Context(), sc)  | 
 | 189 | +	ts := time.Unix(int64(i), int64(i))  | 
 | 190 | +	val := NewValue(N(i))  | 
 | 191 | +	attrs := []attribute.KeyValue{attribute.Int("i", i)}  | 
 | 192 | +	return ctx, ts, val, attrs  | 
 | 193 | +}  | 
 | 194 | + | 
 | 195 | +func validateExemplar[N int64 | float64](t *testing.T, e Exemplar) {  | 
 | 196 | +	i := 0  | 
 | 197 | +	switch e.Value.Type() {  | 
 | 198 | +	case Int64ValueType:  | 
 | 199 | +		i = int(e.Value.Int64())  | 
 | 200 | +	case Float64ValueType:  | 
 | 201 | +		i = int(e.Value.Float64())  | 
 | 202 | +	}  | 
 | 203 | +	ctx, ts, _, attrs := generateOfferInputs[N](t, i)  | 
 | 204 | +	sc := trace.SpanContextFromContext(ctx)  | 
 | 205 | +	assert.Equal(t, sc.TraceID(), e.TraceID)  | 
 | 206 | +	assert.Equal(t, sc.SpanID(), e.SpanID)  | 
 | 207 | +	assert.Equal(t, ts, e.Time)  | 
 | 208 | +	assert.Equal(t, attrs, e.FilteredAttributes)  | 
 | 209 | +}  | 
0 commit comments