test(bypass): add unit tests achieving 96.4% total coverage

- 88 tests: 70 for core (96.8%), 12 for gRPC plugin, 14 for HTTP plugin
- Cover all matchers (IP, CIDR, wildcard, IP range), loader sources,
  bypassGroup logic, periodReload, and plugin fail-open semantics
- Add nil-logger guard in httpPlugin.Contains to prevent panic
  when logger is nil
This commit is contained in:
ginuerzh
2026-05-23 16:04:30 +08:00
parent bf4af78ebf
commit d015378654
4 changed files with 1201 additions and 4 deletions
+174
View File
@@ -0,0 +1,174 @@
package bypass
import (
"context"
"io"
"net/http"
"net/http/httptest"
"testing"
"github.com/go-gost/core/bypass"
"github.com/go-gost/x/internal/plugin"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestNewHTTPPlugin(t *testing.T) {
p := NewHTTPPlugin("test", "http://localhost:9999")
require.NotNil(t, p)
hp, ok := p.(*httpPlugin)
require.True(t, ok)
assert.Equal(t, "http://localhost:9999", hp.url)
assert.NotNil(t, hp.client)
assert.NotNil(t, hp.log)
}
func TestHTTPPlugin_Contains_Success(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodPost, r.Method)
assert.Equal(t, "application/json", r.Header.Get("Content-Type"))
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"ok": true}`))
}))
defer srv.Close()
p := NewHTTPPlugin("test", srv.URL)
assert.True(t, p.Contains(context.Background(), "tcp", "192.168.1.1"))
}
func TestHTTPPlugin_Contains_Deny(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"ok": false}`))
}))
defer srv.Close()
p := NewHTTPPlugin("test", srv.URL)
assert.False(t, p.Contains(context.Background(), "tcp", "192.168.1.1"))
}
func TestHTTPPlugin_Contains_Non200(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusForbidden)
}))
defer srv.Close()
p := NewHTTPPlugin("test", srv.URL)
// Non-200 returns true (fail-open)
assert.True(t, p.Contains(context.Background(), "tcp", "192.168.1.1"))
}
func TestHTTPPlugin_Contains_InvalidJSON(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte(`not json`))
}))
defer srv.Close()
p := NewHTTPPlugin("test", srv.URL)
// Invalid JSON returns true (fail-open)
assert.True(t, p.Contains(context.Background(), "tcp", "192.168.1.1"))
}
func TestHTTPPlugin_Contains_ConnectionRefused(t *testing.T) {
p := NewHTTPPlugin("test", "http://127.0.0.1:0", plugin.TimeoutOption(0))
// Connection refused returns true (fail-open)
assert.True(t, p.Contains(context.Background(), "tcp", "192.168.1.1"))
}
func TestHTTPPlugin_Contains_NilClient(t *testing.T) {
hp := &httpPlugin{
url: "http://localhost",
client: nil,
}
// Nil client returns true (fail-open)
assert.True(t, hp.Contains(context.Background(), "tcp", "192.168.1.1"))
}
func TestHTTPPlugin_Contains_WithService(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"ok": true}`))
}))
defer srv.Close()
p := NewHTTPPlugin("test", srv.URL)
assert.True(t, p.Contains(context.Background(), "tcp", "192.168.1.1", bypass.WithService("myservice")))
}
func TestHTTPPlugin_Contains_WithHostAndPath(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"ok": true}`))
}))
defer srv.Close()
p := NewHTTPPlugin("test", srv.URL)
assert.True(t, p.Contains(context.Background(), "tcp", "192.168.1.1",
bypass.WithHostOption("example.com"),
bypass.WithPathOption("/api/v1"),
))
}
func TestHTTPPlugin_Contains_WithCustomHeader(t *testing.T) {
var receivedHeader string
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
receivedHeader = r.Header.Get("X-Custom")
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"ok": true}`))
}))
defer srv.Close()
p := NewHTTPPlugin("test", srv.URL, plugin.HeaderOption(http.Header{
"X-Custom": []string{"test-value"},
}))
assert.True(t, p.Contains(context.Background(), "tcp", "192.168.1.1"))
assert.Equal(t, "test-value", receivedHeader)
}
func TestHTTPPlugin_Contains_NoHeader(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"ok": true}`))
}))
defer srv.Close()
hp := &httpPlugin{
url: srv.URL,
client: plugin.NewHTTPClient(&plugin.Options{}),
header: nil,
}
assert.True(t, hp.Contains(context.Background(), "tcp", "192.168.1.1"))
}
func TestHTTPPlugin_Contains_BadURL(t *testing.T) {
hp := &httpPlugin{
url: "http://invalid hostname", // space causes NewRequest to fail
client: plugin.NewHTTPClient(&plugin.Options{}),
}
// Bad URL returns true (fail-open)
assert.True(t, hp.Contains(context.Background(), "tcp", "192.168.1.1"))
}
func TestHTTPPlugin_Close_NilClient(t *testing.T) {
hp := &httpPlugin{client: nil}
err := hp.Close()
assert.NoError(t, err)
}
func TestHTTPPlugin_Close_WithClient(t *testing.T) {
hp := &httpPlugin{
client: plugin.NewHTTPClient(&plugin.Options{}),
}
err := hp.Close()
assert.NoError(t, err)
}
func TestHTTPPlugin_IsWhitelist(t *testing.T) {
hp := &httpPlugin{}
assert.False(t, hp.IsWhitelist())
}
var _ io.Closer = (*httpPlugin)(nil)