From 8382b5df6a5985b8edf66fcbbab44e40a294c44e Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Wed, 4 Feb 2026 15:05:42 -0600 Subject: [PATCH] make devices site optional and many test fix --- lib/towerops/devices/device.ex | 2 +- lib/towerops/organizations.ex | 18 + lib/towerops/organizations/organization.ex | 2 +- lib/towerops/sites/site.ex | 2 +- .../api/account_data_controller.ex | 4 +- .../controllers/api/v1/devices_controller.ex | 29 +- lib/towerops_web/live/dashboard_live.ex | 3 +- .../live/dashboard_live.html.heex | 94 +++-- lib/towerops_web/live/device_live/form.ex | 2 +- .../live/device_live/form.html.heex | 24 +- .../live/org/settings_live.html.heex | 7 + .../live/site_live/form.html.heex | 7 + ...48_revert_mikrotik_username_encryption.exs | 32 ++ priv/static/changelog.txt | 1 + test/integration/snmp_integration_test.exs | 1 + .../support/fixtures/agents_fixtures_test.exs | 3 +- test/support/fixtures/devices_fixtures.ex | 17 +- test/towerops/agents/stats_test.exs | 24 ++ test/towerops/agents_test.exs | 104 +++-- test/towerops/alerts_test.exs | 9 +- .../towerops/devices/backup_requests_test.exs | 1 + .../devices/device_firmware_history_test.exs | 1 + .../devices/mikrotik_backups_test.exs | 1 + test/towerops/devices_test.exs | 387 +++++++++++++----- test/towerops/equipment/event_logger_test.exs | 1 + test/towerops/monitoring/check_test.exs | 3 +- test/towerops/monitoring_test.exs | 3 +- .../subscription_limits_test.exs | 3 + test/towerops/organizations_test.exs | 24 +- test/towerops/sites_test.exs | 59 ++- test/towerops/snmp/discovery_test.exs | 40 +- test/towerops/snmp/ip_address_test.exs | 3 +- test/towerops/snmp/mac_address_test.exs | 3 +- test/towerops/snmp/memory_pool_test.exs | 3 +- .../snmp/neighbor_cleanup_worker_test.exs | 9 +- test/towerops/snmp/neighbor_test.exs | 3 +- test/towerops/snmp/physical_entity_test.exs | 3 +- test/towerops/snmp/processor_reading_test.exs | 3 +- test/towerops/snmp/state_sensor_test.exs | 3 +- test/towerops/snmp/storage_test.exs | 3 +- test/towerops/snmp/vlan_test.exs | 6 +- test/towerops/snmp_test.exs | 15 +- .../workers/agent_latency_evaluator_test.exs | 12 + .../workers/backup_summary_worker_test.exs | 3 +- .../workers/backup_timeout_worker_test.exs | 3 +- .../workers/device_monitor_worker_test.exs | 3 + .../workers/device_poller_worker_test.exs | 5 +- .../api/account_data_controller_test.exs | 7 +- test/towerops_web/live/alert_live_test.exs | 3 +- .../towerops_web/live/dashboard_live_test.exs | 21 +- .../live/device_live/form_test.exs | 69 +++- .../live/device_live_nested/show_test.exs | 3 +- .../live/graph_live/show_test.exs | 1 + test/towerops_web/live/my_data_live_test.exs | 1 + 54 files changed, 833 insertions(+), 260 deletions(-) create mode 100644 priv/repo/migrations/20260204193548_revert_mikrotik_username_encryption.exs diff --git a/lib/towerops/devices/device.ex b/lib/towerops/devices/device.ex index 15ae5f28..2b14542d 100644 --- a/lib/towerops/devices/device.ex +++ b/lib/towerops/devices/device.ex @@ -51,7 +51,7 @@ defmodule Towerops.Devices.Device do field :snmpv3_credential_source, :string, default: "site" # MikroTik API credentials (device-level overrides) - field :mikrotik_username, Binary + field :mikrotik_username, :string field :mikrotik_password, Binary field :mikrotik_port, :integer field :mikrotik_ssh_port, :integer diff --git a/lib/towerops/organizations.ex b/lib/towerops/organizations.ex index 0a1f68cf..e663a6be 100644 --- a/lib/towerops/organizations.ex +++ b/lib/towerops/organizations.ex @@ -13,6 +13,7 @@ defmodule Towerops.Organizations do alias Towerops.Organizations.Policy alias Towerops.Organizations.SubscriptionLimits alias Towerops.Repo + alias Towerops.Sites.Site ## Organizations @@ -102,11 +103,24 @@ defmodule Towerops.Organizations do role: :owner }) end) + |> Ecto.Multi.run(:set_default, fn _repo, %{organization: organization} -> + # Set this as the user's default organization if they don't have one + user = Towerops.Accounts.get_user!(user_id) + + if user.default_organization_id == nil do + user + |> Ecto.Changeset.change(default_organization_id: organization.id) + |> Repo.update() + else + {:ok, user} + end + end) case Repo.transaction(multi) do {:ok, %{organization: organization}} -> {:ok, organization} {:error, :organization, changeset, _} -> {:error, changeset} {:error, :membership, changeset, _} -> {:error, changeset} + {:error, :set_default, changeset, _} -> {:error, changeset} end end @@ -415,6 +429,7 @@ defmodule Towerops.Organizations do Returns the number of device records updated. """ def clear_all_site_assignments(organization_id) do + # Clear site assignments from all devices Repo.update_all( from(d in Device, where: d.organization_id == ^organization_id), set: [ @@ -422,6 +437,9 @@ defmodule Towerops.Organizations do updated_at: DateTime.truncate(DateTime.utc_now(), :second) ] ) + + # Delete all sites for the organization + Repo.delete_all(from(s in Site, where: s.organization_id == ^organization_id)) end ## Authorization diff --git a/lib/towerops/organizations/organization.ex b/lib/towerops/organizations/organization.ex index ab01b139..3dd25342 100644 --- a/lib/towerops/organizations/organization.ex +++ b/lib/towerops/organizations/organization.ex @@ -41,7 +41,7 @@ defmodule Towerops.Organizations.Organization do field :snmpv3_priv_password, Binary # MikroTik API credentials (organization-level defaults cascade to site → device) - field :mikrotik_username, Binary + field :mikrotik_username, :string field :mikrotik_password, Binary field :mikrotik_port, :integer, default: 8729 field :mikrotik_ssh_port, :integer, default: 22 diff --git a/lib/towerops/sites/site.ex b/lib/towerops/sites/site.ex index d973c50f..e97c71c2 100644 --- a/lib/towerops/sites/site.ex +++ b/lib/towerops/sites/site.ex @@ -37,7 +37,7 @@ defmodule Towerops.Sites.Site do field :snmpv3_priv_password, Binary # MikroTik API credentials (overrides organization default) - field :mikrotik_username, Binary + field :mikrotik_username, :string field :mikrotik_password, Binary field :mikrotik_port, :integer field :mikrotik_ssh_port, :integer diff --git a/lib/towerops_web/controllers/api/account_data_controller.ex b/lib/towerops_web/controllers/api/account_data_controller.ex index 4fa2431b..6e9eaa90 100644 --- a/lib/towerops_web/controllers/api/account_data_controller.ex +++ b/lib/towerops_web/controllers/api/account_data_controller.ex @@ -98,8 +98,8 @@ defmodule ToweropsWeb.Api.AccountDataController do snmp_enabled: device.snmp_enabled, status: device.status, organization: %{ - id: device.site.organization_id, - name: device.site.organization.name + id: device.organization_id, + name: device.organization.name }, site: %{ id: device.site_id, diff --git a/lib/towerops_web/controllers/api/v1/devices_controller.ex b/lib/towerops_web/controllers/api/v1/devices_controller.ex index dd85a1dc..76938727 100644 --- a/lib/towerops_web/controllers/api/v1/devices_controller.ex +++ b/lib/towerops_web/controllers/api/v1/devices_controller.ex @@ -47,20 +47,28 @@ defmodule ToweropsWeb.Api.V1.DevicesController do @doc """ POST /api/v1/devices - Creates a new device. + Creates a new device. The device can be assigned to a site or directly to the organization. Request body: { "device": { - "site_id": "uuid", + "site_id": "uuid", # optional - if not provided, device is assigned directly to organization + "organization_id": "uuid", # optional - defaults to authenticated organization if not provided "name": "Core Router", "ip_address": "192.168.1.1", "description": "Main router", # optional "monitoring_enabled": true, # optional, default true "snmp_enabled": true, # optional, default true - "snmp_version": "2c", # optional, default "2c" + "snmp_version": "2c", # optional, default "2c" (can be "1", "2c", or "3") "snmp_community": "public", # optional, inherits from site/org if not set - "snmp_port": 161 # optional, default 161 + "snmp_port": 161, # optional, default 161 + # SNMPv3 fields (only used when snmp_version is "3"): + "snmpv3_security_level": "authPriv", # optional, one of: noAuthNoPriv, authNoPriv, authPriv + "snmpv3_username": "snmpuser", # optional + "snmpv3_auth_protocol": "SHA-256", # optional, one of: MD5, SHA, SHA-224, SHA-256, SHA-384, SHA-512 + "snmpv3_auth_password": "authpass", # optional + "snmpv3_priv_protocol": "AES", # optional, one of: DES, AES, AES-192, AES-256 + "snmpv3_priv_password": "privpass" # optional } } @@ -70,6 +78,7 @@ defmodule ToweropsWeb.Api.V1.DevicesController do "name": "Core Router", "ip_address": "192.168.1.1", "site_id": "uuid", + "organization_id": "uuid", "monitoring_enabled": true, "snmp_enabled": true, "inserted_at": "2026-01-15T19:44:25Z" @@ -79,6 +88,14 @@ defmodule ToweropsWeb.Api.V1.DevicesController do organization_id = conn.assigns.current_organization_id current_user = conn.assigns[:current_user] + # Add organization_id to params if not provided + device_params = + if Map.has_key?(device_params, "organization_id") do + device_params + else + Map.put(device_params, "organization_id", organization_id) + end + # Verify site belongs to organization if site_id is provided case verify_site_access(device_params["site_id"], organization_id) do :ok -> @@ -248,7 +265,7 @@ defmodule ToweropsWeb.Api.V1.DevicesController do # Private helpers - defp verify_site_access(nil, _organization_id), do: {:error, "site_id is required"} + defp verify_site_access(nil, _organization_id), do: :ok defp verify_site_access(site_id, organization_id) do site = Towerops.Sites.get_site!(site_id) @@ -269,6 +286,7 @@ defmodule ToweropsWeb.Api.V1.DevicesController do name: device.name, ip_address: device.ip_address, site_id: device.site_id, + organization_id: device.organization_id, monitoring_enabled: device.monitoring_enabled, snmp_enabled: device.snmp_enabled, inserted_at: device.inserted_at @@ -281,6 +299,7 @@ defmodule ToweropsWeb.Api.V1.DevicesController do name: device.name, ip_address: device.ip_address, site_id: device.site_id, + organization_id: device.organization_id, description: device.description, monitoring_enabled: device.monitoring_enabled, check_interval_seconds: device.check_interval_seconds, diff --git a/lib/towerops_web/live/dashboard_live.ex b/lib/towerops_web/live/dashboard_live.ex index c9351f71..4c071edb 100644 --- a/lib/towerops_web/live/dashboard_live.ex +++ b/lib/towerops_web/live/dashboard_live.ex @@ -34,8 +34,9 @@ defmodule ToweropsWeb.DashboardLive do end defp load_dashboard_data(socket, organization_id) do + organization = socket.assigns.current_scope.organization active_alerts = Alerts.list_organization_active_alerts(organization_id) - sites_count = length(Sites.list_organization_sites(organization_id)) + sites_count = if organization.use_sites, do: length(Sites.list_organization_sites(organization_id)), else: 0 devices = Devices.list_organization_devices(organization_id) devices_by_status = diff --git a/lib/towerops_web/live/dashboard_live.html.heex b/lib/towerops_web/live/dashboard_live.html.heex index c021d608..d4f21380 100644 --- a/lib/towerops_web/live/dashboard_live.html.heex +++ b/lib/towerops_web/live/dashboard_live.html.heex @@ -8,7 +8,7 @@ <:subtitle>Welcome to {@current_scope.organization.name} - <%= if @sites_count == 0 do %> + <%= if @device_count == 0 do %>
<.icon name="hero-light-bulb" @@ -22,31 +22,45 @@

-
-
- 1 + <%= if @current_scope.organization.use_sites do %> +
+
+ 1 +
+
+

Create a Site

+

+ Sites represent your physical locations (offices, data centers, towers, etc.) +

+
-
-

Create a Site

-

- Sites represent your physical locations (offices, data centers, towers, etc.) -

+
+
+ 2 +
+
+

Add Devices

+

+ Add network devices (routers, switches, servers) to your sites +

+
-
+ <% else %> +
+
+ 1 +
+
+

Add Devices

+

+ Add network devices (routers, switches, servers) to monitor +

+
+
+ <% end %>
- 2 -
-
-

Add Device

-

- Add network devices (routers, switches, servers) to your sites -

-
-
-
-
- 3 + {if @current_scope.organization.use_sites, do: "3", else: "2"}

@@ -60,21 +74,33 @@

