303 lines
9.2 KiB
Elixir
303 lines
9.2 KiB
Elixir
defmodule Towerops.Workers.DataRetentionWorkerTest do
|
|
use Towerops.DataCase, async: false
|
|
|
|
import Towerops.AccountsFixtures
|
|
import Towerops.DevicesFixtures
|
|
import Towerops.OrganizationsFixtures
|
|
|
|
alias Towerops.Organizations
|
|
alias Towerops.Repo
|
|
alias Towerops.Workers.DataRetentionWorker
|
|
|
|
describe "perform/1" do
|
|
test "deletes monitoring_checks older than org retention period" do
|
|
user = user_fixture()
|
|
org = organization_fixture(user.id)
|
|
{:ok, org} = Organizations.update_organization(org, %{data_retention_days: 30})
|
|
device = device_fixture(%{organization_id: org.id})
|
|
|
|
now = Towerops.Time.now()
|
|
old_time = DateTime.add(now, -31, :day)
|
|
recent_time = DateTime.add(now, -10, :day)
|
|
|
|
old_id = Ecto.UUID.generate()
|
|
recent_id = Ecto.UUID.generate()
|
|
|
|
Repo.insert_all("monitoring_checks", [
|
|
%{
|
|
id: Ecto.UUID.dump!(old_id),
|
|
device_id: Ecto.UUID.dump!(device.id),
|
|
status: "success",
|
|
checked_at: old_time,
|
|
inserted_at: old_time
|
|
},
|
|
%{
|
|
id: Ecto.UUID.dump!(recent_id),
|
|
device_id: Ecto.UUID.dump!(device.id),
|
|
status: "success",
|
|
checked_at: recent_time,
|
|
inserted_at: recent_time
|
|
}
|
|
])
|
|
|
|
assert {:ok, result} = DataRetentionWorker.perform(%Oban.Job{args: %{}})
|
|
assert result.total_deleted >= 1
|
|
|
|
# Old record should be deleted
|
|
remaining =
|
|
Repo.all(
|
|
from(m in "monitoring_checks",
|
|
where: m.device_id == type(^device.id, :binary_id),
|
|
select: m.id
|
|
)
|
|
)
|
|
|
|
remaining_uuids = Enum.map(remaining, &Ecto.UUID.cast!/1)
|
|
refute old_id in remaining_uuids
|
|
assert recent_id in remaining_uuids
|
|
end
|
|
|
|
test "deletes check_results older than org retention (direct org_id)" do
|
|
user = user_fixture()
|
|
org = organization_fixture(user.id)
|
|
{:ok, org} = Organizations.update_organization(org, %{data_retention_days: 30})
|
|
|
|
now = Towerops.Time.now()
|
|
old_time = DateTime.add(now, -31, :day)
|
|
recent_time = DateTime.add(now, -10, :day)
|
|
|
|
# Create a check for the org
|
|
{:ok, check} =
|
|
Towerops.Monitoring.create_check(%{
|
|
organization_id: org.id,
|
|
check_type: "http",
|
|
name: "Test Check",
|
|
interval_seconds: 60,
|
|
config: %{"url" => "http://example.com"}
|
|
})
|
|
|
|
old_id = Ecto.UUID.generate()
|
|
recent_id = Ecto.UUID.generate()
|
|
|
|
Repo.insert_all("check_results", [
|
|
%{
|
|
id: Ecto.UUID.dump!(old_id),
|
|
organization_id: Ecto.UUID.dump!(org.id),
|
|
check_id: Ecto.UUID.dump!(check.id),
|
|
status: 0,
|
|
checked_at: old_time
|
|
},
|
|
%{
|
|
id: Ecto.UUID.dump!(recent_id),
|
|
organization_id: Ecto.UUID.dump!(org.id),
|
|
check_id: Ecto.UUID.dump!(check.id),
|
|
status: 0,
|
|
checked_at: recent_time
|
|
}
|
|
])
|
|
|
|
assert {:ok, result} = DataRetentionWorker.perform(%Oban.Job{args: %{}})
|
|
assert result.total_deleted >= 1
|
|
|
|
remaining =
|
|
Repo.all(
|
|
from(cr in "check_results",
|
|
where: cr.organization_id == type(^org.id, :binary_id),
|
|
select: cr.id
|
|
)
|
|
)
|
|
|
|
remaining_uuids = Enum.map(remaining, &Ecto.UUID.cast!/1)
|
|
refute old_id in remaining_uuids
|
|
assert recent_id in remaining_uuids
|
|
end
|
|
|
|
test "respects different retention periods per org" do
|
|
user1 = user_fixture()
|
|
org1 = organization_fixture(user1.id)
|
|
{:ok, org1} = Organizations.update_organization(org1, %{data_retention_days: 60})
|
|
device1 = device_fixture(%{organization_id: org1.id})
|
|
|
|
user2 = user_fixture()
|
|
org2 = organization_fixture(user2.id)
|
|
{:ok, org2} = Organizations.update_organization(org2, %{data_retention_days: 90})
|
|
device2 = device_fixture(%{organization_id: org2.id})
|
|
|
|
now = Towerops.Time.now()
|
|
# 75 days old: past org1's 60-day retention, within org2's 90-day retention
|
|
mid_time = DateTime.add(now, -75, :day)
|
|
|
|
org1_check_id = Ecto.UUID.generate()
|
|
org2_check_id = Ecto.UUID.generate()
|
|
|
|
Repo.insert_all("monitoring_checks", [
|
|
%{
|
|
id: Ecto.UUID.dump!(org1_check_id),
|
|
device_id: Ecto.UUID.dump!(device1.id),
|
|
status: "success",
|
|
checked_at: mid_time,
|
|
inserted_at: mid_time
|
|
},
|
|
%{
|
|
id: Ecto.UUID.dump!(org2_check_id),
|
|
device_id: Ecto.UUID.dump!(device2.id),
|
|
status: "success",
|
|
checked_at: mid_time,
|
|
inserted_at: mid_time
|
|
}
|
|
])
|
|
|
|
assert {:ok, _result} = DataRetentionWorker.perform(%Oban.Job{args: %{}})
|
|
|
|
# org1 record should be deleted (75 days > 60 day retention)
|
|
org1_remaining =
|
|
Repo.all(
|
|
from(m in "monitoring_checks",
|
|
where: m.device_id == type(^device1.id, :binary_id),
|
|
select: m.id
|
|
)
|
|
)
|
|
|
|
assert org1_remaining == []
|
|
|
|
# org2 record should remain (75 days < 90 day retention)
|
|
org2_remaining =
|
|
Repo.all(
|
|
from(m in "monitoring_checks",
|
|
where: m.device_id == type(^device2.id, :binary_id),
|
|
select: m.id
|
|
)
|
|
)
|
|
|
|
org2_remaining_uuids = Enum.map(org2_remaining, &Ecto.UUID.cast!/1)
|
|
assert org2_check_id in org2_remaining_uuids
|
|
end
|
|
|
|
test "does NOT delete data within retention window" do
|
|
user = user_fixture()
|
|
org = organization_fixture(user.id)
|
|
# Default 365-day retention
|
|
device = device_fixture(%{organization_id: org.id})
|
|
|
|
now = Towerops.Time.now()
|
|
recent_time = DateTime.add(now, -100, :day)
|
|
|
|
recent_id = Ecto.UUID.generate()
|
|
|
|
Repo.insert_all("monitoring_checks", [
|
|
%{
|
|
id: Ecto.UUID.dump!(recent_id),
|
|
device_id: Ecto.UUID.dump!(device.id),
|
|
status: "success",
|
|
checked_at: recent_time,
|
|
inserted_at: recent_time
|
|
}
|
|
])
|
|
|
|
assert {:ok, result} = DataRetentionWorker.perform(%Oban.Job{args: %{}})
|
|
|
|
remaining =
|
|
Repo.all(
|
|
from(m in "monitoring_checks",
|
|
where: m.device_id == type(^device.id, :binary_id),
|
|
select: m.id
|
|
)
|
|
)
|
|
|
|
remaining_uuids = Enum.map(remaining, &Ecto.UUID.cast!/1)
|
|
assert recent_id in remaining_uuids
|
|
assert result.total_deleted == 0
|
|
end
|
|
|
|
test "returns summary with deletion counts" do
|
|
user = user_fixture()
|
|
org = organization_fixture(user.id)
|
|
{:ok, org} = Organizations.update_organization(org, %{data_retention_days: 30})
|
|
device = device_fixture(%{organization_id: org.id})
|
|
|
|
now = Towerops.Time.now()
|
|
old_time = DateTime.add(now, -31, :day)
|
|
|
|
Repo.insert_all("monitoring_checks", [
|
|
%{
|
|
id: Ecto.UUID.dump!(Ecto.UUID.generate()),
|
|
device_id: Ecto.UUID.dump!(device.id),
|
|
status: "success",
|
|
checked_at: old_time,
|
|
inserted_at: old_time
|
|
},
|
|
%{
|
|
id: Ecto.UUID.dump!(Ecto.UUID.generate()),
|
|
device_id: Ecto.UUID.dump!(device.id),
|
|
status: "success",
|
|
checked_at: old_time,
|
|
inserted_at: old_time
|
|
}
|
|
])
|
|
|
|
assert {:ok, result} = DataRetentionWorker.perform(%Oban.Job{args: %{}})
|
|
assert result.total_deleted >= 2
|
|
assert is_map(result.details)
|
|
assert Map.get(result.details, "monitoring_checks") >= 2
|
|
end
|
|
|
|
test "only deletes resolved alerts, keeps unresolved regardless of age" do
|
|
user = user_fixture()
|
|
org = organization_fixture(user.id)
|
|
{:ok, org} = Organizations.update_organization(org, %{data_retention_days: 30})
|
|
device = device_fixture(%{organization_id: org.id})
|
|
|
|
now = Towerops.Time.now()
|
|
old_time = DateTime.add(now, -31, :day)
|
|
|
|
resolved_id = Ecto.UUID.generate()
|
|
unresolved_id = Ecto.UUID.generate()
|
|
|
|
Repo.insert_all("alerts", [
|
|
%{
|
|
id: Ecto.UUID.dump!(resolved_id),
|
|
organization_id: Ecto.UUID.dump!(org.id),
|
|
device_id: Ecto.UUID.dump!(device.id),
|
|
alert_type: "device_down",
|
|
triggered_at: old_time,
|
|
resolved_at: old_time,
|
|
storm_suppressed: false,
|
|
notification_sent: false,
|
|
inserted_at: old_time,
|
|
updated_at: old_time
|
|
},
|
|
%{
|
|
id: Ecto.UUID.dump!(unresolved_id),
|
|
organization_id: Ecto.UUID.dump!(org.id),
|
|
device_id: Ecto.UUID.dump!(device.id),
|
|
alert_type: "device_down",
|
|
triggered_at: old_time,
|
|
resolved_at: nil,
|
|
storm_suppressed: false,
|
|
notification_sent: false,
|
|
inserted_at: old_time,
|
|
updated_at: old_time
|
|
}
|
|
])
|
|
|
|
assert {:ok, _result} = DataRetentionWorker.perform(%Oban.Job{args: %{}})
|
|
|
|
remaining =
|
|
Repo.all(
|
|
from(a in "alerts",
|
|
where: a.organization_id == type(^org.id, :binary_id),
|
|
select: a.id
|
|
)
|
|
)
|
|
|
|
remaining_uuids = Enum.map(remaining, &Ecto.UUID.cast!/1)
|
|
refute resolved_id in remaining_uuids
|
|
assert unresolved_id in remaining_uuids
|
|
end
|
|
|
|
test "works when no organizations exist" do
|
|
assert {:ok, result} = DataRetentionWorker.perform(%Oban.Job{args: %{}})
|
|
assert result.total_deleted == 0
|
|
end
|
|
end
|
|
end
|