Files

279 lines
6.8 KiB
Go
Raw Permalink Normal View History

package tuning
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestTimeoutAnalyzer(t *testing.T) {
ta := NewTimeoutAnalyzer(t.TempDir())
// Record some metrics
ta.RecordExecution("activity1", 1*time.Second, true, nil)
ta.RecordExecution("activity1", 2*time.Second, true, nil)
ta.RecordExecution("activity1", 3*time.Second, true, nil)
assert.Equal(t, 3, ta.GetMetricsCount())
}
func TestAnalyzeMetrics(t *testing.T) {
ta := NewTimeoutAnalyzer(t.TempDir())
// Record metrics with P95 around 9s
for i := 1; i <= 20; i++ {
duration := time.Duration(i) * time.Second
ta.RecordExecution("activity1", duration, true, nil)
}
currentTimeouts := map[string]time.Duration{
"activity1": 5 * time.Second,
}
recommendations, err := ta.Analyze(currentTimeouts)
assert.NoError(t, err)
assert.Greater(t, len(recommendations), 0)
rec := recommendations[0]
assert.Equal(t, "activity1", rec.ActivityType)
assert.Equal(t, 5*time.Second, rec.CurrentTimeout)
assert.Greater(t, rec.RecommendedTimeout, rec.CurrentTimeout)
}
func TestAnalyzeWithFailures(t *testing.T) {
ta := NewTimeoutAnalyzer(t.TempDir())
// Record some failures
for i := 0; i < 5; i++ {
ta.RecordExecution("slow_activity", 10*time.Second, false, assert.AnError)
}
currentTimeouts := map[string]time.Duration{
"slow_activity": 5 * time.Second,
}
recommendations, err := ta.Analyze(currentTimeouts)
assert.NoError(t, err)
if len(recommendations) > 0 {
rec := recommendations[0]
assert.Equal(t, 5, rec.FailureCount)
assert.Greater(t, rec.RecommendedTimeout, rec.CurrentTimeout)
}
}
func TestCalculatePercentile(t *testing.T) {
durations := []time.Duration{
1 * time.Second,
2 * time.Second,
3 * time.Second,
4 * time.Second,
5 * time.Second,
6 * time.Second,
7 * time.Second,
8 * time.Second,
9 * time.Second,
10 * time.Second,
}
p95 := calculatePercentile(durations, 0.95)
assert.NotZero(t, p95)
assert.LessOrEqual(t, p95, 10*time.Second)
p99 := calculatePercentile(durations, 0.99)
assert.NotZero(t, p99)
assert.GreaterOrEqual(t, p99, p95)
}
func TestCalculateAverage(t *testing.T) {
durations := []time.Duration{
1 * time.Second,
2 * time.Second,
3 * time.Second,
}
avg := calculateAverage(durations)
assert.Equal(t, 2*time.Second, avg)
}
func TestCalculateConfidence(t *testing.T) {
// Perfect success
conf := calculateConfidence(100, 0)
assert.Equal(t, 1.0, conf)
// 50% success
conf = calculateConfidence(50, 50)
assert.Greater(t, conf, 0.0)
assert.Less(t, conf, 1.0)
// All failures
conf = calculateConfidence(0, 100)
assert.Less(t, conf, 1.0)
}
func TestGroupMetricsByActivity(t *testing.T) {
ta := NewTimeoutAnalyzer(t.TempDir())
ta.RecordExecution("activity1", 1*time.Second, true, nil)
ta.RecordExecution("activity1", 2*time.Second, true, nil)
ta.RecordExecution("activity2", 3*time.Second, true, nil)
groups := ta.groupMetricsByActivity()
assert.Equal(t, 2, len(groups))
assert.Equal(t, 2, len(groups["activity1"]))
assert.Equal(t, 1, len(groups["activity2"]))
}
func TestClearMetrics(t *testing.T) {
ta := NewTimeoutAnalyzer(t.TempDir())
ta.RecordExecution("activity1", 1*time.Second, true, nil)
assert.Equal(t, 1, ta.GetMetricsCount())
ta.ClearMetrics()
assert.Equal(t, 0, ta.GetMetricsCount())
}
func TestGetRecommendations(t *testing.T) {
ta := NewTimeoutAnalyzer(t.TempDir())
ta.RecordExecution("activity1", 1*time.Second, true, nil)
ta.RecordExecution("activity1", 2*time.Second, true, nil)
currentTimeouts := map[string]time.Duration{
"activity1": 5 * time.Second,
}
ta.Analyze(currentTimeouts)
recs := ta.GetRecommendations()
assert.IsType(t, make(map[string]*TimeoutRecommendation), recs)
}
func TestRecommendationStructure(t *testing.T) {
ta := NewTimeoutAnalyzer(t.TempDir())
// Record consistent executions
for i := 0; i < 10; i++ {
ta.RecordExecution("activity1", 5*time.Second, true, nil)
}
currentTimeouts := map[string]time.Duration{
"activity1": 2 * time.Second, // Too tight
}
recommendations, err := ta.Analyze(currentTimeouts)
assert.NoError(t, err)
if len(recommendations) > 0 {
rec := recommendations[0]
assert.NotEmpty(t, rec.ActivityType)
assert.NotZero(t, rec.CurrentTimeout)
assert.NotZero(t, rec.P95Duration)
assert.Greater(t, rec.SuccessCount, 0)
assert.NotEmpty(t, rec.Reason)
assert.Greater(t, rec.Confidence, 0.0)
}
}
func TestMultipleActivities(t *testing.T) {
ta := NewTimeoutAnalyzer(t.TempDir())
// Record metrics for multiple activities
for i := 0; i < 10; i++ {
ta.RecordExecution("fast_activity", time.Duration(i+1)*time.Second, true, nil)
ta.RecordExecution("slow_activity", time.Duration(i+10)*time.Second, true, nil)
}
currentTimeouts := map[string]time.Duration{
"fast_activity": 3 * time.Second,
"slow_activity": 5 * time.Second,
}
recommendations, err := ta.Analyze(currentTimeouts)
assert.NoError(t, err)
assert.Greater(t, len(recommendations), 0)
// Check that we get recommendations for both activities
hasSlowActivity := false
for _, rec := range recommendations {
if rec.ActivityType == "slow_activity" {
hasSlowActivity = true
break
}
}
assert.True(t, hasSlowActivity)
}
func TestEmptyMetrics(t *testing.T) {
ta := NewTimeoutAnalyzer(t.TempDir())
currentTimeouts := map[string]time.Duration{
"activity1": 5 * time.Second,
}
recommendations, err := ta.Analyze(currentTimeouts)
assert.NoError(t, err)
assert.Equal(t, 0, len(recommendations))
}
func TestAllFailures(t *testing.T) {
ta := NewTimeoutAnalyzer(t.TempDir())
// Record only failures
for i := 0; i < 5; i++ {
ta.RecordExecution("activity1", 1*time.Second, false, assert.AnError)
}
currentTimeouts := map[string]time.Duration{
"activity1": 5 * time.Second,
}
recommendations, err := ta.Analyze(currentTimeouts)
assert.NoError(t, err)
// Should recommend increase despite no successes
if len(recommendations) > 0 {
rec := recommendations[0]
assert.Equal(t, 5, rec.FailureCount)
assert.Equal(t, 0, rec.SuccessCount)
}
}
func TestSaveAndLoadMetrics(t *testing.T) {
tmpDir := t.TempDir()
ta1 := NewTimeoutAnalyzer(tmpDir)
// Record and save
ta1.RecordExecution("activity1", 1*time.Second, true, nil)
ta1.RecordExecution("activity1", 2*time.Second, true, nil)
err := ta1.SaveMetrics()
assert.NoError(t, err)
// Load in new analyzer
ta2 := NewTimeoutAnalyzer(tmpDir)
err = ta2.LoadMetrics()
assert.NoError(t, err)
assert.Equal(t, ta1.GetMetricsCount(), ta2.GetMetricsCount())
}
func TestSaveRecommendations(t *testing.T) {
tmpDir := t.TempDir()
ta := NewTimeoutAnalyzer(tmpDir)
recommendations := []TimeoutRecommendation{
{
ActivityType: "activity1",
CurrentTimeout: 5 * time.Second,
RecommendedTimeout: 10 * time.Second,
Confidence: 0.95,
Timestamp: time.Now(),
},
}
err := ta.SaveRecommendations(recommendations)
assert.NoError(t, err)
}