banner dissmiss and mikrotik version and license
This commit is contained in:
parent
12a777d13d
commit
480789c3e2
8 changed files with 291 additions and 13 deletions
|
|
@ -913,3 +913,4 @@ When writing new LiveView code or JavaScript hooks:
|
||||||
- Navigate away and back multiple times
|
- Navigate away and back multiple times
|
||||||
- Take another snapshot
|
- Take another snapshot
|
||||||
- Compare - memory should not continuously grow
|
- Compare - memory should not continuously grow
|
||||||
|
- assets are rebuilt automatically on filesystem change
|
||||||
|
|
@ -402,6 +402,47 @@ const AutoDismissFlash = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LiveView hook for dismissible beta banner
|
||||||
|
const BetaBannerDismiss = {
|
||||||
|
handleDismiss: null as ((e: Event) => void) | null,
|
||||||
|
|
||||||
|
mounted(this: any) {
|
||||||
|
const isHelpPage = this.el.dataset.alwaysShow === "true"
|
||||||
|
|
||||||
|
if (isHelpPage) {
|
||||||
|
// On help page: hide dismiss button only
|
||||||
|
const dismissBtn = this.el.querySelector('[data-dismiss]')
|
||||||
|
if (dismissBtn) {
|
||||||
|
(dismissBtn as HTMLElement).style.display = 'none'
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// On other pages: check if dismissed and set up dismiss handler
|
||||||
|
const isDismissed = localStorage.getItem('betaBannerDismissed') === 'true'
|
||||||
|
if (isDismissed) {
|
||||||
|
this.el.style.display = 'none'
|
||||||
|
}
|
||||||
|
|
||||||
|
const dismissBtn = this.el.querySelector('[data-dismiss]')
|
||||||
|
if (dismissBtn) {
|
||||||
|
this.handleDismiss = (e: Event) => {
|
||||||
|
e.preventDefault()
|
||||||
|
localStorage.setItem('betaBannerDismissed', 'true')
|
||||||
|
this.el.style.display = 'none'
|
||||||
|
}
|
||||||
|
dismissBtn.addEventListener('click', this.handleDismiss)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
destroyed(this: any) {
|
||||||
|
const dismissBtn = this.el.querySelector('[data-dismiss]')
|
||||||
|
if (dismissBtn && this.handleDismiss) {
|
||||||
|
dismissBtn.removeEventListener('click', this.handleDismiss)
|
||||||
|
this.handleDismiss = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Network Map hook for Cytoscape.js topology visualization
|
// Network Map hook for Cytoscape.js topology visualization
|
||||||
const NetworkMap = {
|
const NetworkMap = {
|
||||||
cy: null as any,
|
cy: null as any,
|
||||||
|
|
@ -666,7 +707,7 @@ const userTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC"
|
||||||
const liveSocket = new LiveSocket("/live", Socket, {
|
const liveSocket = new LiveSocket("/live", Socket, {
|
||||||
longPollFallbackMs: 2500,
|
longPollFallbackMs: 2500,
|
||||||
params: { _csrf_token: csrfToken, timezone: userTimezone },
|
params: { _csrf_token: csrfToken, timezone: userTimezone },
|
||||||
hooks: { ...colocatedHooks, SensorChart, CopyToClipboard, ScrollToTop, AutoDismissFlash, NetworkMap, DeviceListReorder },
|
hooks: { ...colocatedHooks, SensorChart, CopyToClipboard, ScrollToTop, AutoDismissFlash, BetaBannerDismiss, NetworkMap, DeviceListReorder },
|
||||||
})
|
})
|
||||||
|
|
||||||
// Show progress bar on live navigation and form submits
|
// Show progress bar on live navigation and form submits
|
||||||
|
|
|
||||||
|
|
@ -40,13 +40,18 @@ defmodule Towerops.Snmp.Profiles.Dynamic do
|
||||||
detect_vendor_version(profile, client_opts) ||
|
detect_vendor_version(profile, client_opts) ||
|
||||||
format_firmware_version(profile, device_data)
|
format_firmware_version(profile, device_data)
|
||||||
|
|
||||||
|
# Get serial number: YAML serial_number OID → vendor-specific
|
||||||
|
serial_number =
|
||||||
|
Map.get(device_data, :serial_number) ||
|
||||||
|
detect_vendor_serial_number(profile, client_opts)
|
||||||
|
|
||||||
# Merge with system_info
|
# Merge with system_info
|
||||||
system_info
|
system_info
|
||||||
|> Map.merge(%{
|
|> Map.merge(%{
|
||||||
manufacturer: profile.vendor,
|
manufacturer: profile.vendor,
|
||||||
model: model,
|
model: model,
|
||||||
firmware_version: firmware_version,
|
firmware_version: firmware_version,
|
||||||
serial_number: Map.get(device_data, :serial_number),
|
serial_number: serial_number,
|
||||||
latitude: Map.get(device_data, :latitude),
|
latitude: Map.get(device_data, :latitude),
|
||||||
longitude: Map.get(device_data, :longitude)
|
longitude: Map.get(device_data, :longitude)
|
||||||
})
|
})
|
||||||
|
|
@ -153,6 +158,22 @@ defmodule Towerops.Snmp.Profiles.Dynamic do
|
||||||
|
|
||||||
defp detect_vendor_version(_profile, _client_opts), do: nil
|
defp detect_vendor_version(_profile, _client_opts), do: nil
|
||||||
|
|
||||||
|
# Vendor-specific serial number detection using vendor modules
|
||||||
|
defp detect_vendor_serial_number(%{name: name}, client_opts) do
|
||||||
|
case VendorRegistry.get_vendor(name) do
|
||||||
|
nil ->
|
||||||
|
nil
|
||||||
|
|
||||||
|
vendor ->
|
||||||
|
# Check if vendor module implements detect_serial_number/1
|
||||||
|
if function_exported?(vendor, :detect_serial_number, 1) do
|
||||||
|
vendor.detect_serial_number(client_opts)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp detect_vendor_serial_number(_profile, _client_opts), do: nil
|
||||||
|
|
||||||
# Extract hardware model from sysDescr using profile's sysDescr_regex
|
# Extract hardware model from sysDescr using profile's sysDescr_regex
|
||||||
# LibreNMS uses named capture groups like (?<hardware>...) in the regex
|
# LibreNMS uses named capture groups like (?<hardware>...) in the regex
|
||||||
defp extract_hardware_from_regex(%{hardware_regex: regex}, sys_descr)
|
defp extract_hardware_from_regex(%{hardware_regex: regex}, sys_descr)
|
||||||
|
|
|
||||||
76
lib/towerops/snmp/profiles/vendors/routeros.ex
vendored
76
lib/towerops/snmp/profiles/vendors/routeros.ex
vendored
|
|
@ -18,8 +18,14 @@ defmodule Towerops.Snmp.Profiles.Vendors.Routeros do
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
# OID for license level (used in firmware version display)
|
# OID for license level (integer) - MIKROTIK-MIB::mtxrLicLevel.0
|
||||||
@license_oid "1.3.6.1.4.1.14988.1.1.4.4.0"
|
@license_level_oid "1.3.6.1.4.1.14988.1.1.4.3.0"
|
||||||
|
|
||||||
|
# OID for license version (string) - MIKROTIK-MIB::mtxrLicVersion.0
|
||||||
|
@version_oid "1.3.6.1.4.1.14988.1.1.4.4.0"
|
||||||
|
|
||||||
|
# OID for serial number (string) - MIKROTIK-MIB::mtxrSerialNumber.0
|
||||||
|
@serial_number_oid "1.3.6.1.4.1.14988.1.1.7.3.0"
|
||||||
|
|
||||||
# Table OIDs for walking
|
# Table OIDs for walking
|
||||||
@wl_ap_table "1.3.6.1.4.1.14988.1.1.1.3.1"
|
@wl_ap_table "1.3.6.1.4.1.14988.1.1.1.3.1"
|
||||||
|
|
@ -50,8 +56,8 @@ defmodule Towerops.Snmp.Profiles.Vendors.Routeros do
|
||||||
@impl true
|
@impl true
|
||||||
def detect_hardware(client_opts) do
|
def detect_hardware(client_opts) do
|
||||||
# MikroTik hardware is typically identified by sysDescr
|
# MikroTik hardware is typically identified by sysDescr
|
||||||
# We enhance the firmware version with license level
|
# Use the license level OID to get the integer license level
|
||||||
case Client.get(client_opts, @license_oid) do
|
case Client.get(client_opts, @license_level_oid) do
|
||||||
{:ok, license} when is_integer(license) ->
|
{:ok, license} when is_integer(license) ->
|
||||||
"RouterOS Level #{license}"
|
"RouterOS Level #{license}"
|
||||||
|
|
||||||
|
|
@ -60,6 +66,68 @@ defmodule Towerops.Snmp.Profiles.Vendors.Routeros do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Get RouterOS firmware version from MIKROTIK-MIB.
|
||||||
|
Returns version string with "RouterOS" prefix and license level in parentheses.
|
||||||
|
Example: "RouterOS 7.14.1 (Level 6)"
|
||||||
|
"""
|
||||||
|
def detect_version(client_opts) do
|
||||||
|
# Query the version OID which returns the version string
|
||||||
|
version_result = Client.get(client_opts, @version_oid)
|
||||||
|
|
||||||
|
case version_result do
|
||||||
|
{:ok, version} when is_binary(version) and version != "" ->
|
||||||
|
# Got version string, now try to get license level
|
||||||
|
# The license level can be derived from the version or queried separately
|
||||||
|
license_level = detect_license_level(client_opts)
|
||||||
|
|
||||||
|
formatted_version =
|
||||||
|
case license_level do
|
||||||
|
level when is_integer(level) ->
|
||||||
|
"RouterOS #{version} (Level #{level})"
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
"RouterOS #{version}"
|
||||||
|
end
|
||||||
|
|
||||||
|
Logger.debug("RouterOS: Detected version: #{formatted_version}")
|
||||||
|
formatted_version
|
||||||
|
|
||||||
|
other ->
|
||||||
|
Logger.warning("RouterOS: Failed to detect version: #{inspect(other)}")
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Get RouterOS serial number from MIKROTIK-MIB.
|
||||||
|
Returns the RouterBOARD serial number string.
|
||||||
|
Example: "HC907K5P55K"
|
||||||
|
"""
|
||||||
|
def detect_serial_number(client_opts) do
|
||||||
|
case Client.get(client_opts, @serial_number_oid) do
|
||||||
|
{:ok, serial} when is_binary(serial) and serial != "" ->
|
||||||
|
Logger.debug("RouterOS: Detected serial number: #{serial}")
|
||||||
|
serial
|
||||||
|
|
||||||
|
other ->
|
||||||
|
Logger.debug("RouterOS: Failed to detect serial number: #{inspect(other)}")
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Try to detect the license level as an integer from mtxrLicLevel OID
|
||||||
|
defp detect_license_level(client_opts) do
|
||||||
|
case Client.get(client_opts, @license_level_oid) do
|
||||||
|
{:ok, level} when is_integer(level) ->
|
||||||
|
level
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
# Couldn't get license level, return nil
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def discover_wireless_sensors(client_opts) do
|
def discover_wireless_sensors(client_opts) do
|
||||||
# Discover from multiple tables like LibreNMS does
|
# Discover from multiple tables like LibreNMS does
|
||||||
|
|
|
||||||
|
|
@ -127,11 +127,15 @@ defmodule ToweropsWeb.Layouts do
|
||||||
# Get policies needing consent from assigns (set in CheckPolicyConsent plug)
|
# Get policies needing consent from assigns (set in CheckPolicyConsent plug)
|
||||||
policies_needing_consent = Map.get(assigns, :policies_needing_consent, [])
|
policies_needing_consent = Map.get(assigns, :policies_needing_consent, [])
|
||||||
|
|
||||||
|
# Check if this is the help page for banner display
|
||||||
|
always_show_banner = if Map.get(assigns, :active_page) == "help", do: "true", else: "false"
|
||||||
|
|
||||||
assigns =
|
assigns =
|
||||||
assigns
|
assigns
|
||||||
|> Map.put(:current_organization, current_organization)
|
|> Map.put(:current_organization, current_organization)
|
||||||
|> Map.put(:timezone, timezone)
|
|> Map.put(:timezone, timezone)
|
||||||
|> Map.put(:policies_needing_consent, policies_needing_consent)
|
|> Map.put(:policies_needing_consent, policies_needing_consent)
|
||||||
|
|> Map.put(:always_show_banner, always_show_banner)
|
||||||
|
|
||||||
~H"""
|
~H"""
|
||||||
<div class="flex min-h-screen flex-col bg-gray-50 dark:bg-gray-950">
|
<div class="flex min-h-screen flex-col bg-gray-50 dark:bg-gray-950">
|
||||||
|
|
@ -400,7 +404,12 @@ defmodule ToweropsWeb.Layouts do
|
||||||
<main id="main-content" tabindex="-1" class="flex-1 py-6 sm:py-10">
|
<main id="main-content" tabindex="-1" class="flex-1 py-6 sm:py-10">
|
||||||
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||||
<!-- Beta Testing Banner -->
|
<!-- Beta Testing Banner -->
|
||||||
<div class="mb-6 rounded-lg bg-blue-50 dark:bg-blue-900/20 p-4 border border-blue-200 dark:border-blue-800">
|
<div
|
||||||
|
id="beta-banner"
|
||||||
|
phx-hook="BetaBannerDismiss"
|
||||||
|
data-always-show={@always_show_banner}
|
||||||
|
class="mb-6 rounded-lg bg-blue-50 dark:bg-blue-900/20 p-4 border border-blue-200 dark:border-blue-800"
|
||||||
|
>
|
||||||
<div class="flex items-start gap-3">
|
<div class="flex items-start gap-3">
|
||||||
<.icon
|
<.icon
|
||||||
name="hero-heart"
|
name="hero-heart"
|
||||||
|
|
@ -421,8 +430,38 @@ defmodule ToweropsWeb.Layouts do
|
||||||
for support, feature requests, or just to say hello!
|
for support, feature requests, or just to say hello!
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
data-dismiss
|
||||||
|
class="flex-shrink-0 rounded-md p-1.5 text-blue-600 dark:text-blue-400 hover:bg-blue-100 dark:hover:bg-blue-800/50 focus:outline-none focus:ring-2 focus:ring-blue-600 dark:focus:ring-blue-400"
|
||||||
|
aria-label="Dismiss banner"
|
||||||
|
>
|
||||||
|
<.icon name="hero-x-mark" class="h-5 w-5" />
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
var banner = document.getElementById('beta-banner');
|
||||||
|
if (banner) {
|
||||||
|
var isHelpPage = banner.dataset.alwaysShow === 'true';
|
||||||
|
|
||||||
|
if (isHelpPage) {
|
||||||
|
// On help page: keep banner visible, hide dismiss button
|
||||||
|
var dismissBtn = banner.querySelector('[data-dismiss]');
|
||||||
|
if (dismissBtn) {
|
||||||
|
dismissBtn.style.display = 'none';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// On other pages: check if dismissed
|
||||||
|
var isDismissed = localStorage.getItem('betaBannerDismissed') === 'true';
|
||||||
|
if (isDismissed) {
|
||||||
|
banner.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
{render_slot(@inner_block)}
|
{render_slot(@inner_block)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -255,6 +255,16 @@
|
||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
:if={@snmp_device.serial_number}
|
||||||
|
class="flex justify-between py-1.5 border-b border-gray-100 dark:border-white/5"
|
||||||
|
>
|
||||||
|
<dt class="text-sm text-gray-600 dark:text-gray-400">Serial Number</dt>
|
||||||
|
<dd class="text-sm font-medium text-gray-900 dark:text-white font-mono">
|
||||||
|
{@snmp_device.serial_number}
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-between py-1.5 border-b border-gray-100 dark:border-white/5">
|
<div class="flex justify-between py-1.5 border-b border-gray-100 dark:border-white/5">
|
||||||
<dt class="text-sm text-gray-600 dark:text-gray-400">Object ID</dt>
|
<dt class="text-sm text-gray-600 dark:text-gray-400">Object ID</dt>
|
||||||
<dd class="text-sm font-medium text-gray-900 dark:text-white font-mono">
|
<dd class="text-sm font-medium text-gray-900 dark:text-white font-mono">
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
Devices Working
|
Devices Tested & Working
|
||||||
* Mikrotik RouterOS
|
* Mikrotik RB5009UG+S+, CCR1009-7G-1C-1S+,
|
||||||
* Ubiquiti AC, LTU, AirFiber
|
* Ubiquiti AC, LTU, AirFiber
|
||||||
|
|
||||||
2026-01-31
|
2026-01-31
|
||||||
* Small ui tweaks
|
* Small ui tweaks
|
||||||
* Backend refactoring
|
* Backend refactoring
|
||||||
* Patched some potential memory leaks
|
* Patched some potential memory leaks
|
||||||
|
* Show version and license for Mikrotik devices
|
||||||
|
|
||||||
2026-01-30
|
2026-01-30
|
||||||
* Completely overhaul poller agent to not track any state
|
* Completely overhaul poller agent to not track any state
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,9 @@ defmodule Towerops.Snmp.Profiles.Vendors.RouterosTest do
|
||||||
]
|
]
|
||||||
|
|
||||||
# OID constants from the module
|
# OID constants from the module
|
||||||
@license_oid "1.3.6.1.4.1.14988.1.1.4.4.0"
|
@license_level_oid "1.3.6.1.4.1.14988.1.1.4.3.0"
|
||||||
|
@version_oid "1.3.6.1.4.1.14988.1.1.4.4.0"
|
||||||
|
@serial_number_oid "1.3.6.1.4.1.14988.1.1.7.3.0"
|
||||||
@wl_ap_table "1.3.6.1.4.1.14988.1.1.1.3.1"
|
@wl_ap_table "1.3.6.1.4.1.14988.1.1.1.3.1"
|
||||||
@wl_stat_table "1.3.6.1.4.1.14988.1.1.1.1.1"
|
@wl_stat_table "1.3.6.1.4.1.14988.1.1.1.1.1"
|
||||||
@wl_60g_table "1.3.6.1.4.1.14988.1.1.1.8.1"
|
@wl_60g_table "1.3.6.1.4.1.14988.1.1.1.8.1"
|
||||||
|
|
@ -33,7 +35,7 @@ defmodule Towerops.Snmp.Profiles.Vendors.RouterosTest do
|
||||||
|
|
||||||
describe "detect_hardware/1" do
|
describe "detect_hardware/1" do
|
||||||
test "returns RouterOS Level when SNMP responds with integer license" do
|
test "returns RouterOS Level when SNMP responds with integer license" do
|
||||||
expect(SnmpMock, :get, fn _, @license_oid, _ ->
|
expect(SnmpMock, :get, fn _, @license_level_oid, _ ->
|
||||||
{:ok, 6}
|
{:ok, 6}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
@ -41,7 +43,7 @@ defmodule Towerops.Snmp.Profiles.Vendors.RouterosTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns nil when SNMP fails" do
|
test "returns nil when SNMP fails" do
|
||||||
expect(SnmpMock, :get, fn _, @license_oid, _ ->
|
expect(SnmpMock, :get, fn _, @license_level_oid, _ ->
|
||||||
{:error, :timeout}
|
{:error, :timeout}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
@ -49,7 +51,7 @@ defmodule Towerops.Snmp.Profiles.Vendors.RouterosTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns nil when license is not an integer" do
|
test "returns nil when license is not an integer" do
|
||||||
expect(SnmpMock, :get, fn _, @license_oid, _ ->
|
expect(SnmpMock, :get, fn _, @license_level_oid, _ ->
|
||||||
{:ok, "not an integer"}
|
{:ok, "not an integer"}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
@ -57,6 +59,101 @@ defmodule Towerops.Snmp.Profiles.Vendors.RouterosTest do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "detect_version/1" do
|
||||||
|
test "returns RouterOS version with prefix and license level when both available" do
|
||||||
|
expect(SnmpMock, :get, 2, fn
|
||||||
|
_, @version_oid, _ -> {:ok, "7.14.1"}
|
||||||
|
_, @license_level_oid, _ -> {:ok, 6}
|
||||||
|
end)
|
||||||
|
|
||||||
|
assert Routeros.detect_version(@client_opts) == "RouterOS 7.14.1 (Level 6)"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns RouterOS version without license level when level unavailable" do
|
||||||
|
expect(SnmpMock, :get, 2, fn
|
||||||
|
_, @version_oid, _ -> {:ok, "7.14.1"}
|
||||||
|
_, @license_level_oid, _ -> {:error, :timeout}
|
||||||
|
end)
|
||||||
|
|
||||||
|
assert Routeros.detect_version(@client_opts) == "RouterOS 7.14.1"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "handles different version formats" do
|
||||||
|
expect(SnmpMock, :get, 2, fn
|
||||||
|
_, @version_oid, _ -> {:ok, "6.48.3"}
|
||||||
|
_, @license_level_oid, _ -> {:ok, 4}
|
||||||
|
end)
|
||||||
|
|
||||||
|
assert Routeros.detect_version(@client_opts) == "RouterOS 6.48.3 (Level 4)"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns nil when version is empty string" do
|
||||||
|
expect(SnmpMock, :get, fn _, @version_oid, _ ->
|
||||||
|
{:ok, ""}
|
||||||
|
end)
|
||||||
|
|
||||||
|
assert Routeros.detect_version(@client_opts) == nil
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns nil when SNMP times out" do
|
||||||
|
expect(SnmpMock, :get, fn _, @version_oid, _ ->
|
||||||
|
{:error, :timeout}
|
||||||
|
end)
|
||||||
|
|
||||||
|
assert Routeros.detect_version(@client_opts) == nil
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns nil when SNMP returns no_such_object" do
|
||||||
|
expect(SnmpMock, :get, fn _, @version_oid, _ ->
|
||||||
|
{:error, :no_such_object}
|
||||||
|
end)
|
||||||
|
|
||||||
|
assert Routeros.detect_version(@client_opts) == nil
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns nil when version is not a string" do
|
||||||
|
expect(SnmpMock, :get, fn _, @version_oid, _ ->
|
||||||
|
{:ok, 123}
|
||||||
|
end)
|
||||||
|
|
||||||
|
assert Routeros.detect_version(@client_opts) == nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "detect_serial_number/1" do
|
||||||
|
test "returns serial number when SNMP responds" do
|
||||||
|
expect(SnmpMock, :get, fn _, @serial_number_oid, _ ->
|
||||||
|
{:ok, "HC907K5P55K"}
|
||||||
|
end)
|
||||||
|
|
||||||
|
assert Routeros.detect_serial_number(@client_opts) == "HC907K5P55K"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns nil when serial number is empty string" do
|
||||||
|
expect(SnmpMock, :get, fn _, @serial_number_oid, _ ->
|
||||||
|
{:ok, ""}
|
||||||
|
end)
|
||||||
|
|
||||||
|
assert Routeros.detect_serial_number(@client_opts) == nil
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns nil when SNMP times out" do
|
||||||
|
expect(SnmpMock, :get, fn _, @serial_number_oid, _ ->
|
||||||
|
{:error, :timeout}
|
||||||
|
end)
|
||||||
|
|
||||||
|
assert Routeros.detect_serial_number(@client_opts) == nil
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns nil when serial number is not a string" do
|
||||||
|
expect(SnmpMock, :get, fn _, @serial_number_oid, _ ->
|
||||||
|
{:ok, 12_345}
|
||||||
|
end)
|
||||||
|
|
||||||
|
assert Routeros.detect_serial_number(@client_opts) == nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "wireless_oid_defs/0" do
|
describe "wireless_oid_defs/0" do
|
||||||
test "returns list of sensor definitions" do
|
test "returns list of sensor definitions" do
|
||||||
defs = Routeros.wireless_oid_defs()
|
defs = Routeros.wireless_oid_defs()
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue