mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-15 21:13:00 +08:00
243 lines
7.9 KiB
Go
243 lines
7.9 KiB
Go
package policy
|
|
|
|
import (
|
|
"slices"
|
|
"testing"
|
|
|
|
"github.com/matthewlu070111/smart-srun/core/internal/domain"
|
|
)
|
|
|
|
func wired(id, iface string, managed bool) domain.CampusAccount {
|
|
return domain.CampusAccount{
|
|
ID: id, AccessMode: domain.AccessModeWired,
|
|
WiredIface: iface, AuthEnabled: managed,
|
|
}
|
|
}
|
|
|
|
func wireless(id, ssid string) domain.CampusAccount {
|
|
return domain.CampusAccount{
|
|
ID: id, AccessMode: domain.AccessModeWiFi, SSID: ssid,
|
|
}
|
|
}
|
|
|
|
func idsOf(targets []Target) []string {
|
|
out := make([]string, 0, len(targets))
|
|
for _, target := range targets {
|
|
out = append(out, target.AccountID)
|
|
}
|
|
return out
|
|
}
|
|
|
|
// T21 -- the forced-logout set is the union, with the account that is in both
|
|
// halves appearing once.
|
|
//
|
|
// The active campus account is very often also a managed one. Logging it out
|
|
// twice makes the second attempt fail -- it is already gone -- and the sweep
|
|
// then reports a failure and retries it for the rest of the window.
|
|
func TestTheForcedLogoutSetDeduplicatesTheActiveAccount(t *testing.T) {
|
|
config := &domain.Config{
|
|
MultiWANEnabled: true,
|
|
CampusAccounts: []domain.CampusAccount{
|
|
wired("wan-a", "wan", true),
|
|
wired("wan-b", "wan2", true),
|
|
wired("wan-c", "wan3", false),
|
|
},
|
|
Selection: domain.Selection{ActiveCampusID: "wan-a"},
|
|
}
|
|
|
|
targets := ForcedLogoutTargets(config)
|
|
if got := idsOf(targets); !slices.Equal(got, []string{"wan-a", "wan-b"}) {
|
|
t.Fatalf("targets = %v, want the two managed accounts once each", got)
|
|
}
|
|
for _, target := range targets {
|
|
if target.AccountID == "wan-a" && !target.Active {
|
|
t.Error("the active account was not marked active")
|
|
}
|
|
if !target.Managed {
|
|
t.Errorf("%s should be marked managed", target.AccountID)
|
|
}
|
|
}
|
|
}
|
|
|
|
// T21 -- an empty managed set still has to log the active account out.
|
|
//
|
|
// This is the configuration most users have: multi-WAN off, one account. A
|
|
// sweep that skipped it whenever the managed set was empty would mean quiet
|
|
// hours did nothing at all for them.
|
|
func TestAnEmptyManagedSetStillHandlesTheActiveAccount(t *testing.T) {
|
|
config := &domain.Config{
|
|
MultiWANEnabled: false,
|
|
CampusAccounts: []domain.CampusAccount{
|
|
wired("only", "wan", true), // opted in, but the global switch is off
|
|
},
|
|
Selection: domain.Selection{ActiveCampusID: "only"},
|
|
}
|
|
|
|
if managed := Managed(config); len(managed) != 0 {
|
|
t.Fatalf("managed = %v, want none while the global switch is off",
|
|
idsOf(managed))
|
|
}
|
|
targets := ForcedLogoutTargets(config)
|
|
if got := idsOf(targets); !slices.Equal(got, []string{"only"}) {
|
|
t.Fatalf("targets = %v, want the active account", got)
|
|
}
|
|
if targets[0].Managed {
|
|
t.Error("an account was reported as managed while multi-WAN is off")
|
|
}
|
|
}
|
|
|
|
// T21 -- a wireless active account joins the set, and is marked as wireless
|
|
// rather than being given somebody else's line.
|
|
func TestAWirelessActiveAccountJoinsTheWiredOnes(t *testing.T) {
|
|
config := &domain.Config{
|
|
MultiWANEnabled: true,
|
|
CampusAccounts: []domain.CampusAccount{
|
|
wired("wan-a", "wan", true),
|
|
wireless("wifi-a", "campus"),
|
|
},
|
|
Selection: domain.Selection{ActiveCampusID: "wifi-a"},
|
|
}
|
|
|
|
targets := ForcedLogoutTargets(config)
|
|
if got := idsOf(targets); !slices.Equal(got, []string{"wan-a", "wifi-a"}) {
|
|
t.Fatalf("targets = %v", got)
|
|
}
|
|
last := targets[len(targets)-1]
|
|
if !last.Wireless || last.Line != "" {
|
|
t.Errorf("the wireless account got line %q, wireless=%v; its line is "+
|
|
"whatever the STA associated to, which configuration does not know",
|
|
last.Line, last.Wireless)
|
|
}
|
|
}
|
|
|
|
// A selection pointing at an account that no longer exists is not a target.
|
|
// Config normalization repairs the pointer; producing a target for a missing
|
|
// account would make the sweep fail forever on something nobody can see.
|
|
func TestADanglingActiveSelectionIsNotATarget(t *testing.T) {
|
|
config := &domain.Config{
|
|
Selection: domain.Selection{ActiveCampusID: "deleted"},
|
|
}
|
|
if targets := ForcedLogoutTargets(config); len(targets) != 0 {
|
|
t.Errorf("targets = %v, want none", idsOf(targets))
|
|
}
|
|
}
|
|
|
|
// T21/T20 -- a success inside one occurrence stays recorded, and only failures
|
|
// come back.
|
|
func TestTheSweepRetriesOnlyWhatFailed(t *testing.T) {
|
|
config := &domain.Config{
|
|
MultiWANEnabled: true,
|
|
CampusAccounts: []domain.CampusAccount{
|
|
wired("wan-a", "wan", true),
|
|
wired("wan-b", "wan2", true),
|
|
},
|
|
}
|
|
targets := ForcedLogoutTargets(config)
|
|
|
|
var sweep Sweep
|
|
const tonight = "20260305T0100+0800"
|
|
|
|
if got := idsOf(sweep.Pending(tonight, targets)); len(got) != 2 {
|
|
t.Fatalf("first pass = %v, want both", got)
|
|
}
|
|
sweep.Succeeded(tonight, "wan-a")
|
|
|
|
// wan-b failed, so it is still pending; wan-a is not.
|
|
if got := idsOf(sweep.Pending(tonight, targets)); !slices.Equal(got, []string{"wan-b"}) {
|
|
t.Fatalf("second pass = %v, want only the one that failed", got)
|
|
}
|
|
sweep.Succeeded(tonight, "wan-b")
|
|
if got := sweep.Pending(tonight, targets); len(got) != 0 {
|
|
t.Fatalf("third pass = %v, want nothing left", idsOf(got))
|
|
}
|
|
|
|
// The next night is a new occurrence and starts over.
|
|
const tomorrow = "20260306T0100+0800"
|
|
if got := idsOf(sweep.Pending(tomorrow, targets)); len(got) != 2 {
|
|
t.Errorf("the next occurrence = %v, want both again", got)
|
|
}
|
|
}
|
|
|
|
// T21 -- switching forced logout on while the window is already open applies to
|
|
// the accounts that have not been handled yet.
|
|
//
|
|
// It falls out of recomputing the target list every pass instead of capturing
|
|
// it when the window opened, which is the point: the alternative needs its own
|
|
// branch and the branch is what gets forgotten.
|
|
func TestTurningForcedLogoutOnMidWindowCatchesTheRest(t *testing.T) {
|
|
config := &domain.Config{
|
|
MultiWANEnabled: true,
|
|
CampusAccounts: []domain.CampusAccount{
|
|
wired("wan-a", "wan", true),
|
|
},
|
|
}
|
|
var sweep Sweep
|
|
const tonight = "20260305T0100+0800"
|
|
|
|
sweep.Succeeded(tonight, "wan-a")
|
|
if got := sweep.Pending(tonight, ForcedLogoutTargets(config)); len(got) != 0 {
|
|
t.Fatalf("pending = %v, want nothing", idsOf(got))
|
|
}
|
|
|
|
// The user adds a second managed account while the window is open.
|
|
config.CampusAccounts = append(config.CampusAccounts, wired("wan-b", "wan2", true))
|
|
got := idsOf(sweep.Pending(tonight, ForcedLogoutTargets(config)))
|
|
if !slices.Equal(got, []string{"wan-b"}) {
|
|
t.Errorf("pending = %v, want the account that has not been handled", got)
|
|
}
|
|
}
|
|
|
|
// Two accounts on one resolved line is refused rather than guessed at: they
|
|
// cannot both be online, so each login knocks the other off and the pair take
|
|
// turns doing it forever.
|
|
func TestTwoAccountsOnOneLineAreReportedAsAConflict(t *testing.T) {
|
|
targets := []Target{
|
|
{AccountID: "a", Line: "wan"},
|
|
{AccountID: "b", Line: "wan.v2"},
|
|
{AccountID: "c", Line: "wan2"},
|
|
{AccountID: "d", Line: ""},
|
|
}
|
|
// Different logical names, same L3 device underneath. Comparing the
|
|
// configured names would miss it.
|
|
resolve := func(target Target) string {
|
|
switch target.Line {
|
|
case "wan", "wan.v2":
|
|
return "eth0"
|
|
case "wan2":
|
|
return "eth1"
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
conflicts := Conflicts(targets, resolve)
|
|
if len(conflicts) != 1 {
|
|
t.Fatalf("conflicts = %+v, want exactly one", conflicts)
|
|
}
|
|
if conflicts[0].Line != "eth0" {
|
|
t.Errorf("line = %q, want the resolved device", conflicts[0].Line)
|
|
}
|
|
if !slices.Equal(conflicts[0].AccountIDs, []string{"a", "b"}) {
|
|
t.Errorf("accounts = %v", conflicts[0].AccountIDs)
|
|
}
|
|
|
|
// An unresolved line is not a conflict: not knowing is not the same as
|
|
// clashing, and refusing on it would block an account whose interface is
|
|
// merely still coming up.
|
|
unknown := []Target{{AccountID: "a"}, {AccountID: "b"}}
|
|
if got := Conflicts(unknown, func(Target) string { return "" }); len(got) != 0 {
|
|
t.Errorf("unresolved lines produced %+v", got)
|
|
}
|
|
}
|
|
|
|
// The ceilings are the ones spec 02 fixes. Raising one silently would change
|
|
// how much memory the daemon can use on a router that has none to spare.
|
|
func TestTheConcurrencyCeilingsAreTheDocumentedOnes(t *testing.T) {
|
|
if MaxManagedWired != 8 {
|
|
t.Errorf("MaxManagedWired = %d, want 8", MaxManagedWired)
|
|
}
|
|
if MaxConcurrentLines != 4 {
|
|
t.Errorf("MaxConcurrentLines = %d, want 4", MaxConcurrentLines)
|
|
}
|
|
}
|