A cell reads allow, block or partly (some new connections let through, the rest not), with its exceptions counted by what they do (+3 -1), and what they let through: services with the addresses they are limited to, under the grid in hc matrix and in each cell on the Matrix page. A zone to itself is marked: only traffic routed between its interfaces passes the firewall. The details list each rule's hits. hc matrix pads the grid by visible width: the colours' escape codes had thrown it out of line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
69 lines
2.6 KiB
Go
69 lines
2.6 KiB
Go
package main
|
|
|
|
import (
|
|
"regexp"
|
|
"strings"
|
|
"testing"
|
|
|
|
"housecarl/internal/matrix"
|
|
"housecarl/internal/model"
|
|
)
|
|
|
|
func TestDurations(t *testing.T) {
|
|
for in, want := range map[string]int{"3600": 3600, "12h": 43200, "30m": 1800, "1d": 86400, "1d12h": 129600, "1h30m": 5400} {
|
|
if got, err := parseSeconds(in); err != nil || got != want {
|
|
t.Errorf("parseSeconds(%q) = %d, %v; want %d", in, got, err, want)
|
|
}
|
|
}
|
|
for _, bad := range []string{"12x", "d", "1d2x"} {
|
|
if _, err := parseSeconds(bad); err == nil {
|
|
t.Errorf("parseSeconds(%q) accepted", bad)
|
|
}
|
|
}
|
|
for n, want := range map[int]string{43200: "12h", 5400: "1h30m", 90061: "1d1h1m1s", 0: "-"} {
|
|
if got := fmtSeconds(n); got != want {
|
|
t.Errorf("fmtSeconds(%d) = %q, want %q", n, got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestLimitAndDescribe(t *testing.T) {
|
|
l, err := parseLimit("3/minutes,burst=5,over,per-source")
|
|
if err != nil || l.Rate != 3 || l.Per != "minute" || l.Burst != 5 || !l.Over || !l.PerSource {
|
|
t.Errorf("parseLimit: %+v %v", l, err)
|
|
}
|
|
if _, err := parseLimit("fast"); err == nil {
|
|
t.Error("a bad limit accepted")
|
|
}
|
|
m := model.Match{InZones: []string{"wan"}, NotSources: true, Sources: []string{"trusted"}, Services: []string{"ssh", "tcp/8080"}}
|
|
if got := describe(m); got != "in wan from not trusted ssh,tcp/8080" {
|
|
t.Errorf("describe: %q", got)
|
|
}
|
|
if got := editList([]string{"a", "b", "c"}, []string{"d"}, []string{"b"}); len(got) != 3 || got[1] != "c" || got[2] != "d" {
|
|
t.Errorf("editList: %v", got)
|
|
}
|
|
}
|
|
|
|
// TestMatrixAligned: the grid's columns line up in colour too (the
|
|
// escape codes take no room on screen).
|
|
func TestMatrixAligned(t *testing.T) {
|
|
st := model.NewState()
|
|
st.Zones = []*model.Zone{{ID: 1, Name: "lan", Interfaces: []string{"eth1"}}, {ID: 2, Name: "wan", Interfaces: []string{"wan"}, External: true}}
|
|
st.Rules = []*model.Rule{{ID: 3, Chain: model.ChainForward, Position: 1, Action: model.ActionAccept, Match: model.Match{InZones: []string{"lan"}, Services: []string{"https"}}}}
|
|
st.Settings.InputPolicy, st.Settings.ForwardPolicy = model.PolicyDrop, model.PolicyDrop
|
|
var b strings.Builder
|
|
writeMatrix(&b, matrix.Build(st), true)
|
|
esc := regexp.MustCompile("\x1b\\[[0-9]+m")
|
|
lines := strings.Split(esc.ReplaceAllString(b.String(), ""), "\n")
|
|
col := strings.Index(lines[0], "wan")
|
|
for _, l := range lines[1:4] {
|
|
if r := []rune(l); len(r) <= col || r[col-1] != ' ' || r[col] == ' ' {
|
|
t.Errorf("misaligned at column %d:\n%s", col, strings.Join(lines[:4], "\n"))
|
|
break
|
|
}
|
|
}
|
|
if !strings.Contains(b.String(), "\x1b[33mpartly +1") || !strings.Contains(b.String(), "lan → wan\thttps") {
|
|
t.Errorf("no partly cell, or no list of what's open:\n%s", b.String())
|
|
}
|
|
}
|