towerops/test/towerops_web/live/graph_live/show_helpers_test.exs
Graham McIntire 7a3950d1ad chore: add jump_credo_checks ~> 0.4 with all 19 checks enabled
All checks set to exit_status: 0 initially to avoid blocking on
pre-existing violations. Remove exit_status overrides as each
check category is cleaned up incrementally.

Dependency added to dev/test only.
2026-06-12 13:45:59 -05:00

311 lines
10 KiB
Elixir

defmodule ToweropsWeb.GraphLive.ShowHelpersTest do
use ExUnit.Case, async: true
alias ToweropsWeb.GraphLive.Show
describe "get_time_range_for_graph/1" do
test "known ranges return {from, to}" do
for range <- ["1h", "6h", "12h", "24h", "7d", "30d"] do
assert {%DateTime{} = from, %DateTime{} = to} = Show.get_time_range_for_graph(range)
assert DateTime.before?(from, to)
end
end
test "unknown range falls back to 24h" do
{from, to} = Show.get_time_range_for_graph("foo")
diff_hours = DateTime.diff(to, from, :hour)
assert_in_delta diff_hours, 24, 1
end
test "1h range is about 1 hour wide" do
{from, to} = Show.get_time_range_for_graph("1h")
assert_in_delta DateTime.diff(to, from, :second), 3600, 2
end
test "7d range is about 7 days wide" do
{from, to} = Show.get_time_range_for_graph("7d")
assert_in_delta DateTime.diff(to, from, :day), 7, 1
end
end
describe "get_check_unit_and_scale/1" do
test "snmp_sensor uses config[:sensor_unit]" do
assert {"Celsius", true} ==
Show.get_check_unit_and_scale(%{check_type: "snmp_sensor", config: %{"sensor_unit" => "Celsius"}})
end
test "snmp_sensor with missing unit defaults to empty" do
assert {"", true} == Show.get_check_unit_and_scale(%{check_type: "snmp_sensor", config: %{}})
end
test "snmp_processor and snmp_storage are % (no scale)" do
assert {"%", false} == Show.get_check_unit_and_scale(%{check_type: "snmp_processor"})
assert {"%", false} == Show.get_check_unit_and_scale(%{check_type: "snmp_storage"})
end
test "http/tcp/dns are ms with scale" do
assert {"ms", true} == Show.get_check_unit_and_scale(%{check_type: "http"})
assert {"ms", true} == Show.get_check_unit_and_scale(%{check_type: "tcp"})
assert {"ms", true} == Show.get_check_unit_and_scale(%{check_type: "dns"})
end
test "unknown check_type defaults to empty + scale" do
assert {"", true} == Show.get_check_unit_and_scale(%{check_type: "unknown"})
assert {"", true} == Show.get_check_unit_and_scale(%{})
end
end
describe "format_value/2" do
test "empty unit formats as integer" do
assert "5" == Show.format_value(5.0, "")
assert "7" == Show.format_value(7, "")
end
test "float with unit" do
assert "23.4 Celsius" == Show.format_value(23.42, "Celsius")
end
test "integer with unit" do
assert "42.0 ms" == Show.format_value(42, "ms")
end
test "bps unit with Gbps scale" do
assert "1.5 Gbps" == Show.format_value(1_500_000_000, "bps")
end
test "bps unit with Mbps scale" do
assert "50.0 Mbps" == Show.format_value(50_000_000, "bps")
end
test "bps unit with Kbps scale" do
assert "2.5 Kbps" == Show.format_value(2500, "bps")
end
test "bps unit with bps scale" do
assert "500.0 bps" == Show.format_value(500.0, "bps")
end
test "bps handles negative values (outbound)" do
assert "1.0 Mbps" == Show.format_value(-1_000_000, "bps")
end
end
describe "get_chart_config/1" do
test "latency returns Ping Latency in ms with auto-scale" do
assert {"Ping Latency", "ms", true} == Show.get_chart_config("latency")
end
test "processors returns Processor Usage in % without auto-scale" do
assert {"Processor Usage", "%", false} == Show.get_chart_config("processors")
end
test "memory returns Memory Usage in % without auto-scale" do
assert {"Memory Usage", "%", false} == Show.get_chart_config("memory")
end
test "storage returns Storage Usage in % without auto-scale" do
assert {"Storage Usage", "%", false} == Show.get_chart_config("storage")
end
test "storage_volume returns Storage Usage in % without auto-scale" do
assert {"Storage Usage", "%", false} == Show.get_chart_config("storage_volume")
end
test "temperature returns Temperature in °C with auto-scale" do
assert {"Temperature", "°C", true} == Show.get_chart_config("temperature")
end
test "voltage returns Voltage in V with auto-scale" do
assert {"Voltage", "V", true} == Show.get_chart_config("voltage")
end
test "traffic returns Overall Traffic in bps with auto-scale" do
assert {"Overall Traffic", "bps", true} == Show.get_chart_config("traffic")
end
test "interface_errors returns Interface Errors & Discards with auto-scale" do
assert {"Interface Errors & Discards", "", true} == Show.get_chart_config("interface_errors")
end
test "count returns Count with auto-scale" do
assert {"Count", "", true} == Show.get_chart_config("count")
end
test "pppoe_sessions returns PPPoE Sessions with auto-scale" do
assert {"PPPoE Sessions", "", true} == Show.get_chart_config("pppoe_sessions")
end
test "connections returns Connections with auto-scale" do
assert {"Connections", "", true} == Show.get_chart_config("connections")
end
test "wireless returns Wireless Metrics with auto-scale" do
assert {"Wireless Metrics", "", true} == Show.get_chart_config("wireless")
end
test "unknown sensor type falls back to humanized version" do
assert {"Cpu Load", "", true} == Show.get_chart_config("cpu_load")
assert {"Custom Metric", "", true} == Show.get_chart_config("custom_metric")
end
end
describe "get_sensor_types_for_chart/1" do
test "processors maps to cpu_load" do
assert ["cpu_load"] == Show.get_sensor_types_for_chart("processors")
end
test "memory maps to memory_usage" do
assert ["memory_usage"] == Show.get_sensor_types_for_chart("memory")
end
test "storage maps to disk_usage" do
assert ["disk_usage"] == Show.get_sensor_types_for_chart("storage")
end
test "temperature maps to multiple sensor types" do
result = Show.get_sensor_types_for_chart("temperature")
assert "temperature" in result
assert "cpu_temperature" in result
assert "celsius" in result
end
test "voltage maps to voltage and volts" do
result = Show.get_sensor_types_for_chart("voltage")
assert "voltage" in result
assert "volts" in result
end
test "traffic returns nil" do
assert nil == Show.get_sensor_types_for_chart("traffic")
end
test "unknown sensor type returns itself in a list" do
assert ["count"] == Show.get_sensor_types_for_chart("count")
assert ["pppoe_sessions"] == Show.get_sensor_types_for_chart("pppoe_sessions")
assert ["connections"] == Show.get_sensor_types_for_chart("connections")
assert ["my_custom_type"] == Show.get_sensor_types_for_chart("my_custom_type")
end
end
describe "calculate_chart_stats/1" do
test "returns {nil, nil} for nil input" do
assert {nil, nil} == Show.calculate_chart_stats(nil)
end
test "computes max and min from chart data" do
chart_data =
Jason.encode!(%{
datasets: [
%{data: [%{y: 10}, %{y: 20}, %{y: 5}]}
]
})
assert {20, 5} == Show.calculate_chart_stats(chart_data)
end
test "handles multiple datasets" do
chart_data =
Jason.encode!(%{
datasets: [
%{data: [%{y: 100}, %{y: 200}]},
%{data: [%{y: 50}, %{y: 300}]}
]
})
assert {300, 50} == Show.calculate_chart_stats(chart_data)
end
test "returns {nil, nil} for empty datasets" do
chart_data = Jason.encode!(%{datasets: [%{data: []}]})
assert {nil, nil} == Show.calculate_chart_stats(chart_data)
end
test "returns {nil, nil} for invalid JSON" do
assert {nil, nil} == Show.calculate_chart_stats("not valid json")
end
test "returns {nil, nil} for JSON with missing datasets key" do
assert {nil, nil} == Show.calculate_chart_stats(~s({"foo": "bar"}))
end
test "handles nil y values by skipping them" do
chart_data =
Jason.encode!(%{
datasets: [
%{data: [%{y: 10}, %{y: nil}, %{y: 30}]}
]
})
assert {30, 10} == Show.calculate_chart_stats(chart_data)
end
test "handles single data point" do
chart_data =
Jason.encode!(%{
datasets: [
%{data: [%{y: 42}]}
]
})
assert {42, 42} == Show.calculate_chart_stats(chart_data)
end
end
describe "humanize_sensor_type/1" do
test "converts snake_case to capitalized words" do
assert "Cpu Load" == Show.humanize_sensor_type("cpu_load")
assert "My Custom Type" == Show.humanize_sensor_type("my_custom_type")
end
test "handles single word" do
assert "Temperature" == Show.humanize_sensor_type("temperature")
end
test "handles empty string" do
assert "" == Show.humanize_sensor_type("")
end
test "handles already uppercase" do
assert "Cpu Temperature" == Show.humanize_sensor_type("cpu_temperature")
end
end
describe "build_graph_params/2" do
test "builds params with just range when no filters present" do
assigns = %{range: "24h", interface_id: nil, sensor_id: nil, storage_id: nil}
assert %{"range" => "24h"} == Show.build_graph_params(assigns, "24h")
end
test "builds params with interface_id when present" do
assigns = %{range: "1h", interface_id: "iface-1", sensor_id: nil, storage_id: nil}
assert %{"range" => "1h", "interface_id" => "iface-1"} == Show.build_graph_params(assigns, "1h")
end
test "builds params with sensor_id when present" do
assigns = %{range: "6h", interface_id: nil, sensor_id: "sensor-42", storage_id: nil}
assert %{"range" => "6h", "sensor_id" => "sensor-42"} == Show.build_graph_params(assigns, "6h")
end
test "builds params with storage_id when present" do
assigns = %{range: "7d", interface_id: nil, sensor_id: nil, storage_id: "storage-5"}
assert %{"range" => "7d", "storage_id" => "storage-5"} == Show.build_graph_params(assigns, "7d")
end
test "builds params with all filters when present" do
assigns = %{
range: "30d",
interface_id: "iface-1",
sensor_id: "sensor-42",
storage_id: "storage-5"
}
assert %{"range" => "30d", "interface_id" => "iface-1", "sensor_id" => "sensor-42", "storage_id" => "storage-5"} ==
Show.build_graph_params(assigns, "30d")
end
test "uses custom range override" do
assigns = %{range: "24h", interface_id: nil, sensor_id: nil, storage_id: nil}
assert %{"range" => "1h"} == Show.build_graph_params(assigns, "1h")
end
end
end