backupy-agent/apps/agent/internal/config/config_test.go
TronoSfera f9160a7686 fix(agent): env vars BACKUPY_* and accept 64-hex agent keys
Two defects exposed by the first real-world deployment (Flw VPS):
- Env tags were BACKUP_* (no Y). Server + dashboard use BACKUPY_*.
- agentKeyPattern only matched bkpy_(live|test)_<32 alnum>; server's
  generateAgentKey emits 64 lowercase hex chars. Accept both.
2026-05-18 14:17:54 +03:00

107 lines
2.8 KiB
Go

package config
import (
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/require"
)
const validKey = "bkpy_live_abcdefghijklmnopqrstuvwxyz012345"
func TestValidate_Happy(t *testing.T) {
dir := t.TempDir()
cfg := &Config{
ServerURL: "https://api.backupy.ru",
AgentKey: validKey,
StateDir: dir,
LogLevel: "info",
}
require.NoError(t, cfg.Validate())
require.Equal(t, filepath.Join(dir, "state.db"), cfg.StateDBPath())
}
func TestValidate_ServerURL(t *testing.T) {
cases := []struct {
name string
url string
insec bool
errSub string
}{
{"https ok", "https://api.backupy.ru", false, ""},
{"http rejected by default", "http://localhost:8080", false, "must use https"},
{"http allowed with dev flag", "http://localhost:8080", true, ""},
{"ftp rejected", "ftp://example.com", false, "unsupported scheme"},
{"missing host", "https://", false, "missing host"},
{"unparsable", "://broken", false, "valid URL"},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
err := validateServerURL(tc.url, tc.insec)
if tc.errSub == "" {
require.NoError(t, err)
return
}
require.Error(t, err)
require.Contains(t, err.Error(), tc.errSub)
})
}
}
func TestValidate_AgentKey(t *testing.T) {
dir := t.TempDir()
cases := []struct {
name string
key string
ok bool
}{
{"live key", "bkpy_live_abcdefghijklmnopqrstuvwxyz012345", true},
{"test key", "bkpy_test_abcdefghijklmnopqrstuvwxyz012345", true},
{"wrong prefix", "bkpy_dev_abcdefghijklmnopqrstuvwxyz012345", false},
{"too short", "bkpy_live_abc", false},
{"too long", "bkpy_live_abcdefghijklmnopqrstuvwxyz0123456", false},
{"invalid char", "bkpy_live_abcdefghijklmnopqrstuvwxyz01234!", false},
{"empty", "", false},
{"missing underscore", "bkpylive_abcdefghijklmnopqrstuvwxyz012345", false},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
cfg := &Config{
ServerURL: "https://api.backupy.ru",
AgentKey: tc.key,
StateDir: dir,
}
err := cfg.Validate()
if tc.ok {
require.NoError(t, err)
} else {
require.Error(t, err)
require.Contains(t, err.Error(), "BACKUPY_AGENT_KEY")
}
})
}
}
func TestValidate_StateDir(t *testing.T) {
t.Run("empty rejected", func(t *testing.T) {
err := validateStateDirWritable("")
require.Error(t, err)
})
t.Run("creates missing dir", func(t *testing.T) {
root := t.TempDir()
nested := filepath.Join(root, "nested", "state")
require.NoError(t, validateStateDirWritable(nested))
})
t.Run("redaction in errors", func(t *testing.T) {
// Sanity check: error text never mentions the agent key.
cfg := &Config{
ServerURL: "https://api.backupy.ru",
AgentKey: validKey,
StateDir: "", // invalid
}
err := cfg.Validate()
require.Error(t, err)
require.False(t, strings.Contains(err.Error(), validKey))
})
}