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  }