245 lines
7 KiB
Elixir
245 lines
7 KiB
Elixir
defmodule Towerops.Snmp.IpAddressTest do
|
|
use Towerops.DataCase, async: true
|
|
|
|
import Towerops.AccountsFixtures
|
|
|
|
alias Towerops.Snmp.Device
|
|
alias Towerops.Snmp.Interface
|
|
alias Towerops.Snmp.IpAddress
|
|
|
|
setup do
|
|
user = user_fixture()
|
|
|
|
{:ok, organization} =
|
|
Towerops.Organizations.create_organization(%{name: "Test Org"}, user.id)
|
|
|
|
{:ok, site} =
|
|
Towerops.Sites.create_site(%{
|
|
name: "Test Site",
|
|
organization_id: organization.id
|
|
})
|
|
|
|
{:ok, device_schema} =
|
|
Towerops.Devices.create_device(%{
|
|
name: "Test Router",
|
|
ip_address: "192.168.1.1",
|
|
snmp_enabled: true,
|
|
snmp_version: "2c",
|
|
snmp_community: "public",
|
|
snmp_port: 161,
|
|
site_id: site.id,
|
|
organization_id: organization.id
|
|
})
|
|
|
|
snmp_device =
|
|
%Device{}
|
|
|> Device.changeset(%{
|
|
device_id: device_schema.id,
|
|
sys_name: "test-router",
|
|
sys_descr: "Test Router"
|
|
})
|
|
|> Repo.insert!()
|
|
|
|
interface =
|
|
%Interface{}
|
|
|> Interface.changeset(%{
|
|
snmp_device_id: snmp_device.id,
|
|
if_index: 1,
|
|
if_descr: "eth0",
|
|
if_type: 6,
|
|
if_admin_status: "up",
|
|
if_oper_status: "up"
|
|
})
|
|
|> Repo.insert!()
|
|
|
|
%{device: device_schema, snmp_device: snmp_device, interface: interface}
|
|
end
|
|
|
|
describe "changeset/2" do
|
|
test "valid changeset with all required fields", %{interface: interface} do
|
|
attrs = %{
|
|
snmp_interface_id: interface.id,
|
|
ip_address: "192.168.1.100",
|
|
ip_type: "ipv4"
|
|
}
|
|
|
|
changeset = IpAddress.changeset(%IpAddress{}, attrs)
|
|
assert changeset.valid?
|
|
end
|
|
|
|
test "valid changeset with all fields", %{interface: interface} do
|
|
attrs = %{
|
|
snmp_interface_id: interface.id,
|
|
ip_address: "192.168.1.100",
|
|
subnet_mask: "255.255.255.0",
|
|
prefix_length: 24,
|
|
ip_type: "ipv4",
|
|
is_primary: true,
|
|
last_checked_at: DateTime.utc_now(),
|
|
metadata: %{"source" => "ip-mib"}
|
|
}
|
|
|
|
changeset = IpAddress.changeset(%IpAddress{}, attrs)
|
|
assert changeset.valid?
|
|
assert get_field(changeset, :ip_address) == "192.168.1.100"
|
|
assert get_field(changeset, :subnet_mask) == "255.255.255.0"
|
|
assert get_field(changeset, :prefix_length) == 24
|
|
assert get_field(changeset, :is_primary) == true
|
|
end
|
|
|
|
test "valid changeset with IPv6 address", %{interface: interface} do
|
|
attrs = %{
|
|
snmp_interface_id: interface.id,
|
|
ip_address: "2001:db8::1",
|
|
prefix_length: 64,
|
|
ip_type: "ipv6"
|
|
}
|
|
|
|
changeset = IpAddress.changeset(%IpAddress{}, attrs)
|
|
assert changeset.valid?
|
|
assert get_field(changeset, :ip_type) == "ipv6"
|
|
end
|
|
|
|
test "invalid changeset without snmp_interface_id" do
|
|
attrs = %{
|
|
ip_address: "192.168.1.100",
|
|
ip_type: "ipv4"
|
|
}
|
|
|
|
changeset = IpAddress.changeset(%IpAddress{}, attrs)
|
|
refute changeset.valid?
|
|
assert "can't be blank" in errors_on(changeset).snmp_interface_id
|
|
end
|
|
|
|
test "invalid changeset without ip_address", %{interface: interface} do
|
|
attrs = %{
|
|
snmp_interface_id: interface.id,
|
|
ip_type: "ipv4"
|
|
}
|
|
|
|
changeset = IpAddress.changeset(%IpAddress{}, attrs)
|
|
refute changeset.valid?
|
|
assert "can't be blank" in errors_on(changeset).ip_address
|
|
end
|
|
|
|
test "invalid changeset without ip_type", %{interface: interface} do
|
|
attrs = %{
|
|
snmp_interface_id: interface.id,
|
|
ip_address: "192.168.1.100"
|
|
}
|
|
|
|
changeset = IpAddress.changeset(%IpAddress{}, attrs)
|
|
refute changeset.valid?
|
|
assert "can't be blank" in errors_on(changeset).ip_type
|
|
end
|
|
|
|
test "invalid ip_type value", %{interface: interface} do
|
|
attrs = %{
|
|
snmp_interface_id: interface.id,
|
|
ip_address: "192.168.1.100",
|
|
ip_type: "invalid"
|
|
}
|
|
|
|
changeset = IpAddress.changeset(%IpAddress{}, attrs)
|
|
refute changeset.valid?
|
|
assert "is invalid" in errors_on(changeset).ip_type
|
|
end
|
|
|
|
test "valid ip_type values", %{interface: interface} do
|
|
for ip_type <- ~w(ipv4 ipv6) do
|
|
attrs = %{
|
|
snmp_interface_id: interface.id,
|
|
ip_address:
|
|
if(ip_type == "ipv4", do: "192.168.1.#{:rand.uniform(254)}", else: "2001:db8::#{:rand.uniform(100)}"),
|
|
ip_type: ip_type
|
|
}
|
|
|
|
changeset = IpAddress.changeset(%IpAddress{}, attrs)
|
|
assert changeset.valid?, "ip_type '#{ip_type}' should be valid"
|
|
end
|
|
end
|
|
|
|
test "validates prefix_length range for IPv4", %{interface: interface} do
|
|
for invalid_prefix <- [-1, 33, 128] do
|
|
attrs = %{
|
|
snmp_interface_id: interface.id,
|
|
ip_address: "192.168.1.100",
|
|
ip_type: "ipv4",
|
|
prefix_length: invalid_prefix
|
|
}
|
|
|
|
changeset = IpAddress.changeset(%IpAddress{}, attrs)
|
|
refute changeset.valid?, "prefix_length #{invalid_prefix} should be invalid for IPv4"
|
|
end
|
|
end
|
|
|
|
test "accepts valid prefix_length for IPv4", %{interface: interface} do
|
|
for valid_prefix <- [0, 8, 16, 24, 32] do
|
|
attrs = %{
|
|
snmp_interface_id: interface.id,
|
|
ip_address: "192.168.1.100",
|
|
ip_type: "ipv4",
|
|
prefix_length: valid_prefix
|
|
}
|
|
|
|
changeset = IpAddress.changeset(%IpAddress{}, attrs)
|
|
assert changeset.valid?, "prefix_length #{valid_prefix} should be valid for IPv4"
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "unique constraint" do
|
|
test "prevents duplicate IP addresses on same interface", %{interface: interface} do
|
|
attrs = %{
|
|
snmp_interface_id: interface.id,
|
|
ip_address: "192.168.1.100",
|
|
ip_type: "ipv4"
|
|
}
|
|
|
|
# Insert first IP
|
|
changeset = IpAddress.changeset(%IpAddress{}, attrs)
|
|
assert {:ok, _ip} = Repo.insert(changeset)
|
|
|
|
# Attempt to insert duplicate
|
|
changeset2 = IpAddress.changeset(%IpAddress{}, attrs)
|
|
|
|
assert {:error, changeset} = Repo.insert(changeset2)
|
|
errors = errors_on(changeset)
|
|
|
|
assert Enum.any?([:ip_address, :snmp_interface_id], &("has already been taken" in Map.get(errors, &1, [])))
|
|
end
|
|
|
|
test "allows same IP address on different interfaces", %{snmp_device: snmp_device, interface: interface} do
|
|
# Create second interface
|
|
interface2 =
|
|
%Interface{}
|
|
|> Interface.changeset(%{
|
|
snmp_device_id: snmp_device.id,
|
|
if_index: 2,
|
|
if_descr: "eth1",
|
|
if_type: 6,
|
|
if_admin_status: "up",
|
|
if_oper_status: "up"
|
|
})
|
|
|> Repo.insert!()
|
|
|
|
attrs1 = %{
|
|
snmp_interface_id: interface.id,
|
|
ip_address: "192.168.1.100",
|
|
ip_type: "ipv4"
|
|
}
|
|
|
|
attrs2 = %{
|
|
snmp_interface_id: interface2.id,
|
|
ip_address: "192.168.1.100",
|
|
ip_type: "ipv4"
|
|
}
|
|
|
|
changeset1 = IpAddress.changeset(%IpAddress{}, attrs1)
|
|
assert {:ok, _ip1} = Repo.insert(changeset1)
|
|
|
|
changeset2 = IpAddress.changeset(%IpAddress{}, attrs2)
|
|
assert {:ok, _ip2} = Repo.insert(changeset2)
|
|
end
|
|
end
|
|
end
|