mirror of
https://github.com/XTLS/Xray-core.git
synced 2024-11-25 10:01:28 +00:00
fa5d7a255b
* v5: Health Check & LeastLoad Strategy (rebased from 2c5a71490368500a982018a74a6d519c7e121816) Some changes will be necessary to integrate it into V2Ray * Update proto * parse duration conf with time.Parse() * moving health ping to observatory as a standalone component * moving health ping to observatory as a standalone component: auto generated file * add initialization for health ping * incorporate changes in router implementation * support principle target output * add v4 json support for BurstObservatory & fix balancer reference * update API command * remove cancelled API * return zero length value when observer is not found * remove duplicated targeted dispatch * adjust test with updated structure * bug fix for observer * fix strategy selector * fix strategy least load * Fix ticker usage ticker.Close does not close ticker.C * feat: Replace default Health Ping URL to HTTPS (#1991) * fix selectLeastLoad() returns wrong number of nodes (#2083) * Test: fix leastload strategy unit test * fix(router): panic caused by concurrent map read and write (#2678) * Clean up code --------- Co-authored-by: Jebbs <qjebbs@gmail.com> Co-authored-by: Shelikhoo <xiaokangwang@outlook.com> Co-authored-by: 世界 <i@sekai.icu> Co-authored-by: Bernd Eichelberger <46166740+4-FLOSS-Free-Libre-Open-Source-Software@users.noreply.github.com> Co-authored-by: 秋のかえで <autmaple@protonmail.com> Co-authored-by: Rinka <kujourinka@gmail.com>
180 lines
5 KiB
Go
180 lines
5 KiB
Go
package router
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
/*
|
|
Split into multiple package, need to be tested separately
|
|
|
|
func TestSelectLeastLoad(t *testing.T) {
|
|
settings := &StrategyLeastLoadConfig{
|
|
HealthCheck: &HealthPingConfig{
|
|
SamplingCount: 10,
|
|
},
|
|
Expected: 1,
|
|
MaxRTT: int64(time.Millisecond * time.Duration(800)),
|
|
}
|
|
strategy := NewLeastLoadStrategy(settings)
|
|
// std 40
|
|
strategy.PutResult("a", time.Millisecond*time.Duration(60))
|
|
strategy.PutResult("a", time.Millisecond*time.Duration(140))
|
|
strategy.PutResult("a", time.Millisecond*time.Duration(60))
|
|
strategy.PutResult("a", time.Millisecond*time.Duration(140))
|
|
// std 60
|
|
strategy.PutResult("b", time.Millisecond*time.Duration(40))
|
|
strategy.PutResult("b", time.Millisecond*time.Duration(160))
|
|
strategy.PutResult("b", time.Millisecond*time.Duration(40))
|
|
strategy.PutResult("b", time.Millisecond*time.Duration(160))
|
|
// std 0, but >MaxRTT
|
|
strategy.PutResult("c", time.Millisecond*time.Duration(1000))
|
|
strategy.PutResult("c", time.Millisecond*time.Duration(1000))
|
|
strategy.PutResult("c", time.Millisecond*time.Duration(1000))
|
|
strategy.PutResult("c", time.Millisecond*time.Duration(1000))
|
|
expected := "a"
|
|
actual := strategy.SelectAndPick([]string{"a", "b", "c", "untested"})
|
|
if actual != expected {
|
|
t.Errorf("expected: %v, actual: %v", expected, actual)
|
|
}
|
|
}
|
|
|
|
func TestSelectLeastLoadWithCost(t *testing.T) {
|
|
settings := &StrategyLeastLoadConfig{
|
|
HealthCheck: &HealthPingConfig{
|
|
SamplingCount: 10,
|
|
},
|
|
Costs: []*StrategyWeight{
|
|
{Match: "a", Value: 9},
|
|
},
|
|
Expected: 1,
|
|
}
|
|
strategy := NewLeastLoadStrategy(settings, nil)
|
|
// std 40, std+c 120
|
|
strategy.PutResult("a", time.Millisecond*time.Duration(60))
|
|
strategy.PutResult("a", time.Millisecond*time.Duration(140))
|
|
strategy.PutResult("a", time.Millisecond*time.Duration(60))
|
|
strategy.PutResult("a", time.Millisecond*time.Duration(140))
|
|
// std 60
|
|
strategy.PutResult("b", time.Millisecond*time.Duration(40))
|
|
strategy.PutResult("b", time.Millisecond*time.Duration(160))
|
|
strategy.PutResult("b", time.Millisecond*time.Duration(40))
|
|
strategy.PutResult("b", time.Millisecond*time.Duration(160))
|
|
expected := "b"
|
|
actual := strategy.SelectAndPick([]string{"a", "b", "untested"})
|
|
if actual != expected {
|
|
t.Errorf("expected: %v, actual: %v", expected, actual)
|
|
}
|
|
}
|
|
*/
|
|
func TestSelectLeastExpected(t *testing.T) {
|
|
strategy := &LeastLoadStrategy{
|
|
settings: &StrategyLeastLoadConfig{
|
|
Baselines: nil,
|
|
Expected: 3,
|
|
},
|
|
}
|
|
nodes := []*node{
|
|
{Tag: "a", RTTDeviationCost: 100},
|
|
{Tag: "b", RTTDeviationCost: 200},
|
|
{Tag: "c", RTTDeviationCost: 300},
|
|
{Tag: "d", RTTDeviationCost: 350},
|
|
}
|
|
expected := 3
|
|
ns := strategy.selectLeastLoad(nodes)
|
|
if len(ns) != expected {
|
|
t.Errorf("expected: %v, actual: %v", expected, len(ns))
|
|
}
|
|
}
|
|
func TestSelectLeastExpected2(t *testing.T) {
|
|
strategy := &LeastLoadStrategy{
|
|
settings: &StrategyLeastLoadConfig{
|
|
Baselines: nil,
|
|
Expected: 3,
|
|
},
|
|
}
|
|
nodes := []*node{
|
|
{Tag: "a", RTTDeviationCost: 100},
|
|
{Tag: "b", RTTDeviationCost: 200},
|
|
}
|
|
expected := 2
|
|
ns := strategy.selectLeastLoad(nodes)
|
|
if len(ns) != expected {
|
|
t.Errorf("expected: %v, actual: %v", expected, len(ns))
|
|
}
|
|
}
|
|
func TestSelectLeastExpectedAndBaselines(t *testing.T) {
|
|
strategy := &LeastLoadStrategy{
|
|
settings: &StrategyLeastLoadConfig{
|
|
Baselines: []int64{200, 300, 400},
|
|
Expected: 3,
|
|
},
|
|
}
|
|
nodes := []*node{
|
|
{Tag: "a", RTTDeviationCost: 100},
|
|
{Tag: "b", RTTDeviationCost: 200},
|
|
{Tag: "c", RTTDeviationCost: 250},
|
|
{Tag: "d", RTTDeviationCost: 300},
|
|
{Tag: "e", RTTDeviationCost: 310},
|
|
}
|
|
expected := 3
|
|
ns := strategy.selectLeastLoad(nodes)
|
|
if len(ns) != expected {
|
|
t.Errorf("expected: %v, actual: %v", expected, len(ns))
|
|
}
|
|
}
|
|
func TestSelectLeastExpectedAndBaselines2(t *testing.T) {
|
|
strategy := &LeastLoadStrategy{
|
|
settings: &StrategyLeastLoadConfig{
|
|
Baselines: []int64{200, 300, 400},
|
|
Expected: 3,
|
|
},
|
|
}
|
|
nodes := []*node{
|
|
{Tag: "a", RTTDeviationCost: 500},
|
|
{Tag: "b", RTTDeviationCost: 600},
|
|
{Tag: "c", RTTDeviationCost: 700},
|
|
{Tag: "d", RTTDeviationCost: 800},
|
|
{Tag: "e", RTTDeviationCost: 900},
|
|
}
|
|
expected := 3
|
|
ns := strategy.selectLeastLoad(nodes)
|
|
if len(ns) != expected {
|
|
t.Errorf("expected: %v, actual: %v", expected, len(ns))
|
|
}
|
|
}
|
|
func TestSelectLeastLoadBaselines(t *testing.T) {
|
|
strategy := &LeastLoadStrategy{
|
|
settings: &StrategyLeastLoadConfig{
|
|
Baselines: []int64{200, 400, 600},
|
|
Expected: 0,
|
|
},
|
|
}
|
|
nodes := []*node{
|
|
{Tag: "a", RTTDeviationCost: 100},
|
|
{Tag: "b", RTTDeviationCost: 200},
|
|
{Tag: "c", RTTDeviationCost: 300},
|
|
}
|
|
expected := 1
|
|
ns := strategy.selectLeastLoad(nodes)
|
|
if len(ns) != expected {
|
|
t.Errorf("expected: %v, actual: %v", expected, len(ns))
|
|
}
|
|
}
|
|
func TestSelectLeastLoadBaselinesNoQualified(t *testing.T) {
|
|
strategy := &LeastLoadStrategy{
|
|
settings: &StrategyLeastLoadConfig{
|
|
Baselines: []int64{200, 400, 600},
|
|
Expected: 0,
|
|
},
|
|
}
|
|
nodes := []*node{
|
|
{Tag: "a", RTTDeviationCost: 800},
|
|
{Tag: "b", RTTDeviationCost: 1000},
|
|
}
|
|
expected := 0
|
|
ns := strategy.selectLeastLoad(nodes)
|
|
if len(ns) != expected {
|
|
t.Errorf("expected: %v, actual: %v", expected, len(ns))
|
|
}
|
|
}
|