74 lines
2.2 KiB
Go
74 lines
2.2 KiB
Go
package wake_test
|
|
|
|
import (
|
|
"net"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.wntrmute.dev/kyle/crossbar/internal/wake"
|
|
)
|
|
|
|
// listener returns a UDP socket on 127.0.0.1 and a channel that gets one value per datagram.
|
|
func listener(t *testing.T) (string, <-chan []byte) {
|
|
t.Helper()
|
|
pc, err := net.ListenPacket("udp4", "127.0.0.1:0")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Cleanup(func() { pc.Close() })
|
|
got := make(chan []byte, 4)
|
|
go func() {
|
|
buf := make([]byte, 256)
|
|
for {
|
|
n, _, err := pc.ReadFrom(buf)
|
|
if err != nil {
|
|
return
|
|
}
|
|
b := make([]byte, n)
|
|
copy(b, buf[:n])
|
|
got <- b
|
|
}
|
|
}()
|
|
return pc.LocalAddr().String(), got
|
|
}
|
|
|
|
func expectPacket(t *testing.T, name string, got <-chan []byte) {
|
|
t.Helper()
|
|
select {
|
|
case b := <-got:
|
|
if len(b) != 102 {
|
|
t.Errorf("%s: got %d bytes, want a 102-byte magic packet", name, len(b))
|
|
}
|
|
case <-time.After(2 * time.Second):
|
|
t.Errorf("%s: no packet within two seconds", name)
|
|
}
|
|
}
|
|
|
|
// A target may name several broadcast addresses (a host that roams between two networks): the
|
|
// packet goes to every one of them, and one address that cannot be resolved does not stop the
|
|
// others.
|
|
func TestWakeSendsToEveryBroadcast(t *testing.T) {
|
|
a, gotA := listener(t)
|
|
b, gotB := listener(t)
|
|
h := &fakeHealth{after: 1 << 30} // never healthy
|
|
w := wake.New(map[string]wake.Target{"titan": {MAC: "aa:bb:cc:dd:ee:ff", Broadcasts: []string{a, "256.1.1.1:9", b}, Wait: 300 * time.Millisecond}}, h)
|
|
w.PollEvery(20 * time.Millisecond)
|
|
if w.Wake(t.Context(), "titan") {
|
|
t.Errorf("Wake must report false when the host never comes up")
|
|
}
|
|
expectPacket(t, "first address", gotA)
|
|
expectPacket(t, "third address, after an unresolvable second", gotB)
|
|
}
|
|
|
|
// The single-address form keeps working, alone or together with the list.
|
|
func TestWakeBroadcastAndBroadcastsCombine(t *testing.T) {
|
|
a, gotA := listener(t)
|
|
b, gotB := listener(t)
|
|
h := &fakeHealth{after: 1 << 30} // never healthy
|
|
w := wake.New(map[string]wake.Target{"titan": {MAC: "aa:bb:cc:dd:ee:ff", Broadcast: a, Broadcasts: []string{b}, Wait: 300 * time.Millisecond}}, h)
|
|
w.PollEvery(20 * time.Millisecond)
|
|
w.Wake(t.Context(), "titan")
|
|
expectPacket(t, "Broadcast", gotA)
|
|
expectPacket(t, "Broadcasts[0]", gotB)
|
|
}
|