649 lines
22 KiB
Elixir
649 lines
22 KiB
Elixir
defmodule Towerops.GaiiaTest do
|
|
use Towerops.DataCase, async: true
|
|
|
|
import Towerops.AccountsFixtures
|
|
import Towerops.DevicesFixtures
|
|
import Towerops.OrganizationsFixtures
|
|
|
|
alias Towerops.Gaiia
|
|
alias Towerops.Snmp.Device
|
|
|
|
setup do
|
|
user = user_fixture()
|
|
org = organization_fixture(user.id)
|
|
%{org: org}
|
|
end
|
|
|
|
describe "accounts" do
|
|
test "upsert_account/2 creates a new account", %{org: org} do
|
|
attrs = %{gaiia_id: "acct-1", name: "Alice", status: "Active"}
|
|
assert {:ok, account} = Gaiia.upsert_account(org.id, attrs)
|
|
assert account.gaiia_id == "acct-1"
|
|
assert account.name == "Alice"
|
|
end
|
|
|
|
test "upsert_account/2 updates existing account", %{org: org} do
|
|
attrs = %{gaiia_id: "acct-1", name: "Alice"}
|
|
{:ok, _} = Gaiia.upsert_account(org.id, attrs)
|
|
{:ok, updated} = Gaiia.upsert_account(org.id, %{gaiia_id: "acct-1", name: "Alice Smith"})
|
|
assert updated.name == "Alice Smith"
|
|
assert length(Gaiia.list_accounts(org.id)) == 1
|
|
end
|
|
|
|
test "list_accounts/1 returns accounts for organization", %{org: org} do
|
|
{:ok, _} = Gaiia.upsert_account(org.id, %{gaiia_id: "acct-1", name: "Alice"})
|
|
{:ok, _} = Gaiia.upsert_account(org.id, %{gaiia_id: "acct-2", name: "Bob"})
|
|
assert length(Gaiia.list_accounts(org.id)) == 2
|
|
end
|
|
|
|
test "get_account/2 returns account by gaiia_id", %{org: org} do
|
|
{:ok, _} = Gaiia.upsert_account(org.id, %{gaiia_id: "acct-1", name: "Alice"})
|
|
assert %{name: "Alice"} = Gaiia.get_account(org.id, "acct-1")
|
|
assert is_nil(Gaiia.get_account(org.id, "nonexistent"))
|
|
end
|
|
end
|
|
|
|
describe "network_sites" do
|
|
test "upsert_network_site/2 creates a new site", %{org: org} do
|
|
attrs = %{gaiia_id: "site-1", name: "Tower 3", ip_blocks: ["10.0.0.0/24"]}
|
|
assert {:ok, site} = Gaiia.upsert_network_site(org.id, attrs)
|
|
assert site.gaiia_id == "site-1"
|
|
assert site.ip_blocks == ["10.0.0.0/24"]
|
|
end
|
|
|
|
test "upsert_network_site/2 preserves site_id mapping on update", %{org: org} do
|
|
{:ok, site} = Gaiia.upsert_network_site(org.id, %{gaiia_id: "site-1", name: "Tower 3"})
|
|
assert is_nil(site.site_id)
|
|
|
|
# Simulate user mapping
|
|
towerops_site = create_site(org.id)
|
|
Gaiia.update_network_site_mapping(site, %{site_id: towerops_site.id})
|
|
|
|
# Re-sync should preserve mapping
|
|
{:ok, updated} = Gaiia.upsert_network_site(org.id, %{gaiia_id: "site-1", name: "Tower 3 Updated"})
|
|
assert updated.name == "Tower 3 Updated"
|
|
assert updated.site_id == towerops_site.id
|
|
end
|
|
|
|
test "list_network_sites/1 returns sites for organization", %{org: org} do
|
|
{:ok, _} = Gaiia.upsert_network_site(org.id, %{gaiia_id: "site-1", name: "Tower 1"})
|
|
assert length(Gaiia.list_network_sites(org.id)) == 1
|
|
end
|
|
end
|
|
|
|
describe "inventory_items" do
|
|
test "upsert_inventory_item/2 creates a new item", %{org: org} do
|
|
attrs = %{gaiia_id: "item-1", name: "AF5XHD", serial_number: "SN123"}
|
|
assert {:ok, item} = Gaiia.upsert_inventory_item(org.id, attrs)
|
|
assert item.serial_number == "SN123"
|
|
end
|
|
|
|
test "upsert_inventory_item/2 preserves device_id mapping on update", %{org: org} do
|
|
{:ok, item} = Gaiia.upsert_inventory_item(org.id, %{gaiia_id: "item-1", name: "AF5XHD"})
|
|
assert is_nil(item.device_id)
|
|
|
|
device = device_fixture(%{organization_id: org.id})
|
|
Gaiia.update_inventory_item_mapping(item, %{device_id: device.id})
|
|
|
|
{:ok, updated} = Gaiia.upsert_inventory_item(org.id, %{gaiia_id: "item-1", name: "AF5XHD v2"})
|
|
assert updated.name == "AF5XHD v2"
|
|
assert updated.device_id == device.id
|
|
end
|
|
|
|
test "list_inventory_items/1 returns items for organization", %{org: org} do
|
|
{:ok, _} = Gaiia.upsert_inventory_item(org.id, %{gaiia_id: "item-1", name: "AF5XHD"})
|
|
assert length(Gaiia.list_inventory_items(org.id)) == 1
|
|
end
|
|
end
|
|
|
|
describe "billing_subscriptions" do
|
|
test "upsert_billing_subscription/2 creates a new subscription", %{org: org} do
|
|
attrs = %{gaiia_id: "sub-1", account_gaiia_id: "acct-1", product_name: "100Mbps"}
|
|
assert {:ok, sub} = Gaiia.upsert_billing_subscription(org.id, attrs)
|
|
assert sub.product_name == "100Mbps"
|
|
end
|
|
|
|
test "list_billing_subscriptions_for_account/2 filters by account", %{org: org} do
|
|
{:ok, _} = Gaiia.upsert_billing_subscription(org.id, %{gaiia_id: "sub-1", account_gaiia_id: "acct-1"})
|
|
{:ok, _} = Gaiia.upsert_billing_subscription(org.id, %{gaiia_id: "sub-2", account_gaiia_id: "acct-2"})
|
|
|
|
assert length(Gaiia.list_billing_subscriptions_for_account(org.id, "acct-1")) == 1
|
|
end
|
|
|
|
test "list_billing_subscriptions/1 returns all subscriptions", %{org: org} do
|
|
{:ok, _} = Gaiia.upsert_billing_subscription(org.id, %{gaiia_id: "sub-1"})
|
|
{:ok, _} = Gaiia.upsert_billing_subscription(org.id, %{gaiia_id: "sub-2"})
|
|
assert length(Gaiia.list_billing_subscriptions(org.id)) == 2
|
|
end
|
|
end
|
|
|
|
defp create_site(organization_id) do
|
|
{:ok, site} =
|
|
Towerops.Sites.create_site(%{
|
|
name: "Test Site #{System.unique_integer([:positive])}",
|
|
organization_id: organization_id
|
|
})
|
|
|
|
site
|
|
end
|
|
|
|
describe "get_org_subscriber_totals/1" do
|
|
test "returns zero totals when no network sites", %{org: org} do
|
|
assert %{total_subscribers: 0, total_mrr: total_mrr} = Gaiia.get_org_subscriber_totals(org.id)
|
|
assert Decimal.equal?(total_mrr, Decimal.new(0))
|
|
end
|
|
|
|
test "sums account_count and total_mrr from network sites", %{org: org} do
|
|
{:ok, _} =
|
|
Gaiia.upsert_network_site(org.id, %{
|
|
gaiia_id: "ns-1",
|
|
name: "Tower A",
|
|
account_count: 50,
|
|
total_mrr: Decimal.new("2500.00")
|
|
})
|
|
|
|
{:ok, _} =
|
|
Gaiia.upsert_network_site(org.id, %{
|
|
gaiia_id: "ns-2",
|
|
name: "Tower B",
|
|
account_count: 30,
|
|
total_mrr: Decimal.new("1500.00")
|
|
})
|
|
|
|
result = Gaiia.get_org_subscriber_totals(org.id)
|
|
assert result.total_subscribers == 80
|
|
assert Decimal.equal?(result.total_mrr, Decimal.new("4000.00"))
|
|
end
|
|
|
|
test "handles nil values gracefully", %{org: org} do
|
|
{:ok, _} =
|
|
Gaiia.upsert_network_site(org.id, %{
|
|
gaiia_id: "ns-nil",
|
|
name: "Tower Nil",
|
|
account_count: nil,
|
|
total_mrr: nil
|
|
})
|
|
|
|
result = Gaiia.get_org_subscriber_totals(org.id)
|
|
assert result.total_subscribers == 0
|
|
assert Decimal.equal?(result.total_mrr, Decimal.new(0))
|
|
end
|
|
end
|
|
|
|
describe "get_devices_impact/1" do
|
|
test "deduplicates accounts across devices, preferring higher-confidence matches", %{org: org} do
|
|
site = create_site(org.id)
|
|
|
|
# Create two devices: a router and an AP
|
|
router = device_fixture(%{organization_id: org.id, site: site, name: "Router"})
|
|
ap = device_fixture(%{organization_id: org.id, site: site, name: "AP-1"})
|
|
|
|
# Create an account with an active subscription
|
|
{:ok, account} =
|
|
Gaiia.upsert_account(org.id, %{
|
|
gaiia_id: "acct-1",
|
|
name: "Alice",
|
|
subscription_count: 1
|
|
})
|
|
|
|
{:ok, _} =
|
|
Gaiia.upsert_billing_subscription(org.id, %{
|
|
gaiia_id: "sub-1",
|
|
account_gaiia_id: "acct-1",
|
|
status: "ACTIVE",
|
|
mrr_amount: Decimal.new("50.00")
|
|
})
|
|
|
|
now = Towerops.Time.now()
|
|
|
|
# Same account linked to AP via wireless_mac (high confidence)
|
|
Repo.insert!(%Gaiia.DeviceSubscriberLink{
|
|
organization_id: org.id,
|
|
device_id: ap.id,
|
|
gaiia_account_id: account.id,
|
|
match_method: "wireless_mac",
|
|
confidence: "high",
|
|
subscriber_mac: "aa:bb:cc:dd:ee:ff",
|
|
inserted_at: now,
|
|
updated_at: now
|
|
})
|
|
|
|
# Same account linked to Router via arp_ip (medium confidence)
|
|
Repo.insert!(%Gaiia.DeviceSubscriberLink{
|
|
organization_id: org.id,
|
|
device_id: router.id,
|
|
gaiia_account_id: account.id,
|
|
match_method: "arp_ip",
|
|
confidence: "medium",
|
|
subscriber_ip: "10.0.0.5",
|
|
inserted_at: now,
|
|
updated_at: now
|
|
})
|
|
|
|
impact = Gaiia.get_devices_impact([router.id, ap.id])
|
|
|
|
# Account should be counted only on the AP (wireless_mac beats arp_ip)
|
|
assert impact[ap.id].subscriber_count == 1
|
|
assert Decimal.equal?(impact[ap.id].mrr, Decimal.new("50.00"))
|
|
|
|
# Router should have 0 subscribers (deduped to AP)
|
|
router_impact = Map.get(impact, router.id, %{subscriber_count: 0, mrr: Decimal.new(0)})
|
|
assert router_impact.subscriber_count == 0
|
|
end
|
|
|
|
test "keeps ARP match on router when no higher-confidence match exists elsewhere", %{org: org} do
|
|
site = create_site(org.id)
|
|
router = device_fixture(%{organization_id: org.id, site: site, name: "Router"})
|
|
ap = device_fixture(%{organization_id: org.id, site: site, name: "AP-1"})
|
|
|
|
{:ok, account} =
|
|
Gaiia.upsert_account(org.id, %{
|
|
gaiia_id: "acct-only-router",
|
|
name: "Bob",
|
|
subscription_count: 1
|
|
})
|
|
|
|
{:ok, _} =
|
|
Gaiia.upsert_billing_subscription(org.id, %{
|
|
gaiia_id: "sub-bob",
|
|
account_gaiia_id: "acct-only-router",
|
|
status: "ACTIVE",
|
|
mrr_amount: Decimal.new("75.00")
|
|
})
|
|
|
|
now = Towerops.Time.now()
|
|
|
|
# Account only linked to router via ARP (no AP match)
|
|
Repo.insert!(%Gaiia.DeviceSubscriberLink{
|
|
organization_id: org.id,
|
|
device_id: router.id,
|
|
gaiia_account_id: account.id,
|
|
match_method: "arp_ip",
|
|
confidence: "medium",
|
|
subscriber_ip: "10.0.0.10",
|
|
inserted_at: now,
|
|
updated_at: now
|
|
})
|
|
|
|
impact = Gaiia.get_devices_impact([router.id, ap.id])
|
|
|
|
# Router should keep the account since no better match exists
|
|
assert impact[router.id].subscriber_count == 1
|
|
assert Decimal.equal?(impact[router.id].mrr, Decimal.new("75.00"))
|
|
end
|
|
|
|
test "deduplicates across same-method matches, keeping first device", %{org: org} do
|
|
site = create_site(org.id)
|
|
router = device_fixture(%{organization_id: org.id, site: site, name: "Router"})
|
|
ap = device_fixture(%{organization_id: org.id, site: site, name: "AP-1"})
|
|
|
|
{:ok, account} =
|
|
Gaiia.upsert_account(org.id, %{
|
|
gaiia_id: "acct-both-arp",
|
|
name: "Charlie",
|
|
subscription_count: 1
|
|
})
|
|
|
|
{:ok, _} =
|
|
Gaiia.upsert_billing_subscription(org.id, %{
|
|
gaiia_id: "sub-charlie",
|
|
account_gaiia_id: "acct-both-arp",
|
|
status: "ACTIVE",
|
|
mrr_amount: Decimal.new("60.00")
|
|
})
|
|
|
|
now = Towerops.Time.now()
|
|
|
|
# Same account linked to both devices via arp_ip (same method)
|
|
Repo.insert!(%Gaiia.DeviceSubscriberLink{
|
|
organization_id: org.id,
|
|
device_id: ap.id,
|
|
gaiia_account_id: account.id,
|
|
match_method: "arp_ip",
|
|
confidence: "medium",
|
|
subscriber_ip: "10.0.0.20",
|
|
inserted_at: now,
|
|
updated_at: now
|
|
})
|
|
|
|
Repo.insert!(%Gaiia.DeviceSubscriberLink{
|
|
organization_id: org.id,
|
|
device_id: router.id,
|
|
gaiia_account_id: account.id,
|
|
match_method: "arp_ip",
|
|
confidence: "medium",
|
|
subscriber_ip: "100.64.0.20",
|
|
inserted_at: now,
|
|
updated_at: now
|
|
})
|
|
|
|
impact = Gaiia.get_devices_impact([router.id, ap.id])
|
|
|
|
# Account should be counted on exactly one device (not both)
|
|
router_count = get_in(impact, [router.id, :subscriber_count]) || 0
|
|
ap_count = get_in(impact, [ap.id, :subscriber_count]) || 0
|
|
assert router_count + ap_count == 1
|
|
end
|
|
|
|
test "excludes links matched through CGNAT IPs (100.64.0.0/10)", %{org: org} do
|
|
site = create_site(org.id)
|
|
router = device_fixture(%{organization_id: org.id, site: site, name: "Router"})
|
|
|
|
{:ok, account} =
|
|
Gaiia.upsert_account(org.id, %{
|
|
gaiia_id: "acct-cgnat",
|
|
name: "CGNAT Sub",
|
|
subscription_count: 1
|
|
})
|
|
|
|
{:ok, _} =
|
|
Gaiia.upsert_billing_subscription(org.id, %{
|
|
gaiia_id: "sub-cgnat",
|
|
account_gaiia_id: "acct-cgnat",
|
|
status: "ACTIVE",
|
|
mrr_amount: Decimal.new("50.00")
|
|
})
|
|
|
|
now = Towerops.Time.now()
|
|
|
|
# Link via CGNAT IP — should be excluded from per-device counts
|
|
Repo.insert!(%Gaiia.DeviceSubscriberLink{
|
|
organization_id: org.id,
|
|
device_id: router.id,
|
|
gaiia_account_id: account.id,
|
|
match_method: "arp_ip",
|
|
confidence: "medium",
|
|
subscriber_ip: "100.64.62.50",
|
|
inserted_at: now,
|
|
updated_at: now
|
|
})
|
|
|
|
impact = Gaiia.get_devices_impact([router.id])
|
|
|
|
router_impact = Map.get(impact, router.id, %{subscriber_count: 0, mrr: Decimal.new(0)})
|
|
assert router_impact.subscriber_count == 0
|
|
end
|
|
|
|
test "keeps links with non-CGNAT IPs", %{org: org} do
|
|
site = create_site(org.id)
|
|
ap = device_fixture(%{organization_id: org.id, site: site, name: "AP-1"})
|
|
|
|
{:ok, account} =
|
|
Gaiia.upsert_account(org.id, %{
|
|
gaiia_id: "acct-lan",
|
|
name: "LAN Sub",
|
|
subscription_count: 1
|
|
})
|
|
|
|
{:ok, _} =
|
|
Gaiia.upsert_billing_subscription(org.id, %{
|
|
gaiia_id: "sub-lan",
|
|
account_gaiia_id: "acct-lan",
|
|
status: "ACTIVE",
|
|
mrr_amount: Decimal.new("80.00")
|
|
})
|
|
|
|
now = Towerops.Time.now()
|
|
|
|
Repo.insert!(%Gaiia.DeviceSubscriberLink{
|
|
organization_id: org.id,
|
|
device_id: ap.id,
|
|
gaiia_account_id: account.id,
|
|
match_method: "arp_ip",
|
|
confidence: "medium",
|
|
subscriber_ip: "10.0.0.5",
|
|
inserted_at: now,
|
|
updated_at: now
|
|
})
|
|
|
|
impact = Gaiia.get_devices_impact([ap.id])
|
|
|
|
assert impact[ap.id].subscriber_count == 1
|
|
assert Decimal.equal?(impact[ap.id].mrr, Decimal.new("80.00"))
|
|
end
|
|
end
|
|
|
|
describe "get_site_impact/1" do
|
|
test "excludes router devices from per-device impact", %{org: org} do
|
|
site = create_site(org.id)
|
|
router = device_fixture(%{organization_id: org.id, site: site, name: "Router"})
|
|
ap = device_fixture(%{organization_id: org.id, site: site, name: "AP-1"})
|
|
|
|
# Mark router as a RouterOS device via SNMP
|
|
Repo.insert!(%Device{
|
|
device_id: router.id,
|
|
sys_descr: "RouterOS CCR1009-7G-1C-1S+",
|
|
sys_object_id: "1.3.6.1.4.1.14988.1",
|
|
sys_name: "router"
|
|
})
|
|
|
|
{:ok, account} =
|
|
Gaiia.upsert_account(org.id, %{
|
|
gaiia_id: "acct-r",
|
|
name: "Router Sub",
|
|
subscription_count: 1
|
|
})
|
|
|
|
{:ok, _} =
|
|
Gaiia.upsert_billing_subscription(org.id, %{
|
|
gaiia_id: "sub-r",
|
|
account_gaiia_id: "acct-r",
|
|
status: "ACTIVE",
|
|
mrr_amount: Decimal.new("50.00")
|
|
})
|
|
|
|
now = Towerops.Time.now()
|
|
|
|
# Link to router via LAN IP
|
|
Repo.insert!(%Gaiia.DeviceSubscriberLink{
|
|
organization_id: org.id,
|
|
device_id: router.id,
|
|
gaiia_account_id: account.id,
|
|
match_method: "arp_ip",
|
|
confidence: "medium",
|
|
subscriber_ip: "10.0.0.5",
|
|
inserted_at: now,
|
|
updated_at: now
|
|
})
|
|
|
|
result = Gaiia.get_site_impact(site.id)
|
|
|
|
# Site totals should exclude router-only subscribers
|
|
assert result.subscriber_count == 0
|
|
assert Decimal.equal?(result.mrr, Decimal.new(0))
|
|
|
|
# Router's per-device entry should show 0
|
|
router_device = Enum.find(result.devices, &(&1.device_id == router.id))
|
|
assert router_device.count == 0
|
|
|
|
# AP should show 0 (no links to it)
|
|
ap_device = Enum.find(result.devices, &(&1.device_id == ap.id))
|
|
assert ap_device.count == 0
|
|
end
|
|
|
|
test "site totals equal sum of non-router per-device impacts", %{org: org} do
|
|
site = create_site(org.id)
|
|
router = device_fixture(%{organization_id: org.id, site: site, name: "Router"})
|
|
ap1 = device_fixture(%{organization_id: org.id, site: site, name: "AP-1"})
|
|
ap2 = device_fixture(%{organization_id: org.id, site: site, name: "AP-2"})
|
|
|
|
Repo.insert!(%Device{
|
|
device_id: router.id,
|
|
sys_descr: "RouterOS CCR1009-7G-1C-1S+",
|
|
sys_object_id: "1.3.6.1.4.1.14988.1",
|
|
sys_name: "router"
|
|
})
|
|
|
|
{:ok, acct1} =
|
|
Gaiia.upsert_account(org.id, %{gaiia_id: "acct-a1", name: "Sub A", subscription_count: 1})
|
|
|
|
{:ok, acct2} =
|
|
Gaiia.upsert_account(org.id, %{gaiia_id: "acct-a2", name: "Sub B", subscription_count: 1})
|
|
|
|
{:ok, _} =
|
|
Gaiia.upsert_billing_subscription(org.id, %{
|
|
gaiia_id: "sub-a1",
|
|
account_gaiia_id: "acct-a1",
|
|
status: "ACTIVE",
|
|
mrr_amount: Decimal.new("40.00")
|
|
})
|
|
|
|
{:ok, _} =
|
|
Gaiia.upsert_billing_subscription(org.id, %{
|
|
gaiia_id: "sub-a2",
|
|
account_gaiia_id: "acct-a2",
|
|
status: "ACTIVE",
|
|
mrr_amount: Decimal.new("60.00")
|
|
})
|
|
|
|
now = Towerops.Time.now()
|
|
|
|
# acct1 on AP-1 and router (AP wins via wireless_mac)
|
|
Repo.insert!(%Gaiia.DeviceSubscriberLink{
|
|
organization_id: org.id,
|
|
device_id: ap1.id,
|
|
gaiia_account_id: acct1.id,
|
|
match_method: "wireless_mac",
|
|
confidence: "high",
|
|
subscriber_mac: "aa:bb:cc:dd:ee:01",
|
|
inserted_at: now,
|
|
updated_at: now
|
|
})
|
|
|
|
Repo.insert!(%Gaiia.DeviceSubscriberLink{
|
|
organization_id: org.id,
|
|
device_id: router.id,
|
|
gaiia_account_id: acct1.id,
|
|
match_method: "arp_ip",
|
|
confidence: "medium",
|
|
subscriber_ip: "10.0.0.1",
|
|
inserted_at: now,
|
|
updated_at: now
|
|
})
|
|
|
|
# acct2 on AP-2 only
|
|
Repo.insert!(%Gaiia.DeviceSubscriberLink{
|
|
organization_id: org.id,
|
|
device_id: ap2.id,
|
|
gaiia_account_id: acct2.id,
|
|
match_method: "arp_ip",
|
|
confidence: "medium",
|
|
subscriber_ip: "10.0.0.2",
|
|
inserted_at: now,
|
|
updated_at: now
|
|
})
|
|
|
|
result = Gaiia.get_site_impact(site.id)
|
|
|
|
# Site totals = AP-1 (1 sub, $40) + AP-2 (1 sub, $60) = 2 subs, $100
|
|
assert result.subscriber_count == 2
|
|
assert Decimal.equal?(result.mrr, Decimal.new("100.00"))
|
|
|
|
# Per-device
|
|
ap1_dev = Enum.find(result.devices, &(&1.device_id == ap1.id))
|
|
assert ap1_dev.count == 1
|
|
|
|
ap2_dev = Enum.find(result.devices, &(&1.device_id == ap2.id))
|
|
assert ap2_dev.count == 1
|
|
|
|
router_dev = Enum.find(result.devices, &(&1.device_id == router.id))
|
|
assert router_dev.count == 0
|
|
end
|
|
end
|
|
|
|
describe "get_site_subscriber_summary/1" do
|
|
test "returns subscriber data for a mapped site", %{org: org} do
|
|
site = create_site(org.id)
|
|
|
|
{:ok, _} =
|
|
Gaiia.upsert_network_site(org.id, %{
|
|
gaiia_id: "ns-mapped",
|
|
name: "Mapped Tower",
|
|
account_count: 42,
|
|
total_mrr: Decimal.new("3100.50"),
|
|
site_id: site.id
|
|
})
|
|
|
|
result = Gaiia.get_site_subscriber_summary(site.id)
|
|
assert result.account_count == 42
|
|
assert Decimal.equal?(result.total_mrr, Decimal.new("3100.50"))
|
|
end
|
|
|
|
test "returns nil for unmapped site", %{org: org} do
|
|
site = create_site(org.id)
|
|
assert is_nil(Gaiia.get_site_subscriber_summary(site.id))
|
|
end
|
|
end
|
|
|
|
describe "search_inventory_items/2" do
|
|
test "finds items by name (case insensitive)", %{org: org} do
|
|
{:ok, _} = Gaiia.upsert_inventory_item(org.id, %{gaiia_id: "item-1", name: "ePMP 3000", ip_address: "10.0.0.1"})
|
|
{:ok, _} = Gaiia.upsert_inventory_item(org.id, %{gaiia_id: "item-2", name: "LTU Rocket", ip_address: "10.0.0.2"})
|
|
|
|
results = Gaiia.search_inventory_items(org.id, "epmp")
|
|
assert length(results) == 1
|
|
assert hd(results).gaiia_id == "item-1"
|
|
end
|
|
|
|
test "finds items by IP address", %{org: org} do
|
|
{:ok, _} = Gaiia.upsert_inventory_item(org.id, %{gaiia_id: "item-1", name: "Device A", ip_address: "192.168.1.50"})
|
|
{:ok, _} = Gaiia.upsert_inventory_item(org.id, %{gaiia_id: "item-2", name: "Device B", ip_address: "10.0.0.1"})
|
|
|
|
results = Gaiia.search_inventory_items(org.id, "192.168.1")
|
|
assert length(results) == 1
|
|
assert hd(results).gaiia_id == "item-1"
|
|
end
|
|
|
|
test "finds items by model name", %{org: org} do
|
|
{:ok, _} = Gaiia.upsert_inventory_item(org.id, %{gaiia_id: "item-1", name: "Unit 1", model_name: "AC1000"})
|
|
{:ok, _} = Gaiia.upsert_inventory_item(org.id, %{gaiia_id: "item-2", name: "Unit 2", model_name: "AC2000"})
|
|
|
|
results = Gaiia.search_inventory_items(org.id, "AC1000")
|
|
assert length(results) == 1
|
|
assert hd(results).gaiia_id == "item-1"
|
|
end
|
|
|
|
test "returns empty list when no match", %{org: org} do
|
|
{:ok, _} = Gaiia.upsert_inventory_item(org.id, %{gaiia_id: "item-1", name: "Device A"})
|
|
|
|
results = Gaiia.search_inventory_items(org.id, "nonexistent")
|
|
assert results == []
|
|
end
|
|
|
|
test "does not return items from other orgs", %{org: org} do
|
|
other_user = Towerops.AccountsFixtures.user_fixture()
|
|
other_org = Towerops.OrganizationsFixtures.organization_fixture(other_user.id)
|
|
{:ok, _} = Gaiia.upsert_inventory_item(other_org.id, %{gaiia_id: "item-x", name: "ePMP 3000"})
|
|
|
|
results = Gaiia.search_inventory_items(org.id, "epmp")
|
|
assert results == []
|
|
end
|
|
end
|
|
|
|
describe "search_network_sites/2" do
|
|
test "finds network sites by name (case insensitive)", %{org: org} do
|
|
{:ok, _} = Gaiia.upsert_network_site(org.id, %{gaiia_id: "ns-1", name: "Tower North"})
|
|
{:ok, _} = Gaiia.upsert_network_site(org.id, %{gaiia_id: "ns-2", name: "Tower South"})
|
|
|
|
results = Gaiia.search_network_sites(org.id, "north")
|
|
assert length(results) == 1
|
|
assert hd(results).gaiia_id == "ns-1"
|
|
end
|
|
|
|
test "returns empty list when no match", %{org: org} do
|
|
{:ok, _} = Gaiia.upsert_network_site(org.id, %{gaiia_id: "ns-1", name: "Tower North"})
|
|
|
|
results = Gaiia.search_network_sites(org.id, "nothing")
|
|
assert results == []
|
|
end
|
|
|
|
test "does not return sites from other orgs", %{org: org} do
|
|
other_user = Towerops.AccountsFixtures.user_fixture()
|
|
other_org = Towerops.OrganizationsFixtures.organization_fixture(other_user.id)
|
|
{:ok, _} = Gaiia.upsert_network_site(other_org.id, %{gaiia_id: "ns-x", name: "Tower North"})
|
|
|
|
results = Gaiia.search_network_sites(org.id, "north")
|
|
assert results == []
|
|
end
|
|
end
|
|
end
|