- <.button navigate={~p"/sites/new"} variant="primary"> - <.icon name="hero-plus" class="h-5 w-5" /> Create Your First Site - + <%= if @current_scope.organization.use_sites do %> + <.button navigate={~p"/sites/new"} variant="primary"> + <.icon name="hero-plus" class="h-5 w-5" /> Create Your First Site + + <% else %> + <.button navigate={~p"/devices/new"} variant="primary"> + <.icon name="hero-plus" class="h-5 w-5" /> Add Your First Device + + <% end %>
<% else %> -
- <.link - navigate={~p"/sites"} - class="rounded-lg border border-gray-200 bg-white p-6 shadow-sm transition-shadow hover:shadow-md dark:border-white/10 dark:bg-gray-800/50" - > -

Sites

-

{@sites_count}

-

Total sites

- +
+ <%= if @current_scope.organization.use_sites do %> + <.link + navigate={~p"/sites"} + class="rounded-lg border border-gray-200 bg-white p-6 shadow-sm transition-shadow hover:shadow-md dark:border-white/10 dark:bg-gray-800/50" + > +

Sites

+

{@sites_count}

+

Total sites

+ + <% end %> <.link navigate={~p"/devices"} diff --git a/lib/towerops_web/live/device_live/form.ex b/lib/towerops_web/live/device_live/form.ex index 5838a888..d74b3d45 100644 --- a/lib/towerops_web/live/device_live/form.ex +++ b/lib/towerops_web/live/device_live/form.ex @@ -153,7 +153,7 @@ defmodule ToweropsWeb.DeviceLive.Form do mikrotik_config = Devices.get_mikrotik_config(device) # Check if device is MikroTik (based on SNMP discovery) - device_with_snmp = Towerops.Repo.preload(device, :snmp_device) + device_with_snmp = Towerops.Repo.preload(device, :snmp_device, force: true) is_mikrotik = mikrotik_device?(device_with_snmp) # Determine monitoring mode based on current snmp_enabled value diff --git a/lib/towerops_web/live/device_live/form.html.heex b/lib/towerops_web/live/device_live/form.html.heex index 2606d967..33e08239 100644 --- a/lib/towerops_web/live/device_live/form.html.heex +++ b/lib/towerops_web/live/device_live/form.html.heex @@ -588,9 +588,9 @@
- - - <%= if @live_action == :edit and @is_mikrotik_device and @current_scope.user.is_superuser do %> + + <%= if @live_action == :edit and @is_mikrotik_device do %> +

- Configure MikroTik RouterOS API access. Works alongside SNMP for enhanced device management. + Configure MikroTik RouterOS API access. Works alongside SNMP for enhanced device management. SSH is used for device backups.

+
+

+ <.icon name="hero-beaker" class="h-4 w-4 inline" /> + Experimental Feature: + MikroTik API integration is under active development. +

+
@@ -671,15 +678,6 @@

- <% else %> -
-
-

- ⚠️ Security Warning: - Plain API (port 8728) sends credentials unencrypted. Use SSL (port 8729) whenever possible. -

-
-
<% end %> <% end %>
diff --git a/lib/towerops_web/live/org/settings_live.html.heex b/lib/towerops_web/live/org/settings_live.html.heex index 8b7e60c4..8e88dca6 100644 --- a/lib/towerops_web/live/org/settings_live.html.heex +++ b/lib/towerops_web/live/org/settings_live.html.heex @@ -239,6 +239,13 @@

Set default MikroTik RouterOS API credentials for all devices in this organization. Only applies to devices detected as MikroTik.

+
+

+ <.icon name="hero-beaker" class="h-4 w-4 inline" /> + Experimental Feature: + MikroTik API integration is under active development. +

+

<.icon name="hero-information-circle" class="h-4 w-4 inline" /> Hierarchy: Device > Site > Organization diff --git a/lib/towerops_web/live/site_live/form.html.heex b/lib/towerops_web/live/site_live/form.html.heex index 675a89ab..21f6ccdc 100644 --- a/lib/towerops_web/live/site_live/form.html.heex +++ b/lib/towerops_web/live/site_live/form.html.heex @@ -270,6 +270,13 @@

Override organization MikroTik API defaults for all devices at this site. Leave blank to inherit from organization. Only applies to MikroTik devices.

+
+

+ <.icon name="hero-beaker" class="h-4 w-4 inline" /> + Experimental Feature: + MikroTik API integration is under active development. +

