more tests

This commit is contained in:
Graham McIntire 2026-02-03 15:27:05 -06:00
parent 891fb04f5a
commit f6509cac08
No known key found for this signature in database
3 changed files with 569 additions and 0 deletions

View file

@ -0,0 +1,163 @@
defmodule Towerops.Agents.AgentAssignmentTest do
use Towerops.DataCase, async: true
alias Towerops.Agents.AgentAssignment
describe "changeset/2" do
test "valid changeset with required fields" do
agent_token_id = Ecto.UUID.generate()
device_id = Ecto.UUID.generate()
attrs = %{
agent_token_id: agent_token_id,
device_id: device_id
}
changeset = AgentAssignment.changeset(%AgentAssignment{}, attrs)
assert changeset.valid?
assert changeset.changes.agent_token_id == agent_token_id
assert changeset.changes.device_id == device_id
end
test "valid changeset with all fields" do
agent_token_id = Ecto.UUID.generate()
device_id = Ecto.UUID.generate()
attrs = %{
agent_token_id: agent_token_id,
device_id: device_id,
enabled: false
}
changeset = AgentAssignment.changeset(%AgentAssignment{}, attrs)
assert changeset.valid?
assert changeset.changes.agent_token_id == agent_token_id
assert changeset.changes.device_id == device_id
assert changeset.changes.enabled == false
end
test "enabled defaults to true" do
agent_token_id = Ecto.UUID.generate()
device_id = Ecto.UUID.generate()
attrs = %{
agent_token_id: agent_token_id,
device_id: device_id
}
changeset = AgentAssignment.changeset(%AgentAssignment{}, attrs)
assert changeset.valid?
assert Ecto.Changeset.get_field(changeset, :enabled) == true
end
test "requires agent_token_id" do
device_id = Ecto.UUID.generate()
attrs = %{device_id: device_id}
changeset = AgentAssignment.changeset(%AgentAssignment{}, attrs)
refute changeset.valid?
assert %{agent_token_id: ["can't be blank"]} = errors_on(changeset)
end
test "requires device_id" do
agent_token_id = Ecto.UUID.generate()
attrs = %{agent_token_id: agent_token_id}
changeset = AgentAssignment.changeset(%AgentAssignment{}, attrs)
refute changeset.valid?
assert %{device_id: ["can't be blank"]} = errors_on(changeset)
end
test "accepts enabled as true" do
agent_token_id = Ecto.UUID.generate()
device_id = Ecto.UUID.generate()
attrs = %{
agent_token_id: agent_token_id,
device_id: device_id,
enabled: true
}
changeset = AgentAssignment.changeset(%AgentAssignment{}, attrs)
assert changeset.valid?
assert Ecto.Changeset.get_field(changeset, :enabled) == true
end
test "accepts enabled as false" do
agent_token_id = Ecto.UUID.generate()
device_id = Ecto.UUID.generate()
attrs = %{
agent_token_id: agent_token_id,
device_id: device_id,
enabled: false
}
changeset = AgentAssignment.changeset(%AgentAssignment{}, attrs)
assert changeset.valid?
assert changeset.changes.enabled == false
end
test "allows updating enabled field" do
agent_token_id = Ecto.UUID.generate()
device_id = Ecto.UUID.generate()
existing_assignment = %AgentAssignment{
id: Ecto.UUID.generate(),
agent_token_id: agent_token_id,
device_id: device_id,
enabled: true
}
attrs = %{enabled: false}
changeset = AgentAssignment.changeset(existing_assignment, attrs)
assert changeset.valid?
assert changeset.changes.enabled == false
end
test "allows changing agent_token_id" do
old_agent_token_id = Ecto.UUID.generate()
new_agent_token_id = Ecto.UUID.generate()
device_id = Ecto.UUID.generate()
existing_assignment = %AgentAssignment{
id: Ecto.UUID.generate(),
agent_token_id: old_agent_token_id,
device_id: device_id,
enabled: true
}
attrs = %{agent_token_id: new_agent_token_id}
changeset = AgentAssignment.changeset(existing_assignment, attrs)
assert changeset.valid?
assert changeset.changes.agent_token_id == new_agent_token_id
end
test "casts all supported fields" do
agent_token_id = Ecto.UUID.generate()
device_id = Ecto.UUID.generate()
attrs = %{
agent_token_id: agent_token_id,
device_id: device_id,
enabled: false
}
changeset = AgentAssignment.changeset(%AgentAssignment{}, attrs)
assert changeset.valid?
assert Map.has_key?(changeset.changes, :agent_token_id)
assert Map.has_key?(changeset.changes, :device_id)
assert Map.has_key?(changeset.changes, :enabled)
end
end
end

