// Copyright (c) 2026 Petr BalvĂ­n (https://petrbalvin.org) // SPDX-License-Identifier: MIT package main import ( "net" "path/filepath" "testing" "time" ) // TestNotifyReadyWithoutSocket covers the quiet path: no NOTIFY_SOCKET, // no notification, no error. This is every run outside a Type=notify // unit. func TestNotifyReadyWithoutSocket(t *testing.T) { t.Setenv("NOTIFY_SOCKET", "") if err := notifyReady(); err != nil { t.Fatalf("notify without a socket: %v", err) } } // expectReady reads one datagram and reports whether it is READY=1. func expectReady(t *testing.T, ln *net.UnixConn) { t.Helper() buf := make([]byte, 64) ln.SetReadDeadline(time.Now().Add(2 * time.Second)) n, _, err := ln.ReadFrom(buf) if err != nil { t.Fatalf("read: %v", err) } if string(buf[:n]) != "READY=1" { t.Fatalf("message %q, want READY=1", buf[:n]) } } // TestNotifyReadyDelivers covers the pathname socket form. func TestNotifyReadyDelivers(t *testing.T) { sock := filepath.Join(t.TempDir(), "notify.sock") ln, err := net.ListenUnixgram("unixgram", &net.UnixAddr{Name: sock, Net: "unixgram"}) if err != nil { t.Fatalf("listen: %v", err) } defer ln.Close() t.Setenv("NOTIFY_SOCKET", sock) if err := notifyReady(); err != nil { t.Fatalf("notify: %v", err) } expectReady(t, ln) } // TestNotifyReadyAbstract covers the abstract namespace form, the one // systemd hands over on Linux. func TestNotifyReadyAbstract(t *testing.T) { addr := "@" + filepath.Base(t.TempDir()) + "-notify" ln, err := net.ListenUnixgram("unixgram", &net.UnixAddr{Name: addr, Net: "unixgram"}) if err != nil { t.Skipf("abstract unix sockets are unavailable: %v", err) } defer ln.Close() t.Setenv("NOTIFY_SOCKET", addr) if err := notifyReady(); err != nil { t.Fatalf("notify: %v", err) } expectReady(t, ln) }