towerops/test/towerops/organizations/subscription_limits_test.exs
2026-06-13 18:20:20 -05:00

326 lines
11 KiB
Elixir

defmodule Towerops.Organizations.SubscriptionLimitsTest do
use Towerops.DataCase
import Towerops.AccountsFixtures
alias Towerops.Devices
alias Towerops.Organizations
alias Towerops.Organizations.Organization
alias Towerops.Organizations.SubscriptionLimits
alias Towerops.Sites
doctest SubscriptionLimits
describe "device_limit/1" do
test "returns 10 for free plan" do
assert SubscriptionLimits.device_limit("free") == 10
end
test "returns unlimited for any non-free plan" do
# Future: when other plans are added, they will return :unlimited
assert SubscriptionLimits.device_limit("paid") == :unlimited
assert SubscriptionLimits.device_limit("premium") == :unlimited
assert SubscriptionLimits.device_limit("enterprise") == :unlimited
end
end
describe "effective_device_limit/1" do
test "returns default limit for free org without override" do
org = %Organization{subscription_plan: "free", custom_free_device_limit: nil}
assert SubscriptionLimits.effective_device_limit(org) == 10
end
test "returns custom limit for free org with override" do
org = %Organization{subscription_plan: "free", custom_free_device_limit: 50}
assert SubscriptionLimits.effective_device_limit(org) == 50
end
test "returns unlimited for paid org without override" do
org = %Organization{subscription_plan: "paid", custom_free_device_limit: nil}
assert SubscriptionLimits.effective_device_limit(org) == :unlimited
end
test "returns unlimited for paid org even with override" do
org = %Organization{subscription_plan: "paid", custom_free_device_limit: 50}
assert SubscriptionLimits.effective_device_limit(org) == :unlimited
end
end
describe "check_device_limit/1" do
setup do
user = user_fixture()
{:ok, organization} = Organizations.create_organization(%{name: "Test Org"}, user.id)
{:ok, site} = Sites.create_site(%{name: "Test Site", organization_id: organization.id})
%{organization: organization, site: site}
end
test "returns ok when organization has no devices", %{organization: organization} do
assert {:ok, :within_limit} = SubscriptionLimits.check_device_limit(organization)
end
test "returns ok when organization has devices under limit", %{
organization: organization,
site: site
} do
# Create 5 devices
for i <- 1..5 do
create_device(site.id, "Device #{i}", "192.168.1.#{i}")
end
organization = Repo.reload!(organization)
assert {:ok, :within_limit} = SubscriptionLimits.check_device_limit(organization)
end
test "returns error when organization is at device limit", %{
organization: organization,
site: site
} do
# Create 10 devices (the limit)
for i <- 1..10 do
create_device(site.id, "Device #{i}", "192.168.1.#{i}")
end
organization = Repo.reload!(organization)
assert {:error, :at_limit, 10, 10} = SubscriptionLimits.check_device_limit(organization)
end
test "returns error when organization is over device limit", %{
organization: organization,
site: site
} do
# Create 12 devices (over the limit)
for i <- 1..12 do
create_device(site.id, "Device #{i}", "192.168.1.#{i}")
end
organization = Repo.reload!(organization)
assert {:error, :at_limit, 12, 10} = SubscriptionLimits.check_device_limit(organization)
end
test "uses custom limit when set", %{organization: organization, site: site} do
# Set custom limit of 5
organization
|> Organization.billing_override_changeset(%{custom_free_device_limit: 5})
|> Repo.update!()
organization = Repo.get!(Organization, organization.id)
# Create 5 devices (at custom limit)
for i <- 1..5 do
create_device(site.id, "Device #{i}", "192.168.1.#{i}")
end
assert {:error, :at_limit, 5, 5} = SubscriptionLimits.check_device_limit(organization)
end
test "allows more devices with higher custom limit", %{organization: organization, site: site} do
# Set custom limit of 20
organization
|> Organization.billing_override_changeset(%{custom_free_device_limit: 20})
|> Repo.update!()
organization = Repo.get!(Organization, organization.id)
# Create 15 devices (under custom limit of 20)
for i <- 1..15 do
create_device(site.id, "Device #{i}", "192.168.1.#{i}")
end
assert {:ok, :within_limit} = SubscriptionLimits.check_device_limit(organization)
end
end
describe "device_quota/1" do
setup do
user = user_fixture()
{:ok, organization} = Organizations.create_organization(%{name: "Test Org"}, user.id)
{:ok, site} = Sites.create_site(%{name: "Test Site", organization_id: organization.id})
%{organization: organization, site: site}
end
test "returns {0, 10} for free org with no devices", %{organization: organization} do
assert {0, 10} = SubscriptionLimits.device_quota(organization)
end
test "returns {5, 10} for free org with 5 devices", %{organization: organization, site: site} do
for i <- 1..5 do
create_device(site.id, "Device #{i}", "192.168.1.#{i}")
end
organization = Repo.reload!(organization)
assert {5, 10} = SubscriptionLimits.device_quota(organization)
end
test "uses custom limit in quota", %{organization: organization} do
organization
|> Organization.billing_override_changeset(%{custom_free_device_limit: 25})
|> Repo.update!()
organization = Repo.get!(Organization, organization.id)
assert {0, 25} = SubscriptionLimits.device_quota(organization)
end
end
describe "can_create_free_organization?/1" do
test "returns true when user has no free organizations" do
user = user_fixture()
assert SubscriptionLimits.can_create_free_organization?(user.id) == true
end
test "returns false when user owns one free organization" do
user = user_fixture()
{:ok, _org} = Organizations.create_organization(%{name: "Free Org"}, user.id)
assert SubscriptionLimits.can_create_free_organization?(user.id) == false
end
test "returns true when user is member but not owner of free organization" do
owner = user_fixture()
member = user_fixture()
{:ok, organization} = Organizations.create_organization(%{name: "Free Org"}, owner.id)
# Add member to organization
{:ok, _membership} =
Organizations.create_membership(%{
user_id: member.id,
organization_id: organization.id,
role: :member
})
# Member can still create their own free org
assert SubscriptionLimits.can_create_free_organization?(member.id) == true
end
end
describe "count_user_owned_free_organizations/1" do
test "returns 0 when user has no organizations" do
user = user_fixture()
assert SubscriptionLimits.count_user_owned_free_organizations(user.id) == 0
end
test "returns 1 when user owns one free organization" do
user = user_fixture()
{:ok, _org} = Organizations.create_organization(%{name: "Free Org"}, user.id)
assert SubscriptionLimits.count_user_owned_free_organizations(user.id) == 1
end
test "returns 0 when user is member but not owner" do
owner = user_fixture()
member = user_fixture()
{:ok, organization} = Organizations.create_organization(%{name: "Free Org"}, owner.id)
{:ok, _membership} =
Organizations.create_membership(%{
user_id: member.id,
organization_id: organization.id,
role: :admin
})
assert SubscriptionLimits.count_user_owned_free_organizations(member.id) == 0
end
end
describe "count_organization_devices/1" do
setup do
user = user_fixture()
{:ok, organization} = Organizations.create_organization(%{name: "Test Org"}, user.id)
{:ok, site} = Sites.create_site(%{name: "Test Site", organization_id: organization.id})
%{organization: organization, site: site}
end
test "returns 0 for organization with no devices", %{organization: organization} do
assert SubscriptionLimits.count_organization_devices(organization.id) == 0
end
test "returns correct count for organization with devices", %{
organization: organization,
site: site
} do
for i <- 1..7 do
create_device(site.id, "Device #{i}", "192.168.1.#{i}")
end
assert SubscriptionLimits.count_organization_devices(organization.id) == 7
end
test "counts devices across multiple sites", %{organization: organization, site: site1} do
{:ok, site2} = Sites.create_site(%{name: "Site 2", organization_id: organization.id})
for i <- 1..3 do
create_device(site1.id, "Site1 Device #{i}", "192.168.1.#{i}")
end
for i <- 4..8 do
create_device(site2.id, "Site2 Device #{i}", "192.168.2.#{i}")
end
assert SubscriptionLimits.count_organization_devices(organization.id) == 8
end
test "counts devices without site assignment when sites are disabled", %{
organization: organization
} do
# Create devices directly assigned to organization (no site)
for i <- 1..5 do
create_device_without_site(organization.id, "Device #{i}", "192.168.1.#{i}")
end
assert SubscriptionLimits.count_organization_devices(organization.id) == 5
end
test "counts both site-assigned and unassigned devices", %{
organization: organization,
site: site
} do
# Create 3 devices assigned to site
for i <- 1..3 do
create_device(site.id, "Site Device #{i}", "192.168.1.#{i}")
end
# Create 2 devices without site assignment
for i <- 4..5 do
create_device_without_site(organization.id, "Org Device #{i}", "192.168.1.#{i}")
end
assert SubscriptionLimits.count_organization_devices(organization.id) == 5
end
end
# Helper functions
defp create_device(site_id, name, ip_address) do
site = Sites.get_site!(site_id)
{:ok, device} =
Devices.create_device(
%{
name: name,
ip_address: ip_address,
site_id: site_id,
organization_id: site.organization_id,
monitoring_enabled: false,
snmp_enabled: false
},
bypass_limits: true
)
device
end
defp create_device_without_site(organization_id, name, ip_address) do
{:ok, device} =
Devices.create_device(
%{
name: name,
ip_address: ip_address,
organization_id: organization_id,
monitoring_enabled: false,
snmp_enabled: false
},
bypass_limits: true
)
device
end
end