View file

@ -0,0 +1,228 @@
defmodule Towerops.Agents.AgentTokenTest do
use Towerops.DataCase, async: true
alias Towerops.Agents.AgentToken
describe "build_token/3" do
test "generates a token with 48 bytes of entropy" do
org_id = Ecto.UUID.generate()
{token, _changeset} = AgentToken.build_token(org_id, "Test Agent")
# Decode the base64-encoded token
decoded = Base.url_decode64!(token, padding: false)
# Should be exactly 48 bytes
assert byte_size(decoded) == 48
end
test "returns token string and valid changeset for organization agent" do
org_id = Ecto.UUID.generate()
{token, changeset} = AgentToken.build_token(org_id, "My Agent")
assert is_binary(token)
assert changeset.valid?
assert changeset.changes.token == token
assert changeset.changes.name == "My Agent"
assert changeset.changes.organization_id == org_id
assert Ecto.Changeset.get_field(changeset, :is_cloud_poller) == false
end
test "sets is_cloud_poller to false by default" do
org_id = Ecto.UUID.generate()
{_token, changeset} = AgentToken.build_token(org_id, "Test Agent")
assert Ecto.Changeset.get_field(changeset, :is_cloud_poller) == false
end
test "generates unique tokens on each call" do
org_id = Ecto.UUID.generate()
{token1, _} = AgentToken.build_token(org_id, "Agent 1")
{token2, _} = AgentToken.build_token(org_id, "Agent 2")
{token3, _} = AgentToken.build_token(org_id, "Agent 3")
# All tokens should be different
assert token1 != token2
assert token2 != token3
assert token1 != token3
end
test "creates cloud poller token when is_cloud_poller is true" do
{token, changeset} = AgentToken.build_token(nil, "Cloud Poller", is_cloud_poller: true)
assert is_binary(token)
assert changeset.valid?
assert changeset.changes.is_cloud_poller == true
refute Map.has_key?(changeset.changes, :organization_id)
end
test "requires name" do
org_id = Ecto.UUID.generate()
{_token, changeset} = AgentToken.build_token(org_id, nil)
refute changeset.valid?
assert %{name: ["can't be blank"]} = errors_on(changeset)
end
test "adds error if cloud poller has organization_id" do
org_id = Ecto.UUID.generate()
{_token, changeset} = AgentToken.build_token(org_id, "Test", is_cloud_poller: true)
refute changeset.valid?
assert %{organization_id: ["must be nil for cloud pollers"]} = errors_on(changeset)
end
test "adds error if non-cloud poller has nil organization_id" do
{_token, changeset} = AgentToken.build_token(nil, "Test", is_cloud_poller: false)
refute changeset.valid?
assert %{organization_id: ["can't be blank for non-cloud pollers"]} = errors_on(changeset)
end
test "token is URL-safe base64 encoded without padding" do
org_id = Ecto.UUID.generate()
{token, _changeset} = AgentToken.build_token(org_id, "Test Agent")
# Should not contain padding characters
refute String.contains?(token, "=")
# Should only contain URL-safe base64 characters
assert token =~ ~r/^[A-Za-z0-9_-]+$/
end
end
describe "update_changeset/2" do
test "allows updating name" do
agent_token = %AgentToken{
id: Ecto.UUID.generate(),
token: "existing-token",
name: "Old Name",
organization_id: Ecto.UUID.generate()
}
attrs = %{name: "New Name"}
changeset = AgentToken.update_changeset(agent_token, attrs)
assert changeset.valid?
assert changeset.changes.name == "New Name"
end
test "allows updating allow_remote_debug" do
agent_token = %AgentToken{
id: Ecto.UUID.generate(),
token: "existing-token",
name: "Test Agent",
organization_id: Ecto.UUID.generate(),
allow_remote_debug: false
}
attrs = %{allow_remote_debug: true}
changeset = AgentToken.update_changeset(agent_token, attrs)
assert changeset.valid?
assert changeset.changes.allow_remote_debug == true
end
test "allows updating both name and allow_remote_debug" do
agent_token = %AgentToken{
id: Ecto.UUID.generate(),
token: "existing-token",
name: "Old Name",
organization_id: Ecto.UUID.generate(),
allow_remote_debug: false
}
attrs = %{name: "New Name", allow_remote_debug: true}
changeset = AgentToken.update_changeset(agent_token, attrs)
assert changeset.valid?
assert changeset.changes.name == "New Name"
assert changeset.changes.allow_remote_debug == true
end
test "requires name" do
agent_token = %AgentToken{
id: Ecto.UUID.generate(),
token: "existing-token",
name: "Old Name",
organization_id: Ecto.UUID.generate()
}
attrs = %{name: ""}
changeset = AgentToken.update_changeset(agent_token, attrs)
refute changeset.valid?
assert %{name: ["can't be blank"]} = errors_on(changeset)
end
test "ignores attempts to update token" do
agent_token = %AgentToken{
id: Ecto.UUID.generate(),
token: "original-token",
name: "Test Agent",
organization_id: Ecto.UUID.generate()
}
attrs = %{name: "New Name", token: "hacker-token"}
changeset = AgentToken.update_changeset(agent_token, attrs)
assert changeset.valid?
assert changeset.changes.name == "New Name"
refute Map.has_key?(changeset.changes, :token)
end
test "ignores attempts to update organization_id" do
agent_token = %AgentToken{
id: Ecto.UUID.generate(),
token: "existing-token",
name: "Test Agent",
organization_id: Ecto.UUID.generate()
}
new_org_id = Ecto.UUID.generate()
attrs = %{name: "New Name", organization_id: new_org_id}
changeset = AgentToken.update_changeset(agent_token, attrs)
assert changeset.valid?
assert changeset.changes.name == "New Name"
refute Map.has_key?(changeset.changes, :organization_id)
end
test "ignores attempts to update enabled" do
agent_token = %AgentToken{
id: Ecto.UUID.generate(),
token: "existing-token",
name: "Test Agent",
organization_id: Ecto.UUID.generate(),
enabled: true
}
attrs = %{name: "New Name", enabled: false}
changeset = AgentToken.update_changeset(agent_token, attrs)
assert changeset.valid?
assert changeset.changes.name == "New Name"
refute Map.has_key?(changeset.changes, :enabled)
end
end
describe "verify_token/1" do
test "returns {:ok, token} for valid binary token" do
token = "valid-token-string"
assert AgentToken.verify_token(token) == {:ok, token}
end
test "returns {:ok, token} for any binary string" do
assert AgentToken.verify_token("abc123") == {:ok, "abc123"}
assert AgentToken.verify_token("") == {:ok, ""}
assert AgentToken.verify_token("with-dashes") == {:ok, "with-dashes"}
end
test "returns {:error, :invalid_token} for non-binary values" do
assert AgentToken.verify_token(nil) == {:error, :invalid_token}
assert AgentToken.verify_token(12_345) == {:error, :invalid_token}
assert AgentToken.verify_token([]) == {:error, :invalid_token}
assert AgentToken.verify_token(%{}) == {:error, :invalid_token}
assert AgentToken.verify_token(:atom) == {:error, :invalid_token}
end
end
end

