117 lines
3.8 KiB
Go
117 lines
3.8 KiB
Go
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)
|
|
}
|
|
}
|