176 lines
6.3 KiB
Go
176 lines
6.3 KiB
Go
package report
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"llm-api-benchmark-tool/pkg/stats"
|
|
"github.com/go-echarts/go-echarts/v2/opts"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestCalculateHistogram(t *testing.T) {
|
|
// Helper function to create durations from milliseconds
|
|
dms := func(ms int) time.Duration {
|
|
return time.Duration(ms) * time.Millisecond
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
data []time.Duration
|
|
numBins int
|
|
wantCats []string
|
|
wantDataVals []int // Just check the values
|
|
isErrorCase bool // Indicates if we expect the "No Data" case
|
|
}{
|
|
{
|
|
name: "Empty data",
|
|
data: []time.Duration{},
|
|
numBins: 5,
|
|
wantCats: []string{"No Data"},
|
|
wantDataVals: []int{0},
|
|
isErrorCase: true,
|
|
},
|
|
{
|
|
name: "Zero bins",
|
|
data: []time.Duration{dms(100), dms(200)},
|
|
numBins: 0,
|
|
wantCats: []string{"No Data"},
|
|
wantDataVals: []int{0},
|
|
isErrorCase: true,
|
|
},
|
|
{
|
|
name: "Single data point",
|
|
data: []time.Duration{dms(150)},
|
|
numBins: 5,
|
|
wantCats: []string{"150.00 ms"}, // Special case format
|
|
wantDataVals: []int{1},
|
|
},
|
|
{
|
|
name: "All data points same",
|
|
data: []time.Duration{dms(100), dms(100), dms(100)},
|
|
numBins: 3,
|
|
wantCats: []string{"100.00 ms"},
|
|
wantDataVals: []int{3},
|
|
},
|
|
{
|
|
name: "Simple case, 2 bins",
|
|
data: []time.Duration{dms(50), dms(60), dms(110), dms(120), dms(130)},
|
|
// Range: 50 to 130 (80ms)
|
|
// Bin width: 80 / 2 = 40
|
|
// Bins: [50, 90), [90, 130]
|
|
numBins: 2,
|
|
wantCats: []string{"[50.00, 90.00) ms", "[90.00, 130.00] ms"},
|
|
wantDataVals: []int{2, 3},
|
|
},
|
|
{
|
|
name: "Even distribution, 5 bins",
|
|
data: []time.Duration{dms(10), dms(25), dms(35), dms(45), dms(55), dms(65), dms(75), dms(85), dms(95), dms(100)},
|
|
// Range: 10 to 100 (90ms) -> max should be 100? Let's make max 110 for simpler bins
|
|
// Let's adjust data slightly for easier math: min 10, max 110
|
|
// data: {10, 25, 35, 45, 55, 65, 75, 85, 95, 110}
|
|
// Range: 10 to 110 (100ms)
|
|
// Bin width: 100 / 5 = 20
|
|
// Bins: [10,30), [30,50), [50,70), [70,90), [90,110]
|
|
numBins: 5,
|
|
wantCats: []string{"[10.00, 28.00) ms", "[28.00, 46.00) ms", "[46.00, 64.00) ms", "[64.00, 82.00) ms", "[82.00, 100.00] ms"},
|
|
wantDataVals: []int{2, 2, 1, 2, 3},
|
|
},
|
|
{
|
|
name: "Data clustered at ends",
|
|
data: []time.Duration{dms(10), dms(15), dms(20), dms(90), dms(95), dms(100)},
|
|
// Range: 10 to 100 (90). Width (3 bins): 30.
|
|
// Bins: [10, 40), [40, 70), [70, 100]
|
|
numBins: 3,
|
|
wantCats: []string{"[10.00, 40.00) ms", "[40.00, 70.00) ms", "[70.00, 100.00] ms"},
|
|
wantDataVals: []int{3, 0, 3},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
gcats, gdata := calculateHistogram(tt.data, tt.numBins)
|
|
|
|
require.Equal(t, len(tt.wantCats), len(gcats), "Number of categories mismatch")
|
|
assert.Equal(t, tt.wantCats, gcats, "Category labels mismatch")
|
|
|
|
require.Equal(t, len(tt.wantDataVals), len(gdata), "Number of data points mismatch")
|
|
|
|
// Extract values from opts.BarData
|
|
gotDataVals := make([]int, len(gdata))
|
|
for i, item := range gdata {
|
|
// Check if item.Value is an int or can be converted
|
|
if val, ok := item.Value.(int); ok {
|
|
gotDataVals[i] = val
|
|
} else if valF, ok := item.Value.(float64); ok {
|
|
gotDataVals[i] = int(valF) // Or handle float differently if needed
|
|
} else {
|
|
t.Fatalf("Unexpected data type in BarData: %T", item.Value)
|
|
}
|
|
}
|
|
assert.Equal(t, tt.wantDataVals, gotDataVals, "Data values mismatch")
|
|
})
|
|
}
|
|
}
|
|
|
|
// Helper to create durations
|
|
func dms(ms int) time.Duration {
|
|
return time.Duration(ms) * time.Millisecond
|
|
}
|
|
|
|
// TestCreateLatencyHistogram checks if the latency histogram chart is created correctly.
|
|
func TestCreateLatencyHistogram(t *testing.T) {
|
|
mockStats := stats.FinalStats{
|
|
LatencyData: []time.Duration{dms(50), dms(100), dms(110), dms(150), dms(200), dms(210), dms(220)},
|
|
}
|
|
|
|
chart := createLatencyHistogram(mockStats)
|
|
|
|
require.NotNil(t, chart, "Chart should not be nil")
|
|
require.NotNil(t, chart.BaseConfiguration.Title, "Chart title configuration should not be nil")
|
|
|
|
// Check title
|
|
assert.Equal(t, "Latency Distribution", chart.BaseConfiguration.Title.Title, "Chart title mismatch")
|
|
|
|
// Check series data (basic check - assuming one series with correct name)
|
|
require.Len(t, chart.MultiSeries, 1, "Expected one series")
|
|
assert.Equal(t, "Latency", chart.MultiSeries[0].Name, "Series name mismatch")
|
|
|
|
// Optionally, check the number of data points generated by calculateHistogram via the chart
|
|
// This depends on the numBins used internally by createLatencyHistogram (currently 10)
|
|
// For the mock data {50, 100, 110, 150, 200, 210, 220}, range=170, 10 bins -> width=17
|
|
// Bins: [50, 67), [67, 84), [84, 101), [101, 118), [118, 135), [135, 152), [152, 169), [169, 186), [186, 203), [203, 220]
|
|
// Counts: 1, 0, 1, 1, 0, 1, 0, 0, 1, 2 -> Total 7 points, 10 bars
|
|
seriesData, ok := chart.MultiSeries[0].Data.([]opts.BarData)
|
|
require.True(t, ok, "Series data should be of type []opts.BarData")
|
|
assert.Len(t, seriesData, 10, "Expected 10 data points (bins) in the series")
|
|
}
|
|
|
|
// TestCreateTTFTHistogram checks if the TTFT histogram chart is created correctly.
|
|
func TestCreateTTFTHistogram(t *testing.T) {
|
|
mockStats := stats.FinalStats{
|
|
TTFTData: []time.Duration{dms(20), dms(30), dms(35), dms(40), dms(60)},
|
|
}
|
|
|
|
chart := createTTFTHistogram(mockStats)
|
|
|
|
require.NotNil(t, chart, "Chart should not be nil")
|
|
require.NotNil(t, chart.BaseConfiguration.Title, "Chart title configuration should not be nil")
|
|
|
|
// Check title
|
|
assert.Equal(t, "TTFT Distribution", chart.BaseConfiguration.Title.Title, "Chart title mismatch")
|
|
|
|
// Check series data
|
|
require.Len(t, chart.MultiSeries, 1, "Expected one series")
|
|
assert.Equal(t, "TTFT", chart.MultiSeries[0].Name, "Series name mismatch")
|
|
|
|
// Optionally, check the number of data points
|
|
// Data: {20, 30, 35, 40, 60}, Range=40, 10 bins -> width=4
|
|
// Bins: [20,24), [24,28), [28,32), [32,36), [36,40), [40,44), [44,48), [48,52), [52,56), [56,60]
|
|
// Counts: 1, 0, 1, 1, 0, 1, 0, 0, 0, 1 -> Total 5 points, 10 bars
|
|
seriesData, ok := chart.MultiSeries[0].Data.([]opts.BarData)
|
|
require.True(t, ok, "Series data should be of type []opts.BarData")
|
|
assert.Len(t, seriesData, 10, "Expected 10 data points (bins) in the series")
|
|
}
|