test: cloud poller AgentChannel + SNMP sensor v3/no-snmp + firmware month parser
This commit is contained in:
parent
23a21a674d
commit
b51759dfdf
3 changed files with 175 additions and 0 deletions
|
|
@ -286,5 +286,40 @@ defmodule Towerops.Monitoring.Executors.SnmpSensorExecutorTest do
|
|||
|
||||
assert {:error, :timeout} = SnmpSensorExecutor.execute(check)
|
||||
end
|
||||
|
||||
test "returns error when device has no SNMP device record", %{organization: organization} do
|
||||
# Create a device with snmp_enabled but no Snmp.Device association inserted.
|
||||
{:ok, site} = Towerops.Sites.create_site(%{name: "No-SNMP Site", organization_id: organization.id})
|
||||
|
||||
{:ok, device} =
|
||||
Towerops.Devices.create_device(%{
|
||||
name: "No-SNMP Device",
|
||||
ip_address: "10.99.99.99",
|
||||
snmp_enabled: true,
|
||||
snmp_version: "2c",
|
||||
snmp_community: "public",
|
||||
snmp_port: 161,
|
||||
site_id: site.id,
|
||||
organization_id: organization.id
|
||||
})
|
||||
|
||||
{:ok, check} =
|
||||
Monitoring.create_check(%{
|
||||
organization_id: organization.id,
|
||||
device_id: device.id,
|
||||
name: "Bad device check",
|
||||
check_type: "snmp_sensor",
|
||||
source_type: "manual",
|
||||
interval_seconds: 60,
|
||||
enabled: true,
|
||||
config: %{
|
||||
"sensor_id" => Ecto.UUID.generate(),
|
||||
"sensor_oid" => "1.2.3.4",
|
||||
"sensor_type" => "temperature"
|
||||
}
|
||||
})
|
||||
|
||||
assert {:error, _reason} = SnmpSensorExecutor.execute(check)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -175,6 +175,64 @@ defmodule Towerops.Workers.FirmwareVersionFetcherWorkerTest do
|
|||
assert data.release_date == ~D[2025-02-01]
|
||||
end
|
||||
|
||||
test "parses every month abbreviation" do
|
||||
months = [
|
||||
{"Jan", 1},
|
||||
{"Feb", 2},
|
||||
{"Mar", 3},
|
||||
{"Apr", 4},
|
||||
{"May", 5},
|
||||
{"Jun", 6},
|
||||
{"Jul", 7},
|
||||
{"Aug", 8},
|
||||
{"Sep", 9},
|
||||
{"Oct", 10},
|
||||
{"Nov", 11},
|
||||
{"Dec", 12}
|
||||
]
|
||||
|
||||
for {abbrev, month_num} <- months do
|
||||
rss = """
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rss version="2.0">
|
||||
<channel>
|
||||
<title>RouterOS latest stable version</title>
|
||||
<item>
|
||||
<title>7.14.1</title>
|
||||
<link>https://mikrotik.com/download</link>
|
||||
<pubDate>Mon, 15 #{abbrev} 2025 12:00:00 +0000</pubDate>
|
||||
<description>Test</description>
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
||||
"""
|
||||
|
||||
assert {:ok, data} = FirmwareVersionFetcherWorker.parse_rss_feed(rss)
|
||||
assert data.release_date.month == month_num
|
||||
assert data.release_date.year == 2025
|
||||
end
|
||||
end
|
||||
|
||||
test "returns nil release_date for unrecognized month" do
|
||||
rss = """
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rss version="2.0">
|
||||
<channel>
|
||||
<title>RouterOS latest stable version</title>
|
||||
<item>
|
||||
<title>7.14.1</title>
|
||||
<link>https://mikrotik.com/download</link>
|
||||
<pubDate>Mon, 15 Foo 2025 12:00:00 +0000</pubDate>
|
||||
<description>Test</description>
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
||||
"""
|
||||
|
||||
assert {:ok, data} = FirmwareVersionFetcherWorker.parse_rss_feed(rss)
|
||||
assert is_nil(data.release_date)
|
||||
end
|
||||
|
||||
test "handles invalid RFC822 date format gracefully" do
|
||||
invalid_date = """
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,82 @@
|
|||
defmodule ToweropsWeb.AgentChannelCloudPollerTest do
|
||||
@moduledoc """
|
||||
Drives the `is_cloud_poller` join branch + latency_probe_jobs subscribe
|
||||
side-effect. The default AgentChannel test connects with a regular
|
||||
(non-cloud) agent token; this file specifically tests the cloud-poller
|
||||
path so the `Phoenix.PubSub.subscribe(... :latency_probe)` line + downstream
|
||||
handler executes with cloud_poller=true.
|
||||
"""
|
||||
use Towerops.DataCase, async: false
|
||||
|
||||
import Phoenix.ChannelTest
|
||||
|
||||
alias Towerops.AccountsFixtures
|
||||
alias Towerops.Agent.AgentJobList
|
||||
alias Towerops.Agents
|
||||
alias Towerops.OrganizationsFixtures
|
||||
alias ToweropsWeb.AgentSocket
|
||||
|
||||
@endpoint ToweropsWeb.Endpoint
|
||||
|
||||
setup do
|
||||
user = AccountsFixtures.user_fixture()
|
||||
organization = OrganizationsFixtures.organization_fixture(user.id)
|
||||
|
||||
{:ok, agent_token, token_string} = Agents.create_cloud_poller("Test Cloud Poller")
|
||||
|
||||
{:ok, socket} = connect(AgentSocket, %{})
|
||||
|
||||
{:ok, _, socket} =
|
||||
subscribe_and_join(socket, "agent:#{agent_token.id}", %{"token" => token_string})
|
||||
|
||||
assert_push("jobs", _initial_jobs, 1_000)
|
||||
|
||||
%{
|
||||
socket: socket,
|
||||
agent_token: agent_token,
|
||||
token_string: token_string,
|
||||
organization: organization,
|
||||
user: user
|
||||
}
|
||||
end
|
||||
|
||||
describe "cloud poller join + latency_probe subscription" do
|
||||
test "join with a cloud-poller token sets the cloud poller branch", %{
|
||||
agent_token: agent_token,
|
||||
organization: organization
|
||||
} do
|
||||
# Cloud-poller tokens are global (no organization_id), so we use the
|
||||
# test's user-owned organization for the test device. The setup itself
|
||||
# proves the join path subscribed to the latency_probe PubSub topic;
|
||||
# we confirm by broadcasting on it and watching for a "jobs" push.
|
||||
assert agent_token.is_cloud_poller
|
||||
|
||||
{:ok, site} =
|
||||
Towerops.Sites.create_site(%{
|
||||
name: "Cloud Site",
|
||||
organization_id: organization.id
|
||||
})
|
||||
|
||||
{:ok, device} =
|
||||
Towerops.Devices.create_device(%{
|
||||
name: "Probe Device",
|
||||
ip_address: "10.66.0.1",
|
||||
site_id: site.id,
|
||||
organization_id: organization.id
|
||||
})
|
||||
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"agent:#{agent_token.id}:latency_probe",
|
||||
{:latency_probe_jobs, [device]}
|
||||
)
|
||||
|
||||
assert_push("jobs", %{binary: jobs_binary}, 2_000)
|
||||
{:ok, decoded} = Base.decode64(jobs_binary)
|
||||
{:ok, job_list} = AgentJobList.decode(decoded)
|
||||
|
||||
ping_jobs = Enum.filter(job_list.jobs, &(&1.job_type == :PING))
|
||||
assert length(ping_jobs) == 5
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Reference in a new issue