| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- package config
- import (
- "log/slog"
- "testing"
- "time"
- )
- func setRequired(t *testing.T) {
- t.Helper()
- t.Setenv("WIKIJS_URL", "https://wiki.example.com")
- t.Setenv("WIKIJS_API_KEY", "secret")
- }
- func TestLoadDefaults(t *testing.T) {
- setRequired(t)
- t.Setenv("WIKIJS_ENABLE_EDIT", "")
- t.Setenv("WIKIJS_TIMEOUT", "")
- t.Setenv("MCP_TRANSPORT", "")
- t.Setenv("MCP_ADDR", "")
- t.Setenv("MCP_PATH", "")
- t.Setenv("MCP_STATELESS", "")
- t.Setenv("MCP_AUTH_TOKEN", "")
- t.Setenv("LOG_LEVEL", "")
- cfg, err := Load()
- if err != nil {
- t.Fatalf("Load() error = %v", err)
- }
- if cfg.Transport != TransportStdio {
- t.Errorf("Transport = %q, want %q", cfg.Transport, TransportStdio)
- }
- if cfg.Addr != DefaultAddr {
- t.Errorf("Addr = %q, want %q", cfg.Addr, DefaultAddr)
- }
- if cfg.Path != DefaultPath {
- t.Errorf("Path = %q, want %q", cfg.Path, DefaultPath)
- }
- if cfg.Timeout != DefaultTimeout {
- t.Errorf("Timeout = %v, want %v", cfg.Timeout, DefaultTimeout)
- }
- if cfg.EnableEdit {
- t.Error("EnableEdit = true, want false")
- }
- if cfg.Stateless {
- t.Error("Stateless = true, want false")
- }
- if cfg.LogLevel != slog.LevelInfo {
- t.Errorf("LogLevel = %v, want info", cfg.LogLevel)
- }
- if err := cfg.Validate(); err != nil {
- t.Errorf("Validate() error = %v", err)
- }
- }
- func TestLoadCustomValues(t *testing.T) {
- setRequired(t)
- t.Setenv("WIKIJS_ENABLE_EDIT", "true")
- t.Setenv("WIKIJS_TIMEOUT", "5s")
- t.Setenv("MCP_TRANSPORT", "HTTP")
- t.Setenv("MCP_ADDR", "127.0.0.1:9000")
- t.Setenv("MCP_PATH", "/mcp/")
- t.Setenv("MCP_STATELESS", "1")
- t.Setenv("MCP_AUTH_TOKEN", "token")
- t.Setenv("LOG_LEVEL", "debug")
- cfg, err := Load()
- if err != nil {
- t.Fatalf("Load() error = %v", err)
- }
- if cfg.Transport != TransportHTTP {
- t.Errorf("Transport = %q, want %q", cfg.Transport, TransportHTTP)
- }
- if cfg.Addr != "127.0.0.1:9000" {
- t.Errorf("Addr = %q", cfg.Addr)
- }
- if cfg.Path != "/mcp/" {
- t.Errorf("Path = %q", cfg.Path)
- }
- if cfg.Timeout != 5*time.Second {
- t.Errorf("Timeout = %v", cfg.Timeout)
- }
- if !cfg.EnableEdit || !cfg.Stateless {
- t.Errorf("EnableEdit = %v, Stateless = %v, want both true", cfg.EnableEdit, cfg.Stateless)
- }
- if cfg.AuthToken != "token" {
- t.Errorf("AuthToken = %q", cfg.AuthToken)
- }
- if cfg.LogLevel != slog.LevelDebug {
- t.Errorf("LogLevel = %v, want debug", cfg.LogLevel)
- }
- }
- func TestLoadRequired(t *testing.T) {
- tests := []struct {
- name string
- url string
- apiKey string
- wantErr bool
- }{
- {name: "missing url", apiKey: "secret", wantErr: true},
- {name: "missing key", url: "https://wiki.example.com", wantErr: true},
- {name: "present", url: "https://wiki.example.com", apiKey: "secret"},
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- t.Setenv("WIKIJS_URL", tt.url)
- t.Setenv("WIKIJS_API_KEY", tt.apiKey)
- cfg, err := Load()
- if err != nil {
- t.Fatalf("Load() error = %v", err)
- }
- if gotErr := cfg.Validate() != nil; gotErr != tt.wantErr {
- t.Fatalf("Validate() error = %v, wantErr %v", cfg.Validate(), tt.wantErr)
- }
- })
- }
- }
- func TestLoadInvalidValues(t *testing.T) {
- tests := []struct {
- name string
- key string
- value string
- }{
- {name: "edit bool", key: "WIKIJS_ENABLE_EDIT", value: "maybe"},
- {name: "stateless bool", key: "MCP_STATELESS", value: "maybe"},
- {name: "timeout", key: "WIKIJS_TIMEOUT", value: "soon"},
- {name: "log level", key: "LOG_LEVEL", value: "verbose"},
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- setRequired(t)
- t.Setenv(tt.key, tt.value)
- if _, err := Load(); err == nil {
- t.Fatal("Load() error = nil, want error")
- }
- })
- }
- }
- func TestValidateHTTPAuth(t *testing.T) {
- tests := []struct {
- name string
- addr string
- token string
- wantErr bool
- }{
- {name: "all interfaces without token", addr: ":8080", wantErr: true},
- {name: "all interfaces with token", addr: ":8080", token: "secret"},
- {name: "ipv4 any without token", addr: "0.0.0.0:8080", wantErr: true},
- {name: "ipv4 loopback", addr: "127.0.0.1:8080"},
- {name: "ipv6 loopback", addr: "[::1]:8080"},
- {name: "localhost", addr: "localhost:8080"},
- {name: "remote hostname without token", addr: "wiki.internal:8080", wantErr: true},
- {name: "missing port", addr: "127.0.0.1", wantErr: true},
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- cfg := Config{
- WikiJSURL: "https://wiki.example.com",
- WikiJSAPIKey: "secret",
- Transport: TransportHTTP,
- Addr: tt.addr,
- Path: DefaultPath,
- Timeout: DefaultTimeout,
- AuthToken: tt.token,
- }
- if gotErr := cfg.Validate() != nil; gotErr != tt.wantErr {
- t.Fatalf("Validate() error = %v, wantErr %v", cfg.Validate(), tt.wantErr)
- }
- })
- }
- }
- func TestValidate(t *testing.T) {
- valid := func() Config {
- return Config{
- WikiJSURL: "https://wiki.example.com",
- WikiJSAPIKey: "secret",
- Transport: TransportStdio,
- Addr: DefaultAddr,
- Path: DefaultPath,
- Timeout: DefaultTimeout,
- }
- }
- tests := []struct {
- name string
- mutate func(*Config)
- wantErr bool
- }{
- {name: "valid"},
- {name: "missing url", mutate: func(c *Config) { c.WikiJSURL = "" }, wantErr: true},
- {name: "missing key", mutate: func(c *Config) { c.WikiJSAPIKey = "" }, wantErr: true},
- {name: "relative url", mutate: func(c *Config) { c.WikiJSURL = "wiki.example.com" }, wantErr: true},
- {name: "url with query", mutate: func(c *Config) { c.WikiJSURL = "https://wiki.example.com/?a=1" }, wantErr: true},
- {name: "ftp url", mutate: func(c *Config) { c.WikiJSURL = "ftp://wiki.example.com" }, wantErr: true},
- {name: "bad transport", mutate: func(c *Config) { c.Transport = "sse" }, wantErr: true},
- {name: "empty addr", mutate: func(c *Config) { c.Addr = "" }, wantErr: true},
- {name: "path without slash", mutate: func(c *Config) { c.Path = "mcp" }, wantErr: true},
- {name: "healthz path", mutate: func(c *Config) { c.Path = "/healthz" }, wantErr: true},
- {name: "zero timeout", mutate: func(c *Config) { c.Timeout = 0 }, wantErr: true},
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- cfg := valid()
- if tt.mutate != nil {
- tt.mutate(&cfg)
- }
- if gotErr := cfg.Validate() != nil; gotErr != tt.wantErr {
- t.Fatalf("Validate() error = %v, wantErr %v", cfg.Validate(), tt.wantErr)
- }
- })
- }
- }
|