github.com/xtls/xray-core@v1.8.12-0.20240518155711-3168d27b0bdb/app/proxyman/outbound/handler_test.go (about) 1 package outbound_test 2 3 import ( 4 "context" 5 "fmt" 6 "sync" 7 "sync/atomic" 8 "testing" 9 "time" 10 11 "github.com/xtls/xray-core/app/policy" 12 "github.com/xtls/xray-core/app/proxyman" 13 . "github.com/xtls/xray-core/app/proxyman/outbound" 14 "github.com/xtls/xray-core/app/stats" 15 "github.com/xtls/xray-core/common/net" 16 "github.com/xtls/xray-core/common/serial" 17 "github.com/xtls/xray-core/common/session" 18 core "github.com/xtls/xray-core/core" 19 "github.com/xtls/xray-core/features/outbound" 20 "github.com/xtls/xray-core/proxy/freedom" 21 "github.com/xtls/xray-core/transport/internet/stat" 22 ) 23 24 func TestInterfaces(t *testing.T) { 25 _ = (outbound.Handler)(new(Handler)) 26 _ = (outbound.Manager)(new(Manager)) 27 } 28 29 const xrayKey core.XrayKey = 1 30 31 func TestOutboundWithoutStatCounter(t *testing.T) { 32 config := &core.Config{ 33 App: []*serial.TypedMessage{ 34 serial.ToTypedMessage(&stats.Config{}), 35 serial.ToTypedMessage(&policy.Config{ 36 System: &policy.SystemPolicy{ 37 Stats: &policy.SystemPolicy_Stats{ 38 InboundUplink: true, 39 }, 40 }, 41 }), 42 }, 43 } 44 45 v, _ := core.New(config) 46 v.AddFeature((outbound.Manager)(new(Manager))) 47 ctx := context.WithValue(context.Background(), xrayKey, v) 48 ctx = session.ContextWithOutbounds(ctx, []*session.Outbound{{}}) 49 h, _ := NewHandler(ctx, &core.OutboundHandlerConfig{ 50 Tag: "tag", 51 ProxySettings: serial.ToTypedMessage(&freedom.Config{}), 52 }) 53 conn, _ := h.(*Handler).Dial(ctx, net.TCPDestination(net.DomainAddress("localhost"), 13146)) 54 _, ok := conn.(*stat.CounterConnection) 55 if ok { 56 t.Errorf("Expected conn to not be CounterConnection") 57 } 58 } 59 60 func TestOutboundWithStatCounter(t *testing.T) { 61 config := &core.Config{ 62 App: []*serial.TypedMessage{ 63 serial.ToTypedMessage(&stats.Config{}), 64 serial.ToTypedMessage(&policy.Config{ 65 System: &policy.SystemPolicy{ 66 Stats: &policy.SystemPolicy_Stats{ 67 OutboundUplink: true, 68 OutboundDownlink: true, 69 }, 70 }, 71 }), 72 }, 73 } 74 75 v, _ := core.New(config) 76 v.AddFeature((outbound.Manager)(new(Manager))) 77 ctx := context.WithValue(context.Background(), xrayKey, v) 78 ctx = session.ContextWithOutbounds(ctx, []*session.Outbound{{}}) 79 h, _ := NewHandler(ctx, &core.OutboundHandlerConfig{ 80 Tag: "tag", 81 ProxySettings: serial.ToTypedMessage(&freedom.Config{}), 82 }) 83 conn, _ := h.(*Handler).Dial(ctx, net.TCPDestination(net.DomainAddress("localhost"), 13146)) 84 _, ok := conn.(*stat.CounterConnection) 85 if !ok { 86 t.Errorf("Expected conn to be CounterConnection") 87 } 88 } 89 90 func TestTagsCache(t *testing.T) { 91 92 test_duration := 10 * time.Second 93 threads_num := 50 94 delay := 10 * time.Millisecond 95 tags_prefix := "node" 96 97 tags := sync.Map{} 98 counter := atomic.Uint64{} 99 100 ohm, err := New(context.Background(), &proxyman.OutboundConfig{}) 101 if err != nil { 102 t.Error("failed to create outbound handler manager") 103 } 104 config := &core.Config{ 105 App: []*serial.TypedMessage{}, 106 } 107 v, _ := core.New(config) 108 v.AddFeature(ohm) 109 ctx := context.WithValue(context.Background(), xrayKey, v) 110 111 stop_add_rm := false 112 wg_add_rm := sync.WaitGroup{} 113 addHandlers := func() { 114 defer wg_add_rm.Done() 115 for !stop_add_rm { 116 time.Sleep(delay) 117 idx := counter.Add(1) 118 tag := fmt.Sprintf("%s%d", tags_prefix, idx) 119 cfg := &core.OutboundHandlerConfig{ 120 Tag: tag, 121 ProxySettings: serial.ToTypedMessage(&freedom.Config{}), 122 } 123 if h, err := NewHandler(ctx, cfg); err == nil { 124 if err := ohm.AddHandler(ctx, h); err == nil { 125 // t.Log("add handler:", tag) 126 tags.Store(tag, nil) 127 } else { 128 t.Error("failed to add handler:", tag) 129 } 130 } else { 131 t.Error("failed to create handler:", tag) 132 } 133 } 134 } 135 136 rmHandlers := func() { 137 defer wg_add_rm.Done() 138 for !stop_add_rm { 139 time.Sleep(delay) 140 tags.Range(func(key interface{}, value interface{}) bool { 141 if _, ok := tags.LoadAndDelete(key); ok { 142 // t.Log("remove handler:", key) 143 ohm.RemoveHandler(ctx, key.(string)) 144 return false 145 } 146 return true 147 }) 148 } 149 } 150 151 selectors := []string{tags_prefix} 152 wg_get := sync.WaitGroup{} 153 stop_get := false 154 getTags := func() { 155 defer wg_get.Done() 156 for !stop_get { 157 time.Sleep(delay) 158 _ = ohm.Select(selectors) 159 // t.Logf("get tags: %v", tag) 160 } 161 } 162 163 for i := 0; i < threads_num; i++ { 164 wg_add_rm.Add(2) 165 go rmHandlers() 166 go addHandlers() 167 wg_get.Add(1) 168 go getTags() 169 } 170 171 time.Sleep(test_duration) 172 stop_add_rm = true 173 wg_add_rm.Wait() 174 stop_get = true 175 wg_get.Wait() 176 }