2b1e4ca3a7
Covering nil-input safety, plugin backends (HTTP/gRPC/default), loaders (File/HTTP/Redis), selector strategies, edge cases (empty/invalid inputs), and hop-to-node metadata inheritance. All tests passing.
243 lines
5.4 KiB
Go
243 lines
5.4 KiB
Go
package auth
|
|
|
|
import (
|
|
"io"
|
|
"testing"
|
|
|
|
"github.com/go-gost/core/logger"
|
|
"github.com/go-gost/x/config"
|
|
xlogger "github.com/go-gost/x/logger"
|
|
)
|
|
|
|
func TestMain(m *testing.M) {
|
|
logger.SetDefault(xlogger.NewLogger(xlogger.OutputOption(io.Discard)))
|
|
m.Run()
|
|
}
|
|
|
|
func TestInfo_Nil(t *testing.T) {
|
|
if u := Info(nil); u != nil {
|
|
t.Fatal("expected nil for nil config")
|
|
}
|
|
}
|
|
|
|
func TestInfo_EmptyUsername(t *testing.T) {
|
|
u := Info(&config.AuthConfig{Username: ""})
|
|
if u != nil {
|
|
t.Fatal("expected nil for empty username")
|
|
}
|
|
}
|
|
|
|
func TestInfo_UsernameOnly(t *testing.T) {
|
|
u := Info(&config.AuthConfig{Username: "user"})
|
|
if u == nil {
|
|
t.Fatal("expected non-nil userinfo")
|
|
}
|
|
if u.Username() != "user" {
|
|
t.Fatalf("username = %q, want %q", u.Username(), "user")
|
|
}
|
|
if _, hasPassword := u.Password(); hasPassword {
|
|
t.Fatal("expected no password")
|
|
}
|
|
}
|
|
|
|
func TestInfo_UsernameAndPassword(t *testing.T) {
|
|
u := Info(&config.AuthConfig{Username: "user", Password: "pass"})
|
|
if u == nil {
|
|
t.Fatal("expected non-nil userinfo")
|
|
}
|
|
if u.Username() != "user" {
|
|
t.Fatalf("username = %q, want %q", u.Username(), "user")
|
|
}
|
|
if p, ok := u.Password(); !ok || p != "pass" {
|
|
t.Fatalf("password = %q, want %q", p, "pass")
|
|
}
|
|
}
|
|
|
|
func TestInfo_WithFile(t *testing.T) {
|
|
// File that doesn't exist - should fall back to username
|
|
u := Info(&config.AuthConfig{
|
|
Username: "fallback",
|
|
Password: "pass",
|
|
File: "/nonexistent/auth_file",
|
|
})
|
|
if u == nil {
|
|
t.Fatal("expected non-nil userinfo (fallback)")
|
|
}
|
|
if u.Username() != "fallback" {
|
|
t.Fatalf("username = %q, want %q", u.Username(), "fallback")
|
|
}
|
|
}
|
|
|
|
func TestParseAutherFromAuth_Nil(t *testing.T) {
|
|
a := ParseAutherFromAuth(nil)
|
|
if a != nil {
|
|
t.Fatal("expected nil for nil auth config")
|
|
}
|
|
}
|
|
|
|
func TestParseAutherFromAuth_EmptyUsername(t *testing.T) {
|
|
a := ParseAutherFromAuth(&config.AuthConfig{Username: ""})
|
|
if a != nil {
|
|
t.Fatal("expected nil for empty username")
|
|
}
|
|
}
|
|
|
|
func TestParseAutherFromAuth_Valid(t *testing.T) {
|
|
a := ParseAutherFromAuth(&config.AuthConfig{
|
|
Username: "user",
|
|
Password: "pass",
|
|
})
|
|
if a == nil {
|
|
t.Fatal("expected non-nil authenticator")
|
|
}
|
|
}
|
|
|
|
func TestParseAuther_Nil(t *testing.T) {
|
|
a := ParseAuther(nil)
|
|
if a != nil {
|
|
t.Fatal("expected nil for nil config")
|
|
}
|
|
}
|
|
|
|
func TestParseAuther_WithUsers(t *testing.T) {
|
|
a := ParseAuther(&config.AutherConfig{
|
|
Name: "test-auth",
|
|
Auths: []*config.AuthConfig{
|
|
{Username: "u1", Password: "p1"},
|
|
{Username: "u2", Password: "p2"},
|
|
{Username: "", Password: "nope"}, // skipped
|
|
},
|
|
})
|
|
if a == nil {
|
|
t.Fatal("expected non-nil authenticator")
|
|
}
|
|
}
|
|
|
|
func TestParseAuther_WithEmptyAuths(t *testing.T) {
|
|
a := ParseAuther(&config.AutherConfig{
|
|
Name: "empty-auth",
|
|
Auths: []*config.AuthConfig{},
|
|
})
|
|
if a == nil {
|
|
t.Fatal("expected non-nil authenticator")
|
|
}
|
|
}
|
|
|
|
func TestParseAuther_PluginHTTP(t *testing.T) {
|
|
a := ParseAuther(&config.AutherConfig{
|
|
Name: "http-plugin",
|
|
Plugin: &config.PluginConfig{
|
|
Type: "http",
|
|
Addr: "127.0.0.1:9000",
|
|
},
|
|
})
|
|
if a == nil {
|
|
t.Fatal("expected non-nil plugin authenticator")
|
|
}
|
|
}
|
|
|
|
func TestParseAuther_PluginGRPC(t *testing.T) {
|
|
a := ParseAuther(&config.AutherConfig{
|
|
Name: "grpc-plugin",
|
|
Plugin: &config.PluginConfig{
|
|
Type: "grpc",
|
|
Addr: "127.0.0.1:9001",
|
|
Token: "secret",
|
|
TLS: &config.TLSConfig{
|
|
Secure: true,
|
|
ServerName: "auth.local",
|
|
},
|
|
},
|
|
})
|
|
if a == nil {
|
|
t.Fatal("expected non-nil plugin authenticator")
|
|
}
|
|
}
|
|
|
|
func TestParseAuther_PluginDefaultType(t *testing.T) {
|
|
// Default plugin type should be treated as gRPC
|
|
a := ParseAuther(&config.AutherConfig{
|
|
Name: "default-plugin",
|
|
Plugin: &config.PluginConfig{
|
|
Addr: "127.0.0.1:9002",
|
|
},
|
|
})
|
|
if a == nil {
|
|
t.Fatal("expected non-nil plugin authenticator")
|
|
}
|
|
}
|
|
|
|
func TestInfo_ParseFile(t *testing.T) {
|
|
// parseInfo with empty reader should return nil
|
|
u := Info(&config.AuthConfig{
|
|
File: "/nonexistent/file",
|
|
})
|
|
if u != nil {
|
|
t.Fatal("expected nil for nonexistent file (should not crash)")
|
|
}
|
|
}
|
|
|
|
func TestList_ReturnsEntries(t *testing.T) {
|
|
// The registry returns a lazy wrapper for any non-empty name.
|
|
got := List("test-auther", "test-auther-2")
|
|
if len(got) != 2 {
|
|
t.Fatalf("expected 2 entries, got %d", len(got))
|
|
}
|
|
}
|
|
|
|
func TestList_EmptyNameReturnsNothing(t *testing.T) {
|
|
// Empty names are filtered by the registry Get.
|
|
got := List("")
|
|
if len(got) != 0 {
|
|
t.Fatal("expected empty list for empty name")
|
|
}
|
|
}
|
|
|
|
func TestParseAuther_HTTPLoader(t *testing.T) {
|
|
a := ParseAuther(&config.AutherConfig{
|
|
Name: "http-loader-auth",
|
|
HTTP: &config.HTTPLoader{
|
|
URL: "http://localhost:8080/auth",
|
|
},
|
|
})
|
|
if a == nil {
|
|
t.Fatal("expected non-nil authenticator")
|
|
}
|
|
}
|
|
|
|
func TestParseAuther_FileLoader(t *testing.T) {
|
|
a := ParseAuther(&config.AutherConfig{
|
|
Name: "file-loader-auth",
|
|
File: &config.FileLoader{
|
|
Path: "/tmp/auth.txt",
|
|
},
|
|
})
|
|
if a == nil {
|
|
t.Fatal("expected non-nil authenticator")
|
|
}
|
|
}
|
|
|
|
func TestParseAuther_RedisLoader(t *testing.T) {
|
|
a := ParseAuther(&config.AutherConfig{
|
|
Name: "redis-loader-auth",
|
|
Redis: &config.RedisLoader{
|
|
Addr: "127.0.0.1:6379",
|
|
},
|
|
})
|
|
if a == nil {
|
|
t.Fatal("expected non-nil authenticator")
|
|
}
|
|
}
|
|
|
|
func TestInfo_Integration(t *testing.T) {
|
|
// Verify Info returns *url.Userinfo whose String() matches the standard library.
|
|
u := Info(&config.AuthConfig{Username: "alice", Password: "secret"})
|
|
if u == nil {
|
|
t.Fatal("expected non-nil")
|
|
}
|
|
want := "alice:secret"
|
|
if u.String() != want {
|
|
t.Fatalf("String() = %q, want %q", u.String(), want)
|
|
}
|
|
}
|