aprs.me/test/aprsme_web/controllers/page_controller_uptime_test.exs
Graham McIntire f9cfbf630e
Improve test coverage to 88.02%
Adds tests covering:
- Aprsme.Packet edge cases (already committed)
- Encoding valid_codepoint? branches via slow grapheme path and encoding_info shapes
- ErrorHandler database/network error categorization (CastError, ConstraintError, QueryError, Postgrex.Error, RuntimeError circuit_open/timeout, custom map :reason)
- HealthCheck plug ask_shutting_down? nil and unresponsive-pid paths
- SpatialPubSub ensure_float branches, dateline broadcast wrap-around, monitored client DOWN handler, no-coordinate broadcast skip
- DataBuilder weather popup, weather-only fallback, tuple value conversion, string weather convert_unit branches
- DeviceIdentification fetch_devices_from_url default-arg head
- PageController format_uptime branches via fake Aprsme.Is GenServer
- WeatherLive.CallsignView compare_timestamps branches via :weather_packet messages
- PacketConsumer field-conversion private helpers via crafted handle_events events
2026-05-08 11:58:09 -05:00

100 lines
3.1 KiB
Elixir

defmodule AprsmeWeb.PageControllerUptimeTest do
@moduledoc """
Direct tests for the four `format_uptime_parts/4` branches in PageController.
We can't call the private function directly. Instead, register a fake
`Aprsme.Is` process that responds to `:get_status` with a chosen
`uptime_seconds`, then hit the controller and check the formatted string.
"""
use AprsmeWeb.ConnCase, async: false
defmodule FakeIs do
@moduledoc false
use GenServer
def start_link(uptime_seconds) do
GenServer.start_link(__MODULE__, uptime_seconds, name: Aprsme.Is)
end
@impl true
def init(uptime_seconds), do: {:ok, uptime_seconds}
@impl true
def handle_call(:get_status, _from, uptime_seconds) do
now = DateTime.utc_now()
connected_at = DateTime.add(now, -uptime_seconds, :second)
reply = %{
connected: true,
server: "test.local",
port: 14_580,
connected_at: connected_at,
uptime_seconds: uptime_seconds,
login_id: "N0CALL",
filter: "r/0/0/100",
packet_stats: %{total_packets: 0, packets_per_second: 0, last_packet_at: nil},
stored_packet_count: 0,
oldest_packet_timestamp: nil
}
{:reply, reply, uptime_seconds}
end
end
setup do
# The real Aprsme.Is doesn't start in :test env, so the name is free.
# Defensive: if some prior test registered something under it, unregister.
if pid = Process.whereis(Aprsme.Is) do
:erlang.unregister(Aprsme.Is)
_ = pid
end
original_cluster = Application.get_env(:aprsme, :cluster_enabled)
Application.put_env(:aprsme, :cluster_enabled, false)
on_exit(fn -> Application.put_env(:aprsme, :cluster_enabled, original_cluster) end)
:ok
end
defp call_with_uptime(uptime_seconds) do
{:ok, fake} = FakeIs.start_link(uptime_seconds)
try do
conn = Phoenix.ConnTest.build_conn()
result = AprsmeWeb.PageController.status_json(conn, %{})
Jason.decode!(result.resp_body)
after
if Process.alive?(fake), do: GenServer.stop(fake)
end
end
describe "format_uptime branches via status_json" do
test "formats multi-day uptime as 'Xd Yh Zm Ss'" do
body = call_with_uptime(2 * 86_400 + 3 * 3600 + 15 * 60 + 5)
display = body["aprs_is"]["uptime_display"]
assert display =~ ~r/^\d+d \d+h \d+m \d+s$/
assert String.starts_with?(display, "2d ")
end
test "formats sub-day, multi-hour uptime as 'Yh Zm Ss'" do
body = call_with_uptime(5 * 3600 + 30 * 60 + 12)
display = body["aprs_is"]["uptime_display"]
assert display =~ ~r/^\d+h \d+m \d+s$/
refute display =~ "d "
end
test "formats sub-hour, multi-minute uptime as 'Zm Ss'" do
body = call_with_uptime(30 * 60 + 7)
display = body["aprs_is"]["uptime_display"]
assert display =~ ~r/^\d+m \d+s$/
refute display =~ "h "
end
test "formats sub-minute uptime as 'Ss'" do
body = call_with_uptime(45)
display = body["aprs_is"]["uptime_display"]
assert display =~ ~r/^\d+s$/
refute display =~ "m "
end
end
end