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 }