mirror of
https://github.com/andwati/telecom-platform.git
synced 2026-10-28 23:52:15 +00:00
- Add SelectionAlgorithm with scoring, weighting, and ML-based carrier selection - Add SelectionCriteria struct with region, profile type, urgency, and cost/performance weights - Add CarrierScore with performance, reliability, cost, region, and capability scores - Add calculateWeightedScore combining all scores with ML-optimized weights - Add getWeights with urgency-based adjustments
309 lines
9.2 KiB
Go
309 lines
9.2 KiB
Go
package smdp
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
)
|
|
|
|
// TestMachineLearningModel tests the ML learning capabilities
|
|
func TestMachineLearningModel(t *testing.T) {
|
|
mlModel := NewLearningModel()
|
|
|
|
// Test initial state
|
|
t.Run("InitialState", func(t *testing.T) {
|
|
weights := mlModel.GetOptimizedWeights()
|
|
|
|
// Should start with base weights
|
|
if weights.Performance < 0.29 || weights.Performance > 0.31 {
|
|
t.Errorf("Expected performance weight around 0.3, got %.3f", weights.Performance)
|
|
}
|
|
|
|
stats := mlModel.GetLearningStats()
|
|
if stats["learning_rate"].(float64) <= 0 {
|
|
t.Error("Learning rate should be positive")
|
|
}
|
|
})
|
|
|
|
// Test learning updates
|
|
t.Run("LearningUpdates", func(t *testing.T) {
|
|
carrierID := "test-ml-carrier"
|
|
|
|
// Simulate multiple selections with feedback
|
|
for i := range 10 {
|
|
expectedScore := float64(70 + i*2) // Improving expected scores
|
|
actualScore := float64(65 + i*3) // Actual performance
|
|
|
|
mlModel.UpdateLearning(carrierID, actualScore, expectedScore)
|
|
}
|
|
|
|
// Check that weights have been optimized
|
|
optimizedWeights := mlModel.GetOptimizedWeights()
|
|
originalWeights := WeightVector{Performance: 0.3, Reliability: 0.3, Cost: 0.2, Region: 0.1, Capability: 0.1}
|
|
|
|
// Weights should have changed from original
|
|
if optimizedWeights.Performance == originalWeights.Performance &&
|
|
optimizedWeights.Reliability == originalWeights.Reliability {
|
|
t.Error("Expected weights to change after learning")
|
|
}
|
|
|
|
// Weights should still sum to 1
|
|
total := optimizedWeights.Performance + optimizedWeights.Reliability +
|
|
optimizedWeights.Cost + optimizedWeights.Region + optimizedWeights.Capability
|
|
if total < 0.99 || total > 1.01 {
|
|
t.Errorf("Weights should sum to 1.0, got %.3f", total)
|
|
}
|
|
})
|
|
|
|
// Test performance metrics tracking
|
|
t.Run("PerformanceMetrics", func(t *testing.T) {
|
|
carrierID := "metrics-carrier"
|
|
|
|
// Add some performance data
|
|
mlModel.UpdateLearning(carrierID, 85.0, 80.0)
|
|
mlModel.UpdateLearning(carrierID, 90.0, 85.0)
|
|
mlModel.UpdateLearning(carrierID, 78.0, 82.0)
|
|
|
|
metrics := mlModel.GetCarrierPerformance(carrierID)
|
|
if metrics == nil {
|
|
t.Fatal("Expected performance metrics for carrier")
|
|
}
|
|
|
|
if metrics.SampleCount != 3 {
|
|
t.Errorf("Expected 3 samples, got %d", metrics.SampleCount)
|
|
}
|
|
|
|
if metrics.SuccessRate < 0 || metrics.SuccessRate > 1 {
|
|
t.Errorf("Success rate should be between 0 and 1, got %.3f", metrics.SuccessRate)
|
|
}
|
|
})
|
|
|
|
// Test performance prediction
|
|
t.Run("PerformancePrediction", func(t *testing.T) {
|
|
carrierID := "prediction-carrier"
|
|
criteria := &SelectionCriteria{
|
|
Region: "US",
|
|
ProfileType: "operational",
|
|
Urgency: "medium",
|
|
CostSensitivity: 0.5,
|
|
PerformanceWeight: 0.4,
|
|
ReliabilityWeight: 0.4,
|
|
}
|
|
|
|
// Add training data
|
|
for i := range 5 {
|
|
mlModel.UpdateLearning(carrierID, 80.0+float64(i*2), 75.0+float64(i))
|
|
}
|
|
|
|
prediction := mlModel.PredictPerformance(carrierID, criteria)
|
|
if prediction < 0 || prediction > 100 {
|
|
t.Errorf("Prediction should be between 0 and 100, got %.2f", prediction)
|
|
}
|
|
|
|
// Prediction for unknown carrier should return default
|
|
unknownPrediction := mlModel.PredictPerformance("unknown-carrier", criteria)
|
|
if unknownPrediction != 75.0 {
|
|
t.Errorf("Expected default prediction for unknown carrier, got %.2f", unknownPrediction)
|
|
}
|
|
})
|
|
}
|
|
|
|
// TestMLIntegration tests the integration of ML with SelectionAlgorithm
|
|
func TestMLIntegration(t *testing.T) {
|
|
selector := NewSelectionAlgorithm()
|
|
|
|
// Create test carriers
|
|
carriers := []*Carrier{
|
|
createTestCarrier("ml-test-1", "ML Test 1", "US", 80, 85, 150, 5.0),
|
|
createTestCarrier("ml-test-2", "ML Test 2", "US", 75, 90, 120, 4.0),
|
|
}
|
|
|
|
criteria := &SelectionCriteria{
|
|
Region: "US",
|
|
ProfileType: "operational",
|
|
Urgency: "medium",
|
|
CostSensitivity: 0.5,
|
|
PerformanceWeight: 0.4,
|
|
ReliabilityWeight: 0.4,
|
|
}
|
|
|
|
// Test initial selection
|
|
t.Run("InitialSelection", func(t *testing.T) {
|
|
score, err := selector.SelectOptimalCarrier(context.Background(), carriers, criteria)
|
|
if err != nil {
|
|
t.Fatalf("Selection failed: %v", err)
|
|
}
|
|
|
|
// Provide learning feedback
|
|
selector.UpdateLearning(score.CarrierID, 85.0)
|
|
|
|
// Check learning stats
|
|
stats := selector.GetLearningStats()
|
|
if stats["total_carriers_tracked"].(int) == 0 {
|
|
t.Error("Expected carriers to be tracked in ML model")
|
|
}
|
|
})
|
|
|
|
// Test learning over multiple iterations
|
|
t.Run("IterativeLearning", func(t *testing.T) {
|
|
weightsBefore := selector.mlModel.GetOptimizedWeights()
|
|
|
|
// Perform multiple selections with feedback
|
|
for i := range 5 {
|
|
score, err := selector.SelectOptimalCarrier(context.Background(), carriers, criteria)
|
|
if err != nil {
|
|
t.Fatalf("Selection %d failed: %v", i, err)
|
|
}
|
|
|
|
// Simulate performance feedback (varying performance)
|
|
actualPerformance := 70.0 + float64(i*3)
|
|
selector.UpdateLearning(score.CarrierID, actualPerformance)
|
|
}
|
|
|
|
weightsAfter := selector.mlModel.GetOptimizedWeights()
|
|
|
|
// Weights should have been optimized
|
|
if weightsAfter.Performance == weightsBefore.Performance &&
|
|
weightsAfter.Reliability == weightsBefore.Reliability {
|
|
t.Error("Expected weights to change after learning iterations")
|
|
}
|
|
|
|
// Check performance prediction
|
|
prediction := selector.PredictPerformance("ml-test-1", criteria)
|
|
if prediction < 0 || prediction > 100 {
|
|
t.Errorf("Prediction should be between 0 and 100, got %.2f", prediction)
|
|
}
|
|
})
|
|
|
|
// Test carrier performance metrics
|
|
t.Run("CarrierPerformanceMetrics", func(t *testing.T) {
|
|
// Get performance metrics for a carrier
|
|
metrics := selector.GetCarrierPerformance("ml-test-1")
|
|
if metrics == nil {
|
|
t.Error("Expected performance metrics for carrier")
|
|
}
|
|
|
|
if metrics.SampleCount == 0 {
|
|
t.Error("Expected sample count > 0 after learning")
|
|
}
|
|
})
|
|
}
|
|
|
|
// TestMLWeightOptimization tests the weight optimization logic
|
|
func TestMLWeightOptimization(t *testing.T) {
|
|
mlModel := NewLearningModel()
|
|
|
|
t.Run("GradientDescent", func(t *testing.T) {
|
|
carrierID := "gradient-test"
|
|
|
|
// Simulate consistent poor performance to trigger weight optimization
|
|
for range 10 {
|
|
expectedScore := 80.0
|
|
actualScore := 50.0 // Consistently poor performance
|
|
|
|
mlModel.UpdateLearning(carrierID, actualScore, expectedScore)
|
|
}
|
|
|
|
weights := mlModel.GetOptimizedWeights()
|
|
|
|
// After consistent poor performance, weights should be adjusted
|
|
// This is a simplified test - in practice, the optimization is more complex
|
|
total := weights.Performance + weights.Reliability + weights.Cost + weights.Region + weights.Capability
|
|
if total < 0.99 || total > 1.01 {
|
|
t.Errorf("Weights should still sum to 1.0 after optimization, got %.3f", total)
|
|
}
|
|
|
|
// All weights should be non-negative
|
|
if weights.Performance < 0 || weights.Reliability < 0 || weights.Cost < 0 ||
|
|
weights.Region < 0 || weights.Capability < 0 {
|
|
t.Error("All weights should be non-negative")
|
|
}
|
|
})
|
|
|
|
t.Run("Regularization", func(t *testing.T) {
|
|
// Test that regularization prevents extreme weight values
|
|
carrierID := "regularization-test"
|
|
|
|
// Simulate extreme performance variations
|
|
for i := range 20 {
|
|
expectedScore := 80.0
|
|
actualScore := 20.0 + float64(i*3) // Wide range of performance
|
|
|
|
mlModel.UpdateLearning(carrierID, actualScore, expectedScore)
|
|
}
|
|
|
|
weights := mlModel.GetOptimizedWeights()
|
|
|
|
// Weights should be reasonable (not too extreme)
|
|
for _, weight := range []float64{
|
|
weights.Performance, weights.Reliability, weights.Cost,
|
|
weights.Region, weights.Capability} {
|
|
if weight < 0.05 || weight > 0.7 {
|
|
t.Errorf("Weight %.3f seems too extreme (should be between 0.05 and 0.7)", weight)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
// TestMLLearningRate tests the learning rate adaptation
|
|
func TestMLLearningRate(t *testing.T) {
|
|
mlModel := NewLearningModel()
|
|
|
|
initialLearningRate := mlModel.GetLearningStats()["learning_rate"].(float64)
|
|
|
|
// Add some learning data
|
|
for range 10 {
|
|
mlModel.UpdateLearning("rate-test", 75.0, 70.0)
|
|
}
|
|
|
|
finalLearningRate := mlModel.GetLearningStats()["learning_rate"].(float64)
|
|
|
|
// Learning rate should have decayed
|
|
if finalLearningRate >= initialLearningRate {
|
|
t.Error("Learning rate should decay over time")
|
|
}
|
|
|
|
// Learning rate should not go below minimum
|
|
if finalLearningRate < 0.001 {
|
|
t.Error("Learning rate should not go below minimum threshold")
|
|
}
|
|
}
|
|
|
|
// BenchmarkMLModel benchmarks the ML model performance
|
|
func BenchmarkMLModel(b *testing.B) {
|
|
mlModel := NewLearningModel()
|
|
carrierID := "benchmark-carrier"
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
mlModel.UpdateLearning(carrierID, 75.0, 70.0)
|
|
}
|
|
}
|
|
|
|
// BenchmarkSelectionWithML benchmarks selection with ML integration
|
|
func BenchmarkSelectionWithML(b *testing.B) {
|
|
selector := NewSelectionAlgorithm()
|
|
|
|
carriers := []*Carrier{
|
|
createTestCarrier("benchmark-1", "Benchmark 1", "US", 80, 85, 150, 5.0),
|
|
createTestCarrier("benchmark-2", "Benchmark 2", "US", 75, 90, 120, 4.0),
|
|
}
|
|
|
|
criteria := &SelectionCriteria{
|
|
Region: "US",
|
|
ProfileType: "operational",
|
|
Urgency: "medium",
|
|
CostSensitivity: 0.5,
|
|
PerformanceWeight: 0.4,
|
|
ReliabilityWeight: 0.4,
|
|
}
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
_, err := selector.SelectOptimalCarrier(context.Background(), carriers, criteria)
|
|
if err != nil {
|
|
b.Fatalf("Selection failed: %v", err)
|
|
}
|
|
selector.UpdateLearning("benchmark-1", 75.0)
|
|
}
|
|
}
|