Files
proxy-gost/gost-geo-plugin/main_test.go
2026-10-15 15:40:19 +08:00

92 lines
2.9 KiB
Go

package main
import (
"context"
"errors"
"net/http"
"net/http/httptest"
"net/netip"
"testing"
"github.com/go-gost/plugin/bypass/proto"
)
func TestBypass(t *testing.T) {
for _, tc := range []struct {
name string
addr string
ips []netip.Addr
err error
deny bool
}{
{name: "listed IPv4", addr: "203.0.113.1:443"},
{name: "foreign IPv4", addr: "198.51.100.1:443", deny: true},
{name: "listed IPv6", addr: "[2001:db8::1]:443"},
{name: "bare IPv6", addr: "2001:db8::1"},
{name: "foreign IPv6", addr: "[2001:db9::1]:443", deny: true},
{name: "mapped IPv4", addr: "[::ffff:203.0.113.1]:443"},
{name: "listed domain", addr: "allowed.test:443", ips: []netip.Addr{netip.MustParseAddr("203.0.113.2")}},
{name: "mixed answers", addr: "mixed.test:443", ips: []netip.Addr{netip.MustParseAddr("203.0.113.2"), netip.MustParseAddr("198.51.100.2")}, deny: true},
{name: "no addresses", addr: "empty.test:443", deny: true},
{name: "DNS failure", addr: "error.test:443", err: errors.New("DNS unavailable"), deny: true},
} {
t.Run(tc.name, func(t *testing.T) {
s := &server{
list: []netip.Prefix{netip.MustParsePrefix("203.0.113.0/24"), netip.MustParsePrefix("2001:db8::/32")},
lookup: func(ctx context.Context, _, _ string) ([]netip.Addr, error) {
if _, ok := ctx.Deadline(); !ok {
t.Error("DNS lookup has no deadline")
}
return tc.ips, tc.err
},
}
reply, err := s.Bypass(context.Background(), &proto.BypassRequest{Addr: tc.addr})
if err != nil || reply.Ok != tc.deny {
t.Fatalf("Bypass = %v, %v; want deny=%v", reply, err, tc.deny)
}
})
}
}
func TestRefresh(t *testing.T) {
status, body := 200, "# list\n203.0.113.7/24 # normalize\n2001:db8::/32\n"
upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(status)
_, _ = w.Write([]byte(body))
}))
defer upstream.Close()
s := &server{}
if err := s.refresh(upstream.URL); err != nil {
t.Fatal(err)
}
for _, tc := range []struct {
name string
status int
body string
}{
{"HTTP failure", 503, "unavailable"},
{"empty list", 200, "# empty\n"},
{"malformed list", 200, "198.51.100.0/24\n<html>error</html>"},
} {
t.Run(tc.name, func(t *testing.T) {
status, body = tc.status, tc.body
if err := s.refresh(upstream.URL); err == nil {
t.Fatal("accepted invalid list")
}
reply, _ := s.Bypass(context.Background(), &proto.BypassRequest{Addr: "203.0.113.1:443"})
if reply.Ok || len(s.list) != 2 {
t.Fatal("failed refresh discarded previous rules")
}
})
}
status, body = 200, "198.51.100.0/24\n"
if err := s.refresh(upstream.URL); err != nil {
t.Fatal(err)
}
old, _ := s.Bypass(context.Background(), &proto.BypassRequest{Addr: "203.0.113.1:443"})
updated, _ := s.Bypass(context.Background(), &proto.BypassRequest{Addr: "198.51.100.1:443"})
if !old.Ok || updated.Ok {
t.Fatal("refresh did not replace rules")
}
}