
Some checks failed
CI/CD Pipeline / Run Tests (push) Has been cancelled
CI/CD Pipeline / Build Application (push) Has been cancelled
CI/CD Pipeline / Build Docker Image (push) Has been cancelled
CI/CD Pipeline / Security Scan (push) Has been cancelled
CI/CD Pipeline / Create Release (push) Has been cancelled
270 lines
8.1 KiB
Go
270 lines
8.1 KiB
Go
package proxy
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/iwasforcedtobehere/goRZ/internal/config"
|
|
)
|
|
|
|
func TestRoundRobinLoadBalancer(t *testing.T) {
|
|
targets := []config.TargetConfig{
|
|
{Name: "target1", Address: "http://localhost:8081", Protocol: "http", Weight: 1, Healthy: true},
|
|
{Name: "target2", Address: "http://localhost:8082", Protocol: "http", Weight: 1, Healthy: true},
|
|
{Name: "target3", Address: "http://localhost:8083", Protocol: "http", Weight: 1, Healthy: true},
|
|
}
|
|
|
|
lb := NewRoundRobinLoadBalancer(targets)
|
|
|
|
// Test that targets are selected in round-robin order
|
|
for i := 0; i < 6; i++ {
|
|
target, err := lb.NextTarget()
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error: %v", err)
|
|
}
|
|
|
|
expectedTarget := targets[i%3]
|
|
if target.Name != expectedTarget.Name {
|
|
t.Errorf("Expected target %s, got %s", expectedTarget.Name, target.Name)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRoundRobinLoadBalancerWithUnhealthyTargets(t *testing.T) {
|
|
targets := []config.TargetConfig{
|
|
{Name: "target1", Address: "http://localhost:8081", Protocol: "http", Weight: 1, Healthy: true},
|
|
{Name: "target2", Address: "http://localhost:8082", Protocol: "http", Weight: 1, Healthy: false},
|
|
{Name: "target3", Address: "http://localhost:8083", Protocol: "http", Weight: 1, Healthy: true},
|
|
}
|
|
|
|
lb := NewRoundRobinLoadBalancer(targets)
|
|
|
|
// Test that only healthy targets are selected
|
|
for i := 0; i < 4; i++ {
|
|
target, err := lb.NextTarget()
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error: %v", err)
|
|
}
|
|
|
|
if target.Name == "target2" {
|
|
t.Errorf("Selected unhealthy target: %s", target.Name)
|
|
}
|
|
|
|
// Should alternate between target1 and target3
|
|
if i%2 == 0 && target.Name != "target1" {
|
|
t.Errorf("Expected target1, got %s", target.Name)
|
|
}
|
|
if i%2 == 1 && target.Name != "target3" {
|
|
t.Errorf("Expected target3, got %s", target.Name)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRoundRobinLoadBalancerNoHealthyTargets(t *testing.T) {
|
|
targets := []config.TargetConfig{
|
|
{Name: "target1", Address: "http://localhost:8081", Protocol: "http", Weight: 1, Healthy: false},
|
|
{Name: "target2", Address: "http://localhost:8082", Protocol: "http", Weight: 1, Healthy: false},
|
|
}
|
|
|
|
lb := NewRoundRobinLoadBalancer(targets)
|
|
|
|
_, err := lb.NextTarget()
|
|
if err != ErrNoHealthyTargets {
|
|
t.Errorf("Expected ErrNoHealthyTargets, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestRoundRobinLoadBalancerUpdateTargets(t *testing.T) {
|
|
targets := []config.TargetConfig{
|
|
{Name: "target1", Address: "http://localhost:8081", Protocol: "http", Weight: 1, Healthy: true},
|
|
}
|
|
|
|
lb := NewRoundRobinLoadBalancer(targets)
|
|
|
|
// Get first target
|
|
target, err := lb.NextTarget()
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error: %v", err)
|
|
}
|
|
if target.Name != "target1" {
|
|
t.Errorf("Expected target1, got %s", target.Name)
|
|
}
|
|
|
|
// Update targets
|
|
newTargets := []config.TargetConfig{
|
|
{Name: "target2", Address: "http://localhost:8082", Protocol: "http", Weight: 1, Healthy: true},
|
|
{Name: "target3", Address: "http://localhost:8083", Protocol: "http", Weight: 1, Healthy: true},
|
|
}
|
|
lb.UpdateTargets(newTargets)
|
|
|
|
// Test that new targets are selected
|
|
for i := 0; i < 4; i++ {
|
|
target, err := lb.NextTarget()
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error: %v", err)
|
|
}
|
|
|
|
expectedTarget := newTargets[i%2]
|
|
if target.Name != expectedTarget.Name {
|
|
t.Errorf("Expected target %s, got %s", expectedTarget.Name, target.Name)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRandomLoadBalancer(t *testing.T) {
|
|
targets := []config.TargetConfig{
|
|
{Name: "target1", Address: "http://localhost:8081", Protocol: "http", Weight: 1, Healthy: true},
|
|
{Name: "target2", Address: "http://localhost:8082", Protocol: "http", Weight: 1, Healthy: true},
|
|
{Name: "target3", Address: "http://localhost:8083", Protocol: "http", Weight: 1, Healthy: true},
|
|
}
|
|
|
|
lb := NewRandomLoadBalancer(targets)
|
|
|
|
// Test that targets are selected randomly
|
|
// We'll just check that we don't get errors and that all targets are eventually selected
|
|
selected := make(map[string]bool)
|
|
for i := 0; i < 100; i++ {
|
|
target, err := lb.NextTarget()
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error: %v", err)
|
|
}
|
|
selected[target.Name] = true
|
|
}
|
|
|
|
// Check that all targets were selected at least once
|
|
for _, target := range targets {
|
|
if !selected[target.Name] {
|
|
t.Errorf("Target %s was never selected", target.Name)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRandomLoadBalancerWithUnhealthyTargets(t *testing.T) {
|
|
targets := []config.TargetConfig{
|
|
{Name: "target1", Address: "http://localhost:8081", Protocol: "http", Weight: 1, Healthy: true},
|
|
{Name: "target2", Address: "http://localhost:8082", Protocol: "http", Weight: 1, Healthy: false},
|
|
{Name: "target3", Address: "http://localhost:8083", Protocol: "http", Weight: 1, Healthy: true},
|
|
}
|
|
|
|
lb := NewRandomLoadBalancer(targets)
|
|
|
|
// Test that only healthy targets are selected
|
|
for i := 0; i < 100; i++ {
|
|
target, err := lb.NextTarget()
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error: %v", err)
|
|
}
|
|
|
|
if target.Name == "target2" {
|
|
t.Errorf("Selected unhealthy target: %s", target.Name)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestLeastConnectionsLoadBalancer(t *testing.T) {
|
|
targets := []config.TargetConfig{
|
|
{Name: "target1", Address: "http://localhost:8081", Protocol: "http", Weight: 1, Healthy: true},
|
|
{Name: "target2", Address: "http://localhost:8082", Protocol: "http", Weight: 1, Healthy: true},
|
|
}
|
|
|
|
lb := NewLeastConnectionsLoadBalancer(targets)
|
|
|
|
// Initially, both targets should have 0 connections
|
|
// The first target should be selected
|
|
target, err := lb.NextTarget()
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error: %v", err)
|
|
}
|
|
if target.Name != "target1" {
|
|
t.Errorf("Expected target1, got %s", target.Name)
|
|
}
|
|
|
|
// Now target1 should have 1 connection, target2 should have 0
|
|
// So target2 should be selected
|
|
target, err = lb.NextTarget()
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error: %v", err)
|
|
}
|
|
if target.Name != "target2" {
|
|
t.Errorf("Expected target2, got %s", target.Name)
|
|
}
|
|
|
|
// Now both targets should have 1 connection
|
|
// target1 should be selected again
|
|
target, err = lb.NextTarget()
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error: %v", err)
|
|
}
|
|
if target.Name != "target1" {
|
|
t.Errorf("Expected target1, got %s", target.Name)
|
|
}
|
|
|
|
// Release a connection from target1
|
|
lb.(*LeastConnectionsLoadBalancer).ReleaseConnection("target1")
|
|
|
|
// Now target1 should have 1 connection, target2 should have 1 connection
|
|
// But since we released from target1, it should be selected
|
|
target, err = lb.NextTarget()
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error: %v", err)
|
|
}
|
|
if target.Name != "target1" {
|
|
t.Errorf("Expected target1, got %s", target.Name)
|
|
}
|
|
}
|
|
|
|
func TestLeastConnectionsLoadBalancerUpdateTargets(t *testing.T) {
|
|
targets := []config.TargetConfig{
|
|
{Name: "target1", Address: "http://localhost:8081", Protocol: "http", Weight: 1, Healthy: true},
|
|
}
|
|
|
|
lb := NewLeastConnectionsLoadBalancer(targets)
|
|
|
|
// Get first target
|
|
target, err := lb.NextTarget()
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error: %v", err)
|
|
}
|
|
if target.Name != "target1" {
|
|
t.Errorf("Expected target1, got %s", target.Name)
|
|
}
|
|
|
|
// Update targets
|
|
newTargets := []config.TargetConfig{
|
|
{Name: "target2", Address: "http://localhost:8082", Protocol: "http", Weight: 1, Healthy: true},
|
|
{Name: "target3", Address: "http://localhost:8083", Protocol: "http", Weight: 1, Healthy: true},
|
|
}
|
|
lb.UpdateTargets(newTargets)
|
|
|
|
// Test that new targets are selected
|
|
// The first new target should be selected
|
|
target, err = lb.NextTarget()
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error: %v", err)
|
|
}
|
|
if target.Name != "target2" {
|
|
t.Errorf("Expected target2, got %s", target.Name)
|
|
}
|
|
|
|
// The second new target should be selected
|
|
target, err = lb.NextTarget()
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error: %v", err)
|
|
}
|
|
if target.Name != "target3" {
|
|
t.Errorf("Expected target3, got %s", target.Name)
|
|
}
|
|
}
|
|
|
|
func TestLeastConnectionsLoadBalancerNoHealthyTargets(t *testing.T) {
|
|
targets := []config.TargetConfig{
|
|
{Name: "target1", Address: "http://localhost:8081", Protocol: "http", Weight: 1, Healthy: false},
|
|
{Name: "target2", Address: "http://localhost:8082", Protocol: "http", Weight: 1, Healthy: false},
|
|
}
|
|
|
|
lb := NewLeastConnectionsLoadBalancer(targets)
|
|
|
|
_, err := lb.NextTarget()
|
|
if err != ErrNoHealthyTargets {
|
|
t.Errorf("Expected ErrNoHealthyTargets, got %v", err)
|
|
}
|
|
} |