test: 更新单元测试
This commit is contained in:
parent
31cd078455
commit
d4d211c50b
|
|
@ -1,190 +1,90 @@
|
|||
using IP2Region.Net.XDB;
|
||||
using System.Buffers;
|
||||
using System.Buffers.Binary;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using Xunit;
|
||||
|
||||
namespace IP2Region.Net.Test;
|
||||
|
||||
public class SearcherTest
|
||||
{
|
||||
private readonly string _xdbPath = Path.Combine(AppContext.BaseDirectory, "TestData", "ip2region_v6.xdb");
|
||||
private readonly string _xdbPathV4 = Path.Combine(AppContext.BaseDirectory, "TestData", "ip2region_v4.xdb");
|
||||
private readonly string _xdbPathV6 = Path.Combine(AppContext.BaseDirectory, "TestData", "ip2region_v6.xdb");
|
||||
|
||||
[Theory]
|
||||
[InlineData("58.251.27.201", "中国|广东省|深圳市|联通", "v4")]
|
||||
[InlineData("114.114.114.114", "中国|江苏省|南京市|0", "v4")]
|
||||
[InlineData("119.29.29.29", "中国|北京|北京市|腾讯", "v4")]
|
||||
[InlineData("223.5.5.5", "中国|浙江省|杭州市|阿里云", "v4")]
|
||||
[InlineData("180.76.76.76", "中国|北京|北京市|百度", "v4")]
|
||||
[InlineData("8.8.8.8", "", "v4")]
|
||||
[InlineData("240e:3b7:3272:d8d0:db09:c067:8d59:539e", "中国|广东省|深圳市|家庭宽带", "v6")]
|
||||
public void TestSearchCacheContent(string ip, string expected, string version)
|
||||
{
|
||||
var _xdbPath = version == "v4" ? _xdbPathV4 : _xdbPathV6;
|
||||
var contentSearcher = new Searcher(CachePolicy.Content, _xdbPath);
|
||||
var region = contentSearcher.Search(ip);
|
||||
Assert.Equal(expected, region);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("58.251.27.201", "中国|广东省|深圳市|联通", "v4")]
|
||||
[InlineData("114.114.114.114", "中国|江苏省|南京市|0", "v4")]
|
||||
[InlineData("119.29.29.29", "中国|北京|北京市|腾讯", "v4")]
|
||||
[InlineData("223.5.5.5", "中国|浙江省|杭州市|阿里云", "v4")]
|
||||
[InlineData("180.76.76.76", "中国|北京|北京市|百度", "v4")]
|
||||
[InlineData("8.8.8.8", "", "v4")]
|
||||
[InlineData("240e:3b7:3272:d8d0:db09:c067:8d59:539e", "中国|广东省|深圳市|家庭宽带", "v6")]
|
||||
public void TestSearchCacheVector(string ip, string expected, string version)
|
||||
{
|
||||
var _xdbPath = version == "v4" ? _xdbPathV4 : _xdbPathV6;
|
||||
var vectorSearcher = new Searcher(CachePolicy.VectorIndex, _xdbPath);
|
||||
var region = vectorSearcher.Search(ip);
|
||||
Assert.Equal(expected, region);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("58.251.27.201", "中国|广东省|深圳市|联通", "v4")]
|
||||
[InlineData("114.114.114.114", "中国|江苏省|南京市|0", "v4")]
|
||||
[InlineData("119.29.29.29", "中国|北京|北京市|腾讯", "v4")]
|
||||
[InlineData("223.5.5.5", "中国|浙江省|杭州市|阿里云", "v4")]
|
||||
[InlineData("180.76.76.76", "中国|北京|北京市|百度", "v4")]
|
||||
[InlineData("8.8.8.8", "", "v4")]
|
||||
[InlineData("240e:3b7:3272:d8d0:db09:c067:8d59:539e", "中国|广东省|深圳市|家庭宽带", "v6")]
|
||||
public void TestSearchCacheFile(string ip, string expected, string version)
|
||||
{
|
||||
var _xdbPath = version == "v4" ? _xdbPathV4 : _xdbPathV6;
|
||||
var fileSearcher = new Searcher(CachePolicy.File, _xdbPath);
|
||||
var region = fileSearcher.Search(ip);
|
||||
Assert.Equal(expected, region);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Test()
|
||||
{
|
||||
// 常量定义
|
||||
// 每个 vector 索引项的字节数
|
||||
var VectorIndexSize = 8;
|
||||
|
||||
// vector 索引的列数
|
||||
var VectorIndexCols = 256;
|
||||
|
||||
// vector 索引段整个的字节数
|
||||
var VectorIndexLength = 512;
|
||||
|
||||
//var ipAddress = IPAddress.Parse("240e:3b7:3272:d8d0:db09:c067:8d59:539e");
|
||||
var ipAddress = IPAddress.Parse("2c0f:fda8:21::");
|
||||
// [36,14,3,183,50,114,216,208,219,9,192,103,141,89,83,158]
|
||||
//var ipAddress = IPAddress.Parse("58.251.27.201");
|
||||
byte[] ip_bytes = ipAddress.GetAddressBytes();
|
||||
//Array.Reverse(bytes);
|
||||
|
||||
//var ip = MemoryMarshal.Read<uint>(bytes);
|
||||
|
||||
var il0 = ip_bytes[0] & 0xFF;
|
||||
var il1 = ip_bytes[1] & 0xFF;
|
||||
|
||||
var idx = il0 * VectorIndexCols * VectorIndexSize + il1 * VectorIndexSize;
|
||||
|
||||
var data = Read(256 + idx, VectorIndexSize);
|
||||
var sPtr = BinaryPrimitives.ReadUInt32LittleEndian(data.Span);
|
||||
var ePtr = BinaryPrimitives.ReadUInt32LittleEndian(data.Span.Slice(4));
|
||||
|
||||
var indexSize = 38;
|
||||
var l = 0;
|
||||
var h = (ePtr - sPtr) / indexSize;
|
||||
var dataLen = 0;
|
||||
var dataPtr = 0l;
|
||||
|
||||
var bytes = ip_bytes.Length;
|
||||
var dBytes = ip_bytes.Length << 1;
|
||||
var buff = new byte[indexSize];
|
||||
|
||||
while (l < h)
|
||||
{
|
||||
// 得到中间的索引项
|
||||
int m = (int)(l + h) >> 1;
|
||||
|
||||
var p = (int)sPtr + m * indexSize;
|
||||
|
||||
buff = Read(p, buff.Length).ToArray();
|
||||
|
||||
var s1 = BinaryPrimitives.ReadUInt32BigEndian(ip_bytes);
|
||||
var s = BinaryPrimitives.ReadUInt32BigEndian(buff.AsSpan().Slice(0, ip_bytes.Length).ToArray());
|
||||
var e = BinaryPrimitives.ReadUInt32BigEndian(buff.AsSpan().Slice(ip_bytes.Length).ToArray());
|
||||
if (s1 < s)
|
||||
{
|
||||
h = m - 1;
|
||||
}
|
||||
else if (s1 > e)
|
||||
{
|
||||
l = m + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
dataLen = BinaryPrimitives.ReadUInt16LittleEndian(buff.AsSpan().Slice(dBytes, 2));
|
||||
dataPtr = BinaryPrimitives.ReadUInt32LittleEndian(buff.AsSpan().Slice(dBytes + 2));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var regionBuff = Read((int)dataPtr, (int)dataLen);
|
||||
var address = Encoding.UTF8.GetString(regionBuff.Span.ToArray());
|
||||
}
|
||||
|
||||
private ReadOnlyMemory<byte> Read(int offset, int length)
|
||||
{
|
||||
int BufferSize = 4096;
|
||||
|
||||
var stream = new FileStream(_xdbPath, FileMode.Open, FileAccess.Read, FileShare.Read, BufferSize, useAsync: true);
|
||||
|
||||
byte[] buffer = ArrayPool<byte>.Shared.Rent(length);
|
||||
int totalBytesRead = 0;
|
||||
try
|
||||
{
|
||||
stream.Seek(offset, SeekOrigin.Begin);
|
||||
|
||||
int bytesRead;
|
||||
do
|
||||
{
|
||||
int bytesToRead = Math.Min(BufferSize, length - totalBytesRead);
|
||||
bytesRead = stream.Read(buffer, totalBytesRead, bytesToRead);
|
||||
totalBytesRead += bytesRead;
|
||||
|
||||
} while (bytesRead > 0 && totalBytesRead < length);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(buffer);
|
||||
}
|
||||
|
||||
return new ReadOnlyMemory<byte>(buffer, 0, totalBytesRead);
|
||||
var ip = XDB.Util.IpAddressToUInt32("58.251.27.201");
|
||||
var searcher = new Searcher(CachePolicy.File, _xdbPathV4);
|
||||
var region = searcher.Search(ip);
|
||||
Assert.Equal("中国|广东省|深圳市|联通", region);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("114.114.114.114")]
|
||||
[InlineData("119.29.29.29")]
|
||||
[InlineData("223.5.5.5")]
|
||||
[InlineData("180.76.76.76")]
|
||||
[InlineData("8.8.8.8")]
|
||||
public void TestSearchCacheContent(string ip)
|
||||
[InlineData(CachePolicy.Content, "v4")]
|
||||
[InlineData(CachePolicy.VectorIndex, "v4")]
|
||||
[InlineData(CachePolicy.File, "v4")]
|
||||
public void TestBenchSearch(CachePolicy cachePolicy, string version)
|
||||
{
|
||||
var contentSearcher = new Searcher(CachePolicy.Content, _xdbPath);
|
||||
var region = contentSearcher.Search(ip);
|
||||
Console.WriteLine(region);
|
||||
}
|
||||
var _xdbPath = version == "v4" ? _xdbPathV4 : _xdbPathV6;
|
||||
var searcher = new Searcher(cachePolicy, _xdbPath);
|
||||
var srcPath = Path.Combine(AppContext.BaseDirectory, "TestData", $"ip{version}_source.txt");
|
||||
|
||||
[Theory]
|
||||
[InlineData("114.114.114.114")]
|
||||
[InlineData("119.29.29.29")]
|
||||
[InlineData("223.5.5.5")]
|
||||
[InlineData("180.76.76.76")]
|
||||
[InlineData("8.8.8.8")]
|
||||
public void TestSearchCacheVector(string ip)
|
||||
{
|
||||
var vectorSearcher = new Searcher(CachePolicy.VectorIndex, _xdbPath);
|
||||
var region = vectorSearcher.Search(ip);
|
||||
Console.WriteLine(region);
|
||||
}
|
||||
//foreach (var line in File.ReadLines(srcPath))
|
||||
//{
|
||||
// var ps = line.Trim().Split("|", 3);
|
||||
// var sip = ps[0];
|
||||
// var eip = ps[1];
|
||||
|
||||
[Theory]
|
||||
[InlineData("114.114.114.114")]
|
||||
[InlineData("119.29.29.29")]
|
||||
[InlineData("223.5.5.5")]
|
||||
[InlineData("180.76.76.76")]
|
||||
[InlineData("8.8.8.8")]
|
||||
public void TestSearchCacheFile(string ip)
|
||||
{
|
||||
var fileSearcher = new Searcher(CachePolicy.File, _xdbPath);
|
||||
var region = fileSearcher.Search(ip);
|
||||
Console.WriteLine(region);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(CachePolicy.Content)]
|
||||
[InlineData(CachePolicy.VectorIndex)]
|
||||
[InlineData(CachePolicy.File)]
|
||||
public void TestBenchSearch(CachePolicy cachePolicy)
|
||||
{
|
||||
Searcher searcher = new Searcher(cachePolicy, _xdbPath);
|
||||
var srcPath = Path.Combine(AppContext.BaseDirectory, "TestData", "ipv4_source.txt");
|
||||
|
||||
foreach (var line in File.ReadLines(srcPath))
|
||||
{
|
||||
var ps = line.Trim().Split("|", 3);
|
||||
|
||||
if (ps.Length != 3)
|
||||
{
|
||||
throw new ArgumentException($"invalid ip segment line {line}", nameof(line));
|
||||
}
|
||||
|
||||
var sip = Util.IpAddressToUInt32(ps[0]);
|
||||
var eip = Util.IpAddressToUInt32(ps[1]);
|
||||
var mip = Util.GetMidIp(sip, eip);
|
||||
|
||||
uint[] temp = { sip, Util.GetMidIp(sip, mip), mip, Util.GetMidIp(mip, eip), eip };
|
||||
|
||||
foreach (var ip in temp)
|
||||
{
|
||||
//var region = searcher.Search(ip);
|
||||
|
||||
//if (region != ps[2])
|
||||
//{
|
||||
// throw new Exception($"failed search {ip} with ({region}!={ps[2]})");
|
||||
//}
|
||||
}
|
||||
}
|
||||
// var s1 = searcher.Search(sip);
|
||||
// var s2 = searcher.Search(eip);
|
||||
// //Assert.Equal(s1, ps[2]);
|
||||
// //Assert.Equal(s2, ps[2]);
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,44 +1,76 @@
|
|||
using IP2Region.Net.XDB;
|
||||
using System.Buffers;
|
||||
using System.Buffers;
|
||||
using System.Buffers.Binary;
|
||||
using System.Net;
|
||||
using Xunit;
|
||||
|
||||
namespace IP2Region.Net.Test;
|
||||
|
||||
public class XdbTest
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("v4")]
|
||||
[InlineData("v6")]
|
||||
public async Task Version_Ok(string version)
|
||||
[Fact]
|
||||
public async Task VersionIPV4_Ok()
|
||||
{
|
||||
var db = Path.Combine(AppContext.BaseDirectory, "TestData", $"ip2region_{version}.xdb");
|
||||
var db = Path.Combine(AppContext.BaseDirectory, "TestData", $"ip2region_v4.xdb");
|
||||
using var reader = File.OpenRead(db);
|
||||
|
||||
using var owner = MemoryPool<byte>.Shared.Rent(256);
|
||||
var length = await reader.ReadAsync(owner.Memory[0..256]);
|
||||
Assert.Equal(256, length);
|
||||
|
||||
var ver = BinaryPrimitives.ReadUInt16LittleEndian(owner.Memory[..2].ToArray());
|
||||
var indexPolicy = BinaryPrimitives.ReadUInt16LittleEndian(owner.Memory.Slice(2, 2).ToArray());
|
||||
var createdAt = BinaryPrimitives.ReadUInt16LittleEndian(owner.Memory.Slice(4, 4).ToArray());
|
||||
var startIndexPtr = BinaryPrimitives.ReadUInt16LittleEndian(owner.Memory.Slice(8, 4).ToArray());
|
||||
var endIndexPtr = BinaryPrimitives.ReadUInt16LittleEndian(owner.Memory.Slice(12, 4).ToArray());
|
||||
var ver = BinaryPrimitives.ReadUInt16LittleEndian(owner.Memory.Span[..2]);
|
||||
Assert.Equal(3, ver);
|
||||
|
||||
var indexPolicy = BinaryPrimitives.ReadUInt16LittleEndian(owner.Memory.Span.Slice(2, 2));
|
||||
Assert.Equal(1, indexPolicy);
|
||||
|
||||
var createdAt = BinaryPrimitives.ReadUInt32LittleEndian(owner.Memory.Span.Slice(4, 4));
|
||||
var dtm = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
dtm = dtm.AddSeconds(createdAt);
|
||||
Assert.Equal("2025-09-06 02:24:16", dtm.ToString("yyyy-MM-dd HH:mm:ss"));
|
||||
|
||||
var startIndexPtr = BinaryPrimitives.ReadUInt32LittleEndian(owner.Memory.Span.Slice(8, 4));
|
||||
Assert.Equal((uint)955933, startIndexPtr);
|
||||
|
||||
var endIndexPtr = BinaryPrimitives.ReadUInt32LittleEndian(owner.Memory.Span.Slice(12, 4));
|
||||
Assert.Equal((uint)11042415, endIndexPtr);
|
||||
|
||||
// since IPv6 supporting
|
||||
var ipVersion = BinaryPrimitives.ReadUInt16LittleEndian(owner.Memory.Slice(16, 2).ToArray());
|
||||
var runtimePtrBytes = BinaryPrimitives.ReadUInt16LittleEndian(owner.Memory.Slice(18, 2).ToArray());
|
||||
var ipVersion = BinaryPrimitives.ReadUInt16LittleEndian(owner.Memory.Span.Slice(16, 2));
|
||||
Assert.Equal(4, ipVersion);
|
||||
|
||||
var runtimePtrBytes = BinaryPrimitives.ReadUInt16LittleEndian(owner.Memory.Span.Slice(18, 2));
|
||||
Assert.Equal(4, runtimePtrBytes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ParseIp()
|
||||
public async Task VersionIPV6_Ok()
|
||||
{
|
||||
//var ip = IPAddress.Parse("2409:895a:8b4:2de4:20e7:5a15:fe6f:431c");
|
||||
var ip = IPAddress.Parse("183.160.236.53");
|
||||
var ipNum = Util.IpAddressToUInt32(ip);
|
||||
var db = Path.Combine(AppContext.BaseDirectory, "TestData", $"ip2region_v6.xdb");
|
||||
using var reader = File.OpenRead(db);
|
||||
|
||||
var searcher = new Searcher(CachePolicy.Content, Path.Combine(AppContext.BaseDirectory, "TestData", "ip2region_v4.xdb"));
|
||||
var result = searcher.Search(ip);
|
||||
using var owner = MemoryPool<byte>.Shared.Rent(256);
|
||||
var length = await reader.ReadAsync(owner.Memory[0..256]);
|
||||
Assert.Equal(256, length);
|
||||
|
||||
var ver = BinaryPrimitives.ReadUInt16LittleEndian(owner.Memory.Span[..2]);
|
||||
Assert.Equal(3, ver);
|
||||
|
||||
var indexPolicy = BinaryPrimitives.ReadUInt16LittleEndian(owner.Memory.Span.Slice(2, 2));
|
||||
var createdAt = BinaryPrimitives.ReadUInt32LittleEndian(owner.Memory.Span.Slice(4, 4));
|
||||
var dtm = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
dtm = dtm.AddSeconds(createdAt);
|
||||
Assert.Equal("2025-10-17 04:41:04", dtm.ToString("yyyy-MM-dd HH:mm:ss"));
|
||||
|
||||
var startIndexPtr = BinaryPrimitives.ReadUInt32LittleEndian(owner.Memory.Span.Slice(8, 4));
|
||||
Assert.Equal((uint)3094259, startIndexPtr);
|
||||
|
||||
var endIndexPtr = BinaryPrimitives.ReadUInt32LittleEndian(owner.Memory.Span.Slice(12, 4));
|
||||
Assert.Equal((uint)36258303, endIndexPtr);
|
||||
|
||||
// since IPv6 supporting
|
||||
var ipVersion = BinaryPrimitives.ReadUInt16LittleEndian(owner.Memory.Span.Slice(16, 2));
|
||||
Assert.Equal(6, ipVersion);
|
||||
|
||||
var runtimePtrBytes = BinaryPrimitives.ReadUInt16LittleEndian(owner.Memory.Span.Slice(18, 2));
|
||||
Assert.Equal(4, runtimePtrBytes);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue