defmodule Aprsme.Cluster.PacketDistributorTest do use ExUnit.Case, async: false alias Aprsme.Cluster.LeaderElection alias Aprsme.Cluster.PacketDistributor @test_packet %{raw: "TEST>APRS:test packet", sender: "TEST"} setup do # Ensure cluster_enabled is false initially Application.put_env(:aprsme, :cluster_enabled, false) # Stop any running LeaderElection process if Process.whereis(LeaderElection) do try do GenServer.stop(LeaderElection, :normal, 100) catch :exit, _ -> :ok end end # Start LeaderElection in non-clustered mode {:ok, _} = LeaderElection.start_link([]) # Sync with the GenServer so election (0ms in test config) has run. LeaderElection.leader?() on_exit(fn -> try do if Process.whereis(LeaderElection) do GenServer.stop(LeaderElection, :normal, 100) end catch :exit, _ -> :ok end # Reset cluster_enabled to false Application.put_env(:aprsme, :cluster_enabled, false) end) :ok end describe "distribute_packet/1" do test "does not distribute when cluster is disabled" do # cluster_enabled is false from setup PacketDistributor.subscribe() PacketDistributor.distribute_packet(@test_packet) refute_receive {:distributed_packet, _}, 10 end test "distributes packet when cluster is enabled and node is leader" do Application.put_env(:aprsme, :cluster_enabled, true) PacketDistributor.subscribe() PacketDistributor.distribute_packet(@test_packet) assert_receive {:distributed_packet, packet}, 1000 assert packet.raw == "TEST>APRS:test packet" assert packet.sender == "TEST" end end describe "subscribe/0" do test "subscribes to cluster:packets topic" do PacketDistributor.subscribe() Phoenix.PubSub.broadcast( Aprsme.PubSub, "cluster:packets", {:distributed_packet, @test_packet} ) assert_receive {:distributed_packet, _}, 1000 end end describe "handle_distributed_packet/1" do test "processes a distributed packet without crashing" do # StreamingPacketsPubSub and PacketStore are already running in test result = PacketDistributor.handle_distributed_packet({:distributed_packet, @test_packet}) # Broadcasts to local clients and stores in PacketStore assert result == :ok end end describe "GenServer callbacks" do test "init/1 subscribes to the topic and returns empty state" do assert {:ok, %{}} = PacketDistributor.init([]) # Callback subscribes the caller to cluster:packets. Phoenix.PubSub.broadcast(Aprsme.PubSub, "cluster:packets", :ping) assert_receive :ping, 1000 end test "handle_info forwards distributed packets" do state = %{} assert {:noreply, ^state} = PacketDistributor.handle_info({:distributed_packet, @test_packet}, state) end test "terminate/2 unsubscribes from the topic and returns :ok" do # Subscribe first so we have something to unsubscribe. PacketDistributor.subscribe() assert :ok = PacketDistributor.terminate(:shutdown, %{}) # After terminate, this process should no longer receive cluster:packets # broadcasts. Phoenix.PubSub.broadcast(Aprsme.PubSub, "cluster:packets", :should_not_arrive) refute_receive :should_not_arrive, 10 end end end