github.com/yaling888/clash@v1.53.0/component/fakeip/pool_test.go (about)

     1  package fakeip
     2  
     3  import (
     4  	"fmt"
     5  	"net/netip"
     6  	"os"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  	"go.etcd.io/bbolt"
    12  
    13  	"github.com/yaling888/clash/component/profile/cachefile"
    14  	"github.com/yaling888/clash/component/trie"
    15  )
    16  
    17  func createPools(options Options) ([]*Pool, string, error) {
    18  	pool, err := New(options)
    19  	if err != nil {
    20  		return nil, "", err
    21  	}
    22  	filePool, tempfile, err := createCachefileStore(options)
    23  	if err != nil {
    24  		return nil, "", err
    25  	}
    26  
    27  	return []*Pool{pool, filePool}, tempfile, nil
    28  }
    29  
    30  func createCachefileStore(options Options) (*Pool, string, error) {
    31  	pool, err := New(options)
    32  	if err != nil {
    33  		return nil, "", err
    34  	}
    35  	f, err := os.CreateTemp("", "clash")
    36  	if err != nil {
    37  		return nil, "", err
    38  	}
    39  
    40  	db, err := bbolt.Open(f.Name(), 0o666, &bbolt.Options{Timeout: time.Second})
    41  	if err != nil {
    42  		return nil, "", err
    43  	}
    44  
    45  	pool.store = &cachefileStore{
    46  		cache: &cachefile.CacheFile{DB: db},
    47  	}
    48  	return pool, f.Name(), nil
    49  }
    50  
    51  func TestPool_Basic(t *testing.T) {
    52  	ipnet := netip.MustParsePrefix("192.168.0.0/28")
    53  	pools, tempfile, err := createPools(Options{
    54  		IPNet: &ipnet,
    55  		Size:  10,
    56  	})
    57  	assert.Nil(t, err)
    58  	defer os.Remove(tempfile)
    59  
    60  	for _, pool := range pools {
    61  		first := pool.Lookup("foo.com")
    62  		last := pool.Lookup("bar.com")
    63  		bar, exist := pool.LookBack(last)
    64  
    65  		assert.True(t, first == netip.AddrFrom4([4]byte{192, 168, 0, 3}))
    66  		assert.True(t, pool.Lookup("foo.com") == netip.AddrFrom4([4]byte{192, 168, 0, 3}))
    67  		assert.True(t, last == netip.AddrFrom4([4]byte{192, 168, 0, 4}))
    68  		assert.True(t, exist)
    69  		assert.Equal(t, bar, "bar.com")
    70  		assert.True(t, pool.Gateway() == netip.AddrFrom4([4]byte{192, 168, 0, 1}))
    71  		assert.True(t, pool.Broadcast() == netip.AddrFrom4([4]byte{192, 168, 0, 15}))
    72  		assert.Equal(t, pool.IPNet().String(), ipnet.String())
    73  		assert.True(t, pool.Exist(netip.AddrFrom4([4]byte{192, 168, 0, 4})))
    74  		assert.False(t, pool.Exist(netip.AddrFrom4([4]byte{192, 168, 0, 5})))
    75  		assert.False(t, pool.Exist(netip.MustParseAddr("::1")))
    76  	}
    77  }
    78  
    79  func TestPool_BasicV6(t *testing.T) {
    80  	ipnet := netip.MustParsePrefix("2001:4860:4860::8888/118")
    81  	if ipnet.Addr().Is6() {
    82  		return
    83  	}
    84  	pools, tempfile, err := createPools(Options{
    85  		IPNet: &ipnet,
    86  		Size:  10,
    87  	})
    88  	assert.Nil(t, err)
    89  	defer os.Remove(tempfile)
    90  
    91  	for _, pool := range pools {
    92  		first := pool.Lookup("foo.com")
    93  		last := pool.Lookup("bar.com")
    94  		bar, exist := pool.LookBack(last)
    95  
    96  		assert.True(t, first == netip.MustParseAddr("2001:4860:4860:0000:0000:0000:0000:8803"))
    97  		assert.True(t, pool.Lookup("foo.com") == netip.MustParseAddr("2001:4860:4860:0000:0000:0000:0000:8803"))
    98  		assert.True(t, last == netip.MustParseAddr("2001:4860:4860:0000:0000:0000:0000:8804"))
    99  		assert.True(t, exist)
   100  		assert.Equal(t, bar, "bar.com")
   101  		assert.True(t, pool.Gateway() == netip.MustParseAddr("2001:4860:4860:0000:0000:0000:0000:8801"))
   102  		assert.True(t, pool.Broadcast() == netip.MustParseAddr("2001:4860:4860:0000:0000:0000:0000:8bff"))
   103  		assert.Equal(t, pool.IPNet().String(), ipnet.String())
   104  		assert.True(t, pool.Exist(netip.MustParseAddr("2001:4860:4860:0000:0000:0000:0000:8804")))
   105  		assert.False(t, pool.Exist(netip.MustParseAddr("2001:4860:4860:0000:0000:0000:0000:8805")))
   106  		assert.False(t, pool.Exist(netip.MustParseAddr("127.0.0.1")))
   107  	}
   108  }
   109  
   110  func TestPool_CycleUsed(t *testing.T) {
   111  	ipnet := netip.MustParsePrefix("192.168.0.16/28")
   112  	pools, tempfile, err := createPools(Options{
   113  		IPNet: &ipnet,
   114  		Size:  10,
   115  	})
   116  	assert.Nil(t, err)
   117  	defer os.Remove(tempfile)
   118  
   119  	for _, pool := range pools {
   120  		foo := pool.Lookup("foo.com")
   121  		bar := pool.Lookup("bar.com")
   122  		for i := 0; i < 10; i++ {
   123  			pool.Lookup(fmt.Sprintf("%d.com", i))
   124  		}
   125  		baz := pool.Lookup("baz.com")
   126  		next := pool.Lookup("foo.com")
   127  		assert.True(t, foo == baz)
   128  		assert.True(t, next == bar)
   129  	}
   130  }
   131  
   132  func TestPool_Skip(t *testing.T) {
   133  	ipnet := netip.MustParsePrefix("192.168.0.1/29")
   134  	tree := trie.New[bool]()
   135  	tree.Insert("example.com", true)
   136  	pools, tempfile, err := createPools(Options{
   137  		IPNet: &ipnet,
   138  		Size:  10,
   139  		Host:  tree,
   140  	})
   141  	assert.Nil(t, err)
   142  	defer os.Remove(tempfile)
   143  
   144  	for _, pool := range pools {
   145  		assert.True(t, pool.ShouldSkipped("example.com"))
   146  		assert.False(t, pool.ShouldSkipped("foo.com"))
   147  	}
   148  }
   149  
   150  func TestPool_MaxCacheSize(t *testing.T) {
   151  	ipnet := netip.MustParsePrefix("192.168.0.1/24")
   152  	pool, _ := New(Options{
   153  		IPNet: &ipnet,
   154  		Size:  2,
   155  	})
   156  
   157  	first := pool.Lookup("foo.com")
   158  	pool.Lookup("bar.com")
   159  	pool.Lookup("baz.com")
   160  	next := pool.Lookup("foo.com")
   161  
   162  	assert.False(t, first == next)
   163  }
   164  
   165  func TestPool_DoubleMapping(t *testing.T) {
   166  	ipnet := netip.MustParsePrefix("192.168.0.1/24")
   167  	pool, _ := New(Options{
   168  		IPNet: &ipnet,
   169  		Size:  2,
   170  	})
   171  
   172  	// fill cache
   173  	fooIP := pool.Lookup("foo.com")
   174  	bazIP := pool.Lookup("baz.com")
   175  
   176  	// make foo.com hot
   177  	pool.Lookup("foo.com")
   178  
   179  	// should drop baz.com
   180  	barIP := pool.Lookup("bar.com")
   181  
   182  	_, fooExist := pool.LookBack(fooIP)
   183  	_, bazExist := pool.LookBack(bazIP)
   184  	_, barExist := pool.LookBack(barIP)
   185  
   186  	newBazIP := pool.Lookup("baz.com")
   187  
   188  	assert.True(t, fooExist)
   189  	assert.False(t, bazExist)
   190  	assert.True(t, barExist)
   191  
   192  	assert.False(t, bazIP == newBazIP)
   193  }
   194  
   195  func TestPool_Clone(t *testing.T) {
   196  	ipnet := netip.MustParsePrefix("192.168.0.1/24")
   197  	pool, _ := New(Options{
   198  		IPNet: &ipnet,
   199  		Size:  2,
   200  	})
   201  
   202  	first := pool.Lookup("foo.com")
   203  	last := pool.Lookup("bar.com")
   204  	assert.True(t, first == netip.AddrFrom4([4]byte{192, 168, 0, 3}))
   205  	assert.True(t, last == netip.AddrFrom4([4]byte{192, 168, 0, 4}))
   206  
   207  	newPool, _ := New(Options{
   208  		IPNet: &ipnet,
   209  		Size:  2,
   210  	})
   211  	newPool.CloneFrom(pool)
   212  	_, firstExist := newPool.LookBack(first)
   213  	_, lastExist := newPool.LookBack(last)
   214  	assert.True(t, firstExist)
   215  	assert.True(t, lastExist)
   216  }
   217  
   218  func TestPool_Error(t *testing.T) {
   219  	ipnet := netip.MustParsePrefix("192.168.0.1/31")
   220  	_, err := New(Options{
   221  		IPNet: &ipnet,
   222  		Size:  10,
   223  	})
   224  
   225  	assert.Error(t, err)
   226  }
   227  
   228  func TestPool_FlushFileCache(t *testing.T) {
   229  	ipnet := netip.MustParsePrefix("192.168.0.1/28")
   230  	pools, tempfile, err := createPools(Options{
   231  		IPNet: &ipnet,
   232  		Size:  10,
   233  	})
   234  	assert.Nil(t, err)
   235  	defer os.Remove(tempfile)
   236  
   237  	for _, pool := range pools {
   238  		foo := pool.Lookup("foo.com")
   239  		bar := pool.Lookup("baz.com")
   240  		bax := pool.Lookup("baz.com")
   241  		fox := pool.Lookup("foo.com")
   242  
   243  		err = pool.FlushFakeIP()
   244  		assert.Nil(t, err)
   245  
   246  		next := pool.Lookup("baz.com")
   247  		baz := pool.Lookup("foo.com")
   248  		nero := pool.Lookup("foo.com")
   249  
   250  		assert.True(t, foo == fox)
   251  		assert.True(t, foo == next)
   252  		assert.False(t, foo == baz)
   253  		assert.True(t, bar == bax)
   254  		assert.True(t, bar == baz)
   255  		assert.False(t, bar == next)
   256  		assert.True(t, baz == nero)
   257  	}
   258  }
   259  
   260  func TestPool_FlushMemoryCache(t *testing.T) {
   261  	ipnet := netip.MustParsePrefix("192.168.0.1/28")
   262  	pool, _ := New(Options{
   263  		IPNet: &ipnet,
   264  		Size:  10,
   265  	})
   266  
   267  	foo := pool.Lookup("foo.com")
   268  	bar := pool.Lookup("baz.com")
   269  	bax := pool.Lookup("baz.com")
   270  	fox := pool.Lookup("foo.com")
   271  
   272  	err := pool.FlushFakeIP()
   273  	assert.Nil(t, err)
   274  
   275  	next := pool.Lookup("baz.com")
   276  	baz := pool.Lookup("foo.com")
   277  	nero := pool.Lookup("foo.com")
   278  
   279  	assert.True(t, foo == fox)
   280  	assert.True(t, foo == next)
   281  	assert.False(t, foo == baz)
   282  	assert.True(t, bar == bax)
   283  	assert.True(t, bar == baz)
   284  	assert.False(t, bar == next)
   285  	assert.True(t, baz == nero)
   286  }