mirror of
https://github.com/HugeFrog24/go-telegram-bot.git
synced 2026-03-02 00:14:34 +00:00
Config unit tests
This commit is contained in:
615
config_test.go
Executable file
615
config_test.go
Executable file
@@ -0,0 +1,615 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/liushuangls/go-anthropic/v2"
|
||||
)
|
||||
|
||||
// Add this at the beginning of the file, after the imports
|
||||
func TestMain(m *testing.M) {
|
||||
initLoggers()
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
// TestBotConfig_UnmarshalJSON tests the custom unmarshalling of BotConfig
|
||||
func TestBotConfig_UnmarshalJSON(t *testing.T) {
|
||||
jsonData := `{
|
||||
"id": "bot123",
|
||||
"telegram_token": "token123",
|
||||
"memory_size": 1024,
|
||||
"messages_per_hour": 10,
|
||||
"messages_per_day": 100,
|
||||
"temp_ban_duration": "1h",
|
||||
"model": "claude-v1",
|
||||
"system_prompts": {"welcome": "Hello!"},
|
||||
"active": true,
|
||||
"owner_telegram_id": 123456789,
|
||||
"anthropic_api_key": "api_key_123"
|
||||
}`
|
||||
|
||||
var config BotConfig
|
||||
if err := json.Unmarshal([]byte(jsonData), &config); err != nil {
|
||||
t.Fatalf("Failed to unmarshal JSON: %v", err)
|
||||
}
|
||||
|
||||
expectedModel := anthropic.Model("claude-v1")
|
||||
if config.Model != expectedModel {
|
||||
t.Errorf("Expected model %s, got %s", expectedModel, config.Model)
|
||||
}
|
||||
|
||||
expectedID := "bot123"
|
||||
if config.ID != expectedID {
|
||||
t.Errorf("Expected ID %s, got %s", expectedID, config.ID)
|
||||
}
|
||||
|
||||
// Add more field checks as necessary
|
||||
}
|
||||
|
||||
// TestValidateConfigPath tests the validateConfigPath function
|
||||
func TestValidateConfigPath(t *testing.T) {
|
||||
execDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get current directory: %v", err)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
configDir string
|
||||
filename string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Valid Path",
|
||||
configDir: execDir,
|
||||
filename: "config.json",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Invalid Extension",
|
||||
configDir: execDir,
|
||||
filename: "config.yaml",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Path Traversal",
|
||||
configDir: execDir,
|
||||
filename: "../config.json",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Absolute Path Outside",
|
||||
configDir: execDir,
|
||||
filename: "/etc/passwd",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Nested Valid Path",
|
||||
configDir: execDir,
|
||||
filename: "subdir/config.json",
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
// Create a subdirectory for testing
|
||||
subDir := filepath.Join(execDir, "subdir")
|
||||
if err := os.MkdirAll(subDir, 0755); err != nil {
|
||||
t.Fatalf("Failed to create subdir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(subDir)
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
configDir := tt.configDir
|
||||
filename := tt.filename
|
||||
if tt.name == "Nested Valid Path" {
|
||||
configDir = subDir
|
||||
}
|
||||
_, err := validateConfigPath(configDir, filename)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("validateConfigPath() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestLoadConfig tests the loadConfig function
|
||||
func TestLoadConfig(t *testing.T) {
|
||||
// Create a temporary directory
|
||||
tempDir, err := os.MkdirTemp("", "config_test")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
// Valid config JSON
|
||||
validConfig := `{
|
||||
"id": "bot123",
|
||||
"telegram_token": "token123",
|
||||
"memory_size": 1024,
|
||||
"messages_per_hour": 10,
|
||||
"messages_per_day": 100,
|
||||
"temp_ban_duration": "1h",
|
||||
"model": "claude-v1",
|
||||
"system_prompts": {"welcome": "Hello!"},
|
||||
"active": true,
|
||||
"owner_telegram_id": 123456789,
|
||||
"anthropic_api_key": "api_key_123"
|
||||
}`
|
||||
|
||||
// Invalid config JSON
|
||||
invalidConfig := `{
|
||||
"id": "bot123",
|
||||
"telegram_token": "token123",
|
||||
"memory_size": "should be int",
|
||||
"model": "claude-v1"
|
||||
}`
|
||||
|
||||
// Write valid config file
|
||||
validPath := filepath.Join(tempDir, "valid_config.json")
|
||||
if err := os.WriteFile(validPath, []byte(validConfig), 0644); err != nil {
|
||||
t.Fatalf("Failed to write valid config: %v", err)
|
||||
}
|
||||
|
||||
// Write invalid config file
|
||||
invalidPath := filepath.Join(tempDir, "invalid_config.json")
|
||||
if err := os.WriteFile(invalidPath, []byte(invalidConfig), 0644); err != nil {
|
||||
t.Fatalf("Failed to write invalid config: %v", err)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
filename string
|
||||
wantErr bool
|
||||
expectID string
|
||||
expectErr string
|
||||
}{
|
||||
{
|
||||
name: "Load Valid Config",
|
||||
filename: validPath,
|
||||
wantErr: false,
|
||||
expectID: "bot123",
|
||||
},
|
||||
{
|
||||
name: "Load Invalid Config",
|
||||
filename: invalidPath,
|
||||
wantErr: true,
|
||||
expectErr: "failed to decode JSON",
|
||||
},
|
||||
{
|
||||
name: "Non-existent File",
|
||||
filename: filepath.Join(tempDir, "nonexistent.json"),
|
||||
wantErr: true,
|
||||
expectErr: "failed to open config file",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
config, err := loadConfig(tt.filename)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("loadConfig() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if tt.wantErr && err != nil && tt.expectErr != "" {
|
||||
if !contains(err.Error(), tt.expectErr) {
|
||||
t.Errorf("loadConfig() error = %v, expected to contain %v", err, tt.expectErr)
|
||||
}
|
||||
return
|
||||
}
|
||||
if config.ID != tt.expectID {
|
||||
t.Errorf("Expected ID %s, got %s", tt.expectID, config.ID)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestValidateConfig tests the validateConfig function
|
||||
func TestValidateConfig(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
config BotConfig
|
||||
ids map[string]bool
|
||||
tokens map[string]bool
|
||||
wantErr bool
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
name: "Valid Config",
|
||||
config: BotConfig{
|
||||
ID: "bot123",
|
||||
TelegramToken: "token123",
|
||||
Model: "claude-v1",
|
||||
Active: true,
|
||||
OwnerTelegramID: 123456789,
|
||||
},
|
||||
ids: make(map[string]bool),
|
||||
tokens: make(map[string]bool),
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Missing ID",
|
||||
config: BotConfig{
|
||||
TelegramToken: "token123",
|
||||
Model: "claude-v1",
|
||||
Active: true,
|
||||
},
|
||||
ids: make(map[string]bool),
|
||||
tokens: make(map[string]bool),
|
||||
wantErr: true,
|
||||
expectedError: "missing 'id' field",
|
||||
},
|
||||
{
|
||||
name: "Duplicate ID",
|
||||
config: BotConfig{
|
||||
ID: "bot123",
|
||||
TelegramToken: "token123",
|
||||
Model: "claude-v1",
|
||||
Active: true,
|
||||
},
|
||||
ids: map[string]bool{"bot123": true},
|
||||
tokens: make(map[string]bool),
|
||||
wantErr: true,
|
||||
expectedError: "duplicate bot id",
|
||||
},
|
||||
{
|
||||
name: "Missing Telegram Token",
|
||||
config: BotConfig{
|
||||
ID: "bot123",
|
||||
Model: "claude-v1",
|
||||
Active: true,
|
||||
},
|
||||
ids: make(map[string]bool),
|
||||
tokens: make(map[string]bool),
|
||||
wantErr: true,
|
||||
expectedError: "missing 'telegram_token' field",
|
||||
},
|
||||
{
|
||||
name: "Duplicate Telegram Token",
|
||||
config: BotConfig{
|
||||
ID: "bot123",
|
||||
TelegramToken: "token123",
|
||||
Model: "claude-v1",
|
||||
Active: true,
|
||||
},
|
||||
ids: make(map[string]bool),
|
||||
tokens: map[string]bool{"token123": true},
|
||||
wantErr: true,
|
||||
expectedError: "duplicate telegram_token",
|
||||
},
|
||||
{
|
||||
name: "Missing Model",
|
||||
config: BotConfig{
|
||||
ID: "bot123",
|
||||
TelegramToken: "token123",
|
||||
Active: true,
|
||||
},
|
||||
ids: make(map[string]bool),
|
||||
tokens: make(map[string]bool),
|
||||
wantErr: true,
|
||||
expectedError: "missing 'model' field",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := validateConfig(&tt.config, tt.ids, tt.tokens)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("validateConfig() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if tt.wantErr && err != nil && tt.expectedError != "" {
|
||||
if !contains(err.Error(), tt.expectedError) {
|
||||
t.Errorf("validateConfig() error = %v, expected to contain %v", err, tt.expectedError)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestLoadAllConfigs tests the loadAllConfigs function
|
||||
func TestLoadAllConfigs(t *testing.T) {
|
||||
// Create a temporary directory
|
||||
tempDir, err := os.MkdirTemp("", "load_all_configs_test")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
setupFiles map[string]string // filename -> content
|
||||
expectConfigs int
|
||||
expectError bool
|
||||
expectErrorMsg string
|
||||
}{
|
||||
{
|
||||
name: "Load All Valid Configs",
|
||||
setupFiles: map[string]string{
|
||||
"valid_config.json": `{
|
||||
"id": "bot123",
|
||||
"telegram_token": "token123",
|
||||
"memory_size": 1024,
|
||||
"messages_per_hour": 10,
|
||||
"messages_per_day": 100,
|
||||
"temp_ban_duration": "1h",
|
||||
"model": "claude-v1",
|
||||
"system_prompts": {"welcome": "Hello!"},
|
||||
"active": true,
|
||||
"owner_telegram_id": 123456789,
|
||||
"anthropic_api_key": "api_key_123"
|
||||
}`,
|
||||
},
|
||||
expectConfigs: 1,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "Skip Inactive Config",
|
||||
setupFiles: map[string]string{
|
||||
"valid_config.json": `{
|
||||
"id": "bot123",
|
||||
"telegram_token": "token123",
|
||||
"memory_size": 1024,
|
||||
"messages_per_hour": 10,
|
||||
"messages_per_day": 100,
|
||||
"temp_ban_duration": "1h",
|
||||
"model": "claude-v1",
|
||||
"system_prompts": {"welcome": "Hello!"},
|
||||
"active": true,
|
||||
"owner_telegram_id": 123456789,
|
||||
"anthropic_api_key": "api_key_123"
|
||||
}`,
|
||||
"inactive_config.json": `{
|
||||
"id": "bot124",
|
||||
"telegram_token": "token124",
|
||||
"memory_size": 512,
|
||||
"messages_per_hour": 5,
|
||||
"messages_per_day": 50,
|
||||
"temp_ban_duration": "30m",
|
||||
"model": "claude-v2",
|
||||
"system_prompts": {"welcome": "Hi!"},
|
||||
"active": false,
|
||||
"owner_telegram_id": 987654321,
|
||||
"anthropic_api_key": "api_key_124"
|
||||
}`,
|
||||
},
|
||||
expectConfigs: 1,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "Duplicate Bot ID",
|
||||
setupFiles: map[string]string{
|
||||
"valid_config.json": `{
|
||||
"id": "bot123",
|
||||
"telegram_token": "token123",
|
||||
"memory_size": 1024,
|
||||
"messages_per_hour": 10,
|
||||
"messages_per_day": 100,
|
||||
"temp_ban_duration": "1h",
|
||||
"model": "claude-v1",
|
||||
"system_prompts": {"welcome": "Hello!"},
|
||||
"active": true,
|
||||
"owner_telegram_id": 123456789,
|
||||
"anthropic_api_key": "api_key_123"
|
||||
}`,
|
||||
"duplicate_id_config.json": `{
|
||||
"id": "bot123",
|
||||
"telegram_token": "token125",
|
||||
"memory_size": 256,
|
||||
"messages_per_hour": 2,
|
||||
"messages_per_day": 20,
|
||||
"temp_ban_duration": "15m",
|
||||
"model": "claude-v3",
|
||||
"system_prompts": {"welcome": "Hey!"},
|
||||
"active": true,
|
||||
"owner_telegram_id": 1122334455,
|
||||
"anthropic_api_key": "api_key_125"
|
||||
}`,
|
||||
},
|
||||
expectConfigs: 1,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "Duplicate Telegram Token",
|
||||
setupFiles: map[string]string{
|
||||
"valid_config.json": `{
|
||||
"id": "bot123",
|
||||
"telegram_token": "token123",
|
||||
"memory_size": 1024,
|
||||
"messages_per_hour": 10,
|
||||
"messages_per_day": 100,
|
||||
"temp_ban_duration": "1h",
|
||||
"model": "claude-v1",
|
||||
"system_prompts": {"welcome": "Hello!"},
|
||||
"active": true,
|
||||
"owner_telegram_id": 123456789,
|
||||
"anthropic_api_key": "api_key_123"
|
||||
}`,
|
||||
"duplicate_token_config.json": `{
|
||||
"id": "bot126",
|
||||
"telegram_token": "token123",
|
||||
"memory_size": 128,
|
||||
"messages_per_hour": 1,
|
||||
"messages_per_day": 10,
|
||||
"temp_ban_duration": "5m",
|
||||
"model": "claude-v4",
|
||||
"system_prompts": {"welcome": "Greetings!"},
|
||||
"active": true,
|
||||
"owner_telegram_id": 5566778899,
|
||||
"anthropic_api_key": "api_key_126"
|
||||
}`,
|
||||
},
|
||||
expectConfigs: 1,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "Invalid Config",
|
||||
setupFiles: map[string]string{
|
||||
"valid_config.json": `{
|
||||
"id": "bot123",
|
||||
"telegram_token": "token123",
|
||||
"memory_size": 1024,
|
||||
"messages_per_hour": 10,
|
||||
"messages_per_day": 100,
|
||||
"temp_ban_duration": "1h",
|
||||
"model": "claude-v1",
|
||||
"system_prompts": {"welcome": "Hello!"},
|
||||
"active": true,
|
||||
"owner_telegram_id": 123456789,
|
||||
"anthropic_api_key": "api_key_123"
|
||||
}`,
|
||||
"invalid_config.json": `{
|
||||
"id": "bot127",
|
||||
"telegram_token": "token127",
|
||||
"model": "",
|
||||
"active": true
|
||||
}`,
|
||||
},
|
||||
expectConfigs: 1,
|
||||
expectError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Clear the tempDir before each test
|
||||
os.RemoveAll(tempDir)
|
||||
os.MkdirAll(tempDir, 0755)
|
||||
|
||||
// Write the test files directly
|
||||
for filename, content := range tt.setupFiles {
|
||||
err := os.WriteFile(filepath.Join(tempDir, filename), []byte(content), 0644)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to write file %s: %v", filename, err)
|
||||
}
|
||||
}
|
||||
|
||||
configs, err := loadAllConfigs(tempDir)
|
||||
if (err != nil) != tt.expectError {
|
||||
t.Errorf("loadAllConfigs() error = %v, wantErr %v", err, tt.expectError)
|
||||
return
|
||||
}
|
||||
if len(configs) != tt.expectConfigs {
|
||||
t.Errorf("Expected %d configs, got %d", tt.expectConfigs, len(configs))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestBotConfig_Reload tests the Reload method of BotConfig
|
||||
func TestBotConfig_Reload(t *testing.T) {
|
||||
// Create a temporary directory
|
||||
tempDir, err := os.MkdirTemp("", "reload_test")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
// Create initial config file
|
||||
config1 := `{
|
||||
"id": "bot123",
|
||||
"telegram_token": "token123",
|
||||
"memory_size": 1024,
|
||||
"messages_per_hour": 10,
|
||||
"messages_per_day": 100,
|
||||
"temp_ban_duration": "1h",
|
||||
"model": "claude-v1",
|
||||
"system_prompts": {"welcome": "Hello!"},
|
||||
"active": true,
|
||||
"owner_telegram_id": 123456789,
|
||||
"anthropic_api_key": "api_key_123"
|
||||
}`
|
||||
configPath := filepath.Join(tempDir, "config.json")
|
||||
if err := os.WriteFile(configPath, []byte(config1), 0644); err != nil {
|
||||
t.Fatalf("Failed to write initial config: %v", err)
|
||||
}
|
||||
|
||||
// Initialize BotConfig
|
||||
var config BotConfig
|
||||
if err := config.Reload(tempDir, "config.json"); err != nil {
|
||||
t.Fatalf("Failed to reload config: %v", err)
|
||||
}
|
||||
|
||||
// Verify initial load
|
||||
if config.ID != "bot123" {
|
||||
t.Errorf("Expected ID 'bot123', got '%s'", config.ID)
|
||||
}
|
||||
if config.Model != "claude-v1" {
|
||||
t.Errorf("Expected Model 'claude-v1', got '%s'", config.Model)
|
||||
}
|
||||
|
||||
// Update config file
|
||||
config2 := `{
|
||||
"id": "bot123",
|
||||
"telegram_token": "token123_updated",
|
||||
"memory_size": 2048,
|
||||
"messages_per_hour": 20,
|
||||
"messages_per_day": 200,
|
||||
"temp_ban_duration": "2h",
|
||||
"model": "claude-v2",
|
||||
"system_prompts": {"welcome": "Hi there!"},
|
||||
"active": true,
|
||||
"owner_telegram_id": 987654321,
|
||||
"anthropic_api_key": "api_key_456"
|
||||
}`
|
||||
if err := os.WriteFile(configPath, []byte(config2), 0644); err != nil {
|
||||
t.Fatalf("Failed to write updated config: %v", err)
|
||||
}
|
||||
|
||||
// Reload config
|
||||
if err := config.Reload(tempDir, "config.json"); err != nil {
|
||||
t.Fatalf("Failed to reload updated config: %v", err)
|
||||
}
|
||||
|
||||
// Verify updated config
|
||||
if config.TelegramToken != "token123_updated" {
|
||||
t.Errorf("Expected TelegramToken 'token123_updated', got '%s'", config.TelegramToken)
|
||||
}
|
||||
if config.MemorySize != 2048 {
|
||||
t.Errorf("Expected MemorySize 2048, got %d", config.MemorySize)
|
||||
}
|
||||
if config.Model != "claude-v2" {
|
||||
t.Errorf("Expected Model 'claude-v2', got '%s'", config.Model)
|
||||
}
|
||||
if config.OwnerTelegramID != 987654321 {
|
||||
t.Errorf("Expected OwnerTelegramID 987654321, got %d", config.OwnerTelegramID)
|
||||
}
|
||||
}
|
||||
|
||||
// TestBotConfig_UnmarshalJSON_Invalid tests unmarshalling with invalid model
|
||||
func TestBotConfig_UnmarshalJSON_Invalid(t *testing.T) {
|
||||
jsonData := `{
|
||||
"id": "bot123",
|
||||
"telegram_token": "token123",
|
||||
"memory_size": 1024,
|
||||
"messages_per_hour": 10,
|
||||
"messages_per_day": 100,
|
||||
"temp_ban_duration": "1h",
|
||||
"model": "",
|
||||
"system_prompts": {"welcome": "Hello!"},
|
||||
"active": true,
|
||||
"owner_telegram_id": 123456789,
|
||||
"anthropic_api_key": "api_key_123"
|
||||
}`
|
||||
|
||||
var config BotConfig
|
||||
err := json.Unmarshal([]byte(jsonData), &config)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to unmarshal JSON: %v", err)
|
||||
}
|
||||
|
||||
if config.Model != "" {
|
||||
t.Errorf("Expected empty model, got %s", config.Model)
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to check substring
|
||||
func contains(s, substr string) bool {
|
||||
return strings.Contains(s, substr)
|
||||
}
|
||||
|
||||
// Additional tests can be added here to cover more scenarios
|
||||
Reference in New Issue
Block a user