diff --git a/test/towerops/snmp/profiles/base_sensors_extra_test.exs b/test/towerops/snmp/profiles/base_sensors_extra_test.exs new file mode 100644 index 00000000..ef10713e --- /dev/null +++ b/test/towerops/snmp/profiles/base_sensors_extra_test.exs @@ -0,0 +1,171 @@ +defmodule Towerops.Snmp.Profiles.BaseSensorsExtraTest do + @moduledoc """ + Targets `Towerops.Snmp.Profiles.Base.discover_sensors/1` branches that map + ENTITY-SENSOR-MIB type/unit/scale/status codes — exercising + `parse_sensor_type/1`, `sensor_type_to_unit/1`, `scale_to_divisor/1`, + and `parse_sensor_status/1` clauses. + """ + + use Towerops.DataCase, async: true + + alias Towerops.Snmp.Adapters.Replay + alias Towerops.Snmp.Profiles.Base + + describe "discover_sensors/1 type/unit/scale/status mapping" do + test "discovers an amperes sensor with milli scale and ok status" do + client_opts = [ + adapter: Replay, + oid_map: %{ + # entPhysSensorType: 5 = amperes + "1.3.6.1.2.1.99.1.1.1.1.1" => "5", + # scale: -3 (milli) + "1.3.6.1.2.1.99.1.1.1.2.1" => "-3", + # precision: 0 + "1.3.6.1.2.1.99.1.1.1.3.1" => "0", + # value + "1.3.6.1.2.1.99.1.1.1.4.1" => "1500", + # oper status: 1 = ok + "1.3.6.1.2.1.99.1.1.1.5.1" => "1" + } + ] + + assert {:ok, [sensor]} = Base.discover_sensors(client_opts) + assert sensor.sensor_type == "amperes" + assert sensor.sensor_unit == "A" + assert sensor.status == "ok" + assert sensor.sensor_divisor == 1_000 + end + + test "discovers a watts sensor with micro scale" do + client_opts = [ + adapter: Replay, + oid_map: %{ + # entPhysSensorType: 6 = watts + "1.3.6.1.2.1.99.1.1.1.1.2" => "6", + # scale: -6 (micro) + "1.3.6.1.2.1.99.1.1.1.2.2" => "-6", + "1.3.6.1.2.1.99.1.1.1.3.2" => "0", + "1.3.6.1.2.1.99.1.1.1.4.2" => "2_500_000", + "1.3.6.1.2.1.99.1.1.1.5.2" => "1" + } + ] + + assert {:ok, [sensor]} = Base.discover_sensors(client_opts) + assert sensor.sensor_type == "watts" + assert sensor.sensor_unit == "W" + assert sensor.sensor_divisor == 1_000_000 + end + + test "discovers a hertz sensor and a percent sensor with various statuses" do + client_opts = [ + adapter: Replay, + oid_map: %{ + # Sensor 1: hertz (type 7) + "1.3.6.1.2.1.99.1.1.1.1.1" => "7", + "1.3.6.1.2.1.99.1.1.1.2.1" => "0", + "1.3.6.1.2.1.99.1.1.1.3.1" => "0", + "1.3.6.1.2.1.99.1.1.1.4.1" => "60", + # status 2 = unavailable + "1.3.6.1.2.1.99.1.1.1.5.1" => "2", + + # Sensor 2: percent (type 9) + "1.3.6.1.2.1.99.1.1.1.1.2" => "9", + "1.3.6.1.2.1.99.1.1.1.2.2" => "0", + "1.3.6.1.2.1.99.1.1.1.3.2" => "0", + "1.3.6.1.2.1.99.1.1.1.4.2" => "75", + # status 3 = nonoperational + "1.3.6.1.2.1.99.1.1.1.5.2" => "3" + } + ] + + assert {:ok, sensors} = Base.discover_sensors(client_opts) + assert length(sensors) == 2 + + hz = Enum.find(sensors, &(&1.sensor_type == "hertz")) + assert hz.sensor_unit == "Hz" + assert hz.status == "unavailable" + + pct = Enum.find(sensors, &(&1.sensor_type == "percent")) + assert pct.sensor_unit == "%" + assert pct.status == "nonoperational" + end + + test "discovers rpm and cmm sensors" do + client_opts = [ + adapter: Replay, + oid_map: %{ + # rpm (type 10) + "1.3.6.1.2.1.99.1.1.1.1.1" => "10", + "1.3.6.1.2.1.99.1.1.1.2.1" => "0", + "1.3.6.1.2.1.99.1.1.1.3.1" => "0", + "1.3.6.1.2.1.99.1.1.1.4.1" => "3000", + "1.3.6.1.2.1.99.1.1.1.5.1" => "1", + + # cmm (type 11) + "1.3.6.1.2.1.99.1.1.1.1.2" => "11", + "1.3.6.1.2.1.99.1.1.1.2.2" => "0", + "1.3.6.1.2.1.99.1.1.1.3.2" => "0", + "1.3.6.1.2.1.99.1.1.1.4.2" => "12", + "1.3.6.1.2.1.99.1.1.1.5.2" => "1" + } + ] + + assert {:ok, sensors} = Base.discover_sensors(client_opts) + rpm = Enum.find(sensors, &(&1.sensor_type == "rpm")) + assert rpm.sensor_unit == "RPM" + cmm = Enum.find(sensors, &(&1.sensor_type == "cmm")) + # cmm has empty unit (sensor_type_to_unit fallthrough) + assert cmm.sensor_unit == "" + end + + test "unknown sensor type and unknown status fall through to defaults" do + client_opts = [ + adapter: Replay, + oid_map: %{ + # type 99 - unknown + "1.3.6.1.2.1.99.1.1.1.1.1" => "99", + "1.3.6.1.2.1.99.1.1.1.2.1" => "0", + "1.3.6.1.2.1.99.1.1.1.3.1" => "0", + "1.3.6.1.2.1.99.1.1.1.4.1" => "10", + # status 99 - unknown + "1.3.6.1.2.1.99.1.1.1.5.1" => "99" + } + ] + + assert {:ok, [sensor]} = Base.discover_sensors(client_opts) + assert sensor.sensor_type == "unknown" + assert sensor.sensor_unit == "" + assert sensor.status == "unknown" + end + + test "uses ENTITY-MIB name when present, descr when name is empty" do + client_opts = [ + adapter: Replay, + oid_map: %{ + # Sensor 1 — has name + "1.3.6.1.2.1.99.1.1.1.1.1" => "8", + "1.3.6.1.2.1.99.1.1.1.2.1" => "0", + "1.3.6.1.2.1.99.1.1.1.3.1" => "0", + "1.3.6.1.2.1.99.1.1.1.4.1" => "42", + "1.3.6.1.2.1.99.1.1.1.5.1" => "1", + "1.3.6.1.2.1.47.1.1.1.1.7.1" => "Inlet Temperature", + + # Sensor 2 — no name, has descr + "1.3.6.1.2.1.99.1.1.1.1.2" => "8", + "1.3.6.1.2.1.99.1.1.1.2.2" => "0", + "1.3.6.1.2.1.99.1.1.1.3.2" => "0", + "1.3.6.1.2.1.99.1.1.1.4.2" => "55", + "1.3.6.1.2.1.99.1.1.1.5.2" => "1", + "1.3.6.1.2.1.47.1.1.1.1.2.2" => "CPU thermal probe" + } + ] + + assert {:ok, sensors} = Base.discover_sensors(client_opts) + named = Enum.find(sensors, &(&1.sensor_index == "1")) + assert named.sensor_descr == "Inlet Temperature" + + descr_only = Enum.find(sensors, &(&1.sensor_index == "2")) + assert descr_only.sensor_descr == "CPU thermal probe" + end + end +end