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) }