package profilemanager import ( "os" "os/user" "path/filepath" "testing" "github.com/stretchr/testify/assert" ) func withTempConfigDir(t *testing.T, testFunc func(configDir string)) { t.Helper() tempDir := t.TempDir() t.Setenv("NETBIRD_CONFIG_DIR", tempDir) defer os.Unsetenv("NETBIRD_CONFIG_DIR") testFunc(tempDir) } func withPatchedGlobals(t *testing.T, configDir string, testFunc func()) { origDefaultConfigPathDir := DefaultConfigPathDir origDefaultConfigPath := DefaultConfigPath origActiveProfileStatePath := ActiveProfileStatePath origOldDefaultConfigPath := oldDefaultConfigPath origConfigDirOverride := ConfigDirOverride DefaultConfigPathDir = configDir DefaultConfigPath = filepath.Join(configDir, "default.json") ActiveProfileStatePath = filepath.Join(configDir, "active_profile.json") oldDefaultConfigPath = filepath.Join(configDir, "old_config.json") ConfigDirOverride = configDir // Clean up any files in the config dir to ensure isolation os.RemoveAll(configDir) os.MkdirAll(configDir, 0755) //nolint: errcheck defer func() { DefaultConfigPathDir = origDefaultConfigPathDir DefaultConfigPath = origDefaultConfigPath ActiveProfileStatePath = origActiveProfileStatePath oldDefaultConfigPath = origOldDefaultConfigPath ConfigDirOverride = origConfigDirOverride }() testFunc() } func TestServiceManager_CreateAndGetDefaultProfile(t *testing.T) { withTempConfigDir(t, func(configDir string) { withPatchedGlobals(t, configDir, func() { sm := &ServiceManager{} err := sm.CreateDefaultProfile() assert.NoError(t, err) state, err := sm.GetActiveProfileState() assert.NoError(t, err) assert.Equal(t, state.Name, defaultProfileName) // No active profile state yet err = sm.SetActiveProfileStateToDefault() assert.NoError(t, err) active, err := sm.GetActiveProfileState() assert.NoError(t, err) assert.Equal(t, "default", active.Name) }) }) } func TestServiceManager_CopyDefaultProfileIfNotExists(t *testing.T) { withTempConfigDir(t, func(configDir string) { withPatchedGlobals(t, configDir, func() { sm := &ServiceManager{} // Case: old default config does not exist ok, err := sm.CopyDefaultProfileIfNotExists() assert.False(t, ok) assert.ErrorIs(t, err, ErrorOldDefaultConfigNotFound) // Case: old default config exists, should be moved f, err := os.Create(oldDefaultConfigPath) assert.NoError(t, err) f.Close() ok, err = sm.CopyDefaultProfileIfNotExists() assert.True(t, ok) assert.NoError(t, err) _, err = os.Stat(DefaultConfigPath) assert.NoError(t, err) }) }) } func TestServiceManager_SetActiveProfileState(t *testing.T) { withTempConfigDir(t, func(configDir string) { withPatchedGlobals(t, configDir, func() { currUser, err := user.Current() assert.NoError(t, err) sm := &ServiceManager{} state := &ActiveProfileState{Name: "foo", Username: currUser.Username} err = sm.SetActiveProfileState(state) assert.NoError(t, err) // Should error on nil or incomplete state err = sm.SetActiveProfileState(nil) assert.Error(t, err) err = sm.SetActiveProfileState(&ActiveProfileState{Name: "", Username: ""}) assert.Error(t, err) }) }) } func TestServiceManager_DefaultProfilePath(t *testing.T) { withTempConfigDir(t, func(configDir string) { withPatchedGlobals(t, configDir, func() { sm := &ServiceManager{} assert.Equal(t, DefaultConfigPath, sm.DefaultProfilePath()) }) }) } func TestSanitizeProfileName(t *testing.T) { tests := []struct { in, want string }{ // unchanged {"Alice", "Alice"}, {"bob123", "bob123"}, {"under_score", "under_score"}, {"dash-name", "dash-name"}, // spaces and forbidden chars removed {"Alice Smith", "AliceSmith"}, {"bad/char\\name", "badcharname"}, {"colon:name*?", "colonname"}, {"quotes\"<>|", "quotes"}, // mixed {"User_123-Test!@#", "User_123-Test"}, // empty and all-bad {"", ""}, {"!@#$%^&*()", ""}, // unicode letters and digits {"ÜserÇ", "ÜserÇ"}, {"漢字テスト123", "漢字テスト123"}, } for _, tc := range tests { got := sanitizeProfileName(tc.in) if got != tc.want { t.Errorf("sanitizeProfileName(%q) = %q; want %q", tc.in, got, tc.want) } } }