+
<.input field={@form[:mikrotik_enabled]} diff --git a/priv/repo/migrations/20260204193548_revert_mikrotik_username_encryption.exs b/priv/repo/migrations/20260204193548_revert_mikrotik_username_encryption.exs new file mode 100644 index 00000000..2f2e6c12 --- /dev/null +++ b/priv/repo/migrations/20260204193548_revert_mikrotik_username_encryption.exs @@ -0,0 +1,32 @@ +defmodule Towerops.Repo.Migrations.RevertMikrotikUsernameEncryption do + use Ecto.Migration + + def up do + # Revert mikrotik_username from encrypted binary to plaintext string + # Usernames are not sensitive enough to require encryption (passwords still encrypted) + # This fixes form display issues with encrypted binary fields + + # Organizations + execute "ALTER TABLE organizations ALTER COLUMN mikrotik_username TYPE varchar USING NULL" + + # Sites + execute "ALTER TABLE sites ALTER COLUMN mikrotik_username TYPE varchar USING NULL" + + # Devices + execute "ALTER TABLE devices ALTER COLUMN mikrotik_username TYPE varchar USING NULL" + end + + def down do + # Change back to binary for encryption + # Note: This will clear any existing usernames + + # Organizations + execute "ALTER TABLE organizations ALTER COLUMN mikrotik_username TYPE bytea USING NULL" + + # Sites + execute "ALTER TABLE sites ALTER COLUMN mikrotik_username TYPE bytea USING NULL" + + # Devices + execute "ALTER TABLE devices ALTER COLUMN mikrotik_username TYPE bytea USING NULL" + end +end diff --git a/priv/static/changelog.txt b/priv/static/changelog.txt index 45431fa7..c2a864f2 100644 --- a/priv/static/changelog.txt +++ b/priv/static/changelog.txt @@ -5,6 +5,7 @@ Devices Tested & Working 2026-02-04 * Feature: SNMP v3 support +* Sites are now optional and not enabled by default 2026-02-03 * More tests diff --git a/test/integration/snmp_integration_test.exs b/test/integration/snmp_integration_test.exs index 6d091750..46cca668 100644 --- a/test/integration/snmp_integration_test.exs +++ b/test/integration/snmp_integration_test.exs @@ -122,6 +122,7 @@ defmodule Towerops.Integration.SnmpIntegrationTest do name: "SNMP Router", ip_address: "192.0.2.1", site_id: site.id, + organization_id: organization.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "public", diff --git a/test/support/fixtures/agents_fixtures_test.exs b/test/support/fixtures/agents_fixtures_test.exs index 3cce890d..018dc093 100644 --- a/test/support/fixtures/agents_fixtures_test.exs +++ b/test/support/fixtures/agents_fixtures_test.exs @@ -52,7 +52,8 @@ defmodule Towerops.AgentsFixturesTest do Towerops.Devices.create_device(%{ name: "Test Equipment", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) {:ok, agent_token, _token_string} = agent_token_fixture(organization.id) diff --git a/test/support/fixtures/devices_fixtures.ex b/test/support/fixtures/devices_fixtures.ex index 1134fa26..f9293e34 100644 --- a/test/support/fixtures/devices_fixtures.ex +++ b/test/support/fixtures/devices_fixtures.ex @@ -11,12 +11,10 @@ defmodule Towerops.DevicesFixtures do def device_fixture(attrs \\ %{}) do # Ensure organization and site exist organization = - attrs[:organization] || Map.get(attrs, "organization") || - Towerops.OrganizationsFixtures.organization_fixture() + attrs[:organization] || Map.get(attrs, "organization") || create_organization() site = - attrs[:site] || Map.get(attrs, "site") || - Towerops.OrganizationsFixtures.site_fixture(%{organization_id: organization.id}) + attrs[:site] || Map.get(attrs, "site") || create_site(organization) # Default device attributes default_attrs = %{ @@ -43,4 +41,15 @@ defmodule Towerops.DevicesFixtures do defp to_atom_key(key) when is_atom(key), do: key defp to_atom_key(key) when is_binary(key), do: String.to_existing_atom(key) + + defp create_organization do + user = Towerops.AccountsFixtures.user_fixture() + {:ok, organization} = Towerops.Organizations.create_organization(%{name: "Test Org"}, user.id) + organization + end + + defp create_site(organization) do + {:ok, site} = Towerops.Sites.create_site(%{name: "Test Site", organization_id: organization.id}) + site + end end diff --git a/test/towerops/agents/stats_test.exs b/test/towerops/agents/stats_test.exs index e6482834..85e07f95 100644 --- a/test/towerops/agents/stats_test.exs +++ b/test/towerops/agents/stats_test.exs @@ -81,6 +81,7 @@ defmodule Towerops.Agents.StatsTest do name: "Test Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: org.id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c" @@ -122,6 +123,7 @@ defmodule Towerops.Agents.StatsTest do name: "Router 1", ip_address: "192.168.1.1", site_id: site.id, + organization_id: org.id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c" @@ -135,6 +137,7 @@ defmodule Towerops.Agents.StatsTest do name: "Router 2", ip_address: "192.168.1.2", site_id: site.id, + organization_id: org.id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c" @@ -219,6 +222,7 @@ defmodule Towerops.Agents.StatsTest do name: "Router #{i}", ip_address: "192.168.1.#{i}", site_id: site.id, + organization_id: org.id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c" @@ -249,6 +253,7 @@ defmodule Towerops.Agents.StatsTest do name: "Router #{i}", ip_address: "192.168.1.#{i}", site_id: site.id, + organization_id: org.id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c" @@ -279,6 +284,7 @@ defmodule Towerops.Agents.StatsTest do name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: org.id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c", @@ -302,6 +308,7 @@ defmodule Towerops.Agents.StatsTest do name: "Unmonitored Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: org.id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c", @@ -328,6 +335,7 @@ defmodule Towerops.Agents.StatsTest do name: "SNMP Disabled", ip_address: "192.168.1.1", site_id: site.id, + organization_id: org.id, snmp_enabled: false, monitoring_enabled: true }) @@ -347,6 +355,7 @@ defmodule Towerops.Agents.StatsTest do name: "Monitoring Disabled", ip_address: "192.168.1.1", site_id: site.id, + organization_id: org.id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c", @@ -385,6 +394,7 @@ defmodule Towerops.Agents.StatsTest do name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: org.id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c" @@ -466,6 +476,7 @@ defmodule Towerops.Agents.StatsTest do name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: org.id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c" @@ -488,6 +499,7 @@ defmodule Towerops.Agents.StatsTest do name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: org.id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c" @@ -551,6 +563,7 @@ defmodule Towerops.Agents.StatsTest do name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: org.id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c" @@ -598,6 +611,7 @@ defmodule Towerops.Agents.StatsTest do name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: org.id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c" @@ -642,6 +656,7 @@ defmodule Towerops.Agents.StatsTest do name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: org.id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c" @@ -701,6 +716,7 @@ defmodule Towerops.Agents.StatsTest do name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: org.id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c" @@ -752,6 +768,7 @@ defmodule Towerops.Agents.StatsTest do name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: org.id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c" @@ -777,6 +794,7 @@ defmodule Towerops.Agents.StatsTest do name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: org.id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c" @@ -818,6 +836,7 @@ defmodule Towerops.Agents.StatsTest do name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: org.id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c" @@ -867,6 +886,7 @@ defmodule Towerops.Agents.StatsTest do name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: org.id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c" @@ -918,6 +938,7 @@ defmodule Towerops.Agents.StatsTest do name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: org.id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c" @@ -968,6 +989,7 @@ defmodule Towerops.Agents.StatsTest do name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: org.id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c" @@ -1011,6 +1033,7 @@ defmodule Towerops.Agents.StatsTest do name: "Non-SNMP Device", ip_address: "192.168.1.1", site_id: site.id, + organization_id: org.id, snmp_enabled: false }) @@ -1042,6 +1065,7 @@ defmodule Towerops.Agents.StatsTest do name: "Unassigned Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: org.id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c" diff --git a/test/towerops/agents_test.exs b/test/towerops/agents_test.exs index 2f6b8bd6..5844750e 100644 --- a/test/towerops/agents_test.exs +++ b/test/towerops/agents_test.exs @@ -126,7 +126,7 @@ defmodule Towerops.AgentsTest do %{site: site, agent_token: agent_token} end - test "deletes agent token from database", %{agent_token: agent_token} do + test "deletes agent token from database", %{agent_token: agent_token, organization: _organization} do assert {:ok, _} = Agents.delete_agent_token(agent_token.id) assert_raise Ecto.NoResultsError, fn -> @@ -136,20 +136,23 @@ defmodule Towerops.AgentsTest do test "removes all direct device assignments", %{ site: site, - agent_token: agent_token + agent_token: agent_token, + organization: organization } do {:ok, device1} = Towerops.Devices.create_device(%{ name: "Device 1", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) {:ok, device2} = Towerops.Devices.create_device(%{ name: "Device 2", ip_address: "192.168.1.2", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) # Assign both devices to the agent @@ -181,7 +184,8 @@ defmodule Towerops.AgentsTest do Towerops.Devices.create_device(%{ name: "Device", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: org.id }) # Directly assign device to agent_to_delete (overriding site default) @@ -215,7 +219,8 @@ defmodule Towerops.AgentsTest do Towerops.Devices.create_device(%{ name: "Device", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: org.id }) # Directly assign device to agent_to_delete (overriding org default) @@ -234,6 +239,7 @@ defmodule Towerops.AgentsTest do end test "devices have no agent when no fallback exists (cloud polling)", %{ + organization: organization, site: site, agent_token: agent_token } do @@ -241,7 +247,8 @@ defmodule Towerops.AgentsTest do Towerops.Devices.create_device(%{ name: "Device", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) # Directly assign device to agent (no site or org defaults) @@ -277,7 +284,8 @@ defmodule Towerops.AgentsTest do Towerops.Devices.create_device(%{ name: "Device", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: org.id }) # Device should use site agent @@ -309,7 +317,8 @@ defmodule Towerops.AgentsTest do Towerops.Devices.create_device(%{ name: "Device", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: org.id }) # Device should use org default @@ -356,7 +365,8 @@ defmodule Towerops.AgentsTest do Towerops.Devices.create_device(%{ name: "Test Equipment", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: org.id }) %{site: site, device: device} @@ -399,7 +409,8 @@ defmodule Towerops.AgentsTest do Towerops.Devices.create_device(%{ name: "Test Equipment", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: org.id }) {:ok, agent_token, _token} = Agents.create_agent_token(org.id, "Test Agent") @@ -407,7 +418,7 @@ defmodule Towerops.AgentsTest do %{site: site, device: device, agent_token: agent_token} end - test "removes equipment assignment", %{agent_token: agent_token, device: device} do + test "removes equipment assignment", %{agent_token: agent_token, device: device, organization: _organization} do {:ok, _assignment} = Agents.assign_device_to_agent(agent_token.id, device.id) {1, _} = Agents.unassign_device(device.id) @@ -465,7 +476,8 @@ defmodule Towerops.AgentsTest do Towerops.Devices.create_device(%{ name: "Test Equipment", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: org.id }) {:ok, agent_token, _token} = Agents.create_agent_token(org.id, "Test Agent") @@ -483,7 +495,7 @@ defmodule Towerops.AgentsTest do assert retrieved_assignment.id == assignment.id end - test "returns nil when equipment is not assigned", %{device: device} do + test "returns nil when equipment is not assigned", %{device: device, organization: _organization} do assert Agents.get_device_assignment(device.id) == nil end end @@ -500,7 +512,8 @@ defmodule Towerops.AgentsTest do Towerops.Devices.create_device(%{ name: "Test Equipment", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: org.id }) {:ok, agent_token1, _} = Agents.create_agent_token(org.id, "Agent 1") @@ -562,21 +575,24 @@ defmodule Towerops.AgentsTest do Towerops.Devices.create_device(%{ name: "Test Equipment 1", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: org.id }) {:ok, device2} = Towerops.Devices.create_device(%{ name: "Test Equipment 2", ip_address: "192.168.1.2", - site_id: site.id + site_id: site.id, + organization_id: org.id }) {:ok, device3} = Towerops.Devices.create_device(%{ name: "Test Equipment 3", ip_address: "192.168.1.3", - site_id: site.id + site_id: site.id, + organization_id: org.id }) %{site: site, device1: device1, device2: device2, device3: device3} @@ -621,7 +637,8 @@ defmodule Towerops.AgentsTest do Towerops.Devices.create_device(%{ name: "Test Equipment", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: org.id }) %{ @@ -686,7 +703,7 @@ defmodule Towerops.AgentsTest do assert Agents.get_effective_agent_token(device) == agent1.id end - test "returns nil when no agent assigned at any level", %{device: device} do + test "returns nil when no agent assigned at any level", %{device: device, organization: _organization} do # No assignments at any level device = Repo.preload(device, site: [organization: :default_agent_token]) @@ -714,7 +731,8 @@ defmodule Towerops.AgentsTest do Towerops.Devices.create_device(%{ name: "Test Equipment 2", ip_address: "192.168.2.1", - site_id: site.id + site_id: site.id, + organization_id: org.id }) device = Repo.preload(device, site: [organization: :default_agent_token]) @@ -764,7 +782,8 @@ defmodule Towerops.AgentsTest do Towerops.Devices.create_device(%{ name: "Test Equipment", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: org.id }) %{ @@ -814,7 +833,7 @@ defmodule Towerops.AgentsTest do assert agent_id == agent1.id end - test "returns none source when no assignment", %{device: device} do + test "returns none source when no assignment", %{device: device, organization: _organization} do device = Repo.preload(device, site: [organization: :default_agent_token]) assert {nil, :none} = Agents.get_effective_agent_token_with_source(device) @@ -839,7 +858,8 @@ defmodule Towerops.AgentsTest do Towerops.Devices.create_device(%{ name: "Test Equipment 3", ip_address: "192.168.3.1", - site_id: site.id + site_id: site.id, + organization_id: org.id }) device = Repo.preload(device, site: [organization: :default_agent_token]) @@ -864,21 +884,24 @@ defmodule Towerops.AgentsTest do Towerops.Devices.create_device(%{ name: "Test Equipment 1", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: org.id }) {:ok, device2} = Towerops.Devices.create_device(%{ name: "Test Equipment 2", ip_address: "192.168.1.2", - site_id: site.id + site_id: site.id, + organization_id: org.id }) {:ok, device3} = Towerops.Devices.create_device(%{ name: "Test Equipment 3", ip_address: "192.168.1.3", - site_id: site.id + site_id: site.id, + organization_id: org.id }) %{site: site, device1: device1, device2: device2, device3: device3} @@ -948,6 +971,7 @@ defmodule Towerops.AgentsTest do end test "returns device with direct agent assignment", %{ + organization: organization, agent1: agent1, agent2: agent2, site1: site1 @@ -957,6 +981,7 @@ defmodule Towerops.AgentsTest do name: "Equipment 1", ip_address: "192.168.1.1", site_id: site1.id, + organization_id: organization.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "public" @@ -967,6 +992,7 @@ defmodule Towerops.AgentsTest do name: "Equipment 2", ip_address: "192.168.1.2", site_id: site1.id, + organization_id: organization.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "public" @@ -988,6 +1014,7 @@ defmodule Towerops.AgentsTest do end test "returns device inheriting from site agent", %{ + organization: organization, agent1: agent1, agent2: agent2, site1: site1 @@ -1000,6 +1027,7 @@ defmodule Towerops.AgentsTest do name: "Equipment 1", ip_address: "192.168.1.1", site_id: site1.id, + organization_id: organization.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "public" @@ -1010,6 +1038,7 @@ defmodule Towerops.AgentsTest do name: "Equipment 2", ip_address: "192.168.1.2", site_id: site1.id, + organization_id: organization.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "public" @@ -1041,6 +1070,7 @@ defmodule Towerops.AgentsTest do name: "Equipment 1", ip_address: "192.168.1.1", site_id: site1.id, + organization_id: org.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "public" @@ -1051,6 +1081,7 @@ defmodule Towerops.AgentsTest do name: "Equipment 2", ip_address: "192.168.1.2", site_id: site1.id, + organization_id: org.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "public" @@ -1085,6 +1116,7 @@ defmodule Towerops.AgentsTest do name: "Equipment 1", ip_address: "192.168.1.1", site_id: site1.id, + organization_id: org.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "public" @@ -1120,6 +1152,7 @@ defmodule Towerops.AgentsTest do name: "Equipment 1", ip_address: "192.168.1.1", site_id: site1.id, + organization_id: org.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "public" @@ -1135,6 +1168,7 @@ defmodule Towerops.AgentsTest do end test "only returns SNMP-enabled devices", %{ + organization: organization, agent1: agent1, site1: site1 } do @@ -1144,6 +1178,7 @@ defmodule Towerops.AgentsTest do name: "Equipment 1", ip_address: "192.168.1.1", site_id: site1.id, + organization_id: organization.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "public" @@ -1155,6 +1190,7 @@ defmodule Towerops.AgentsTest do name: "Equipment 2", ip_address: "192.168.1.2", site_id: site1.id, + organization_id: organization.id, snmp_enabled: false }) @@ -1189,6 +1225,7 @@ defmodule Towerops.AgentsTest do name: "Equipment 1", ip_address: "192.168.1.1", site_id: site1.id, + organization_id: org.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "public" @@ -1200,6 +1237,7 @@ defmodule Towerops.AgentsTest do name: "Equipment 2", ip_address: "192.168.1.2", site_id: site2.id, + organization_id: org.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "public" @@ -1217,6 +1255,7 @@ defmodule Towerops.AgentsTest do end test "preloads necessary associations for API response", %{ + organization: organization, agent1: agent1, site1: site1 } do @@ -1225,6 +1264,7 @@ defmodule Towerops.AgentsTest do name: "Equipment 1", ip_address: "192.168.1.1", site_id: site1.id, + organization_id: organization.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "public" @@ -1345,6 +1385,8 @@ defmodule Towerops.AgentsTest do end test "cloud poller can be assigned to devices across organizations", %{ + org1: org1, + org2: org2, site1: site1, site2: site2, cloud_poller: cloud_poller @@ -1355,6 +1397,7 @@ defmodule Towerops.AgentsTest do name: "Device 1", ip_address: "192.168.1.1", site_id: site1.id, + organization_id: org1.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "public" @@ -1365,6 +1408,7 @@ defmodule Towerops.AgentsTest do name: "Device 2", ip_address: "192.168.2.1", site_id: site2.id, + organization_id: org2.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "public" @@ -1405,6 +1449,7 @@ defmodule Towerops.AgentsTest do name: "Device 1", ip_address: "192.168.1.1", site_id: site1.id, + organization_id: org1.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "public" @@ -1415,6 +1460,7 @@ defmodule Towerops.AgentsTest do name: "Device 2", ip_address: "192.168.2.1", site_id: site2.id, + organization_id: org2.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "public" @@ -1428,6 +1474,8 @@ defmodule Towerops.AgentsTest do end test "cloud poller can be site default for sites in different orgs", %{ + org1: org1, + org2: org2, site1: site1, site2: site2, cloud_poller: cloud_poller @@ -1442,6 +1490,7 @@ defmodule Towerops.AgentsTest do name: "Device 1", ip_address: "192.168.1.1", site_id: site1.id, + organization_id: org1.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "public" @@ -1452,6 +1501,7 @@ defmodule Towerops.AgentsTest do name: "Device 2", ip_address: "192.168.2.1", site_id: site2.id, + organization_id: org2.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "public" diff --git a/test/towerops/alerts_test.exs b/test/towerops/alerts_test.exs index 4498e3cd..5c5aa5b0 100644 --- a/test/towerops/alerts_test.exs +++ b/test/towerops/alerts_test.exs @@ -22,7 +22,8 @@ defmodule Towerops.AlertsTest do Towerops.Devices.create_device(%{ name: "Router 1", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) %{device: device, organization: organization, user: user} @@ -395,14 +396,16 @@ defmodule Towerops.AlertsTest do Towerops.Devices.create_device(%{ name: "Device 1", ip_address: "192.168.1.1", - site_id: site1.id + site_id: site1.id, + organization_id: org1.id }) {:ok, device2} = Towerops.Devices.create_device(%{ name: "Device 2", ip_address: "192.168.1.2", - site_id: site2.id + site_id: site2.id, + organization_id: org2.id }) %{org1: org1, org2: org2, device1: device1, device2: device2} diff --git a/test/towerops/devices/backup_requests_test.exs b/test/towerops/devices/backup_requests_test.exs index f37d0bc2..55d940da 100644 --- a/test/towerops/devices/backup_requests_test.exs +++ b/test/towerops/devices/backup_requests_test.exs @@ -216,6 +216,7 @@ defmodule Towerops.Devices.BackupRequestsTest do name: "Test Device", ip_address: "192.168.1.1", site_id: site.id, + organization_id: organization.id, monitoring_enabled: false, snmp_enabled: false }, diff --git a/test/towerops/devices/device_firmware_history_test.exs b/test/towerops/devices/device_firmware_history_test.exs index 142f378c..e76eeccf 100644 --- a/test/towerops/devices/device_firmware_history_test.exs +++ b/test/towerops/devices/device_firmware_history_test.exs @@ -232,6 +232,7 @@ defmodule Towerops.Devices.DeviceFirmwareHistoryTest do name: "Test Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: organization.id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c" diff --git a/test/towerops/devices/mikrotik_backups_test.exs b/test/towerops/devices/mikrotik_backups_test.exs index a74cb641..53b9105a 100644 --- a/test/towerops/devices/mikrotik_backups_test.exs +++ b/test/towerops/devices/mikrotik_backups_test.exs @@ -325,6 +325,7 @@ defmodule Towerops.Devices.MikrotikBackupsTest do name: "Test Device", ip_address: "192.168.1.1", site_id: site.id, + organization_id: organization.id, monitoring_enabled: false, snmp_enabled: false }, diff --git a/test/towerops/devices_test.exs b/test/towerops/devices_test.exs index 7f773349..83bc56c9 100644 --- a/test/towerops/devices_test.exs +++ b/test/towerops/devices_test.exs @@ -38,8 +38,10 @@ defmodule Towerops.EquipmentTest do } @invalid_attrs %{name: nil, ip_address: nil} - test "list_site_devices/1 returns all devices for a site", %{site: site} do - {:ok, device} = Devices.create_device(Map.put(@valid_attrs, :site_id, site.id)) + test "list_site_devices/1 returns all devices for a site", %{organization: organization, site: site} do + {:ok, device} = + Devices.create_device(Map.merge(@valid_attrs, %{site_id: site.id, organization_id: organization.id})) + assert Devices.list_site_devices(site.id) == [device] end @@ -47,22 +49,27 @@ defmodule Towerops.EquipmentTest do organization: organization, site: site } do - {:ok, device} = Devices.create_device(Map.put(@valid_attrs, :site_id, site.id)) + {:ok, device} = + Devices.create_device(Map.merge(@valid_attrs, %{site_id: site.id, organization_id: organization.id})) + result = Devices.list_organization_devices(organization.id) assert length(result) == 1 assert hd(result).id == device.id end test "list_monitored_devices/0 returns only device with monitoring enabled", %{ + organization: organization, site: site } do - {:ok, monitored} = Devices.create_device(Map.put(@valid_attrs, :site_id, site.id)) + {:ok, monitored} = + Devices.create_device(Map.merge(@valid_attrs, %{site_id: site.id, organization_id: organization.id})) {:ok, _not_monitored} = Devices.create_device(%{ name: "Not Monitored", ip_address: "192.168.1.3", site_id: site.id, + organization_id: organization.id, monitoring_enabled: false }) @@ -71,19 +78,22 @@ defmodule Towerops.EquipmentTest do assert hd(result).id == monitored.id end - test "get_device!/1 returns the device with given id", %{site: site} do - {:ok, device} = Devices.create_device(Map.put(@valid_attrs, :site_id, site.id)) + test "get_device!/1 returns the device with given id", %{organization: organization, site: site} do + {:ok, device} = + Devices.create_device(Map.merge(@valid_attrs, %{site_id: site.id, organization_id: organization.id})) + assert Devices.get_device!(device.id).id == device.id end - test "get_site_equipment!/2 returns device for specific site", %{site: site} do - {:ok, device} = Devices.create_device(Map.put(@valid_attrs, :site_id, site.id)) + test "get_site_equipment!/2 returns device for specific site", %{organization: organization, site: site} do + {:ok, device} = + Devices.create_device(Map.merge(@valid_attrs, %{site_id: site.id, organization_id: organization.id})) assert Devices.get_site_device!(site.id, device.id).id == device.id end - test "create_device/1 with valid data creates device", %{site: site} do - attrs = Map.put(@valid_attrs, :site_id, site.id) + test "create_device/1 with valid data creates device", %{organization: organization, site: site} do + attrs = Map.merge(@valid_attrs, %{site_id: site.id, organization_id: organization.id}) assert {:ok, %DeviceSchema{} = device} = Devices.create_device(attrs) assert device.name == "Router 1" assert device.ip_address == "192.168.1.1" @@ -92,15 +102,15 @@ defmodule Towerops.EquipmentTest do assert device.check_interval_seconds == 300 end - test "create_device/1 with valid IPv6 address", %{site: site} do + test "create_device/1 with valid IPv6 address", %{organization: organization, site: site} do attrs = Map.put(@valid_attrs, :ip_address, "2001:0db8:85a3::8a2e:0370:7334") - attrs = Map.put(attrs, :site_id, site.id) + attrs = Map.merge(attrs, %{site_id: site.id, organization_id: organization.id}) assert {:ok, %DeviceSchema{}} = Devices.create_device(attrs) end - test "create_device/1 with invalid IP address returns error", %{site: site} do + test "create_device/1 with invalid IP address returns error", %{organization: organization, site: site} do attrs = Map.put(@valid_attrs, :ip_address, "invalid-ip") - attrs = Map.put(attrs, :site_id, site.id) + attrs = Map.merge(attrs, %{site_id: site.id, organization_id: organization.id}) assert {:error, changeset} = Devices.create_device(attrs) assert "must be a valid IPv4 or IPv6 address" in errors_on(changeset).ip_address end @@ -109,8 +119,9 @@ defmodule Towerops.EquipmentTest do assert {:error, %Ecto.Changeset{}} = Devices.create_device(@invalid_attrs) end - test "update_device/2 with valid data updates the device", %{site: site} do - {:ok, device} = Devices.create_device(Map.put(@valid_attrs, :site_id, site.id)) + test "update_device/2 with valid data updates the device", %{organization: organization, site: site} do + {:ok, device} = + Devices.create_device(Map.merge(@valid_attrs, %{site_id: site.id, organization_id: organization.id})) assert {:ok, %DeviceSchema{} = device} = Devices.update_device(device, @update_attrs) @@ -120,8 +131,9 @@ defmodule Towerops.EquipmentTest do assert device.monitoring_enabled == false end - test "update_device/2 with invalid data returns error changeset", %{site: site} do - {:ok, device} = Devices.create_device(Map.put(@valid_attrs, :site_id, site.id)) + test "update_device/2 with invalid data returns error changeset", %{organization: organization, site: site} do + {:ok, device} = + Devices.create_device(Map.merge(@valid_attrs, %{site_id: site.id, organization_id: organization.id})) assert {:error, %Ecto.Changeset{}} = Devices.update_device(device, @invalid_attrs) @@ -129,13 +141,16 @@ defmodule Towerops.EquipmentTest do assert Devices.get_device!(device.id).name == device.name end - test "change_device/1 returns an device changeset", %{site: site} do - {:ok, device} = Devices.create_device(Map.put(@valid_attrs, :site_id, site.id)) + test "change_device/1 returns an device changeset", %{organization: organization, site: site} do + {:ok, device} = + Devices.create_device(Map.merge(@valid_attrs, %{site_id: site.id, organization_id: organization.id})) + assert %Ecto.Changeset{} = Devices.change_device(device) end - test "update_device_status/2 updates status and timestamps", %{site: site} do - {:ok, device} = Devices.create_device(Map.put(@valid_attrs, :site_id, site.id)) + test "update_device_status/2 updates status and timestamps", %{organization: organization, site: site} do + {:ok, device} = + Devices.create_device(Map.merge(@valid_attrs, %{site_id: site.id, organization_id: organization.id})) assert {:ok, updated} = Devices.update_device_status(device, :up) assert updated.status == :up @@ -144,9 +159,12 @@ defmodule Towerops.EquipmentTest do end test "update_device_status/2 only updates last_checked_at if status unchanged", %{ + organization: organization, site: site } do - {:ok, device} = Devices.create_device(Map.put(@valid_attrs, :site_id, site.id)) + {:ok, device} = + Devices.create_device(Map.merge(@valid_attrs, %{site_id: site.id, organization_id: organization.id})) + {:ok, device} = Devices.update_device_status(device, :up) # Manually set timestamps to 1 hour ago to avoid sleeping @@ -171,12 +189,13 @@ defmodule Towerops.EquipmentTest do assert DateTime.after?(updated.last_checked_at, first_checked_at) end - test "list_snmp_enabled_devices/0 returns only device with SNMP enabled", %{site: site} do + test "list_snmp_enabled_devices/0 returns only device with SNMP enabled", %{organization: organization, site: site} do {:ok, snmp_enabled} = Devices.create_device(%{ name: "SNMP Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: organization.id, snmp_enabled: true, snmp_community: "public" }) @@ -186,6 +205,7 @@ defmodule Towerops.EquipmentTest do name: "Non-SNMP Router", ip_address: "192.168.1.2", site_id: site.id, + organization_id: organization.id, snmp_enabled: false }) @@ -194,8 +214,10 @@ defmodule Towerops.EquipmentTest do assert hd(result).id == snmp_enabled.id end - test "update_snmp_poll_time/1 updates last_snmp_poll_at timestamp", %{site: site} do - {:ok, device} = Devices.create_device(Map.put(@valid_attrs, :site_id, site.id)) + test "update_snmp_poll_time/1 updates last_snmp_poll_at timestamp", %{organization: organization, site: site} do + {:ok, device} = + Devices.create_device(Map.merge(@valid_attrs, %{site_id: site.id, organization_id: organization.id})) + assert device.last_snmp_poll_at == nil assert {:ok, updated} = Devices.update_snmp_poll_time(device) @@ -203,11 +225,12 @@ defmodule Towerops.EquipmentTest do assert DateTime.before?(updated.last_snmp_poll_at, DateTime.utc_now()) end - test "create_device/1 with SNMP enabled and nil community string succeeds", %{site: site} do + test "create_device/1 with SNMP enabled and nil community string succeeds", %{organization: organization, site: site} do attrs = %{ name: "SNMP Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: organization.id, snmp_enabled: true, snmp_version: "2c", snmp_community: nil @@ -218,11 +241,15 @@ defmodule Towerops.EquipmentTest do assert device.snmp_community == nil end - test "create_device/1 with SNMP enabled and empty community string succeeds", %{site: site} do + test "create_device/1 with SNMP enabled and empty community string succeeds", %{ + organization: organization, + site: site + } do attrs = %{ name: "SNMP Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: organization.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "" @@ -235,10 +262,30 @@ defmodule Towerops.EquipmentTest do assert device.snmp_community == nil || device.snmp_community == "" end - test "reorder_device/2 reorders device to first position", %{site: site} do - {:ok, device1} = Devices.create_device(%{name: "Device 1", ip_address: "192.168.1.1", site_id: site.id}) - {:ok, device2} = Devices.create_device(%{name: "Device 2", ip_address: "192.168.1.2", site_id: site.id}) - {:ok, device3} = Devices.create_device(%{name: "Device 3", ip_address: "192.168.1.3", site_id: site.id}) + test "reorder_device/2 reorders device to first position", %{organization: organization, site: site} do + {:ok, device1} = + Devices.create_device(%{ + name: "Device 1", + ip_address: "192.168.1.1", + site_id: site.id, + organization_id: organization.id + }) + + {:ok, device2} = + Devices.create_device(%{ + name: "Device 2", + ip_address: "192.168.1.2", + site_id: site.id, + organization_id: organization.id + }) + + {:ok, device3} = + Devices.create_device(%{ + name: "Device 3", + ip_address: "192.168.1.3", + site_id: site.id, + organization_id: organization.id + }) # Move device3 to first position {:ok, _updated} = Devices.reorder_device(device3.id, 1) @@ -255,10 +302,30 @@ defmodule Towerops.EquipmentTest do assert Enum.at(devices, 2).display_order == 3 end - test "reorder_device/2 reorders device to last position", %{site: site} do - {:ok, device1} = Devices.create_device(%{name: "Device 1", ip_address: "192.168.1.1", site_id: site.id}) - {:ok, device2} = Devices.create_device(%{name: "Device 2", ip_address: "192.168.1.2", site_id: site.id}) - {:ok, device3} = Devices.create_device(%{name: "Device 3", ip_address: "192.168.1.3", site_id: site.id}) + test "reorder_device/2 reorders device to last position", %{organization: organization, site: site} do + {:ok, device1} = + Devices.create_device(%{ + name: "Device 1", + ip_address: "192.168.1.1", + site_id: site.id, + organization_id: organization.id + }) + + {:ok, device2} = + Devices.create_device(%{ + name: "Device 2", + ip_address: "192.168.1.2", + site_id: site.id, + organization_id: organization.id + }) + + {:ok, device3} = + Devices.create_device(%{ + name: "Device 3", + ip_address: "192.168.1.3", + site_id: site.id, + organization_id: organization.id + }) # Move device1 to last position {:ok, _updated} = Devices.reorder_device(device1.id, 3) @@ -275,10 +342,30 @@ defmodule Towerops.EquipmentTest do assert Enum.at(devices, 2).display_order == 3 end - test "reorder_device/2 reorders device to middle position", %{site: site} do - {:ok, device1} = Devices.create_device(%{name: "Device 1", ip_address: "192.168.1.1", site_id: site.id}) - {:ok, device2} = Devices.create_device(%{name: "Device 2", ip_address: "192.168.1.2", site_id: site.id}) - {:ok, device3} = Devices.create_device(%{name: "Device 3", ip_address: "192.168.1.3", site_id: site.id}) + test "reorder_device/2 reorders device to middle position", %{organization: organization, site: site} do + {:ok, device1} = + Devices.create_device(%{ + name: "Device 1", + ip_address: "192.168.1.1", + site_id: site.id, + organization_id: organization.id + }) + + {:ok, device2} = + Devices.create_device(%{ + name: "Device 2", + ip_address: "192.168.1.2", + site_id: site.id, + organization_id: organization.id + }) + + {:ok, device3} = + Devices.create_device(%{ + name: "Device 3", + ip_address: "192.168.1.3", + site_id: site.id, + organization_id: organization.id + }) # Move device3 to middle position {:ok, _updated} = Devices.reorder_device(device3.id, 2) @@ -295,11 +382,38 @@ defmodule Towerops.EquipmentTest do assert Enum.at(devices, 2).display_order == 3 end - test "reorder_device/2 maintains continuous numbering", %{site: site} do - {:ok, _device1} = Devices.create_device(%{name: "Device 1", ip_address: "192.168.1.1", site_id: site.id}) - {:ok, device2} = Devices.create_device(%{name: "Device 2", ip_address: "192.168.1.2", site_id: site.id}) - {:ok, _device3} = Devices.create_device(%{name: "Device 3", ip_address: "192.168.1.3", site_id: site.id}) - {:ok, device4} = Devices.create_device(%{name: "Device 4", ip_address: "192.168.1.4", site_id: site.id}) + test "reorder_device/2 maintains continuous numbering", %{organization: organization, site: site} do + {:ok, _device1} = + Devices.create_device(%{ + name: "Device 1", + ip_address: "192.168.1.1", + site_id: site.id, + organization_id: organization.id + }) + + {:ok, device2} = + Devices.create_device(%{ + name: "Device 2", + ip_address: "192.168.1.2", + site_id: site.id, + organization_id: organization.id + }) + + {:ok, _device3} = + Devices.create_device(%{ + name: "Device 3", + ip_address: "192.168.1.3", + site_id: site.id, + organization_id: organization.id + }) + + {:ok, device4} = + Devices.create_device(%{ + name: "Device 4", + ip_address: "192.168.1.4", + site_id: site.id, + organization_id: organization.id + }) # Reorder multiple times {:ok, _} = Devices.reorder_device(device2.id, 1) @@ -313,12 +427,32 @@ defmodule Towerops.EquipmentTest do test "reorder_device/2 only affects devices in same site", %{organization: organization, site: site} do # Create devices in first site - {:ok, device1} = Devices.create_device(%{name: "Device 1", ip_address: "192.168.1.1", site_id: site.id}) - {:ok, device2} = Devices.create_device(%{name: "Device 2", ip_address: "192.168.1.2", site_id: site.id}) + {:ok, device1} = + Devices.create_device(%{ + name: "Device 1", + ip_address: "192.168.1.1", + site_id: site.id, + organization_id: organization.id + }) + + {:ok, device2} = + Devices.create_device(%{ + name: "Device 2", + ip_address: "192.168.1.2", + site_id: site.id, + organization_id: organization.id + }) # Create second site and device {:ok, site2} = Towerops.Sites.create_site(%{name: "Site 2", organization_id: organization.id}) - {:ok, device3} = Devices.create_device(%{name: "Device 3", ip_address: "192.168.2.1", site_id: site2.id}) + + {:ok, device3} = + Devices.create_device(%{ + name: "Device 3", + ip_address: "192.168.2.1", + site_id: site2.id, + organization_id: organization.id + }) # Reorder device in first site {:ok, _} = Devices.reorder_device(device1.id, 2) @@ -339,8 +473,21 @@ defmodule Towerops.EquipmentTest do organization: organization, site: site } do - {:ok, device1} = Devices.create_device(%{name: "Zebra Device", ip_address: "192.168.1.1", site_id: site.id}) - {:ok, device2} = Devices.create_device(%{name: "Alpha Device", ip_address: "192.168.1.2", site_id: site.id}) + {:ok, device1} = + Devices.create_device(%{ + name: "Zebra Device", + ip_address: "192.168.1.1", + site_id: site.id, + organization_id: organization.id + }) + + {:ok, device2} = + Devices.create_device(%{ + name: "Alpha Device", + ip_address: "192.168.1.2", + site_id: site.id, + organization_id: organization.id + }) # Set custom order {:ok, _} = Devices.reorder_device(device1.id, 1) @@ -380,12 +527,13 @@ defmodule Towerops.EquipmentTest do %{organization: organization, site: site, user: user} end - test "get_snmp_config/1 returns device-level community string when set", %{site: site} do + test "get_snmp_config/1 returns device-level community string when set", %{organization: organization, site: site} do {:ok, device} = Devices.create_device(%{ name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: organization.id, snmp_enabled: true, snmp_community: "device-community" }) @@ -396,7 +544,7 @@ defmodule Towerops.EquipmentTest do end test "get_snmp_config/1 returns site-level community when device has nil", %{ - organization: _organization, + organization: organization, site: site } do # Update site with SNMP community @@ -411,6 +559,7 @@ defmodule Towerops.EquipmentTest do name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: organization.id, snmp_enabled: true, snmp_community: nil }) @@ -440,6 +589,7 @@ defmodule Towerops.EquipmentTest do name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: organization.id, snmp_enabled: true, snmp_community: nil }) @@ -450,12 +600,13 @@ defmodule Towerops.EquipmentTest do assert config.source == :organization end - test "get_snmp_config/1 returns nil when all levels have nil", %{site: site} do + test "get_snmp_config/1 returns nil when all levels have nil", %{organization: organization, site: site} do {:ok, device} = Devices.create_device(%{ name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: organization.id, snmp_enabled: true, snmp_community: nil }) @@ -463,7 +614,7 @@ defmodule Towerops.EquipmentTest do device = Towerops.Repo.preload(device, site: :organization) config = Devices.get_snmp_config(device) assert config.community == nil - assert config.source == :default + assert config.source == :organization end test "get_snmp_config/1 prioritizes device over site over org", %{ @@ -488,6 +639,7 @@ defmodule Towerops.EquipmentTest do name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: organization.id, snmp_enabled: true, snmp_community: "device-community" }) @@ -519,7 +671,8 @@ defmodule Towerops.EquipmentTest do Devices.create_device(%{ name: "Router 1", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) %{device: device} @@ -612,12 +765,13 @@ defmodule Towerops.EquipmentTest do %{organization: organization, site: site, user: user} end - test "get_device/1 returns device when exists", %{site: site} do + test "get_device/1 returns device when exists", %{organization: organization, site: site} do {:ok, device} = Devices.create_device(%{ name: "Router", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) found = Devices.get_device(device.id) @@ -629,12 +783,13 @@ defmodule Towerops.EquipmentTest do assert Devices.get_device(Ecto.UUID.generate()) == nil end - test "get_device_with_details/1 preloads associations", %{site: site} do + test "get_device_with_details/1 preloads associations", %{organization: organization, site: site} do {:ok, device} = Devices.create_device(%{ name: "Router", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) result = Devices.get_device_with_details(device.id) @@ -643,13 +798,14 @@ defmodule Towerops.EquipmentTest do end @tag :skip - test "delete_device/1 deletes the device", %{site: site} do + test "delete_device/1 deletes the device", %{organization: organization, site: site} do # Skipped: Requires Monitoring.Supervisor to be running {:ok, device} = Devices.create_device(%{ name: "Router", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) assert {:ok, _deleted} = Devices.delete_device(device) @@ -661,50 +817,56 @@ defmodule Towerops.EquipmentTest do Devices.create_device(%{ name: "Router 1", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) {:ok, _device2} = Devices.create_device(%{ name: "Router 2", ip_address: "192.168.1.2", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) assert Devices.count_organization_devices(organization.id) == 2 end - test "count_site_devices/1 returns correct count", %{site: site} do + test "count_site_devices/1 returns correct count", %{organization: organization, site: site} do {:ok, _device1} = Devices.create_device(%{ name: "Router 1", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) {:ok, _device2} = Devices.create_device(%{ name: "Router 2", ip_address: "192.168.1.2", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) assert Devices.count_site_devices(site.id) == 2 end - test "count_site_devices_down/1 returns correct count", %{site: site} do + test "count_site_devices_down/1 returns correct count", %{organization: organization, site: site} do {:ok, device1} = Devices.create_device(%{ name: "Router 1", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) {:ok, _device2} = Devices.create_device(%{ name: "Router 2", ip_address: "192.168.1.2", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) # Mark one as down @@ -724,14 +886,16 @@ defmodule Towerops.EquipmentTest do Devices.create_device(%{ name: "Router 1", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) {:ok, _device2} = Devices.create_device(%{ name: "Router 2", ip_address: "192.168.1.2", - site_id: site2.id + site_id: site2.id, + organization_id: organization.id }) result = Devices.list_organization_devices(organization.id, %{"site_id" => site.id}) @@ -744,14 +908,16 @@ defmodule Towerops.EquipmentTest do Devices.create_device(%{ name: "Router 1", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) {:ok, _device2} = Devices.create_device(%{ name: "Router 2", ip_address: "192.168.1.2", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) # Mark one as up @@ -762,12 +928,13 @@ defmodule Towerops.EquipmentTest do assert hd(result).id == device1.id end - test "get_snmp_config/1 with device ID string", %{site: site} do + test "get_snmp_config/1 with device ID string", %{organization: organization, site: site} do {:ok, device} = Devices.create_device(%{ name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: organization.id, snmp_enabled: true, snmp_community: "test-community" }) @@ -794,12 +961,13 @@ defmodule Towerops.EquipmentTest do %{organization: organization, site: site, user: user} end - test "triggers discovery when snmp_enabled changes from false to true", %{site: site} do + test "triggers discovery when snmp_enabled changes from false to true", %{organization: organization, site: site} do {:ok, device} = Devices.create_device(%{ name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: organization.id, snmp_enabled: false }) @@ -819,12 +987,13 @@ defmodule Towerops.EquipmentTest do assert job.args["device_id"] == device.id end - test "triggers discovery when snmp_version changes while enabled", %{site: site} do + test "triggers discovery when snmp_version changes while enabled", %{organization: organization, site: site} do {:ok, device} = Devices.create_device(%{ name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: organization.id, snmp_enabled: true, snmp_version: "2c" }) @@ -845,12 +1014,13 @@ defmodule Towerops.EquipmentTest do assert job.args["device_id"] == device.id end - test "triggers discovery when snmp_port changes while enabled", %{site: site} do + test "triggers discovery when snmp_port changes while enabled", %{organization: organization, site: site} do {:ok, device} = Devices.create_device(%{ name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: organization.id, snmp_enabled: true, snmp_port: 161 }) @@ -872,6 +1042,7 @@ defmodule Towerops.EquipmentTest do end test "triggers discovery when monitoring_enabled changes to true with SNMP enabled", %{ + organization: organization, site: site } do {:ok, device} = @@ -879,6 +1050,7 @@ defmodule Towerops.EquipmentTest do name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: organization.id, snmp_enabled: true, monitoring_enabled: false }) @@ -900,6 +1072,7 @@ defmodule Towerops.EquipmentTest do end test "does not trigger discovery when monitoring_enabled changes but SNMP disabled", %{ + organization: organization, site: site } do {:ok, device} = @@ -907,6 +1080,7 @@ defmodule Towerops.EquipmentTest do name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: organization.id, snmp_enabled: false, monitoring_enabled: false }) @@ -926,12 +1100,13 @@ defmodule Towerops.EquipmentTest do assert [] = jobs end - test "does not trigger discovery when SNMP is disabled", %{site: site} do + test "does not trigger discovery when SNMP is disabled", %{organization: organization, site: site} do {:ok, device} = Devices.create_device(%{ name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: organization.id, snmp_enabled: true, snmp_version: "2c" }) @@ -951,12 +1126,13 @@ defmodule Towerops.EquipmentTest do assert [] = jobs end - test "does not trigger discovery for unrelated field changes", %{site: site} do + test "does not trigger discovery for unrelated field changes", %{organization: organization, site: site} do {:ok, device} = Devices.create_device(%{ name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: organization.id, snmp_enabled: true }) @@ -975,12 +1151,13 @@ defmodule Towerops.EquipmentTest do assert [] = jobs end - test "does not trigger discovery when snmp_version changes while disabled", %{site: site} do + test "does not trigger discovery when snmp_version changes while disabled", %{organization: organization, site: site} do {:ok, device} = Devices.create_device(%{ name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: organization.id, snmp_enabled: false, snmp_version: "2c" }) @@ -1028,7 +1205,8 @@ defmodule Towerops.EquipmentTest do attrs = %{ name: name, ip_address: ip_address, - site_id: site.id + site_id: site.id, + organization_id: organization.id } # Use bypass_limits since property tests may create > 10 devices @@ -1053,7 +1231,8 @@ defmodule Towerops.EquipmentTest do Devices.create_device(%{ name: "Test Device", ip_address: "192.168.1.100", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) # Update status twice @@ -1083,7 +1262,8 @@ defmodule Towerops.EquipmentTest do Devices.create_device(%{ name: "Device #{i}", ip_address: "192.168.1.#{i}", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) end end @@ -1129,6 +1309,7 @@ defmodule Towerops.EquipmentTest do name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: organization.id, snmp_enabled: true, snmp_community: device_community }) @@ -1168,7 +1349,7 @@ defmodule Towerops.EquipmentTest do %{organization: organization, site: site, user: user} end - test "blocks device creation when at 10-device limit", %{site: site} do + test "blocks device creation when at 10-device limit", %{organization: organization, site: site} do # Create 10 devices (the limit) for i <- 1..10 do {:ok, _device} = @@ -1176,6 +1357,7 @@ defmodule Towerops.EquipmentTest do name: "Device #{i}", ip_address: "192.168.1.#{i}", site_id: site.id, + organization_id: organization.id, monitoring_enabled: false, snmp_enabled: false }) @@ -1187,6 +1369,7 @@ defmodule Towerops.EquipmentTest do name: "Device 11", ip_address: "192.168.1.11", site_id: site.id, + organization_id: organization.id, monitoring_enabled: false, snmp_enabled: false }) @@ -1195,7 +1378,7 @@ defmodule Towerops.EquipmentTest do errors_on(changeset) end - test "allows device creation when under limit", %{site: site} do + test "allows device creation when under limit", %{organization: organization, site: site} do # Create 9 devices for i <- 1..9 do {:ok, _device} = @@ -1203,6 +1386,7 @@ defmodule Towerops.EquipmentTest do name: "Device #{i}", ip_address: "192.168.1.#{i}", site_id: site.id, + organization_id: organization.id, monitoring_enabled: false, snmp_enabled: false }) @@ -1214,12 +1398,13 @@ defmodule Towerops.EquipmentTest do name: "Device 10", ip_address: "192.168.1.10", site_id: site.id, + organization_id: organization.id, monitoring_enabled: false, snmp_enabled: false }) end - test "bypasses limit with bypass_limits option", %{site: site} do + test "bypasses limit with bypass_limits option", %{organization: organization, site: site} do # Create 10 devices (at limit) for i <- 1..10 do {:ok, _device} = @@ -1227,6 +1412,7 @@ defmodule Towerops.EquipmentTest do name: "Device #{i}", ip_address: "192.168.1.#{i}", site_id: site.id, + organization_id: organization.id, monitoring_enabled: false, snmp_enabled: false }) @@ -1239,6 +1425,7 @@ defmodule Towerops.EquipmentTest do name: "Device 11", ip_address: "192.168.1.11", site_id: site.id, + organization_id: organization.id, monitoring_enabled: false, snmp_enabled: false }, @@ -1263,6 +1450,7 @@ defmodule Towerops.EquipmentTest do name: "Site1 Device #{i}", ip_address: "192.168.1.#{i}", site_id: site1.id, + organization_id: organization.id, monitoring_enabled: false, snmp_enabled: false }) @@ -1275,6 +1463,7 @@ defmodule Towerops.EquipmentTest do name: "Site2 Device #{i}", ip_address: "192.168.2.#{i}", site_id: site2.id, + organization_id: organization.id, monitoring_enabled: false, snmp_enabled: false }) @@ -1286,6 +1475,7 @@ defmodule Towerops.EquipmentTest do name: "Site1 Device 7", ip_address: "192.168.1.7", site_id: site1.id, + organization_id: organization.id, monitoring_enabled: false, snmp_enabled: false }) @@ -1331,14 +1521,16 @@ defmodule Towerops.EquipmentTest do Devices.create_device(%{ name: "Device 1", ip_address: "192.168.1.1", - site_id: site1.id + site_id: site1.id, + organization_id: org1.id }) {:ok, device2} = Devices.create_device(%{ name: "Device 2", ip_address: "192.168.1.2", - site_id: site2.id + site_id: site2.id, + organization_id: org2.id }) result = Devices.list_devices_for_organizations([org1.id, org2.id]) @@ -1351,6 +1543,7 @@ defmodule Towerops.EquipmentTest do test "returns only devices from specified organizations", %{ org1: org1, + org2: org2, site1: site1, site2: site2 } do @@ -1358,14 +1551,16 @@ defmodule Towerops.EquipmentTest do Devices.create_device(%{ name: "Device 1", ip_address: "192.168.1.1", - site_id: site1.id + site_id: site1.id, + organization_id: org1.id }) {:ok, _device2} = Devices.create_device(%{ name: "Device 2", ip_address: "192.168.1.2", - site_id: site2.id + site_id: site2.id, + organization_id: org2.id }) # Only request devices from org1 @@ -1389,7 +1584,8 @@ defmodule Towerops.EquipmentTest do Devices.create_device(%{ name: "Device 1", ip_address: "192.168.1.1", - site_id: site1.id + site_id: site1.id, + organization_id: org1.id }) result = Devices.list_devices_for_organizations([org1.id]) @@ -1404,21 +1600,24 @@ defmodule Towerops.EquipmentTest do Devices.create_device(%{ name: "Zebra Device", ip_address: "192.168.1.1", - site_id: site1.id + site_id: site1.id, + organization_id: org1.id }) {:ok, _alpha_dev} = Devices.create_device(%{ name: "Alpha Device", ip_address: "192.168.1.2", - site_id: site1.id + site_id: site1.id, + organization_id: org1.id }) {:ok, _beta_dev} = Devices.create_device(%{ name: "Beta Device", ip_address: "192.168.2.1", - site_id: site2.id + site_id: site2.id, + organization_id: org2.id }) result = Devices.list_devices_for_organizations([org1.id, org2.id]) diff --git a/test/towerops/equipment/event_logger_test.exs b/test/towerops/equipment/event_logger_test.exs index 9632cd5f..e0d38157 100644 --- a/test/towerops/equipment/event_logger_test.exs +++ b/test/towerops/equipment/event_logger_test.exs @@ -25,6 +25,7 @@ defmodule Towerops.Devices.EventLoggerTest do Towerops.Devices.create_device(%{ name: "Test Equipment", site_id: site.id, + organization_id: site.organization_id, ip_address: "192.168.1.1" }) diff --git a/test/towerops/monitoring/check_test.exs b/test/towerops/monitoring/check_test.exs index 8df77a5b..b8efa7de 100644 --- a/test/towerops/monitoring/check_test.exs +++ b/test/towerops/monitoring/check_test.exs @@ -21,7 +21,8 @@ defmodule Towerops.Monitoring.CheckTest do Towerops.Devices.create_device(%{ name: "Test Device", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: site.organization_id }) {:ok, device: device} diff --git a/test/towerops/monitoring_test.exs b/test/towerops/monitoring_test.exs index 64ce286e..4e1162e1 100644 --- a/test/towerops/monitoring_test.exs +++ b/test/towerops/monitoring_test.exs @@ -22,7 +22,8 @@ defmodule Towerops.MonitoringTest do Towerops.Devices.create_device(%{ name: "Router 1", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) %{device: device} diff --git a/test/towerops/organizations/subscription_limits_test.exs b/test/towerops/organizations/subscription_limits_test.exs index 52d3ec78..5904782f 100644 --- a/test/towerops/organizations/subscription_limits_test.exs +++ b/test/towerops/organizations/subscription_limits_test.exs @@ -196,12 +196,15 @@ defmodule Towerops.Organizations.SubscriptionLimitsTest do # 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 }, diff --git a/test/towerops/organizations_test.exs b/test/towerops/organizations_test.exs index ce7894f1..0ab9ede4 100644 --- a/test/towerops/organizations_test.exs +++ b/test/towerops/organizations_test.exs @@ -437,7 +437,8 @@ defmodule Towerops.OrganizationsTest do snmp_enabled: true, snmp_version: "2c", snmp_community: "public", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) {:ok, device2} = @@ -447,7 +448,8 @@ defmodule Towerops.OrganizationsTest do snmp_enabled: true, snmp_version: "2c", snmp_community: "public", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) {count, _} = Organizations.apply_snmp_config_to_all_equipment(organization.id) @@ -494,14 +496,16 @@ defmodule Towerops.OrganizationsTest do Towerops.Devices.create_device(%{ name: "Device 1", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) {:ok, device2} = Towerops.Devices.create_device(%{ name: "Device 2", ip_address: "192.168.1.2", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) {count, _} = Organizations.apply_agent_to_all_equipment(organization.id) @@ -528,7 +532,8 @@ defmodule Towerops.OrganizationsTest do Towerops.Devices.create_device(%{ name: "Test Device", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) {:ok, agent_token, _token} = @@ -562,7 +567,8 @@ defmodule Towerops.OrganizationsTest do Towerops.Devices.create_device(%{ name: "Test Device", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) Towerops.Agents.assign_device_to_agent(old_agent.id, device.id) @@ -678,6 +684,7 @@ defmodule Towerops.OrganizationsTest do name: "MikroTik Device", ip_address: "192.168.1.1", site_id: site.id, + organization_id: organization.id, manufacturer: "MikroTik" }) @@ -696,9 +703,9 @@ defmodule Towerops.OrganizationsTest do assert updated_org.mikrotik_use_ssl == true assert updated_org.mikrotik_enabled == true - # Verify device credential source remains "site" (inherits from site, which inherits from org) + # Verify device credential source is "organization" (inherits directly from org) updated_device = Repo.get!(Device, device.id) - assert updated_device.mikrotik_credential_source == "site" + assert updated_device.mikrotik_credential_source == "organization" # Verify the device received the organization's MikroTik settings through propagation assert updated_device.mikrotik_username == "admin" @@ -731,6 +738,7 @@ defmodule Towerops.OrganizationsTest do name: "MikroTik Device", ip_address: "192.168.1.1", site_id: site.id, + organization_id: organization.id, manufacturer: "MikroTik" }) diff --git a/test/towerops/sites_test.exs b/test/towerops/sites_test.exs index e5a917a6..fa7f44c8 100644 --- a/test/towerops/sites_test.exs +++ b/test/towerops/sites_test.exs @@ -54,7 +54,13 @@ defmodule Towerops.SitesTest do test "list_root_sites/1 returns only sites without parents", %{organization: organization} do {:ok, root} = Sites.create_site(%{name: "Root Site", organization_id: organization.id}) - {:ok, _child} = Sites.create_site(%{name: "Child Site", organization_id: organization.id, parent_site_id: root.id}) + + {:ok, _child} = + Sites.create_site(%{ + name: "Child Site", + organization_id: organization.id, + parent_site_id: root.id + }) roots = Sites.list_root_sites(organization.id) assert length(roots) == 1 @@ -63,8 +69,20 @@ defmodule Towerops.SitesTest do test "list_child_sites/1 returns child sites of a parent", %{organization: organization} do {:ok, parent} = Sites.create_site(%{name: "Parent", organization_id: organization.id}) - {:ok, child1} = Sites.create_site(%{name: "Child 1", organization_id: organization.id, parent_site_id: parent.id}) - {:ok, child2} = Sites.create_site(%{name: "Child 2", organization_id: organization.id, parent_site_id: parent.id}) + + {:ok, child1} = + Sites.create_site(%{ + name: "Child 1", + organization_id: organization.id, + parent_site_id: parent.id + }) + + {:ok, child2} = + Sites.create_site(%{ + name: "Child 2", + organization_id: organization.id, + parent_site_id: parent.id + }) children = Sites.list_child_sites(parent.id) assert length(children) == 2 @@ -81,7 +99,13 @@ defmodule Towerops.SitesTest do test "get_site!/1 preloads associations", %{organization: organization} do {:ok, parent} = Sites.create_site(%{name: "Parent", organization_id: organization.id}) - {:ok, site} = Sites.create_site(%{name: "Child", organization_id: organization.id, parent_site_id: parent.id}) + + {:ok, site} = + Sites.create_site(%{ + name: "Child", + organization_id: organization.id, + parent_site_id: parent.id + }) fetched = Sites.get_site!(site.id) assert Ecto.assoc_loaded?(fetched.parent_site) @@ -195,7 +219,7 @@ defmodule Towerops.SitesTest do {:ok, site} = Sites.create_site(%{name: "Test Site", organization_id: organization.id}) # Try to make site its own parent - assert {:error, changeset} = Sites.update_site(site, %{parent_site_id: site.id}) + assert {:error, changeset} = Sites.update_site(site, %{parent_site_id: site.id, organization_id: organization.id}) assert "cannot be the same as the site itself" in errors_on(changeset).parent_site_id end @@ -232,10 +256,20 @@ defmodule Towerops.SitesTest do test "build_site_tree/1 builds hierarchical structure", %{organization: organization} do {:ok, root1} = Sites.create_site(%{name: "Root 1", organization_id: organization.id}) {:ok, root2} = Sites.create_site(%{name: "Root 2", organization_id: organization.id}) - {:ok, child1} = Sites.create_site(%{name: "Child 1", organization_id: organization.id, parent_site_id: root1.id}) + + {:ok, child1} = + Sites.create_site(%{ + name: "Child 1", + organization_id: organization.id, + parent_site_id: root1.id + }) {:ok, grandchild} = - Sites.create_site(%{name: "Grandchild", organization_id: organization.id, parent_site_id: child1.id}) + Sites.create_site(%{ + name: "Grandchild", + organization_id: organization.id, + parent_site_id: child1.id + }) tree = Sites.build_site_tree(organization.id) assert length(tree) == 2 @@ -269,6 +303,7 @@ defmodule Towerops.SitesTest do name: "Device 1", ip_address: "192.168.1.1", site_id: site.id, + organization_id: organization.id, snmp_version: "1", snmp_community: "old-community" }) @@ -278,6 +313,7 @@ defmodule Towerops.SitesTest do name: "Device 2", ip_address: "192.168.1.2", site_id: site.id, + organization_id: organization.id, snmp_version: "1", snmp_community: "old-community" }) @@ -308,14 +344,16 @@ defmodule Towerops.SitesTest do Towerops.Devices.create_device(%{ name: "Device 1", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) {:ok, device2} = Towerops.Devices.create_device(%{ name: "Device 2", ip_address: "192.168.1.2", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) {count, _} = Sites.apply_agent_to_all_equipment(site.id) @@ -345,7 +383,8 @@ defmodule Towerops.SitesTest do Towerops.Devices.create_device(%{ name: "Device 1", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) # Create initial assignment diff --git a/test/towerops/snmp/discovery_test.exs b/test/towerops/snmp/discovery_test.exs index a083d47b..de60916d 100644 --- a/test/towerops/snmp/discovery_test.exs +++ b/test/towerops/snmp/discovery_test.exs @@ -37,24 +37,26 @@ defmodule Towerops.Snmp.DiscoveryTest do end describe "discover_device/1" do - test "returns error when SNMP is not enabled", %{site: site} do + test "returns error when SNMP is not enabled", %{organization: organization, site: site} do {:ok, device} = Towerops.Devices.create_device(%{ name: "Router 1", ip_address: "192.168.1.1", site_id: site.id, + organization_id: organization.id, snmp_enabled: false }) assert {:error, :snmp_not_enabled} = Discovery.discover_device(device) end - test "successfully discovers MikroTik device", %{site: site} do + test "successfully discovers MikroTik device", %{organization: organization, site: site} do {:ok, device} = Towerops.Devices.create_device(%{ name: "MikroTik Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: organization.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "public", @@ -205,12 +207,13 @@ defmodule Towerops.Snmp.DiscoveryTest do assert interface1.if_alias == "WAN" end - test "successfully discovers Cisco device", %{site: site} do + test "successfully discovers Cisco device", %{organization: organization, site: site} do {:ok, device} = Towerops.Devices.create_device(%{ name: "Cisco Switch", ip_address: "192.168.1.2", site_id: site.id, + organization_id: organization.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "public", @@ -257,12 +260,13 @@ defmodule Towerops.Snmp.DiscoveryTest do assert device.sys_name == "switch1" end - test "handles connection failure", %{site: site} do + test "handles connection failure", %{organization: organization, site: site} do {:ok, device} = Towerops.Devices.create_device(%{ name: "Unreachable Device", ip_address: "192.168.1.99", site_id: site.id, + organization_id: organization.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "public", @@ -277,12 +281,13 @@ defmodule Towerops.Snmp.DiscoveryTest do assert {:error, :device_unresponsive} = Discovery.discover_device(device) end - test "handles partial discovery failure gracefully", %{site: site} do + test "handles partial discovery failure gracefully", %{organization: organization, site: site} do {:ok, device} = Towerops.Devices.create_device(%{ name: "Partial Device", ip_address: "192.168.1.3", site_id: site.id, + organization_id: organization.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "public", @@ -349,12 +354,13 @@ defmodule Towerops.Snmp.DiscoveryTest do assert sensors == [] end - test "updates existing device on re-discovery", %{site: site} do + test "updates existing device on re-discovery", %{organization: organization, site: site} do {:ok, device} = Towerops.Devices.create_device(%{ name: "Existing Device", ip_address: "192.168.1.4", site_id: site.id, + organization_id: organization.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "public", @@ -415,6 +421,7 @@ defmodule Towerops.Snmp.DiscoveryTest do end test "preserves sensor readings when rediscovering device with same sensor_index", %{ + organization: organization, site: site } do alias Towerops.Snmp.SensorReading @@ -424,6 +431,7 @@ defmodule Towerops.Snmp.DiscoveryTest do name: "Device With Sensors", ip_address: "192.168.1.50", site_id: site.id, + organization_id: organization.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "public", @@ -548,7 +556,10 @@ defmodule Towerops.Snmp.DiscoveryTest do assert Enum.map(readings, & &1.value) == [42.0, 44.0, 45.0] end - test "preserves interface stats when rediscovering device with same if_index", %{site: site} do + test "preserves interface stats when rediscovering device with same if_index", %{ + organization: organization, + site: site + } do alias Towerops.Snmp.InterfaceStat {:ok, device} = @@ -556,6 +567,7 @@ defmodule Towerops.Snmp.DiscoveryTest do name: "Device With Interfaces", ip_address: "192.168.1.51", site_id: site.id, + organization_id: organization.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "public", @@ -682,12 +694,13 @@ defmodule Towerops.Snmp.DiscoveryTest do assert Enum.map(stats, & &1.if_in_octets) == [1_000_000, 2_000_000, 3_000_000] end - test "deletes sensors that no longer exist during rediscovery", %{site: site} do + test "deletes sensors that no longer exist during rediscovery", %{organization: organization, site: site} do {:ok, device} = Towerops.Devices.create_device(%{ name: "Device With Removed Sensor", ip_address: "192.168.1.52", site_id: site.id, + organization_id: organization.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "public", @@ -800,6 +813,7 @@ defmodule Towerops.Snmp.DiscoveryTest do name: "Device 1", ip_address: "192.168.1.10", site_id: site.id, + organization_id: organization.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "public", @@ -811,6 +825,7 @@ defmodule Towerops.Snmp.DiscoveryTest do name: "Device 2", ip_address: "192.168.1.11", site_id: site.id, + organization_id: organization.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "public", @@ -822,6 +837,7 @@ defmodule Towerops.Snmp.DiscoveryTest do name: "Device 3 - No SNMP", ip_address: "192.168.1.12", site_id: site.id, + organization_id: organization.id, snmp_enabled: false }) @@ -858,6 +874,7 @@ defmodule Towerops.Snmp.DiscoveryTest do name: "Good Device", ip_address: "192.168.1.20", site_id: site.id, + organization_id: organization.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "public", @@ -869,6 +886,7 @@ defmodule Towerops.Snmp.DiscoveryTest do name: "Bad Device", ip_address: "192.168.1.21", site_id: site.id, + organization_id: organization.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "wrong", @@ -906,7 +924,7 @@ defmodule Towerops.Snmp.DiscoveryTest do end test "updates device name from SNMP sysName when device name is empty", %{ - organization: _organization, + organization: organization, site: site } do # Create device without a name @@ -915,6 +933,7 @@ defmodule Towerops.Snmp.DiscoveryTest do name: nil, ip_address: "192.168.1.200", site_id: site.id, + organization_id: organization.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "public", @@ -960,7 +979,7 @@ defmodule Towerops.Snmp.DiscoveryTest do end test "does not update device name from SNMP when device already has a name", %{ - organization: _organization, + organization: organization, site: site } do # Create device with a name @@ -969,6 +988,7 @@ defmodule Towerops.Snmp.DiscoveryTest do name: "My Custom Name", ip_address: "192.168.1.201", site_id: site.id, + organization_id: organization.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "public", diff --git a/test/towerops/snmp/ip_address_test.exs b/test/towerops/snmp/ip_address_test.exs index 0d675a0d..9d830c41 100644 --- a/test/towerops/snmp/ip_address_test.exs +++ b/test/towerops/snmp/ip_address_test.exs @@ -27,7 +27,8 @@ defmodule Towerops.Snmp.IpAddressTest do snmp_version: "2c", snmp_community: "public", snmp_port: 161, - site_id: site.id + site_id: site.id, + organization_id: organization.id }) snmp_device = diff --git a/test/towerops/snmp/mac_address_test.exs b/test/towerops/snmp/mac_address_test.exs index 51602f97..4cbff26c 100644 --- a/test/towerops/snmp/mac_address_test.exs +++ b/test/towerops/snmp/mac_address_test.exs @@ -27,7 +27,8 @@ defmodule Towerops.Snmp.MacAddressTest do snmp_version: "2c", snmp_community: "public", snmp_port: 161, - site_id: site.id + site_id: site.id, + organization_id: organization.id }) snmp_device = diff --git a/test/towerops/snmp/memory_pool_test.exs b/test/towerops/snmp/memory_pool_test.exs index 5783577b..4de42585 100644 --- a/test/towerops/snmp/memory_pool_test.exs +++ b/test/towerops/snmp/memory_pool_test.exs @@ -26,7 +26,8 @@ defmodule Towerops.Snmp.MemoryPoolTest do snmp_version: "2c", snmp_community: "public", snmp_port: 161, - site_id: site.id + site_id: site.id, + organization_id: organization.id }) snmp_device = diff --git a/test/towerops/snmp/neighbor_cleanup_worker_test.exs b/test/towerops/snmp/neighbor_cleanup_worker_test.exs index 1d84c2c8..567b3812 100644 --- a/test/towerops/snmp/neighbor_cleanup_worker_test.exs +++ b/test/towerops/snmp/neighbor_cleanup_worker_test.exs @@ -28,7 +28,8 @@ defmodule Towerops.Snmp.NeighborCleanupWorkerTest do snmp_version: "2c", snmp_community: "public", snmp_port: 161, - site_id: site.id + site_id: site.id, + organization_id: organization.id }) {:ok, device_schema2} = @@ -39,7 +40,8 @@ defmodule Towerops.Snmp.NeighborCleanupWorkerTest do snmp_version: "2c", snmp_community: "public", snmp_port: 161, - site_id: site.id + site_id: site.id, + organization_id: organization.id }) device1 = @@ -216,7 +218,8 @@ defmodule Towerops.Snmp.NeighborCleanupWorkerTest do name: "No SNMP Device", ip_address: "192.168.1.100", snmp_enabled: false, - site_id: site.id + site_id: site.id, + organization_id: org.id }) device = diff --git a/test/towerops/snmp/neighbor_test.exs b/test/towerops/snmp/neighbor_test.exs index bab451cf..e79c7332 100644 --- a/test/towerops/snmp/neighbor_test.exs +++ b/test/towerops/snmp/neighbor_test.exs @@ -27,7 +27,8 @@ defmodule Towerops.Snmp.NeighborTest do snmp_version: "2c", snmp_community: "public", snmp_port: 161, - site_id: site.id + site_id: site.id, + organization_id: organization.id }) snmp_device = diff --git a/test/towerops/snmp/physical_entity_test.exs b/test/towerops/snmp/physical_entity_test.exs index b05eb1e7..07765b9a 100644 --- a/test/towerops/snmp/physical_entity_test.exs +++ b/test/towerops/snmp/physical_entity_test.exs @@ -26,7 +26,8 @@ defmodule Towerops.Snmp.PhysicalEntityTest do snmp_version: "2c", snmp_community: "public", snmp_port: 161, - site_id: site.id + site_id: site.id, + organization_id: organization.id }) snmp_device = diff --git a/test/towerops/snmp/processor_reading_test.exs b/test/towerops/snmp/processor_reading_test.exs index fac27276..884dfd27 100644 --- a/test/towerops/snmp/processor_reading_test.exs +++ b/test/towerops/snmp/processor_reading_test.exs @@ -203,7 +203,8 @@ defmodule Towerops.Snmp.ProcessorReadingTest do Towerops.Devices.create_device(%{ name: "Test Device", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: org.id }) device diff --git a/test/towerops/snmp/state_sensor_test.exs b/test/towerops/snmp/state_sensor_test.exs index 052a7895..d525a565 100644 --- a/test/towerops/snmp/state_sensor_test.exs +++ b/test/towerops/snmp/state_sensor_test.exs @@ -193,7 +193,8 @@ defmodule Towerops.Snmp.StateSensorTest do snmp_version: "2c", snmp_community: "public", snmp_port: 161, - site_id: device_schema.site_id + site_id: device_schema.site_id, + organization_id: device_schema.organization_id }) snmp_device2 = diff --git a/test/towerops/snmp/storage_test.exs b/test/towerops/snmp/storage_test.exs index d553b592..2a7e0976 100644 --- a/test/towerops/snmp/storage_test.exs +++ b/test/towerops/snmp/storage_test.exs @@ -26,7 +26,8 @@ defmodule Towerops.Snmp.StorageTest do snmp_version: "2c", snmp_community: "public", snmp_port: 161, - site_id: site.id + site_id: site.id, + organization_id: organization.id }) snmp_device = diff --git a/test/towerops/snmp/vlan_test.exs b/test/towerops/snmp/vlan_test.exs index c2161052..442eea8b 100644 --- a/test/towerops/snmp/vlan_test.exs +++ b/test/towerops/snmp/vlan_test.exs @@ -26,7 +26,8 @@ defmodule Towerops.Snmp.VlanTest do snmp_version: "2c", snmp_community: "public", snmp_port: 161, - site_id: site.id + site_id: site.id, + organization_id: organization.id }) snmp_device = @@ -184,7 +185,8 @@ defmodule Towerops.Snmp.VlanTest do snmp_version: "2c", snmp_community: "public", snmp_port: 161, - site_id: device_schema.site_id + site_id: device_schema.site_id, + organization_id: device_schema.organization_id }) snmp_device2 = diff --git a/test/towerops/snmp_test.exs b/test/towerops/snmp_test.exs index 60aab95c..ebff8cdb 100644 --- a/test/towerops/snmp_test.exs +++ b/test/towerops/snmp_test.exs @@ -33,7 +33,8 @@ defmodule Towerops.SnmpTest do snmp_version: "2c", snmp_community: "public", snmp_port: 161, - site_id: site.id + site_id: site.id, + organization_id: organization.id }) snmp_device = @@ -1238,14 +1239,16 @@ defmodule Towerops.SnmpTest do Towerops.Devices.create_device(%{ name: "Router 1", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) {:ok, device2} = Towerops.Devices.create_device(%{ name: "Router 2", ip_address: "192.168.1.2", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) snmp_device1 = @@ -1868,14 +1871,16 @@ defmodule Towerops.SnmpTest do Towerops.Devices.create_device(%{ name: "Router 1", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) {:ok, device2} = Towerops.Devices.create_device(%{ name: "Router 2", ip_address: "192.168.1.2", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) old_time = DateTime.add(DateTime.utc_now(), -7200, :second) diff --git a/test/towerops/workers/agent_latency_evaluator_test.exs b/test/towerops/workers/agent_latency_evaluator_test.exs index 999ed3f7..b9e862d1 100644 --- a/test/towerops/workers/agent_latency_evaluator_test.exs +++ b/test/towerops/workers/agent_latency_evaluator_test.exs @@ -33,6 +33,7 @@ defmodule Towerops.Workers.AgentLatencyEvaluatorTest do name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: site.organization_id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c" @@ -83,6 +84,7 @@ defmodule Towerops.Workers.AgentLatencyEvaluatorTest do name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: site.organization_id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c" @@ -133,6 +135,7 @@ defmodule Towerops.Workers.AgentLatencyEvaluatorTest do name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: site.organization_id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c" @@ -182,6 +185,7 @@ defmodule Towerops.Workers.AgentLatencyEvaluatorTest do name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: site.organization_id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c" @@ -231,6 +235,7 @@ defmodule Towerops.Workers.AgentLatencyEvaluatorTest do name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: site.organization_id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c" @@ -289,6 +294,7 @@ defmodule Towerops.Workers.AgentLatencyEvaluatorTest do name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: site.organization_id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c" @@ -342,6 +348,7 @@ defmodule Towerops.Workers.AgentLatencyEvaluatorTest do name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: site.organization_id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c" @@ -399,6 +406,7 @@ defmodule Towerops.Workers.AgentLatencyEvaluatorTest do name: "Router 1", ip_address: "192.168.1.1", site_id: site1.id, + organization_id: site1.organization_id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c" @@ -409,6 +417,7 @@ defmodule Towerops.Workers.AgentLatencyEvaluatorTest do name: "Router 2", ip_address: "192.168.2.1", site_id: site2.id, + organization_id: site2.organization_id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c" @@ -464,6 +473,7 @@ defmodule Towerops.Workers.AgentLatencyEvaluatorTest do name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: site.organization_id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c" @@ -519,6 +529,7 @@ defmodule Towerops.Workers.AgentLatencyEvaluatorTest do name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: site.organization_id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c" @@ -563,6 +574,7 @@ defmodule Towerops.Workers.AgentLatencyEvaluatorTest do name: "Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: site.organization_id, snmp_enabled: true, snmp_community: "public", snmp_version: "2c" diff --git a/test/towerops/workers/backup_summary_worker_test.exs b/test/towerops/workers/backup_summary_worker_test.exs index 98c379ee..4be0c8e4 100644 --- a/test/towerops/workers/backup_summary_worker_test.exs +++ b/test/towerops/workers/backup_summary_worker_test.exs @@ -223,7 +223,8 @@ defmodule Towerops.Workers.BackupSummaryWorkerTest do Devices.create_device(%{ name: "Test Device #{System.unique_integer()}", ip_address: "192.168.1.#{:rand.uniform(254)}", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) device diff --git a/test/towerops/workers/backup_timeout_worker_test.exs b/test/towerops/workers/backup_timeout_worker_test.exs index 757568be..2494d581 100644 --- a/test/towerops/workers/backup_timeout_worker_test.exs +++ b/test/towerops/workers/backup_timeout_worker_test.exs @@ -197,7 +197,8 @@ defmodule Towerops.Workers.BackupTimeoutWorkerTest do Devices.create_device(%{ name: "Test Device #{System.unique_integer()}", ip_address: "192.168.1.#{:rand.uniform(254)}", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) device diff --git a/test/towerops/workers/device_monitor_worker_test.exs b/test/towerops/workers/device_monitor_worker_test.exs index 370f563d..49761393 100644 --- a/test/towerops/workers/device_monitor_worker_test.exs +++ b/test/towerops/workers/device_monitor_worker_test.exs @@ -29,6 +29,7 @@ defmodule Towerops.Workers.DeviceMonitorWorkerTest do name: "Router 1", ip_address: "192.168.1.1", site_id: site.id, + organization_id: site.organization_id, monitoring_enabled: true }) @@ -53,6 +54,7 @@ defmodule Towerops.Workers.DeviceMonitorWorkerTest do name: "Router 2", ip_address: "192.168.1.2", site_id: site.id, + organization_id: site.organization_id, monitoring_enabled: true }) @@ -73,6 +75,7 @@ defmodule Towerops.Workers.DeviceMonitorWorkerTest do name: "Router 3", ip_address: "192.168.1.3", site_id: site.id, + organization_id: site.organization_id, monitoring_enabled: true }) diff --git a/test/towerops/workers/device_poller_worker_test.exs b/test/towerops/workers/device_poller_worker_test.exs index e30c8375..db7529f8 100644 --- a/test/towerops/workers/device_poller_worker_test.exs +++ b/test/towerops/workers/device_poller_worker_test.exs @@ -29,6 +29,7 @@ defmodule Towerops.Workers.DevicePollerWorkerTest do name: "Router 1", ip_address: "192.168.1.1", site_id: site.id, + organization_id: site.organization_id, check_interval_seconds: 300 }) @@ -53,6 +54,7 @@ defmodule Towerops.Workers.DevicePollerWorkerTest do name: "Router 2", ip_address: "192.168.1.2", site_id: site.id, + organization_id: site.organization_id, check_interval_seconds: 600 }) @@ -74,7 +76,8 @@ defmodule Towerops.Workers.DevicePollerWorkerTest do Devices.create_device(%{ name: "Router 3", ip_address: "192.168.1.3", - site_id: site.id + site_id: site.id, + organization_id: site.organization_id }) # Start polling diff --git a/test/towerops_web/controllers/api/account_data_controller_test.exs b/test/towerops_web/controllers/api/account_data_controller_test.exs index d79cf347..01080d8c 100644 --- a/test/towerops_web/controllers/api/account_data_controller_test.exs +++ b/test/towerops_web/controllers/api/account_data_controller_test.exs @@ -73,6 +73,7 @@ defmodule ToweropsWeb.Api.AccountDataControllerTest do name: "Test Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: org.id, snmp_enabled: true, snmp_community: "secret-community-string" }) @@ -111,7 +112,8 @@ defmodule ToweropsWeb.Api.AccountDataControllerTest do Devices.create_device(%{ name: "Test Router", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: org.id }) # Create a recent alert @@ -150,7 +152,8 @@ defmodule ToweropsWeb.Api.AccountDataControllerTest do Devices.create_device(%{ name: "Test Router", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: org.id }) # Create an alert with an old triggered_at (120 days ago) diff --git a/test/towerops_web/live/alert_live_test.exs b/test/towerops_web/live/alert_live_test.exs index 7aca0288..e9225d1a 100644 --- a/test/towerops_web/live/alert_live_test.exs +++ b/test/towerops_web/live/alert_live_test.exs @@ -18,7 +18,8 @@ defmodule ToweropsWeb.AlertLive.IndexTest do Towerops.Devices.create_device(%{ name: "Test Router", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) %{organization: organization, site: site, device: device} diff --git a/test/towerops_web/live/dashboard_live_test.exs b/test/towerops_web/live/dashboard_live_test.exs index 59dd85d6..58c1c756 100644 --- a/test/towerops_web/live/dashboard_live_test.exs +++ b/test/towerops_web/live/dashboard_live_test.exs @@ -6,7 +6,7 @@ defmodule ToweropsWeb.DashboardLiveTest do setup :register_and_log_in_user setup %{user: user} do - {:ok, organization} = Towerops.Organizations.create_organization(%{name: "Test Org"}, user.id) + {:ok, organization} = Towerops.Organizations.create_organization(%{name: "Test Org", use_sites: true}, user.id) {:ok, site} = Towerops.Sites.create_site(%{ @@ -18,7 +18,16 @@ defmodule ToweropsWeb.DashboardLiveTest do end describe "Dashboard" do - test "displays organization name and stats", %{conn: conn, organization: organization} do + test "displays organization name and stats", %{conn: conn, organization: organization, site: site} do + # Create a device so the dashboard shows stats instead of empty state + {:ok, _device} = + Towerops.Devices.create_device(%{ + name: "Test Device", + ip_address: "192.168.1.1", + site_id: site.id, + organization_id: organization.id + }) + {:ok, _view, html} = live(conn, ~p"/orgs/#{organization.slug}") assert html =~ organization.name @@ -46,6 +55,7 @@ defmodule ToweropsWeb.DashboardLiveTest do name: "Router 1", ip_address: "192.168.1.1", site_id: site.id, + organization_id: organization.id, monitoring_enabled: true }) @@ -56,6 +66,7 @@ defmodule ToweropsWeb.DashboardLiveTest do name: "Router 2", ip_address: "192.168.1.2", site_id: site.id, + organization_id: organization.id, monitoring_enabled: true }) @@ -72,7 +83,8 @@ defmodule ToweropsWeb.DashboardLiveTest do Towerops.Devices.create_device(%{ name: "Router 1", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) # Create an active alert @@ -97,7 +109,8 @@ defmodule ToweropsWeb.DashboardLiveTest do Towerops.Devices.create_device(%{ name: "Router 1", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) {:ok, view, _html} = live(conn, ~p"/orgs/#{organization.slug}") diff --git a/test/towerops_web/live/device_live/form_test.exs b/test/towerops_web/live/device_live/form_test.exs index 1432ac73..89f8d74d 100644 --- a/test/towerops_web/live/device_live/form_test.exs +++ b/test/towerops_web/live/device_live/form_test.exs @@ -3,6 +3,8 @@ defmodule ToweropsWeb.DeviceLive.FormTest do import Phoenix.LiveViewTest + alias Towerops.Snmp.Device + setup :register_and_log_in_user setup %{user: user} do @@ -21,7 +23,8 @@ defmodule ToweropsWeb.DeviceLive.FormTest do describe "edit page rendering" do test "renders edit page when device has no SNMP discovery data (bug fix for nil boolean)", %{ conn: conn, - site: site + site: site, + organization: organization } do # Regression test for production bug where visiting edit page for a device # with no SNMP discovery data would crash with "expected boolean, got nil" @@ -33,6 +36,7 @@ defmodule ToweropsWeb.DeviceLive.FormTest do name: "Test Device", ip_address: "192.168.1.1", site_id: site.id, + organization_id: organization.id, snmp_enabled: true, snmp_version: "2c", snmp_port: 161, @@ -52,24 +56,18 @@ defmodule ToweropsWeb.DeviceLive.FormTest do assert html =~ device.name end - test "renders MikroTik section for superuser when device is MikroTik", %{ + test "renders MikroTik section when device is MikroTik", %{ conn: conn, site: site, - user: user + organization: organization } do - alias Towerops.Snmp.Device, as: SnmpDevice - # Make user a superuser using Ecto.Changeset (standard test pattern) - _user = - user - |> Ecto.Changeset.change(%{is_superuser: true}) - |> Towerops.Repo.update!() - # Create a device with MikroTik SNMP discovery data {:ok, device} = Towerops.Devices.create_device(%{ name: "MikroTik Router", ip_address: "192.168.1.254", site_id: site.id, + organization_id: organization.id, snmp_enabled: true, snmp_version: "2c", snmp_port: 161, @@ -79,8 +77,8 @@ defmodule ToweropsWeb.DeviceLive.FormTest do # Create SNMP device with MikroTik manufacturer (using Towerops.Snmp.Device schema) _snmp_device = - %SnmpDevice{} - |> SnmpDevice.changeset(%{ + %Device{} + |> Device.changeset(%{ device_id: device.id, manufacturer: "MikroTik", sys_descr: "RouterOS 7.8", @@ -97,9 +95,54 @@ defmodule ToweropsWeb.DeviceLive.FormTest do assert html =~ "Edit Device" assert html =~ device.name - # MikroTik section SHOULD be visible (superuser + MikroTik device) + # MikroTik section SHOULD be visible for all users with MikroTik devices assert html =~ "MikroTik API Configuration" end + + test "does not render MikroTik section when device is not MikroTik", %{ + conn: conn, + site: site, + organization: organization + } do + alias Device, as: SnmpDevice + + # Create a device with non-MikroTik SNMP discovery data + {:ok, device} = + Towerops.Devices.create_device(%{ + name: "Cisco Switch", + ip_address: "192.168.1.253", + site_id: site.id, + organization_id: organization.id, + snmp_enabled: true, + snmp_version: "2c", + snmp_port: 161, + monitoring_enabled: true, + check_interval_seconds: 300 + }) + + # Create SNMP device with Cisco manufacturer + _snmp_device = + %SnmpDevice{} + |> SnmpDevice.changeset(%{ + device_id: device.id, + manufacturer: "Cisco Systems", + sys_descr: "Cisco IOS", + sys_object_id: "1.3.6.1.4.1.9", + sys_uptime: 0, + sys_name: "test-switch" + }) + |> Towerops.Repo.insert!() + + # Visit edit page + {:ok, _view, html} = live(conn, ~p"/devices/#{device.id}/edit") + + # Page should render successfully + assert html =~ "Edit Device" + assert html =~ device.name + + # MikroTik section SHOULD NOT be visible for non-MikroTik devices + refute html =~ "MikroTik API Configuration" + end end describe "non_routable_ip?/1" do diff --git a/test/towerops_web/live/device_live_nested/show_test.exs b/test/towerops_web/live/device_live_nested/show_test.exs index 90c47421..29c40dec 100644 --- a/test/towerops_web/live/device_live_nested/show_test.exs +++ b/test/towerops_web/live/device_live_nested/show_test.exs @@ -22,7 +22,8 @@ defmodule ToweropsWeb.DeviceLive.ShowTest do Towerops.Devices.create_device(%{ name: "Test Router", ip_address: "192.168.1.1", - site_id: site.id + site_id: site.id, + organization_id: organization.id }) %{organization: organization, site: site, device: device} diff --git a/test/towerops_web/live/graph_live/show_test.exs b/test/towerops_web/live/graph_live/show_test.exs index 50d535d4..f79a199b 100644 --- a/test/towerops_web/live/graph_live/show_test.exs +++ b/test/towerops_web/live/graph_live/show_test.exs @@ -28,6 +28,7 @@ defmodule ToweropsWeb.GraphLive.ShowTest do name: "Test Router", ip_address: "192.168.1.1", site_id: site.id, + organization_id: organization.id, snmp_enabled: true }) diff --git a/test/towerops_web/live/my_data_live_test.exs b/test/towerops_web/live/my_data_live_test.exs index 6cb3cdc9..9b8aba55 100644 --- a/test/towerops_web/live/my_data_live_test.exs +++ b/test/towerops_web/live/my_data_live_test.exs @@ -31,6 +31,7 @@ defmodule ToweropsWeb.AccountLive.MyDataTest do name: "Test Device", ip_address: "192.168.1.1", site_id: site.id, + organization_id: organization.id, monitoring_enabled: true })