add preseem access points schema and migration
This commit is contained in:
parent
9f3eb55476
commit
5f17d5aed1
3 changed files with 182 additions and 0 deletions
65
lib/towerops/preseem/access_point.ex
Normal file
65
lib/towerops/preseem/access_point.ex
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
defmodule Towerops.Preseem.AccessPoint do
|
||||
@moduledoc """
|
||||
Schema for access points synced from Preseem API.
|
||||
"""
|
||||
use Ecto.Schema
|
||||
|
||||
import Ecto.Changeset
|
||||
|
||||
@primary_key {:id, :binary_id, autogenerate: true}
|
||||
@foreign_key_type :binary_id
|
||||
|
||||
@valid_match_confidences ~w(auto_mac auto_ip auto_hostname manual ambiguous unmatched)
|
||||
|
||||
schema "preseem_access_points" do
|
||||
field :preseem_id, :string
|
||||
field :name, :string
|
||||
field :mac_address, :string
|
||||
field :ip_address, :string
|
||||
field :model, :string
|
||||
field :firmware, :string
|
||||
field :capacity_score, :float
|
||||
field :qoe_score, :float
|
||||
field :rf_score, :float
|
||||
field :busy_hours, :integer
|
||||
field :airtime_utilization, :float
|
||||
field :subscriber_count, :integer
|
||||
field :match_confidence, :string, default: "unmatched"
|
||||
field :raw_data, :map
|
||||
|
||||
belongs_to :organization, Towerops.Organizations.Organization
|
||||
belongs_to :device, Towerops.Devices.Device
|
||||
|
||||
timestamps(type: :utc_datetime)
|
||||
end
|
||||
|
||||
def changeset(access_point, attrs) do
|
||||
access_point
|
||||
|> cast(attrs, [
|
||||
:organization_id,
|
||||
:preseem_id,
|
||||
:name,
|
||||
:mac_address,
|
||||
:ip_address,
|
||||
:model,
|
||||
:firmware,
|
||||
:capacity_score,
|
||||
:qoe_score,
|
||||
:rf_score,
|
||||
:busy_hours,
|
||||
:airtime_utilization,
|
||||
:subscriber_count,
|
||||
:device_id,
|
||||
:match_confidence,
|
||||
:raw_data
|
||||
])
|
||||
|> validate_required([:organization_id, :preseem_id])
|
||||
|> validate_inclusion(:match_confidence, @valid_match_confidences)
|
||||
|> unique_constraint([:organization_id, :preseem_id],
|
||||
error_key: :preseem_id,
|
||||
message: "has already been taken"
|
||||
)
|
||||
|> foreign_key_constraint(:organization_id)
|
||||
|> foreign_key_constraint(:device_id)
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
defmodule Towerops.Repo.Migrations.CreatePreseemAccessPoints do
|
||||
use Ecto.Migration
|
||||
|
||||
def change do
|
||||
create table(:preseem_access_points, primary_key: false) do
|
||||
add :id, :binary_id, primary_key: true
|
||||
|
||||
add :organization_id, references(:organizations, type: :binary_id, on_delete: :delete_all),
|
||||
null: false
|
||||
|
||||
add :preseem_id, :string, null: false
|
||||
add :name, :string
|
||||
add :mac_address, :string
|
||||
add :ip_address, :string
|
||||
add :model, :string
|
||||
add :firmware, :string
|
||||
add :capacity_score, :float
|
||||
add :qoe_score, :float
|
||||
add :rf_score, :float
|
||||
add :busy_hours, :integer
|
||||
add :airtime_utilization, :float
|
||||
add :subscriber_count, :integer
|
||||
add :device_id, references(:devices, type: :binary_id, on_delete: :nilify_all)
|
||||
add :match_confidence, :string, default: "unmatched"
|
||||
add :raw_data, :map
|
||||
|
||||
timestamps(type: :utc_datetime)
|
||||
end
|
||||
|
||||
create unique_index(:preseem_access_points, [:organization_id, :preseem_id])
|
||||
create index(:preseem_access_points, [:organization_id])
|
||||
create index(:preseem_access_points, [:device_id])
|
||||
create index(:preseem_access_points, [:match_confidence])
|
||||
end
|
||||
end
|
||||
82
test/towerops/preseem/access_point_test.exs
Normal file
82
test/towerops/preseem/access_point_test.exs
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
defmodule Towerops.Preseem.AccessPointTest do
|
||||
use Towerops.DataCase, async: true
|
||||
|
||||
import Towerops.AccountsFixtures
|
||||
import Towerops.OrganizationsFixtures
|
||||
|
||||
alias Towerops.Preseem.AccessPoint
|
||||
|
||||
setup do
|
||||
user = user_fixture()
|
||||
org = organization_fixture(user.id)
|
||||
%{organization: org}
|
||||
end
|
||||
|
||||
describe "changeset/2" do
|
||||
test "valid changeset with required fields", %{organization: org} do
|
||||
attrs = %{organization_id: org.id, preseem_id: "ap-123", name: "Tower1-AP1"}
|
||||
changeset = AccessPoint.changeset(%AccessPoint{}, attrs)
|
||||
assert changeset.valid?
|
||||
end
|
||||
|
||||
test "requires organization_id" do
|
||||
changeset = AccessPoint.changeset(%AccessPoint{}, %{preseem_id: "ap-1"})
|
||||
refute changeset.valid?
|
||||
assert "can't be blank" in errors_on(changeset).organization_id
|
||||
end
|
||||
|
||||
test "requires preseem_id" do
|
||||
changeset = AccessPoint.changeset(%AccessPoint{}, %{organization_id: Ecto.UUID.generate()})
|
||||
refute changeset.valid?
|
||||
assert "can't be blank" in errors_on(changeset).preseem_id
|
||||
end
|
||||
|
||||
test "validates match_confidence is a known value" do
|
||||
attrs = %{organization_id: Ecto.UUID.generate(), preseem_id: "ap-1", match_confidence: "bogus"}
|
||||
changeset = AccessPoint.changeset(%AccessPoint{}, attrs)
|
||||
refute changeset.valid?
|
||||
assert "is invalid" in errors_on(changeset).match_confidence
|
||||
end
|
||||
|
||||
test "accepts all valid match_confidence values" do
|
||||
for confidence <- ~w(auto_mac auto_ip auto_hostname manual ambiguous unmatched) do
|
||||
attrs = %{organization_id: Ecto.UUID.generate(), preseem_id: "ap-1", match_confidence: confidence}
|
||||
changeset = AccessPoint.changeset(%AccessPoint{}, attrs)
|
||||
assert changeset.valid?, "Expected #{confidence} to be valid"
|
||||
end
|
||||
end
|
||||
|
||||
test "enforces unique preseem_id per org", %{organization: org} do
|
||||
attrs = %{organization_id: org.id, preseem_id: "ap-123"}
|
||||
{:ok, _} = %AccessPoint{} |> AccessPoint.changeset(attrs) |> Repo.insert()
|
||||
assert {:error, changeset} = %AccessPoint{} |> AccessPoint.changeset(attrs) |> Repo.insert()
|
||||
assert "has already been taken" in errors_on(changeset).preseem_id
|
||||
end
|
||||
|
||||
test "stores and retrieves raw_data", %{organization: org} do
|
||||
raw = %{"extra_field" => "value", "nested" => %{"key" => 42}}
|
||||
attrs = %{organization_id: org.id, preseem_id: "ap-raw", raw_data: raw}
|
||||
{:ok, ap} = %AccessPoint{} |> AccessPoint.changeset(attrs) |> Repo.insert()
|
||||
reloaded = Repo.get!(AccessPoint, ap.id)
|
||||
assert reloaded.raw_data == raw
|
||||
end
|
||||
|
||||
test "stores numeric scores", %{organization: org} do
|
||||
attrs = %{
|
||||
organization_id: org.id,
|
||||
preseem_id: "ap-scores",
|
||||
qoe_score: 85.5,
|
||||
capacity_score: 72.0,
|
||||
rf_score: 90.1,
|
||||
busy_hours: 4,
|
||||
airtime_utilization: 65.3,
|
||||
subscriber_count: 42
|
||||
}
|
||||
|
||||
{:ok, ap} = %AccessPoint{} |> AccessPoint.changeset(attrs) |> Repo.insert()
|
||||
reloaded = Repo.get!(AccessPoint, ap.id)
|
||||
assert reloaded.qoe_score == 85.5
|
||||
assert reloaded.subscriber_count == 42
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Reference in a new issue