精简P2: geodata 测试夹具改 protowire 手工编码(geodat.proto 字段号+proto3 零值省略语义原样复刻), 不再依赖 xray-core 生成类型写 .dat 夹具

This commit is contained in:
Muse
2026-10-20 11:04:59 +00:00
parent cb8981158f
commit 70d24d2f15
2 changed files with 148 additions and 65 deletions
+103 -45
View File
@@ -12,24 +12,97 @@ import (
"testing"
"time"
xraygeodata "github.com/xtls/xray-core/common/geodata"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/encoding/protowire"
)
func writeSiteDB(t *testing.T, dir, name string, sites ...*xraygeodata.GeoSite) string {
// The fixtures are encoded with protowire directly: the databases' wire
// layout is the contract this package parses, and spelling it out keeps the
// tests independent of xray-core's generated types. Field numbers follow
// geodat.proto — list entry 1; entry code 1, payload 2; domain type 1,
// value 2, attribute 3; attribute key 1, bool value 2; cidr ip 1, prefix 2.
// proto3 zero-value omission is reproduced exactly (a domain of type 0 and
// a /0 prefix emit no field), because the reader's behavior depends on it.
// Domain match types, mirroring xray's Domain_Type enum.
const (
DomainSubstr = 0
DomainRegex = 1
DomainDomain = 2
DomainFull = 3
)
type fixtureDomain struct {
typ uint64
value string
attrs []string
}
type fixtureSite struct {
code string
domains []fixtureDomain
}
type fixtureIP struct {
code string
prefixes []string
}
func wireBytes(num protowire.Number, payload []byte) []byte {
out := protowire.AppendTag(nil, num, protowire.BytesType)
return protowire.AppendBytes(out, payload)
}
func wireString(num protowire.Number, value string) []byte {
out := protowire.AppendTag(nil, num, protowire.BytesType)
return protowire.AppendString(out, value)
}
func wireVarint(num protowire.Number, value uint64) []byte {
out := protowire.AppendTag(nil, num, protowire.VarintType)
return protowire.AppendVarint(out, value)
}
func encodeFixtureDomain(d fixtureDomain) []byte {
var msg []byte
if d.typ != 0 {
msg = append(msg, wireVarint(1, d.typ)...)
}
msg = append(msg, wireString(2, d.value)...)
for _, attr := range d.attrs {
attrMsg := wireString(1, attr)
attrMsg = append(attrMsg, wireVarint(2, 1)...) // bool_value = true
msg = append(msg, wireBytes(3, attrMsg)...)
}
return msg
}
func writeSiteDB(t *testing.T, dir, name string, sites ...fixtureSite) string {
t.Helper()
data, err := proto.Marshal(&xraygeodata.GeoSiteList{Entry: sites})
if err != nil {
t.Fatalf("marshal geosite list: %v", err)
var data []byte
for _, s := range sites {
entry := wireString(1, s.code)
for _, d := range s.domains {
entry = append(entry, wireBytes(2, encodeFixtureDomain(d))...)
}
data = append(data, wireBytes(1, entry)...)
}
return writeFile(t, dir, name, data)
}
func writeIPDB(t *testing.T, dir, name string, geoips ...*xraygeodata.GeoIP) string {
func writeIPDB(t *testing.T, dir, name string, geoips ...fixtureIP) string {
t.Helper()
data, err := proto.Marshal(&xraygeodata.GeoIPList{Entry: geoips})
if err != nil {
t.Fatalf("marshal geoip list: %v", err)
var data []byte
for _, g := range geoips {
entry := wireString(1, g.code)
for _, raw := range g.prefixes {
prefix := netip.MustParsePrefix(raw)
cidr := wireBytes(1, prefix.Addr().AsSlice())
if prefix.Bits() != 0 {
cidr = append(cidr, wireVarint(2, uint64(prefix.Bits()))...)
}
entry = append(entry, wireBytes(2, cidr)...)
}
data = append(data, wireBytes(1, entry)...)
}
return writeFile(t, dir, name, data)
}
@@ -43,45 +116,30 @@ func writeFile(t *testing.T, dir, name string, data []byte) string {
return path
}
func site(code string, domains ...*xraygeodata.Domain) *xraygeodata.GeoSite {
return &xraygeodata.GeoSite{Code: code, Domain: domains}
func site(code string, domains ...fixtureDomain) fixtureSite {
return fixtureSite{code: code, domains: domains}
}
func domain(domainType xraygeodata.Domain_Type, value string, attributes ...string) *xraygeodata.Domain {
d := &xraygeodata.Domain{Type: domainType, Value: value}
for _, attribute := range attributes {
d.Attribute = append(d.Attribute, &xraygeodata.Domain_Attribute{
Key: attribute,
TypedValue: &xraygeodata.Domain_Attribute_BoolValue{BoolValue: true},
})
}
return d
func domain(domainType uint64, value string, attributes ...string) fixtureDomain {
return fixtureDomain{typ: domainType, value: value, attrs: attributes}
}
func geoip(code string, prefixes ...string) *xraygeodata.GeoIP {
entry := &xraygeodata.GeoIP{Code: code}
for _, raw := range prefixes {
prefix := netip.MustParsePrefix(raw)
entry.Cidr = append(entry.Cidr, &xraygeodata.CIDR{
Ip: prefix.Addr().AsSlice(),
Prefix: uint32(prefix.Bits()),
})
}
return entry
func geoip(code string, prefixes ...string) fixtureIP {
return fixtureIP{code: code, prefixes: prefixes}
}
func sampleSiteDB(t *testing.T, dir string) {
t.Helper()
writeSiteDB(t, dir, "geosite.dat",
site("google",
domain(xraygeodata.Domain_Domain, "google.com"),
domain(xraygeodata.Domain_Full, "ads.google.com", "ads"),
domain(xraygeodata.Domain_Substr, "googlevideo", "cn"),
domain(xraygeodata.Domain_Regex, `^g.*\.cn$`),
domain(DomainDomain, "google.com"),
domain(DomainFull, "ads.google.com", "ads"),
domain(DomainSubstr, "googlevideo", "cn"),
domain(DomainRegex, `^g.*\.cn$`),
),
site("CN",
domain(xraygeodata.Domain_Domain, "baidu.com"),
domain(xraygeodata.Domain_Domain, "qq.com"),
domain(DomainDomain, "baidu.com"),
domain(DomainDomain, "qq.com"),
),
)
}
@@ -126,7 +184,7 @@ func TestListFilesReportsKindAndCategories(t *testing.T) {
func TestKindDetectedFromContentsNotName(t *testing.T) {
dir := t.TempDir()
writeSiteDB(t, dir, "my_ip_rules.dat", site("corp", domain(xraygeodata.Domain_Domain, "intranet.corp.local")))
writeSiteDB(t, dir, "my_ip_rules.dat", site("corp", domain(DomainDomain, "intranet.corp.local")))
writeIPDB(t, dir, "custom_sites.dat", geoip("office", "192.168.7.0/24"))
store := NewStore(dir)
@@ -241,9 +299,9 @@ func TestSearchFilters(t *testing.T) {
func TestPagination(t *testing.T) {
dir := t.TempDir()
domains := make([]*xraygeodata.Domain, 0, 250)
domains := make([]fixtureDomain, 0, 250)
for i := range 250 {
domains = append(domains, domain(xraygeodata.Domain_Domain, "host"+strconv.Itoa(i)+".example.com"))
domains = append(domains, domain(DomainDomain, "host"+strconv.Itoa(i)+".example.com"))
}
writeSiteDB(t, dir, "geosite.dat", site("bulk", domains...))
store := NewStore(dir)
@@ -284,9 +342,9 @@ func TestPagination(t *testing.T) {
func TestCategoriesReturnEverythingWithoutLimit(t *testing.T) {
dir := t.TempDir()
sites := make([]*xraygeodata.GeoSite, 0, MaxPageSize+20)
sites := make([]fixtureSite, 0, MaxPageSize+20)
for i := range MaxPageSize + 20 {
sites = append(sites, site("cat"+strconv.Itoa(i), domain(xraygeodata.Domain_Domain, "example.com")))
sites = append(sites, site("cat"+strconv.Itoa(i), domain(DomainDomain, "example.com")))
}
writeSiteDB(t, dir, "geosite.dat", sites...)
store := NewStore(dir)
@@ -421,9 +479,9 @@ func TestIndexCacheInvalidatedWhenFileChanges(t *testing.T) {
}
path := writeSiteDB(t, dir, "geosite.dat",
site("google", domain(xraygeodata.Domain_Domain, "google.com")),
site("cn", domain(xraygeodata.Domain_Domain, "baidu.com")),
site("telegram", domain(xraygeodata.Domain_Domain, "t.me")),
site("google", domain(DomainDomain, "google.com")),
site("cn", domain(DomainDomain, "baidu.com")),
site("telegram", domain(DomainDomain, "t.me")),
)
touch(t, path, time.Now().Add(time.Second))