nixpkgs/nixos/tests/ax25.nix

128 lines
4.1 KiB
Nix

{ pkgs, lib, ... }:
let
baud = 57600;
tty = "/dev/ttyACM0";
port = "tnc0";
socatPort = 1234;
createAX25Node = nodeId: {
boot.kernelPackages = pkgs.linuxPackages_ham;
boot.kernelModules = [ "ax25" ];
networking.firewall.allowedTCPPorts = [ socatPort ];
environment.systemPackages = with pkgs; [
libax25
ax25-tools
ax25-apps
socat
];
services.ax25.axports."${port}" = {
inherit baud tty;
enable = true;
callsign = "NOCALL-${toString nodeId}";
description = "mocked tnc";
};
services.ax25.axlisten = {
enable = true;
};
# All mocks radios will connect back to socat-broker on node 1 in order to get
# all messages that are "broadcasted over the ether"
systemd.services.ax25-mock-hardware = {
description = "mock AX.25 TNC and Radio";
wantedBy = [ "default.target" ];
before = [
"ax25-kissattach-${port}.service"
"axlisten.service"
];
after = [ "network.target" ];
serviceConfig = {
Type = "exec";
ExecStart = "${pkgs.socat}/bin/socat -d -d tcp:192.168.1.1:${toString socatPort} pty,link=${tty},b${toString baud},raw";
};
};
};
in
{
name = "ax25Simple";
nodes = {
node1 = lib.mkMerge [
(createAX25Node 1)
# mimicking radios on the same frequency
{
systemd.services.ax25-mock-ether = {
description = "mock radio ether";
wantedBy = [ "default.target" ];
requires = [ "network.target" ];
before = [ "ax25-mock-hardware.service" ];
# broken needs access to "ss" or "netstat"
path = [ pkgs.iproute2 ];
serviceConfig = {
Type = "exec";
ExecStart = "${pkgs.socat}/bin/socat-broker.sh tcp4-listen:${toString socatPort}";
};
postStart = "${pkgs.coreutils}/bin/sleep 2";
};
}
];
node2 = createAX25Node 2;
node3 = createAX25Node 3;
};
testScript =
{ ... }:
''
def wait_for_machine(m):
m.succeed("lsmod | grep ax25")
m.wait_for_unit("ax25-axports.target")
m.wait_for_unit("axlisten.service")
m.fail("journalctl -o cat -u axlisten.service | grep -i \"no AX.25 port data configured\"")
# start the first node since the socat-broker needs to be running
node1.start()
node1.wait_for_unit("ax25-mock-ether.service")
wait_for_machine(node1)
node2.start()
node3.start()
wait_for_machine(node2)
wait_for_machine(node3)
# Node 1 -> Node 2
node1.succeed("echo hello | ax25_call ${port} NOCALL-1 NOCALL-2")
node2.sleep(1)
node2.succeed("journalctl -o cat -u axlisten.service | grep -A1 \"NOCALL-1 to NOCALL-2 ctl I00\" | grep hello")
# Node 1 -> Node 3
node1.succeed("echo hello | ax25_call ${port} NOCALL-1 NOCALL-3")
node3.sleep(1)
node3.succeed("journalctl -o cat -u axlisten.service | grep -A1 \"NOCALL-1 to NOCALL-3 ctl I00\" | grep hello")
# Node 2 -> Node 1
# must sleep due to previous ax25_call lingering
node2.sleep(5)
node2.succeed("echo hello | ax25_call ${port} NOCALL-2 NOCALL-1")
node1.sleep(1)
node1.succeed("journalctl -o cat -u axlisten.service | grep -A1 \"NOCALL-2 to NOCALL-1 ctl I00\" | grep hello")
# Node 2 -> Node 3
node2.succeed("echo hello | ax25_call ${port} NOCALL-2 NOCALL-3")
node3.sleep(1)
node3.succeed("journalctl -o cat -u axlisten.service | grep -A1 \"NOCALL-2 to NOCALL-3 ctl I00\" | grep hello")
# Node 3 -> Node 1
# must sleep due to previous ax25_call lingering
node3.sleep(5)
node3.succeed("echo hello | ax25_call ${port} NOCALL-3 NOCALL-1")
node1.sleep(1)
node1.succeed("journalctl -o cat -u axlisten.service | grep -A1 \"NOCALL-3 to NOCALL-1 ctl I00\" | grep hello")
# Node 3 -> Node 2
node3.succeed("echo hello | ax25_call ${port} NOCALL-3 NOCALL-2")
node2.sleep(1)
node2.succeed("journalctl -o cat -u axlisten.service | grep -A1 \"NOCALL-3 to NOCALL-2 ctl I00\" | grep hello")
'';
}