test: AprsIsMock, DeviceIdentification, PacketCleanupWorker coverage
This commit is contained in:
parent
816806e6e2
commit
a7071ecef1
3 changed files with 197 additions and 0 deletions
93
test/aprs_is_mock_test.exs
Normal file
93
test/aprs_is_mock_test.exs
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
defmodule AprsIsMockTest do
|
||||
use ExUnit.Case, async: false
|
||||
|
||||
setup do
|
||||
if Process.whereis(AprsIsMock) do
|
||||
GenServer.stop(AprsIsMock, :normal)
|
||||
# Give OTP a moment to unregister the name
|
||||
Process.sleep(10)
|
||||
end
|
||||
|
||||
on_exit(fn ->
|
||||
if Process.whereis(AprsIsMock) do
|
||||
try do
|
||||
GenServer.stop(AprsIsMock, :normal, 100)
|
||||
catch
|
||||
:exit, _ -> :ok
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
:ok
|
||||
end
|
||||
|
||||
describe "get_status/0" do
|
||||
test "returns a default disconnected status when not running" do
|
||||
status = AprsIsMock.get_status()
|
||||
|
||||
assert status.connected == false
|
||||
assert status.server == "mock.aprs.test"
|
||||
assert status.port == 14_580
|
||||
assert is_nil(status.connected_at)
|
||||
assert is_map(status.packet_stats)
|
||||
assert status.stored_packet_count == 0
|
||||
end
|
||||
|
||||
test "computes uptime when the mock is connected" do
|
||||
{:ok, _} = AprsIsMock.start_link([])
|
||||
:ok = AprsIsMock.simulate_connection_state(true)
|
||||
|
||||
# Small sleep so uptime has a non-zero value.
|
||||
Process.sleep(10)
|
||||
status = AprsIsMock.get_status()
|
||||
|
||||
assert status.connected == true
|
||||
assert status.uptime_seconds >= 0
|
||||
end
|
||||
|
||||
test "returns uptime 0 when no connected_at is set" do
|
||||
{:ok, _} = AprsIsMock.start_link([])
|
||||
status = AprsIsMock.get_status()
|
||||
assert status.uptime_seconds == 0
|
||||
end
|
||||
end
|
||||
|
||||
describe "send_message and filter helpers" do
|
||||
test "filter helpers are :ok no-ops" do
|
||||
assert AprsIsMock.set_filter("r/0/0/1") == :ok
|
||||
assert AprsIsMock.list_active_filters() == :ok
|
||||
end
|
||||
|
||||
test "three-arg send_message is a :ok no-op without running server" do
|
||||
assert AprsIsMock.send_message("TEST", "DEST", "hi") == :ok
|
||||
end
|
||||
|
||||
test "single-arg send_message dispatches to server when running" do
|
||||
{:ok, _} = AprsIsMock.start_link([])
|
||||
assert AprsIsMock.send_message("hi") == :ok
|
||||
end
|
||||
end
|
||||
|
||||
describe "simulate_packet/1" do
|
||||
test "broadcasts to the endpoint without crashing" do
|
||||
# Endpoint is started at boot in test env, so this just needs to not raise.
|
||||
assert AprsIsMock.simulate_packet(%{sender: "TEST"}) == :ok
|
||||
end
|
||||
end
|
||||
|
||||
describe "terminate/2" do
|
||||
test "returns :ok on termination" do
|
||||
{:ok, _} = AprsIsMock.start_link([])
|
||||
assert :ok = AprsIsMock.stop()
|
||||
end
|
||||
end
|
||||
|
||||
describe "handle_info/2" do
|
||||
test "ignores arbitrary messages" do
|
||||
{:ok, pid} = AprsIsMock.start_link([])
|
||||
send(pid, :arbitrary_message)
|
||||
Process.sleep(10)
|
||||
assert Process.alive?(pid)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -203,6 +203,85 @@ defmodule Aprsme.DeviceIdentificationTest do
|
|||
end
|
||||
end
|
||||
|
||||
describe "upsert_devices/1 with all three groups" do
|
||||
test "processes devices from mice and micelegacy groups" do
|
||||
Repo.delete_all(Devices)
|
||||
|
||||
json = %{
|
||||
"tocalls" => %{},
|
||||
"mice" => %{
|
||||
"]=" => %{"vendor" => "Mice", "model" => "MA"}
|
||||
},
|
||||
"micelegacy" => %{
|
||||
"`_#" => %{"vendor" => "Legacy", "model" => "MB"}
|
||||
}
|
||||
}
|
||||
|
||||
assert :ok = DeviceIdentification.upsert_devices(json)
|
||||
assert %Devices{vendor: "Mice"} = Repo.get_by(Devices, identifier: "]=")
|
||||
assert %Devices{vendor: "Legacy"} = Repo.get_by(Devices, identifier: "`_#")
|
||||
end
|
||||
|
||||
test "filters out non-whitelisted JSON keys" do
|
||||
Repo.delete_all(Devices)
|
||||
|
||||
# 'garbage' and 'unused_field' must be stripped by process_device_attrs.
|
||||
json = %{
|
||||
"tocalls" => %{
|
||||
"APRS" => %{
|
||||
"vendor" => "V",
|
||||
"model" => "M",
|
||||
"garbage" => "should-be-dropped",
|
||||
"unused_field" => 42
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert :ok = DeviceIdentification.upsert_devices(json)
|
||||
assert %Devices{vendor: "V", model: "M"} = Repo.get_by(Devices, identifier: "APRS")
|
||||
end
|
||||
|
||||
test "handles nil features value" do
|
||||
Repo.delete_all(Devices)
|
||||
|
||||
json = %{
|
||||
"tocalls" => %{
|
||||
"APNIL" => %{"vendor" => "V", "model" => "M", "features" => nil}
|
||||
}
|
||||
}
|
||||
|
||||
assert :ok = DeviceIdentification.upsert_devices(json)
|
||||
dev = Repo.get_by(Devices, identifier: "APNIL")
|
||||
assert is_nil(dev.features)
|
||||
end
|
||||
end
|
||||
|
||||
describe "maybe_refresh_devices/0 with stale device" do
|
||||
test "triggers refresh when latest device is older than one week" do
|
||||
Repo.delete_all(Devices)
|
||||
# 10 days ago.
|
||||
old_time =
|
||||
DateTime.utc_now()
|
||||
|> DateTime.add(-10 * 24 * 3600, :second)
|
||||
|> DateTime.to_naive()
|
||||
|> NaiveDateTime.truncate(:second)
|
||||
|
||||
Repo.insert!(%Devices{
|
||||
identifier: "STALEROW",
|
||||
vendor: "v",
|
||||
model: "m",
|
||||
inserted_at: old_time,
|
||||
updated_at: old_time
|
||||
})
|
||||
|
||||
# Will attempt a refresh via the CircuitBreaker. Without a real HTTP
|
||||
# stub, it may return an error tuple — either way the stale-branch was
|
||||
# exercised.
|
||||
result = DeviceIdentification.maybe_refresh_devices()
|
||||
assert result == :ok or match?({:error, _}, result)
|
||||
end
|
||||
end
|
||||
|
||||
describe "lookup_device_by_identifier/1" do
|
||||
test "matches APSK21 to APS??? pattern" do
|
||||
# Seed the devices table from the JSON
|
||||
|
|
|
|||
|
|
@ -89,4 +89,29 @@ defmodule Aprsme.Workers.PacketCleanupWorkerTest do
|
|||
assert :ok = PacketCleanupWorker.perform(%{"cleanup_days" => -1})
|
||||
end
|
||||
end
|
||||
|
||||
describe "perform/1 with extra fields that the guard ignores" do
|
||||
test "accepts a map with cleanup_days plus unrelated keys" do
|
||||
{:ok, _} = PartitionManager.ensure_partitions_exist()
|
||||
|
||||
assert :ok =
|
||||
PacketCleanupWorker.perform(%{
|
||||
"cleanup_days" => 30,
|
||||
"random_field" => "ignored"
|
||||
})
|
||||
end
|
||||
|
||||
test "handles zero cleanup_days by falling through to default" do
|
||||
{:ok, _} = PartitionManager.ensure_partitions_exist()
|
||||
|
||||
# 0 doesn't match the `days > 0` guard.
|
||||
assert :ok = PacketCleanupWorker.perform(%{"cleanup_days" => 0})
|
||||
end
|
||||
|
||||
test "handles non-integer cleanup_days by falling through to default" do
|
||||
{:ok, _} = PartitionManager.ensure_partitions_exist()
|
||||
|
||||
assert :ok = PacketCleanupWorker.perform(%{"cleanup_days" => "string"})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue