mirror of
https://github.com/hanzoskill/ecto.git
synced 2026-10-30 21:03:34 +00:00
875 lines
20 KiB
Go
875 lines
20 KiB
Go
package config
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestConfigPath(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
xdgHome string
|
|
want string
|
|
}{
|
|
{
|
|
name: "with XDG_CONFIG_HOME",
|
|
xdgHome: "/custom/config",
|
|
want: "/custom/config/ecto/config.json",
|
|
},
|
|
{
|
|
name: "without XDG_CONFIG_HOME",
|
|
xdgHome: "",
|
|
want: filepath.Join(os.Getenv("HOME"), ".config", "ecto", "config.json"),
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if tt.xdgHome != "" {
|
|
oldXDG := os.Getenv("XDG_CONFIG_HOME")
|
|
os.Setenv("XDG_CONFIG_HOME", tt.xdgHome)
|
|
defer os.Setenv("XDG_CONFIG_HOME", oldXDG)
|
|
} else {
|
|
oldXDG := os.Getenv("XDG_CONFIG_HOME")
|
|
os.Unsetenv("XDG_CONFIG_HOME")
|
|
defer os.Setenv("XDG_CONFIG_HOME", oldXDG)
|
|
}
|
|
|
|
got := ConfigPath()
|
|
if tt.xdgHome != "" {
|
|
assert.Equal(t, tt.want, got)
|
|
} else {
|
|
assert.Contains(t, got, ".config/ecto/config.json")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestLoadFromPath(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
setup func(t *testing.T) string
|
|
wantErr bool
|
|
check func(t *testing.T, cfg *Config)
|
|
}{
|
|
{
|
|
name: "file not found returns empty config",
|
|
setup: func(t *testing.T) string {
|
|
return filepath.Join(t.TempDir(), "nonexistent.json")
|
|
},
|
|
check: func(t *testing.T, cfg *Config) {
|
|
assert.NotNil(t, cfg)
|
|
assert.Empty(t, cfg.Sites)
|
|
assert.Empty(t, cfg.DefaultSite)
|
|
},
|
|
},
|
|
{
|
|
name: "valid config",
|
|
setup: func(t *testing.T) string {
|
|
dir := t.TempDir()
|
|
path := filepath.Join(dir, "config.json")
|
|
data := `{
|
|
"default_site": "mysite",
|
|
"sites": {
|
|
"mysite": {
|
|
"name": "mysite",
|
|
"url": "https://example.ghost.io",
|
|
"api_key": "abc123:def456"
|
|
}
|
|
}
|
|
}`
|
|
os.WriteFile(path, []byte(data), 0644)
|
|
return path
|
|
},
|
|
check: func(t *testing.T, cfg *Config) {
|
|
assert.Equal(t, "mysite", cfg.DefaultSite)
|
|
assert.Len(t, cfg.Sites, 1)
|
|
assert.Equal(t, "https://example.ghost.io", cfg.Sites["mysite"].URL)
|
|
},
|
|
},
|
|
{
|
|
name: "config with null sites",
|
|
setup: func(t *testing.T) string {
|
|
dir := t.TempDir()
|
|
path := filepath.Join(dir, "config.json")
|
|
data := `{"default_site": "test", "sites": null}`
|
|
os.WriteFile(path, []byte(data), 0644)
|
|
return path
|
|
},
|
|
check: func(t *testing.T, cfg *Config) {
|
|
assert.NotNil(t, cfg.Sites)
|
|
assert.Empty(t, cfg.Sites)
|
|
},
|
|
},
|
|
{
|
|
name: "invalid JSON",
|
|
setup: func(t *testing.T) string {
|
|
dir := t.TempDir()
|
|
path := filepath.Join(dir, "config.json")
|
|
os.WriteFile(path, []byte("invalid json"), 0644)
|
|
return path
|
|
},
|
|
wantErr: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
path := tt.setup(t)
|
|
cfg, err := LoadFromPath(path)
|
|
if tt.wantErr {
|
|
require.Error(t, err)
|
|
return
|
|
}
|
|
require.NoError(t, err)
|
|
tt.check(t, cfg)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestConfig_SaveToPath(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
config *Config
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "save empty config",
|
|
config: &Config{
|
|
Sites: make(map[string]Site),
|
|
},
|
|
},
|
|
{
|
|
name: "save with sites",
|
|
config: &Config{
|
|
DefaultSite: "mysite",
|
|
Sites: map[string]Site{
|
|
"mysite": {
|
|
Name: "mysite",
|
|
URL: "https://example.ghost.io",
|
|
APIKey: "key123:secret456",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
path := filepath.Join(dir, "subdir", "config.json")
|
|
|
|
err := tt.config.SaveToPath(path)
|
|
if tt.wantErr {
|
|
require.Error(t, err)
|
|
return
|
|
}
|
|
require.NoError(t, err)
|
|
|
|
// Verify file was created
|
|
_, err = os.Stat(path)
|
|
require.NoError(t, err)
|
|
|
|
// Load and verify
|
|
loaded, err := LoadFromPath(path)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, tt.config.DefaultSite, loaded.DefaultSite)
|
|
assert.Equal(t, len(tt.config.Sites), len(loaded.Sites))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestConfig_AddSiteNoSave(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
initial *Config
|
|
siteName string
|
|
url string
|
|
apiKey string
|
|
wantSites int
|
|
wantDefault string
|
|
}{
|
|
{
|
|
name: "add first site becomes default",
|
|
initial: &Config{
|
|
Sites: make(map[string]Site),
|
|
},
|
|
siteName: "site1",
|
|
url: "https://site1.ghost.io",
|
|
apiKey: "key:secret",
|
|
wantSites: 1,
|
|
wantDefault: "site1",
|
|
},
|
|
{
|
|
name: "add second site keeps existing default",
|
|
initial: &Config{
|
|
DefaultSite: "site1",
|
|
Sites: map[string]Site{
|
|
"site1": {Name: "site1", URL: "https://site1.ghost.io", APIKey: "k1:s1"},
|
|
},
|
|
},
|
|
siteName: "site2",
|
|
url: "https://site2.ghost.io",
|
|
apiKey: "k2:s2",
|
|
wantSites: 2,
|
|
wantDefault: "site1",
|
|
},
|
|
{
|
|
name: "update existing site",
|
|
initial: &Config{
|
|
DefaultSite: "site1",
|
|
Sites: map[string]Site{
|
|
"site1": {Name: "site1", URL: "https://old.ghost.io", APIKey: "old:key"},
|
|
},
|
|
},
|
|
siteName: "site1",
|
|
url: "https://new.ghost.io",
|
|
apiKey: "new:key",
|
|
wantSites: 1,
|
|
wantDefault: "site1",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
tt.initial.AddSiteNoSave(tt.siteName, tt.url, tt.apiKey)
|
|
|
|
assert.Len(t, tt.initial.Sites, tt.wantSites)
|
|
assert.Equal(t, tt.wantDefault, tt.initial.DefaultSite)
|
|
assert.Equal(t, tt.url, tt.initial.Sites[tt.siteName].URL)
|
|
assert.Equal(t, tt.apiKey, tt.initial.Sites[tt.siteName].APIKey)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestConfig_RemoveSiteNoSave(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
initial *Config
|
|
removeName string
|
|
wantSites int
|
|
wantDefault string
|
|
}{
|
|
{
|
|
name: "remove non-default site",
|
|
initial: &Config{
|
|
DefaultSite: "site1",
|
|
Sites: map[string]Site{
|
|
"site1": {Name: "site1"},
|
|
"site2": {Name: "site2"},
|
|
},
|
|
},
|
|
removeName: "site2",
|
|
wantSites: 1,
|
|
wantDefault: "site1",
|
|
},
|
|
{
|
|
name: "remove default site selects new default",
|
|
initial: &Config{
|
|
DefaultSite: "site1",
|
|
Sites: map[string]Site{
|
|
"site1": {Name: "site1"},
|
|
"site2": {Name: "site2"},
|
|
},
|
|
},
|
|
removeName: "site1",
|
|
wantSites: 1,
|
|
wantDefault: "site2",
|
|
},
|
|
{
|
|
name: "remove only site clears default",
|
|
initial: &Config{
|
|
DefaultSite: "site1",
|
|
Sites: map[string]Site{
|
|
"site1": {Name: "site1"},
|
|
},
|
|
},
|
|
removeName: "site1",
|
|
wantSites: 0,
|
|
wantDefault: "",
|
|
},
|
|
{
|
|
name: "remove nonexistent site",
|
|
initial: &Config{
|
|
DefaultSite: "site1",
|
|
Sites: map[string]Site{
|
|
"site1": {Name: "site1"},
|
|
},
|
|
},
|
|
removeName: "nonexistent",
|
|
wantSites: 1,
|
|
wantDefault: "site1",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
tt.initial.RemoveSiteNoSave(tt.removeName)
|
|
|
|
assert.Len(t, tt.initial.Sites, tt.wantSites)
|
|
if tt.wantDefault != "" {
|
|
assert.Equal(t, tt.wantDefault, tt.initial.DefaultSite)
|
|
} else {
|
|
assert.Empty(t, tt.initial.DefaultSite)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestConfig_SetDefaultNoSave(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
initial *Config
|
|
setDefault string
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "set existing site as default",
|
|
initial: &Config{
|
|
DefaultSite: "site1",
|
|
Sites: map[string]Site{
|
|
"site1": {Name: "site1"},
|
|
"site2": {Name: "site2"},
|
|
},
|
|
},
|
|
setDefault: "site2",
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "set nonexistent site as default",
|
|
initial: &Config{
|
|
Sites: map[string]Site{
|
|
"site1": {Name: "site1"},
|
|
},
|
|
},
|
|
setDefault: "nonexistent",
|
|
wantErr: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
err := tt.initial.SetDefaultNoSave(tt.setDefault)
|
|
if tt.wantErr {
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "not found")
|
|
return
|
|
}
|
|
require.NoError(t, err)
|
|
assert.Equal(t, tt.setDefault, tt.initial.DefaultSite)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestConfig_GetSite(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
config *Config
|
|
siteName string
|
|
wantURL string
|
|
wantErr bool
|
|
errMsg string
|
|
}{
|
|
{
|
|
name: "get by name",
|
|
config: &Config{
|
|
Sites: map[string]Site{
|
|
"mysite": {Name: "mysite", URL: "https://mysite.ghost.io"},
|
|
},
|
|
},
|
|
siteName: "mysite",
|
|
wantURL: "https://mysite.ghost.io",
|
|
},
|
|
{
|
|
name: "get default when name is empty",
|
|
config: &Config{
|
|
DefaultSite: "default",
|
|
Sites: map[string]Site{
|
|
"default": {Name: "default", URL: "https://default.ghost.io"},
|
|
},
|
|
},
|
|
siteName: "",
|
|
wantURL: "https://default.ghost.io",
|
|
},
|
|
{
|
|
name: "error when no site and no default",
|
|
config: &Config{
|
|
Sites: make(map[string]Site),
|
|
},
|
|
siteName: "",
|
|
wantErr: true,
|
|
errMsg: "no site specified and no default set",
|
|
},
|
|
{
|
|
name: "error when site not found",
|
|
config: &Config{
|
|
Sites: map[string]Site{
|
|
"other": {Name: "other"},
|
|
},
|
|
},
|
|
siteName: "nonexistent",
|
|
wantErr: true,
|
|
errMsg: "not found",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
site, err := tt.config.GetSite(tt.siteName)
|
|
if tt.wantErr {
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), tt.errMsg)
|
|
return
|
|
}
|
|
require.NoError(t, err)
|
|
assert.Equal(t, tt.wantURL, site.URL)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetActiveClientWithConfig(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
config *Config
|
|
siteName string
|
|
envURL string
|
|
envKey string
|
|
envSite string
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "use environment variables",
|
|
config: &Config{
|
|
Sites: make(map[string]Site),
|
|
},
|
|
envURL: "https://env.ghost.io",
|
|
envKey: "envid:7365637265746b6579313233",
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "use config site",
|
|
config: &Config{
|
|
DefaultSite: "mysite",
|
|
Sites: map[string]Site{
|
|
"mysite": {
|
|
Name: "mysite",
|
|
URL: "https://config.ghost.io",
|
|
APIKey: "configid:7365637265746b6579313233",
|
|
},
|
|
},
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "use GHOST_SITE env",
|
|
config: &Config{
|
|
DefaultSite: "default",
|
|
Sites: map[string]Site{
|
|
"default": {Name: "default", URL: "https://default.ghost.io", APIKey: "d:7365637265746b6579313233"},
|
|
"envsite": {Name: "envsite", URL: "https://envsite.ghost.io", APIKey: "e:7365637265746b6579313233"},
|
|
},
|
|
},
|
|
envSite: "envsite",
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "error no site configured",
|
|
config: &Config{
|
|
Sites: make(map[string]Site),
|
|
},
|
|
wantErr: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
// Set up environment
|
|
if tt.envURL != "" {
|
|
oldURL := os.Getenv("GHOST_URL")
|
|
os.Setenv("GHOST_URL", tt.envURL)
|
|
defer os.Setenv("GHOST_URL", oldURL)
|
|
} else {
|
|
os.Unsetenv("GHOST_URL")
|
|
}
|
|
|
|
if tt.envKey != "" {
|
|
oldKey := os.Getenv("GHOST_ADMIN_KEY")
|
|
os.Setenv("GHOST_ADMIN_KEY", tt.envKey)
|
|
defer os.Setenv("GHOST_ADMIN_KEY", oldKey)
|
|
} else {
|
|
os.Unsetenv("GHOST_ADMIN_KEY")
|
|
}
|
|
|
|
if tt.envSite != "" {
|
|
oldSite := os.Getenv("GHOST_SITE")
|
|
os.Setenv("GHOST_SITE", tt.envSite)
|
|
defer os.Setenv("GHOST_SITE", oldSite)
|
|
} else {
|
|
os.Unsetenv("GHOST_SITE")
|
|
}
|
|
|
|
client, err := GetActiveClientWithConfig(tt.config, tt.siteName)
|
|
if tt.wantErr {
|
|
require.Error(t, err)
|
|
return
|
|
}
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, client)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSite_Structure(t *testing.T) {
|
|
site := Site{
|
|
Name: "test",
|
|
URL: "https://test.ghost.io",
|
|
APIKey: "abc:def",
|
|
}
|
|
|
|
assert.Equal(t, "test", site.Name)
|
|
assert.Equal(t, "https://test.ghost.io", site.URL)
|
|
assert.Equal(t, "abc:def", site.APIKey)
|
|
}
|
|
|
|
func TestConfig_Structure(t *testing.T) {
|
|
cfg := &Config{
|
|
DefaultSite: "main",
|
|
Sites: map[string]Site{
|
|
"main": {Name: "main", URL: "https://main.ghost.io", APIKey: "m:m"},
|
|
"dev": {Name: "dev", URL: "https://dev.ghost.io", APIKey: "d:d"},
|
|
},
|
|
}
|
|
|
|
assert.Equal(t, "main", cfg.DefaultSite)
|
|
assert.Len(t, cfg.Sites, 2)
|
|
assert.Contains(t, cfg.Sites, "main")
|
|
assert.Contains(t, cfg.Sites, "dev")
|
|
}
|
|
|
|
// Tests for functions that use ConfigPath()
|
|
func TestLoad(t *testing.T) {
|
|
// Setup temp config directory
|
|
tmpDir := t.TempDir()
|
|
oldXDG := os.Getenv("XDG_CONFIG_HOME")
|
|
os.Setenv("XDG_CONFIG_HOME", tmpDir)
|
|
defer os.Setenv("XDG_CONFIG_HOME", oldXDG)
|
|
|
|
t.Run("load nonexistent config", func(t *testing.T) {
|
|
cfg, err := Load()
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, cfg)
|
|
assert.Empty(t, cfg.Sites)
|
|
})
|
|
|
|
t.Run("load existing config", func(t *testing.T) {
|
|
// Create config file
|
|
configDir := filepath.Join(tmpDir, "ecto")
|
|
os.MkdirAll(configDir, 0755)
|
|
configPath := filepath.Join(configDir, "config.json")
|
|
data := `{"default_site": "test", "sites": {"test": {"name": "test", "url": "https://test.ghost.io", "api_key": "k:s"}}}`
|
|
os.WriteFile(configPath, []byte(data), 0600)
|
|
|
|
cfg, err := Load()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "test", cfg.DefaultSite)
|
|
assert.Len(t, cfg.Sites, 1)
|
|
})
|
|
|
|
t.Run("load invalid json", func(t *testing.T) {
|
|
configDir := filepath.Join(tmpDir, "ecto")
|
|
configPath := filepath.Join(configDir, "config.json")
|
|
os.WriteFile(configPath, []byte("invalid json"), 0600)
|
|
|
|
_, err := Load()
|
|
require.Error(t, err)
|
|
})
|
|
}
|
|
|
|
func TestSave(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
oldXDG := os.Getenv("XDG_CONFIG_HOME")
|
|
os.Setenv("XDG_CONFIG_HOME", tmpDir)
|
|
defer os.Setenv("XDG_CONFIG_HOME", oldXDG)
|
|
|
|
cfg := &Config{
|
|
DefaultSite: "mysite",
|
|
Sites: map[string]Site{
|
|
"mysite": {Name: "mysite", URL: "https://my.ghost.io", APIKey: "m:s"},
|
|
},
|
|
}
|
|
|
|
err := cfg.Save()
|
|
require.NoError(t, err)
|
|
|
|
// Verify file was created
|
|
configPath := filepath.Join(tmpDir, "ecto", "config.json")
|
|
_, err = os.Stat(configPath)
|
|
require.NoError(t, err)
|
|
|
|
// Load and verify
|
|
loaded, err := Load()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "mysite", loaded.DefaultSite)
|
|
}
|
|
|
|
func TestAddSite(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
oldXDG := os.Getenv("XDG_CONFIG_HOME")
|
|
os.Setenv("XDG_CONFIG_HOME", tmpDir)
|
|
defer os.Setenv("XDG_CONFIG_HOME", oldXDG)
|
|
|
|
cfg := &Config{Sites: make(map[string]Site)}
|
|
err := cfg.AddSite("newsite", "https://new.ghost.io", "n:s")
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, "newsite", cfg.DefaultSite)
|
|
assert.Contains(t, cfg.Sites, "newsite")
|
|
|
|
// Verify it was saved
|
|
loaded, err := Load()
|
|
require.NoError(t, err)
|
|
assert.Contains(t, loaded.Sites, "newsite")
|
|
}
|
|
|
|
func TestRemoveSite(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
oldXDG := os.Getenv("XDG_CONFIG_HOME")
|
|
os.Setenv("XDG_CONFIG_HOME", tmpDir)
|
|
defer os.Setenv("XDG_CONFIG_HOME", oldXDG)
|
|
|
|
cfg := &Config{
|
|
DefaultSite: "site1",
|
|
Sites: map[string]Site{
|
|
"site1": {Name: "site1", URL: "https://s1.ghost.io", APIKey: "1:1"},
|
|
"site2": {Name: "site2", URL: "https://s2.ghost.io", APIKey: "2:2"},
|
|
},
|
|
}
|
|
// Save first
|
|
err := cfg.Save()
|
|
require.NoError(t, err)
|
|
|
|
// Remove site
|
|
err = cfg.RemoveSite("site1")
|
|
require.NoError(t, err)
|
|
|
|
assert.NotContains(t, cfg.Sites, "site1")
|
|
assert.Equal(t, "site2", cfg.DefaultSite) // Should pick new default
|
|
|
|
// Verify saved
|
|
loaded, err := Load()
|
|
require.NoError(t, err)
|
|
assert.NotContains(t, loaded.Sites, "site1")
|
|
}
|
|
|
|
func TestSetDefault(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
oldXDG := os.Getenv("XDG_CONFIG_HOME")
|
|
os.Setenv("XDG_CONFIG_HOME", tmpDir)
|
|
defer os.Setenv("XDG_CONFIG_HOME", oldXDG)
|
|
|
|
cfg := &Config{
|
|
DefaultSite: "site1",
|
|
Sites: map[string]Site{
|
|
"site1": {Name: "site1", URL: "https://s1.ghost.io", APIKey: "1:1"},
|
|
"site2": {Name: "site2", URL: "https://s2.ghost.io", APIKey: "2:2"},
|
|
},
|
|
}
|
|
err := cfg.Save()
|
|
require.NoError(t, err)
|
|
|
|
t.Run("set existing site as default", func(t *testing.T) {
|
|
err := cfg.SetDefault("site2")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "site2", cfg.DefaultSite)
|
|
|
|
// Verify saved
|
|
loaded, err := Load()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "site2", loaded.DefaultSite)
|
|
})
|
|
|
|
t.Run("set nonexistent site as default", func(t *testing.T) {
|
|
err := cfg.SetDefault("nonexistent")
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "not found")
|
|
})
|
|
}
|
|
|
|
func TestGetActiveClient(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
oldXDG := os.Getenv("XDG_CONFIG_HOME")
|
|
os.Setenv("XDG_CONFIG_HOME", tmpDir)
|
|
defer os.Setenv("XDG_CONFIG_HOME", oldXDG)
|
|
|
|
// Clear env vars that might interfere
|
|
oldURL := os.Getenv("GHOST_URL")
|
|
oldKey := os.Getenv("GHOST_ADMIN_KEY")
|
|
oldSite := os.Getenv("GHOST_SITE")
|
|
defer func() {
|
|
if oldURL != "" {
|
|
os.Setenv("GHOST_URL", oldURL)
|
|
}
|
|
if oldKey != "" {
|
|
os.Setenv("GHOST_ADMIN_KEY", oldKey)
|
|
}
|
|
if oldSite != "" {
|
|
os.Setenv("GHOST_SITE", oldSite)
|
|
}
|
|
}()
|
|
os.Unsetenv("GHOST_URL")
|
|
os.Unsetenv("GHOST_ADMIN_KEY")
|
|
os.Unsetenv("GHOST_SITE")
|
|
|
|
t.Run("from env vars", func(t *testing.T) {
|
|
os.Setenv("GHOST_URL", "https://env.ghost.io")
|
|
os.Setenv("GHOST_ADMIN_KEY", "envid:0123456789abcdef0123456789abcdef")
|
|
defer func() {
|
|
os.Unsetenv("GHOST_URL")
|
|
os.Unsetenv("GHOST_ADMIN_KEY")
|
|
}()
|
|
|
|
client, err := GetActiveClient("")
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, client)
|
|
})
|
|
|
|
t.Run("from config", func(t *testing.T) {
|
|
os.Unsetenv("GHOST_URL")
|
|
os.Unsetenv("GHOST_ADMIN_KEY")
|
|
|
|
// Create config
|
|
cfg := &Config{
|
|
DefaultSite: "mysite",
|
|
Sites: map[string]Site{
|
|
"mysite": {Name: "mysite", URL: "https://my.ghost.io", APIKey: "m:0123456789abcdef0123456789abcdef"},
|
|
},
|
|
}
|
|
err := cfg.Save()
|
|
require.NoError(t, err)
|
|
|
|
client, err := GetActiveClient("")
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, client)
|
|
})
|
|
|
|
t.Run("using GHOST_SITE env", func(t *testing.T) {
|
|
os.Unsetenv("GHOST_URL")
|
|
os.Unsetenv("GHOST_ADMIN_KEY")
|
|
|
|
cfg := &Config{
|
|
DefaultSite: "default",
|
|
Sites: map[string]Site{
|
|
"default": {Name: "default", URL: "https://default.ghost.io", APIKey: "d:0123456789abcdef0123456789abcdef"},
|
|
"other": {Name: "other", URL: "https://other.ghost.io", APIKey: "o:0123456789abcdef0123456789abcdef"},
|
|
},
|
|
}
|
|
err := cfg.Save()
|
|
require.NoError(t, err)
|
|
|
|
os.Setenv("GHOST_SITE", "other")
|
|
defer os.Unsetenv("GHOST_SITE")
|
|
|
|
client, err := GetActiveClient("")
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, client)
|
|
})
|
|
|
|
t.Run("no config no env", func(t *testing.T) {
|
|
os.Unsetenv("GHOST_URL")
|
|
os.Unsetenv("GHOST_ADMIN_KEY")
|
|
os.Unsetenv("GHOST_SITE")
|
|
|
|
// Clear config
|
|
configPath := filepath.Join(tmpDir, "ecto", "config.json")
|
|
os.Remove(configPath)
|
|
|
|
_, err := GetActiveClient("")
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "no site specified")
|
|
})
|
|
|
|
t.Run("with site name", func(t *testing.T) {
|
|
os.Unsetenv("GHOST_URL")
|
|
os.Unsetenv("GHOST_ADMIN_KEY")
|
|
|
|
cfg := &Config{
|
|
DefaultSite: "default",
|
|
Sites: map[string]Site{
|
|
"default": {Name: "default", URL: "https://default.ghost.io", APIKey: "d:0123456789abcdef0123456789abcdef"},
|
|
"other": {Name: "other", URL: "https://other.ghost.io", APIKey: "o:0123456789abcdef0123456789abcdef"},
|
|
},
|
|
}
|
|
err := cfg.Save()
|
|
require.NoError(t, err)
|
|
|
|
client, err := GetActiveClient("other")
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, client)
|
|
})
|
|
}
|
|
|
|
func TestSaveToPath_ErrorHandling(t *testing.T) {
|
|
cfg := &Config{
|
|
DefaultSite: "test",
|
|
Sites: map[string]Site{
|
|
"test": {Name: "test", URL: "https://test.ghost.io", APIKey: "t:s"},
|
|
},
|
|
}
|
|
|
|
// Try to save to a directory that exists as a file
|
|
tmpFile, err := os.CreateTemp("", "config-test")
|
|
require.NoError(t, err)
|
|
tmpFile.Close()
|
|
defer os.Remove(tmpFile.Name())
|
|
|
|
// Try to save config where the parent "directory" is actually a file
|
|
invalidPath := filepath.Join(tmpFile.Name(), "config.json")
|
|
err = cfg.SaveToPath(invalidPath)
|
|
require.Error(t, err)
|
|
}
|
|
|
|
// Integration test for full workflow
|
|
func TestConfig_FullWorkflow(t *testing.T) {
|
|
dir := t.TempDir()
|
|
path := filepath.Join(dir, "config.json")
|
|
|
|
// Create new config
|
|
cfg := &Config{Sites: make(map[string]Site)}
|
|
|
|
// Add first site (becomes default)
|
|
cfg.AddSiteNoSave("production", "https://prod.ghost.io", "prod:7365637265746b6579313233")
|
|
assert.Equal(t, "production", cfg.DefaultSite)
|
|
|
|
// Add second site
|
|
cfg.AddSiteNoSave("staging", "https://staging.ghost.io", "stage:7365637265746b6579313233")
|
|
assert.Equal(t, "production", cfg.DefaultSite) // Still production
|
|
|
|
// Change default
|
|
err := cfg.SetDefaultNoSave("staging")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "staging", cfg.DefaultSite)
|
|
|
|
// Save
|
|
err = cfg.SaveToPath(path)
|
|
require.NoError(t, err)
|
|
|
|
// Load and verify
|
|
loaded, err := LoadFromPath(path)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "staging", loaded.DefaultSite)
|
|
assert.Len(t, loaded.Sites, 2)
|
|
|
|
// Get site
|
|
site, err := loaded.GetSite("")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "https://staging.ghost.io", site.URL)
|
|
|
|
// Remove site
|
|
loaded.RemoveSiteNoSave("staging")
|
|
assert.Equal(t, "production", loaded.DefaultSite) // Changed to remaining site
|
|
}
|