towerops/test/test_helper.exs
Graham McIntire 5a9381f91a feat: add /coverage RF prediction feature scaffold
End-to-end CRUD scaffold for per-site, per-antenna RF coverage
prediction. Schema, context, antenna registry, Oban worker stub, and
three LiveViews are wired up; the actual ITM + LIDAR + buildings
compute pipeline lands in a follow-up.

- Migration + Coverage schema with full validation (RF params, pixel-
  budget cap, antenna_slug existence). organization_id excluded from
  cast (programmatic-only).
- Coverages context: org-scoped CRUD, validate_site_in_organization
  rejects cross-tenant site_id refs at insert/update, queue_compute
  with PubSub broadcast on per-coverage and per-org topics.
- MSI Planet .ant parser + persistent_term registry loaded at boot
  from priv/antennas/. Two synthetic .ant fixtures (omni + 90deg
  sector) bundled.
- CoverageWorker on new :coverage Oban queue (concurrency 2). Job
  args carry organization_id; worker refuses to run on org mismatch.
  Stub flips status to "failed" with "compute not yet implemented"
  so the UI flow is exercisable.
- LiveViews: index (org-wide, live status updates), form (antenna
  picker grouped by manufacturer), show (status banners, params
  panel, map placeholder). Sidebar nav link added.
- Routes /coverage, /coverage/new, /coverage/:id, /coverage/:id/edit
  under :require_authenticated_user_with_default_org.
- 41 new tests covering schema validation, .ant parsing, context
  CRUD with cross-org guards, Oban job enqueue.
2026-05-06 13:44:14 -05:00

84 lines
2.6 KiB
Elixir

# Configure MIB directories BEFORE any NIF loading
# This must happen before ExUnit.start() to ensure ToweropsNative NIF
# can find vendor MIBs when it initializes
mib_dir = Application.app_dir(:towerops, "priv/mibs")
if File.dir?(mib_dir) do
# Get main directory plus all subdirectories for vendor MIBs
subdirs =
mib_dir
|> File.ls!()
|> Enum.map(&Path.join(mib_dir, &1))
|> Enum.filter(&File.dir?/1)
mib_dirs = [mib_dir | subdirs]
mibdirs_env = Enum.join(mib_dirs, ":")
# Set environment variables BEFORE initializing the NIF
System.put_env("MIBDIRS", mibdirs_env)
System.put_env("MIBS", "ALL")
# Add each directory to net-snmp's search path
Enum.each(mib_dirs, fn dir ->
case ToweropsNative.load_mib_directory(dir) do
:ok -> :ok
# Ignore errors in test environment
{:error, _reason} -> :ok
end
end)
# Explicitly initialize the MIB library with correct environment variables
case ToweropsNative.init_mib_library() do
result when result in ["initialized", "already_initialized"] ->
IO.puts("Test MIB library initialized: #{result}")
other ->
IO.puts("Warning: Unexpected MIB library init result: #{inspect(other)}")
end
end
# Load antenna pattern registry for tests that exercise the Coverages
# context (the schema validates antenna_slug against this in-memory registry).
Towerops.Coverages.Antenna.load_registry()
ExUnit.start()
# Exclude tests by default
# Run specific tests with: mix test --only <tag>
ExUnit.configure(
exclude: [
:integration,
# Tests making real network calls (ping, DNS, SSL)
:network,
# SnmpKit-specific exclusions
:performance,
:snmpv3,
:memory,
:shell_integration,
:optional,
:needs_simulator,
:manual,
:real_device,
:yecc_required
]
)
# Define mocks for testing
Mox.defmock(Towerops.Monitoring.PingMock, for: Towerops.Monitoring.PingBehaviour)
Mox.defmock(Towerops.Snmp.PollerMock, for: Towerops.Snmp.PollerBehaviour)
Mox.defmock(Towerops.Snmp.SnmpMock, for: Towerops.Snmp.SnmpBehaviour)
Mox.defmock(Towerops.RateLimit.RedisClientMock, for: Towerops.RateLimit.RedisClient)
# Define stub module for SNMP mock (returns errors for all calls)
defmodule Towerops.Snmp.SnmpMockStub do
@moduledoc false
@behaviour Towerops.Snmp.SnmpBehaviour
def get(_target, _oid, _opts), do: {:error, :timeout}
def get_next(_target, _oid, _opts), do: {:error, :timeout}
def walk(_target, _oid, _opts), do: {:error, :timeout}
def get_bulk(_target, _oid, _opts), do: {:error, :timeout}
def get_multiple(_target, _oids, _opts), do: {:error, :timeout}
end
Ecto.Adapters.SQL.Sandbox.mode(Towerops.Repo, :manual)