|
|
@@ -2,9 +2,14 @@ package outbound_test
|
|
|
|
|
|
import (
|
|
|
"context"
|
|
|
+ "fmt"
|
|
|
+ "sync"
|
|
|
+ "sync/atomic"
|
|
|
"testing"
|
|
|
+ "time"
|
|
|
|
|
|
"github.com/xtls/xray-core/app/policy"
|
|
|
+ "github.com/xtls/xray-core/app/proxyman"
|
|
|
. "github.com/xtls/xray-core/app/proxyman/outbound"
|
|
|
"github.com/xtls/xray-core/app/stats"
|
|
|
"github.com/xtls/xray-core/common/net"
|
|
|
@@ -78,3 +83,91 @@ func TestOutboundWithStatCounter(t *testing.T) {
|
|
|
t.Errorf("Expected conn to be CounterConnection")
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+func TestTagsCache(t *testing.T) {
|
|
|
+
|
|
|
+ test_duration := 10 * time.Second
|
|
|
+ threads_num := 50
|
|
|
+ delay := 10 * time.Millisecond
|
|
|
+ tags_prefix := "node"
|
|
|
+
|
|
|
+ tags := sync.Map{}
|
|
|
+ counter := atomic.Uint64{}
|
|
|
+
|
|
|
+ ohm, err := New(context.Background(), &proxyman.OutboundConfig{})
|
|
|
+ if err != nil {
|
|
|
+ t.Error("failed to create outbound handler manager")
|
|
|
+ }
|
|
|
+ config := &core.Config{
|
|
|
+ App: []*serial.TypedMessage{},
|
|
|
+ }
|
|
|
+ v, _ := core.New(config)
|
|
|
+ v.AddFeature(ohm)
|
|
|
+ ctx := context.WithValue(context.Background(), xrayKey, v)
|
|
|
+
|
|
|
+ stop_add_rm := false
|
|
|
+ wg_add_rm := sync.WaitGroup{}
|
|
|
+ addHandlers := func() {
|
|
|
+ defer wg_add_rm.Done()
|
|
|
+ for !stop_add_rm {
|
|
|
+ time.Sleep(delay)
|
|
|
+ idx := counter.Add(1)
|
|
|
+ tag := fmt.Sprintf("%s%d", tags_prefix, idx)
|
|
|
+ cfg := &core.OutboundHandlerConfig{
|
|
|
+ Tag: tag,
|
|
|
+ ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
|
|
+ }
|
|
|
+ if h, err := NewHandler(ctx, cfg); err == nil {
|
|
|
+ if err := ohm.AddHandler(ctx, h); err == nil {
|
|
|
+ // t.Log("add handler:", tag)
|
|
|
+ tags.Store(tag, nil)
|
|
|
+ } else {
|
|
|
+ t.Error("failed to add handler:", tag)
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ t.Error("failed to create handler:", tag)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ rmHandlers := func() {
|
|
|
+ defer wg_add_rm.Done()
|
|
|
+ for !stop_add_rm {
|
|
|
+ time.Sleep(delay)
|
|
|
+ tags.Range(func(key interface{}, value interface{}) bool {
|
|
|
+ if _, ok := tags.LoadAndDelete(key); ok {
|
|
|
+ // t.Log("remove handler:", key)
|
|
|
+ ohm.RemoveHandler(ctx, key.(string))
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ return true
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ selectors := []string{tags_prefix}
|
|
|
+ wg_get := sync.WaitGroup{}
|
|
|
+ stop_get := false
|
|
|
+ getTags := func() {
|
|
|
+ defer wg_get.Done()
|
|
|
+ for !stop_get {
|
|
|
+ time.Sleep(delay)
|
|
|
+ _ = ohm.Select(selectors)
|
|
|
+ // t.Logf("get tags: %v", tag)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for i := 0; i < threads_num; i++ {
|
|
|
+ wg_add_rm.Add(2)
|
|
|
+ go rmHandlers()
|
|
|
+ go addHandlers()
|
|
|
+ wg_get.Add(1)
|
|
|
+ go getTags()
|
|
|
+ }
|
|
|
+
|
|
|
+ time.Sleep(test_duration)
|
|
|
+ stop_add_rm = true
|
|
|
+ wg_add_rm.Wait()
|
|
|
+ stop_get = true
|
|
|
+ wg_get.Wait()
|
|
|
+}
|