(t *testing.T)
| 40 | } |
| 41 | |
| 42 | func TestAvgOverTime(t *testing.T) { |
| 43 | req := &tempopb.QueryRangeRequest{ |
| 44 | Start: 1, |
| 45 | End: uint64(3 * time.Second), |
| 46 | Step: uint64(1 * time.Second), |
| 47 | Query: "{ } | avg_over_time(duration) by (span.service)", |
| 48 | } |
| 49 | |
| 50 | // Test data designed to verify multiplication accuracy in weighted mean calculation |
| 51 | // The addWeigthedMean function uses: meanDelta := ((mean - currentMean.mean) * weight) / sumWeights |
| 52 | in := []Span{ |
| 53 | // Time interval 1: service=a has 2 spans with durations 100, 200 (mean=150, count=2) |
| 54 | newMockSpan(nil).WithStartTime(uint64(1*time.Second)).WithSpanString("service", "a").WithDuration(uint64(100 * time.Second)), |
| 55 | newMockSpan(nil).WithStartTime(uint64(1*time.Second)).WithSpanString("service", "a").WithDuration(uint64(200 * time.Second)), |
| 56 | |
| 57 | // Time interval 1: service=b has 3 spans with durations 300, 600, 900 (mean=600, count=3) |
| 58 | newMockSpan(nil).WithStartTime(uint64(1*time.Second)).WithSpanString("service", "b").WithDuration(uint64(300 * time.Second)), |
| 59 | newMockSpan(nil).WithStartTime(uint64(1*time.Second)).WithSpanString("service", "b").WithDuration(uint64(600 * time.Second)), |
| 60 | newMockSpan(nil).WithStartTime(uint64(1*time.Second)).WithSpanString("service", "b").WithDuration(uint64(900 * time.Second)), |
| 61 | |
| 62 | // Time interval 2: service=a has 4 spans with durations 400, 800, 1200, 1600 (mean=1000, count=4) |
| 63 | newMockSpan(nil).WithStartTime(uint64(2*time.Second)).WithSpanString("service", "a").WithDuration(uint64(400 * time.Second)), |
| 64 | newMockSpan(nil).WithStartTime(uint64(2*time.Second)).WithSpanString("service", "a").WithDuration(uint64(800 * time.Second)), |
| 65 | newMockSpan(nil).WithStartTime(uint64(2*time.Second)).WithSpanString("service", "a").WithDuration(uint64(1200 * time.Second)), |
| 66 | newMockSpan(nil).WithStartTime(uint64(2*time.Second)).WithSpanString("service", "a").WithDuration(uint64(1600 * time.Second)), |
| 67 | |
| 68 | // Time interval 2: service=b has 1 span with duration 2000 (mean=2000, count=1) |
| 69 | newMockSpan(nil).WithStartTime(uint64(2*time.Second)).WithSpanString("service", "b").WithDuration(uint64(2000 * time.Second)), |
| 70 | |
| 71 | // Time interval 3: service=a has varying precision values to test floating point accuracy |
| 72 | newMockSpan(nil).WithStartTime(uint64(3*time.Second)).WithSpanString("service", "a").WithDuration(uint64(123 * time.Second)), |
| 73 | newMockSpan(nil).WithStartTime(uint64(3*time.Second)).WithSpanString("service", "a").WithDuration(uint64(456 * time.Second)), |
| 74 | newMockSpan(nil).WithStartTime(uint64(3*time.Second)).WithSpanString("service", "a").WithDuration(uint64(789 * time.Second)), |
| 75 | } |
| 76 | |
| 77 | result, _, err := runTraceQLMetric(req, in) |
| 78 | require.NoError(t, err) |
| 79 | require.Equal(t, 2, len(result)) |
| 80 | |
| 81 | actualServiceA := result[LabelsFromArgs("span.service", "a").MapKey()] |
| 82 | actualServiceB := result[LabelsFromArgs("span.service", "b").MapKey()] |
| 83 | |
| 84 | expectedServiceA := []struct { |
| 85 | interval int |
| 86 | expected float64 |
| 87 | }{ |
| 88 | {0, 150.0}, // (100 + 200) / 2 = 150 s |
| 89 | {1, 1000.0}, // (400 + 800 + 1200 + 1600) / 4 = 1000 s |
| 90 | {2, 456.0}, // (123 + 456 + 789) / 3 = 456 s |
| 91 | } |
| 92 | expectedServiceB := []struct { |
| 93 | interval int |
| 94 | expected float64 |
| 95 | isNaN bool |
| 96 | }{ |
| 97 | {0, 600.0, false}, // (300 + 600 + 900) / 3 = 600 s |
| 98 | {1, 2000.0, false}, // 2000 / 1 = 2000 s |
| 99 | {2, 0.0, true}, // no spans, should be NaN |
nothing calls this directly
no test coverage detected