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