231 lines
5.5 KiB
Go
231 lines
5.5 KiB
Go
package config
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
const testJSON = `{
|
|
"networks": {
|
|
"smarthost-loadbalancer": {
|
|
"network_name": "smarthost-loadbalancer",
|
|
"subnet": "172.18.103.0/24",
|
|
"gateway": "172.18.103.1"
|
|
},
|
|
"smarthost_backend-1": {
|
|
"network_name": "smarthost_backend-1",
|
|
"subnet": "172.18.104.0/24",
|
|
"gateway": "172.18.104.1"
|
|
}
|
|
},
|
|
"ips": {
|
|
"172.18.103.2": {
|
|
"ip": "172.18.103.2",
|
|
"container_name": "smarthostloadbalancer",
|
|
"selector": "smarthostloadbalancer",
|
|
"service_name": "smarthost-proxy"
|
|
},
|
|
"172.18.104.2": {
|
|
"ip": "172.18.104.2",
|
|
"container_name": "smarthostbackend-1",
|
|
"selector": "smarthostbackend-1",
|
|
"service_name": "smarthost-proxy"
|
|
}
|
|
},
|
|
"policies": [
|
|
{
|
|
"service_name": "smarthost-proxy",
|
|
"container_name": "smarthost_loadbalancer",
|
|
"selector": "smarthostloadbalancer",
|
|
"from": "publicbackend",
|
|
"port": 80,
|
|
"proto": "tcp"
|
|
},
|
|
{
|
|
"service_name": "smarthost-proxy",
|
|
"container_name": "smarthost_loadbalancer",
|
|
"selector": "smarthostloadbalancer",
|
|
"name": "wireguardproxy",
|
|
"iface": "wg0",
|
|
"nat": "dnat",
|
|
"to": "smarthostloadbalancer",
|
|
"port": 80,
|
|
"proto": "tcp"
|
|
}
|
|
]
|
|
}`
|
|
|
|
func TestLoad(t *testing.T) {
|
|
dir := t.TempDir()
|
|
path := filepath.Join(dir, "networks.json")
|
|
if err := os.WriteFile(path, []byte(testJSON), 0644); err != nil {
|
|
t.Fatalf("failed to write test file: %v", err)
|
|
}
|
|
|
|
cfg, err := Load(path)
|
|
if err != nil {
|
|
t.Fatalf("Load() returned error: %v", err)
|
|
}
|
|
|
|
if len(cfg.Networks) != 2 {
|
|
t.Errorf("expected 2 networks, got %d", len(cfg.Networks))
|
|
}
|
|
|
|
if cfg.Networks["smarthost-loadbalancer"].Subnet != "172.18.103.0/24" {
|
|
t.Errorf("unexpected subnet: %s", cfg.Networks["smarthost-loadbalancer"].Subnet)
|
|
}
|
|
|
|
if len(cfg.IPs) != 2 {
|
|
t.Errorf("expected 2 IPs, got %d", len(cfg.IPs))
|
|
}
|
|
|
|
if cfg.IPs["172.18.103.2"].ContainerName != "smarthostloadbalancer" {
|
|
t.Errorf("unexpected container name: %s", cfg.IPs["172.18.103.2"].ContainerName)
|
|
}
|
|
|
|
if len(cfg.Policies) != 2 {
|
|
t.Errorf("expected 2 policies, got %d", len(cfg.Policies))
|
|
}
|
|
|
|
if cfg.Policies[0].From != "publicbackend" {
|
|
t.Errorf("unexpected from: %s", cfg.Policies[0].From)
|
|
}
|
|
|
|
if cfg.Policies[1].Nat != "dnat" {
|
|
t.Errorf("unexpected nat: %s", cfg.Policies[1].Nat)
|
|
}
|
|
}
|
|
|
|
func TestLoadFileNotFound(t *testing.T) {
|
|
_, err := Load("/nonexistent/path/networks.json")
|
|
if err == nil {
|
|
t.Error("expected error for nonexistent file, got nil")
|
|
}
|
|
}
|
|
|
|
func TestLoadInvalidJSON(t *testing.T) {
|
|
dir := t.TempDir()
|
|
path := filepath.Join(dir, "bad.json")
|
|
if err := os.WriteFile(path, []byte("{invalid json"), 0644); err != nil {
|
|
t.Fatalf("failed to write test file: %v", err)
|
|
}
|
|
|
|
_, err := Load(path)
|
|
if err == nil {
|
|
t.Error("expected error for invalid JSON, got nil")
|
|
}
|
|
}
|
|
|
|
func TestToCIDR(t *testing.T) {
|
|
tests := []struct {
|
|
input string
|
|
want string
|
|
}{
|
|
{"172.18.103.0", "172.18.103.0/24"},
|
|
{"172.18.103.2", "172.18.103.2"},
|
|
{"172.18.103.0/24", "172.18.103.0/24"},
|
|
{"10.0.0.0", "10.0.0.0/24"},
|
|
{"invalid", "invalid"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
got := ToCIDR(tt.input)
|
|
if got != tt.want {
|
|
t.Errorf("ToCIDR(%q) = %q, want %q", tt.input, got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestNetworkPrefix(t *testing.T) {
|
|
tests := []struct {
|
|
input string
|
|
want string
|
|
}{
|
|
{"172.18.103.2", "172.18.103.0/24"},
|
|
{"10.0.0.1", "10.0.0.0/24"},
|
|
{"invalid", "invalid"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
got := NetworkPrefix(tt.input)
|
|
if got != tt.want {
|
|
t.Errorf("NetworkPrefix(%q) = %q, want %q", tt.input, got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestIsIP(t *testing.T) {
|
|
tests := []struct {
|
|
input string
|
|
want bool
|
|
}{
|
|
{"172.18.103.2", true},
|
|
{"10.0.0.0", true},
|
|
{"255.255.255.255", true},
|
|
{"publicbackend", false},
|
|
{"172.18.103.0/24", false},
|
|
{"", false},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
got := IsIP(tt.input)
|
|
if got != tt.want {
|
|
t.Errorf("IsIP(%q) = %v, want %v", tt.input, got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestNetworkConfigParseCIDR(t *testing.T) {
|
|
nc := NetworkConfig{Subnet: "172.18.103.0/24"}
|
|
ipNet, err := nc.ParseCIDR()
|
|
if err != nil {
|
|
t.Fatalf("ParseCIDR() returned error: %v", err)
|
|
}
|
|
if ipNet.String() != "172.18.103.0/24" {
|
|
t.Errorf("ParseCIDR() = %s, want 172.18.103.0/24", ipNet.String())
|
|
}
|
|
|
|
nc2 := NetworkConfig{Subnet: "invalid"}
|
|
_, err = nc2.ParseCIDR()
|
|
if err == nil {
|
|
t.Error("expected error for invalid subnet, got nil")
|
|
}
|
|
}
|
|
|
|
func TestLoadReproducible(t *testing.T) {
|
|
dir := t.TempDir()
|
|
path := filepath.Join(dir, "networks.json")
|
|
if err := os.WriteFile(path, []byte(testJSON), 0644); err != nil {
|
|
t.Fatalf("failed to write test file: %v", err)
|
|
}
|
|
|
|
// Load twice and compare
|
|
cfg1, err := Load(path)
|
|
if err != nil {
|
|
t.Fatalf("first Load() error: %v", err)
|
|
}
|
|
|
|
cfg2, err := Load(path)
|
|
if err != nil {
|
|
t.Fatalf("second Load() error: %v", err)
|
|
}
|
|
|
|
// Verify reproducibility
|
|
if len(cfg1.Networks) != len(cfg2.Networks) {
|
|
t.Errorf("reproducibility: network count mismatch %d vs %d", len(cfg1.Networks), len(cfg2.Networks))
|
|
}
|
|
if len(cfg1.IPs) != len(cfg2.IPs) {
|
|
t.Errorf("reproducibility: IP count mismatch %d vs %d", len(cfg1.IPs), len(cfg2.IPs))
|
|
}
|
|
if len(cfg1.Policies) != len(cfg2.Policies) {
|
|
t.Errorf("reproducibility: policy count mismatch %d vs %d", len(cfg1.Policies), len(cfg2.Policies))
|
|
}
|
|
|
|
for name, net1 := range cfg1.Networks {
|
|
net2 := cfg2.Networks[name]
|
|
if net1.Subnet != net2.Subnet || net1.Gateway != net2.Gateway {
|
|
t.Errorf("reproducibility: network %s mismatch", name)
|
|
}
|
|
}
|
|
} |