View file

@ -0,0 +1,178 @@
defmodule Towerops.Alerts.AlertTest do
use Towerops.DataCase, async: true
alias Towerops.Alerts.Alert
describe "changeset/2" do
test "valid changeset with required fields" do
attrs = %{
device_id: Ecto.UUID.generate(),
alert_type: :device_down,
triggered_at: ~U[2026-01-15 10:00:00Z]
}
changeset = Alert.changeset(%Alert{}, attrs)
assert changeset.valid?
assert changeset.changes.device_id == attrs.device_id
assert changeset.changes.alert_type == :device_down
assert changeset.changes.triggered_at == attrs.triggered_at
end
test "valid changeset with all fields" do
device_id = Ecto.UUID.generate()
user_id = Ecto.UUID.generate()
triggered_at = ~U[2026-01-15 10:00:00Z]
acknowledged_at = ~U[2026-01-15 10:05:00Z]
resolved_at = ~U[2026-01-15 10:10:00Z]
email_sent_at = ~U[2026-01-15 10:01:00Z]
attrs = %{
device_id: device_id,
alert_type: :device_up,
triggered_at: triggered_at,
acknowledged_at: acknowledged_at,
acknowledged_by_id: user_id,
resolved_at: resolved_at,
email_sent_at: email_sent_at,
message: "Device came back online"
}
changeset = Alert.changeset(%Alert{}, attrs)
assert changeset.valid?
assert changeset.changes.device_id == device_id
assert changeset.changes.alert_type == :device_up
assert changeset.changes.triggered_at == triggered_at
assert changeset.changes.acknowledged_at == acknowledged_at
assert changeset.changes.acknowledged_by_id == user_id
assert changeset.changes.resolved_at == resolved_at
assert changeset.changes.email_sent_at == email_sent_at
assert changeset.changes.message == "Device came back online"
end
test "requires device_id" do
attrs = %{
alert_type: :device_down,
triggered_at: ~U[2026-01-15 10:00:00Z]
}
changeset = Alert.changeset(%Alert{}, attrs)
refute changeset.valid?
assert %{device_id: ["can't be blank"]} = errors_on(changeset)
end
test "requires alert_type" do
attrs = %{
device_id: Ecto.UUID.generate(),
triggered_at: ~U[2026-01-15 10:00:00Z]
}
changeset = Alert.changeset(%Alert{}, attrs)
refute changeset.valid?
assert %{alert_type: ["can't be blank"]} = errors_on(changeset)
end
test "requires triggered_at" do
attrs = %{
device_id: Ecto.UUID.generate(),
alert_type: :device_down
}
changeset = Alert.changeset(%Alert{}, attrs)
refute changeset.valid?
assert %{triggered_at: ["can't be blank"]} = errors_on(changeset)
end
test "validates alert_type is one of valid enum values" do
attrs = %{
device_id: Ecto.UUID.generate(),
alert_type: :device_down,
triggered_at: ~U[2026-01-15 10:00:00Z]
}
changeset = Alert.changeset(%Alert{}, attrs)
assert changeset.valid?
attrs2 = %{attrs | alert_type: :device_up}
changeset2 = Alert.changeset(%Alert{}, attrs2)
assert changeset2.valid?
end
test "accepts nil for optional fields" do
attrs = %{
device_id: Ecto.UUID.generate(),
alert_type: :device_down,
triggered_at: ~U[2026-01-15 10:00:00Z],
acknowledged_at: nil,
acknowledged_by_id: nil,
resolved_at: nil,
email_sent_at: nil,
message: nil
}
changeset = Alert.changeset(%Alert{}, attrs)
assert changeset.valid?
end
test "allows updating an existing alert" do
device_id = Ecto.UUID.generate()
existing_alert = %Alert{
id: Ecto.UUID.generate(),
device_id: device_id,
alert_type: :device_down,
triggered_at: ~U[2026-01-15 10:00:00Z]
}
user_id = Ecto.UUID.generate()
attrs = %{
acknowledged_at: ~U[2026-01-15 10:05:00Z],
acknowledged_by_id: user_id,
message: "Acknowledged by admin"
}
changeset = Alert.changeset(existing_alert, attrs)
assert changeset.valid?
assert changeset.changes.acknowledged_at == attrs.acknowledged_at
assert changeset.changes.acknowledged_by_id == user_id
assert changeset.changes.message == "Acknowledged by admin"
end
test "casts all supported fields" do
device_id = Ecto.UUID.generate()
user_id = Ecto.UUID.generate()
attrs = %{
device_id: device_id,
alert_type: :device_down,
triggered_at: ~U[2026-01-15 10:00:00Z],
acknowledged_at: ~U[2026-01-15 10:05:00Z],
acknowledged_by_id: user_id,
resolved_at: ~U[2026-01-15 10:10:00Z],
email_sent_at: ~U[2026-01-15 10:01:00Z],
message: "Test message"
}
changeset = Alert.changeset(%Alert{}, attrs)
assert changeset.valid?
# All fields should be in changes
assert Map.has_key?(changeset.changes, :device_id)
assert Map.has_key?(changeset.changes, :alert_type)
assert Map.has_key?(changeset.changes, :triggered_at)
assert Map.has_key?(changeset.changes, :acknowledged_at)
assert Map.has_key?(changeset.changes, :acknowledged_by_id)
assert Map.has_key?(changeset.changes, :resolved_at)
assert Map.has_key?(changeset.changes, :email_sent_at)
assert Map.has_key?(changeset.changes, :message)
end
end
end