@@ -0,0 +1,116 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func validConfig() Config {
|
||||
config := DefaultConfig()
|
||||
config.Server = "https://devplace.net"
|
||||
config.Secret = "dpn_abcdefghijklmnop"
|
||||
return config
|
||||
}
|
||||
|
||||
func TestConfigRoundTripShapeAndMode(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "sub", "config.json")
|
||||
if err := SaveConfig(path, validConfig()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
raw, _ := os.ReadFile(path)
|
||||
keys := map[string]any{}
|
||||
if err := json.Unmarshal(raw, &keys); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, key := range []string{"server", "secret", "bandwidth_mb_day", "max_concurrent", "max_tunnels", "active_from", "active_to", "timezone"} {
|
||||
if _, ok := keys[key]; !ok {
|
||||
t.Errorf("missing key %s", key)
|
||||
}
|
||||
}
|
||||
if len(keys) != 8 {
|
||||
t.Errorf("unexpected keys %v", keys)
|
||||
}
|
||||
if runtime.GOOS != "windows" {
|
||||
info, _ := os.Stat(path)
|
||||
if info.Mode().Perm() != 0o600 {
|
||||
t.Errorf("mode %v", info.Mode().Perm())
|
||||
}
|
||||
}
|
||||
loaded, err := LoadConfig(path)
|
||||
if err != nil || loaded != validConfig() {
|
||||
t.Fatalf("loaded %+v %v", loaded, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigValidationTable(t *testing.T) {
|
||||
cases := map[string]func(*Config){
|
||||
"server scheme": func(c *Config) { c.Server = "ftp://x" },
|
||||
"server empty": func(c *Config) { c.Server = "" },
|
||||
"secret prefix": func(c *Config) { c.Secret = "abc_1234567890" },
|
||||
"secret short": func(c *Config) { c.Secret = "dpn_" },
|
||||
"bandwidth low": func(c *Config) { c.BandwidthMBDay = 0 },
|
||||
"bandwidth high": func(c *Config) { c.BandwidthMBDay = MaxDonorMBPerDay + 1 },
|
||||
"concurrency": func(c *Config) { c.MaxConcurrent = 99 },
|
||||
"tunnels": func(c *Config) { c.MaxTunnels = 0 },
|
||||
"hours format": func(c *Config) { c.ActiveFrom, c.ActiveTo = "9:00", "17:00" },
|
||||
"hours lone": func(c *Config) { c.ActiveFrom = "09:00" },
|
||||
"timezone": func(c *Config) { c.Timezone = "Mars/Base" },
|
||||
}
|
||||
for name, mutate := range cases {
|
||||
config := validConfig()
|
||||
mutate(&config)
|
||||
if config.Validate() == nil {
|
||||
t.Errorf("%s accepted", name)
|
||||
}
|
||||
}
|
||||
good := validConfig()
|
||||
good.ActiveFrom, good.ActiveTo, good.Timezone = "22:00", "06:00", "Europe/Amsterdam"
|
||||
if err := good.Validate(); err != nil {
|
||||
t.Errorf("good config: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadRejectsUnknownFieldsAndMissingFile(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
path := filepath.Join(dir, "config.json")
|
||||
if _, err := LoadConfig(path); err == nil || !strings.Contains(err.Error(), "login") {
|
||||
t.Errorf("missing file: %v", err)
|
||||
}
|
||||
_ = os.WriteFile(path, []byte(`{"server":"https://x.y","secret":"dpn_abcdefghijk","surprise":1}`), 0o600)
|
||||
if _, err := LoadConfig(path); err == nil {
|
||||
t.Error("unknown field accepted")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommandsVersionAndUsage(t *testing.T) {
|
||||
var out, errOut strings.Builder
|
||||
if code := execute([]string{"version"}, &out, &errOut); code != exitOK || !strings.Contains(out.String(), Version) {
|
||||
t.Fatalf("version: %d %q", code, out.String())
|
||||
}
|
||||
if code := execute(nil, &out, &errOut); code != exitUsage {
|
||||
t.Fatalf("no args: %d", code)
|
||||
}
|
||||
if code := execute([]string{"bogus"}, &out, &errOut); code != exitUsage {
|
||||
t.Fatalf("bogus: %d", code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoginStoresWithoutVerifyAndNeverEchoesSecret(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "config.json")
|
||||
var out, errOut strings.Builder
|
||||
args := []string{"--config", path, "--server", "https://devplace.net", "--secret", "dpn_abcdefghijklmnop", "--no-verify"}
|
||||
if code := execute(append([]string{"login"}, args...), &out, &errOut); code != exitOK {
|
||||
t.Fatalf("login: %d %s", code, errOut.String())
|
||||
}
|
||||
if strings.Contains(out.String()+errOut.String(), "dpn_abcdefghijklmnop") {
|
||||
t.Fatal("secret was printed")
|
||||
}
|
||||
out.Reset()
|
||||
if code := execute([]string{"login", "--config", path, "--server", "nope", "--secret", "x"}, &out, &errOut); code != exitUsage {
|
||||
t.Fatalf("bad login accepted: %d", code)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user