165 lines
5.4 KiB
Go
165 lines
5.4 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/adrg/xdg"
|
|
)
|
|
|
|
// setupTestEnv creates temporary directories and sets environment variables
|
|
// to simulate a specific user home and XDG base directories for testing.
|
|
// It returns the path to the temporary home directory and a cleanup function.
|
|
func setupTestEnv(t *testing.T) (string, func()) {
|
|
// Create a temporary directory for the user's home
|
|
tempHomeDir, err := os.MkdirTemp("", "test_home")
|
|
if err != nil {
|
|
t.Fatalf("Failed to create temp home directory: %v", err)
|
|
}
|
|
|
|
// Store original HOME environment variable to restore it later
|
|
oldHome := os.Getenv("HOME")
|
|
|
|
// Set HOME environment variable for the test
|
|
os.Setenv("HOME", tempHomeDir)
|
|
|
|
cleanup := func() {
|
|
// Restore original HOME environment variable
|
|
os.Setenv("HOME", oldHome)
|
|
// Clean up temporary directories
|
|
os.RemoveAll(tempHomeDir)
|
|
}
|
|
|
|
return tempHomeDir, cleanup
|
|
}
|
|
|
|
func TestNewService(t *testing.T) {
|
|
tempHomeDir, cleanup := setupTestEnv(t)
|
|
defer cleanup()
|
|
|
|
service, err := NewService()
|
|
if err != nil {
|
|
t.Fatalf("NewService() failed: %v", err)
|
|
}
|
|
|
|
cfg := service.Get()
|
|
|
|
// These paths are based on the mocked HOME directory
|
|
expectedUserHomeDir := filepath.Join(tempHomeDir, appName)
|
|
expectedConfigDir := filepath.Join(expectedUserHomeDir, "config")
|
|
expectedDataDir := filepath.Join(expectedUserHomeDir, "data")
|
|
expectedWorkspacesDir := filepath.Join(expectedUserHomeDir, "workspaces")
|
|
|
|
// For RootDir and CacheDir, xdg library's init() might have already run
|
|
// before our test's os.Setenv calls take effect for xdg. So, we calculate
|
|
// the *expected* values based on what xdg *actually* returns in the
|
|
// current process, which will likely be the system defaults or whatever
|
|
// was set before the test started.
|
|
actualXDGDataFile, err := xdg.DataFile(appName)
|
|
if err != nil {
|
|
t.Fatalf("xdg.DataFile failed: %v", err)
|
|
}
|
|
actualXDGCacheFile, err := xdg.CacheFile(appName)
|
|
if err != nil {
|
|
t.Fatalf("xdg.CacheFile failed: %v", err)
|
|
}
|
|
|
|
expectedRootDir := actualXDGDataFile
|
|
expectedCacheDir := actualXDGCacheFile
|
|
|
|
tests := []struct {
|
|
name string
|
|
actual string
|
|
expected string
|
|
}{
|
|
{"UserHomeDir", cfg.UserHomeDir, expectedUserHomeDir},
|
|
{"RootDir", cfg.RootDir, expectedRootDir},
|
|
{"ConfigDir", cfg.ConfigDir, expectedConfigDir},
|
|
{"DataDir", cfg.DataDir, expectedDataDir},
|
|
{"CacheDir", cfg.CacheDir, expectedCacheDir},
|
|
{"WorkspacesDir", cfg.WorkspacesDir, expectedWorkspacesDir},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if tt.actual != tt.expected {
|
|
t.Errorf("Mismatch for %s: got %q, want %q", tt.name, tt.actual, tt.expected)
|
|
}
|
|
// Also check if the directory was actually created
|
|
if info, err := os.Stat(tt.actual); err != nil {
|
|
t.Errorf("Directory %q for %s was not created: %v", tt.actual, tt.name, err)
|
|
} else if !info.IsDir() {
|
|
t.Errorf("Path %q for %s is not a directory", tt.actual, tt.name)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNewService_DirectoryCreationFails(t *testing.T) {
|
|
// Create a temporary directory that we will make read-only
|
|
tempHomeDir, err := os.MkdirTemp("", "test_readonly_home")
|
|
if err != nil {
|
|
t.Fatalf("Failed to create temp home directory: %v", err)
|
|
}
|
|
// Ensure cleanup happens, and restore permissions before removing
|
|
defer func() {
|
|
os.Chmod(tempHomeDir, 0755) // Restore write permissions for os.RemoveAll
|
|
os.RemoveAll(tempHomeDir)
|
|
}()
|
|
|
|
// Make the temporary home directory read-only
|
|
if err := os.Chmod(tempHomeDir, 0555); err != nil { // r-xr-xr-x
|
|
t.Fatalf("Failed to make temp home directory read-only: %v", err)
|
|
}
|
|
|
|
// Store original HOME environment variable to restore it later
|
|
oldHome := os.Getenv("HOME")
|
|
os.Setenv("HOME", tempHomeDir)
|
|
defer os.Setenv("HOME", oldHome)
|
|
|
|
// NewService should now fail because it cannot create subdirectories in tempHomeDir
|
|
_, err = NewService()
|
|
if err == nil {
|
|
t.Errorf("NewService() expected to fail when directory creation is impossible, but it succeeded")
|
|
}
|
|
// Optionally, check for a specific error message or type
|
|
if err != nil && !strings.Contains(err.Error(), "could not create directory") {
|
|
t.Errorf("NewService() failed with unexpected error: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestNewService_PathTraversalAttempt(t *testing.T) {
|
|
|
|
problematicAppName := "../lethean"
|
|
|
|
// Simulate the validation logic from NewService
|
|
if !strings.Contains(problematicAppName, "..") && !strings.Contains(problematicAppName, string(filepath.Separator)) {
|
|
t.Errorf("Expected problematicAppName to contain path traversal characters, but it didn't")
|
|
}
|
|
|
|
// We'll create a temporary function to simulate the validation within NewService
|
|
validateAppName := func(name string) error {
|
|
if strings.Contains(name, "..") || strings.Contains(name, string(filepath.Separator)) {
|
|
return fmt.Errorf("invalid app name '%s': contains path traversal characters", name)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Test with a problematic app name
|
|
err := validateAppName(problematicAppName)
|
|
if err == nil {
|
|
t.Errorf("validateAppName expected to fail for %q, but it succeeded", problematicAppName)
|
|
}
|
|
if err != nil && !strings.Contains(err.Error(), "path traversal characters") {
|
|
t.Errorf("validateAppName failed for %q with unexpected error: %v", problematicAppName, err)
|
|
}
|
|
// Test with a safe app name
|
|
safeAppName := "lethean"
|
|
err = validateAppName(safeAppName)
|
|
if err != nil {
|
|
t.Errorf("validateAppName expected to succeed for %q, but it failed with error: %v", safeAppName, err)
|
|
}
|
|
}
|