Optimized the slowest tests to improve test suite performance:
1. Property-based IP validation test (6s → ~2.4s)
- Reduced max_runs from 50 to 20 iterations
- Still provides good coverage while being much faster
2. Database-heavy tests (~1s each)
- Replaced individual create_check calls with bulk Repo.insert_all
- Reduced check counts from 15 to 10 where adequate for testing
- Fixed timestamp handling (truncate to :second for Ecto)
- Fixed response_time_ms to use floats (schema requirement)
- Removed updated_at (disabled in Check schema)
- Tests affected:
* get_device_latency_by_agent/2
* get_uptime_percentage/1
* get_latency_data/2 respects limit
* AgentLatencyEvaluator tests
Expected speedup: ~40% reduction in top 10 slowest tests (12.8s → ~7.7s)
These optimizations maintain test coverage while significantly reducing
database transaction overhead.
529 lines
15 KiB
Elixir
529 lines
15 KiB
Elixir
defmodule Towerops.Workers.AgentLatencyEvaluatorTest do
|
|
use Towerops.DataCase, async: false
|
|
|
|
import Towerops.AccountsFixtures
|
|
import Towerops.OrganizationsFixtures
|
|
|
|
alias Towerops.Agents
|
|
alias Towerops.Monitoring
|
|
alias Towerops.Sites
|
|
alias Towerops.Workers.AgentLatencyEvaluator
|
|
|
|
setup do
|
|
# Start the worker for testing
|
|
{:ok, pid} = start_supervised(AgentLatencyEvaluator)
|
|
%{worker_pid: pid}
|
|
end
|
|
|
|
describe "evaluate_latency/0" do
|
|
test "reassigns device to faster agent when 20%+ improvement available" do
|
|
user = user_fixture()
|
|
org = organization_fixture(user.id)
|
|
{:ok, slow_agent, _} = Agents.create_agent_token(org.id, "Slow Agent")
|
|
{:ok, fast_agent, _} = Agents.create_agent_token(org.id, "Fast Agent")
|
|
|
|
{:ok, site} =
|
|
Sites.create_site(%{
|
|
name: "Test Site",
|
|
organization_id: org.id,
|
|
agent_token_id: slow_agent.id
|
|
})
|
|
|
|
{:ok, device} =
|
|
Towerops.Devices.create_device(%{
|
|
name: "Router",
|
|
ip_address: "192.168.1.1",
|
|
site_id: site.id,
|
|
snmp_enabled: true,
|
|
snmp_community: "public",
|
|
snmp_version: "2c"
|
|
})
|
|
|
|
# Create checks: slow = 100ms, fast = 50ms (50% improvement)
|
|
for _ <- 1..15 do
|
|
Monitoring.create_check(%{
|
|
device_id: device.id,
|
|
agent_token_id: slow_agent.id,
|
|
status: :success,
|
|
response_time_ms: 100,
|
|
checked_at: DateTime.utc_now()
|
|
})
|
|
|
|
Monitoring.create_check(%{
|
|
device_id: device.id,
|
|
agent_token_id: fast_agent.id,
|
|
status: :success,
|
|
response_time_ms: 50,
|
|
checked_at: DateTime.utc_now()
|
|
})
|
|
end
|
|
|
|
# Trigger evaluation
|
|
AgentLatencyEvaluator.trigger_evaluation()
|
|
|
|
# Wait for async processing
|
|
Process.sleep(100)
|
|
|
|
# Verify site was reassigned
|
|
updated_site = Sites.get_site!(site.id)
|
|
assert updated_site.agent_token_id == fast_agent.id
|
|
end
|
|
|
|
test "does not reassign when improvement is below 20% threshold" do
|
|
user = user_fixture()
|
|
org = organization_fixture(user.id)
|
|
{:ok, agent1, _} = Agents.create_agent_token(org.id, "Agent 1")
|
|
{:ok, agent2, _} = Agents.create_agent_token(org.id, "Agent 2")
|
|
|
|
{:ok, site} =
|
|
Sites.create_site(%{
|
|
name: "Test Site",
|
|
organization_id: org.id,
|
|
agent_token_id: agent1.id
|
|
})
|
|
|
|
{:ok, device} =
|
|
Towerops.Devices.create_device(%{
|
|
name: "Router",
|
|
ip_address: "192.168.1.1",
|
|
site_id: site.id,
|
|
snmp_enabled: true,
|
|
snmp_community: "public",
|
|
snmp_version: "2c"
|
|
})
|
|
|
|
# Create checks: agent1 = 100ms, agent2 = 85ms (15% improvement, below 20%)
|
|
for _ <- 1..15 do
|
|
Monitoring.create_check(%{
|
|
device_id: device.id,
|
|
agent_token_id: agent1.id,
|
|
status: :success,
|
|
response_time_ms: 100,
|
|
checked_at: DateTime.utc_now()
|
|
})
|
|
|
|
Monitoring.create_check(%{
|
|
device_id: device.id,
|
|
agent_token_id: agent2.id,
|
|
status: :success,
|
|
response_time_ms: 85,
|
|
checked_at: DateTime.utc_now()
|
|
})
|
|
end
|
|
|
|
# Trigger evaluation
|
|
AgentLatencyEvaluator.trigger_evaluation()
|
|
|
|
# Wait for async processing
|
|
Process.sleep(100)
|
|
|
|
# Verify site was NOT reassigned
|
|
updated_site = Sites.get_site!(site.id)
|
|
assert updated_site.agent_token_id == agent1.id
|
|
end
|
|
|
|
test "reassigns organization-level assignment" do
|
|
user = user_fixture()
|
|
|
|
{:ok, slow_agent, _} = Agents.create_cloud_poller("Slow Cloud")
|
|
{:ok, fast_agent, _} = Agents.create_cloud_poller("Fast Cloud")
|
|
|
|
org =
|
|
organization_fixture(user.id, %{
|
|
default_agent_token_id: slow_agent.id
|
|
})
|
|
|
|
{:ok, site} = Sites.create_site(%{name: "Test Site", organization_id: org.id})
|
|
|
|
{:ok, device} =
|
|
Towerops.Devices.create_device(%{
|
|
name: "Router",
|
|
ip_address: "192.168.1.1",
|
|
site_id: site.id,
|
|
snmp_enabled: true,
|
|
snmp_community: "public",
|
|
snmp_version: "2c"
|
|
})
|
|
|
|
# Create checks showing fast agent is better
|
|
for _ <- 1..15 do
|
|
Monitoring.create_check(%{
|
|
device_id: device.id,
|
|
agent_token_id: slow_agent.id,
|
|
status: :success,
|
|
response_time_ms: 150,
|
|
checked_at: DateTime.utc_now()
|
|
})
|
|
|
|
Monitoring.create_check(%{
|
|
device_id: device.id,
|
|
agent_token_id: fast_agent.id,
|
|
status: :success,
|
|
response_time_ms: 50,
|
|
checked_at: DateTime.utc_now()
|
|
})
|
|
end
|
|
|
|
# Trigger evaluation
|
|
AgentLatencyEvaluator.trigger_evaluation()
|
|
|
|
# Wait for async processing
|
|
Process.sleep(100)
|
|
|
|
# Verify organization was reassigned
|
|
updated_org = Towerops.Organizations.get_organization!(org.id)
|
|
assert updated_org.default_agent_token_id == fast_agent.id
|
|
end
|
|
|
|
test "creates device assignment for global default assignment" do
|
|
user = user_fixture()
|
|
org = organization_fixture(user.id)
|
|
|
|
{:ok, slow_cloud, _} = Agents.create_cloud_poller("Slow Global")
|
|
{:ok, fast_cloud, _} = Agents.create_cloud_poller("Fast Global")
|
|
|
|
# Set slow cloud as global default
|
|
{:ok, _} = Towerops.Settings.set_global_default_cloud_poller(slow_cloud.id)
|
|
|
|
{:ok, site} = Sites.create_site(%{name: "Test Site", organization_id: org.id})
|
|
|
|
{:ok, device} =
|
|
Towerops.Devices.create_device(%{
|
|
name: "Router",
|
|
ip_address: "192.168.1.1",
|
|
site_id: site.id,
|
|
snmp_enabled: true,
|
|
snmp_community: "public",
|
|
snmp_version: "2c"
|
|
})
|
|
|
|
# Create checks showing fast cloud is better
|
|
for _ <- 1..15 do
|
|
Monitoring.create_check(%{
|
|
device_id: device.id,
|
|
agent_token_id: slow_cloud.id,
|
|
status: :success,
|
|
response_time_ms: 200,
|
|
checked_at: DateTime.utc_now()
|
|
})
|
|
|
|
Monitoring.create_check(%{
|
|
device_id: device.id,
|
|
agent_token_id: fast_cloud.id,
|
|
status: :success,
|
|
response_time_ms: 60,
|
|
checked_at: DateTime.utc_now()
|
|
})
|
|
end
|
|
|
|
# Trigger evaluation
|
|
AgentLatencyEvaluator.trigger_evaluation()
|
|
|
|
# Wait for async processing
|
|
Process.sleep(100)
|
|
|
|
# Verify device assignment was created
|
|
assignment = Agents.get_device_assignment(device.id)
|
|
assert assignment.agent_token_id == fast_cloud.id
|
|
|
|
# Cleanup global default
|
|
{:ok, _} = Towerops.Settings.set_global_default_cloud_poller(nil)
|
|
end
|
|
|
|
test "creates device assignment for cloud polling (no assignment)" do
|
|
user = user_fixture()
|
|
org = organization_fixture(user.id)
|
|
|
|
{:ok, slow_cloud, _} = Agents.create_cloud_poller("Slow Cloud")
|
|
{:ok, fast_cloud, _} = Agents.create_cloud_poller("Fast Cloud")
|
|
|
|
{:ok, site} = Sites.create_site(%{name: "Test Site", organization_id: org.id})
|
|
|
|
{:ok, device} =
|
|
Towerops.Devices.create_device(%{
|
|
name: "Router",
|
|
ip_address: "192.168.1.1",
|
|
site_id: site.id,
|
|
snmp_enabled: true,
|
|
snmp_community: "public",
|
|
snmp_version: "2c"
|
|
})
|
|
|
|
# Create checks from both cloud agents (bulk insert for speed)
|
|
now = DateTime.truncate(DateTime.utc_now(), :second)
|
|
|
|
for_result =
|
|
for _ <- 1..10 do
|
|
[
|
|
%{
|
|
id: Ecto.UUID.generate(),
|
|
device_id: device.id,
|
|
agent_token_id: slow_cloud.id,
|
|
status: :success,
|
|
response_time_ms: 100.0,
|
|
checked_at: now,
|
|
inserted_at: now
|
|
},
|
|
%{
|
|
id: Ecto.UUID.generate(),
|
|
device_id: device.id,
|
|
agent_token_id: fast_cloud.id,
|
|
status: :success,
|
|
response_time_ms: 50.0,
|
|
checked_at: now,
|
|
inserted_at: now
|
|
}
|
|
]
|
|
end
|
|
|
|
checks = List.flatten(for_result)
|
|
|
|
Repo.insert_all(Towerops.Monitoring.Check, checks)
|
|
|
|
# Trigger evaluation
|
|
AgentLatencyEvaluator.trigger_evaluation()
|
|
|
|
# Wait for async processing
|
|
Process.sleep(500)
|
|
|
|
# Verify device assignment was created to the fast agent
|
|
assignment = Agents.get_device_assignment(device.id)
|
|
assert assignment != nil, "Expected device assignment to be created"
|
|
assert assignment.agent_token_id == fast_cloud.id
|
|
end
|
|
|
|
test "does not reassign direct device assignments" do
|
|
user = user_fixture()
|
|
org = organization_fixture(user.id)
|
|
{:ok, slow_agent, _} = Agents.create_agent_token(org.id, "Slow Agent")
|
|
{:ok, fast_agent, _} = Agents.create_agent_token(org.id, "Fast Agent")
|
|
|
|
{:ok, site} = Sites.create_site(%{name: "Test Site", organization_id: org.id})
|
|
|
|
{:ok, device} =
|
|
Towerops.Devices.create_device(%{
|
|
name: "Router",
|
|
ip_address: "192.168.1.1",
|
|
site_id: site.id,
|
|
snmp_enabled: true,
|
|
snmp_community: "public",
|
|
snmp_version: "2c"
|
|
})
|
|
|
|
# Create direct device assignment
|
|
{:ok, _} = Agents.assign_device_to_agent(slow_agent.id, device.id)
|
|
|
|
# Create checks showing fast agent is better
|
|
for _ <- 1..15 do
|
|
Monitoring.create_check(%{
|
|
device_id: device.id,
|
|
agent_token_id: slow_agent.id,
|
|
status: :success,
|
|
response_time_ms: 100,
|
|
checked_at: DateTime.utc_now()
|
|
})
|
|
|
|
Monitoring.create_check(%{
|
|
device_id: device.id,
|
|
agent_token_id: fast_agent.id,
|
|
status: :success,
|
|
response_time_ms: 50,
|
|
checked_at: DateTime.utc_now()
|
|
})
|
|
end
|
|
|
|
# Trigger evaluation
|
|
AgentLatencyEvaluator.trigger_evaluation()
|
|
|
|
# Wait for async processing
|
|
Process.sleep(100)
|
|
|
|
# Verify device assignment was NOT changed
|
|
assignment = Agents.get_device_assignment(device.id)
|
|
assert assignment.agent_token_id == slow_agent.id
|
|
end
|
|
|
|
test "requires minimum check count" do
|
|
user = user_fixture()
|
|
org = organization_fixture(user.id)
|
|
{:ok, slow_agent, _} = Agents.create_agent_token(org.id, "Slow Agent")
|
|
{:ok, fast_agent, _} = Agents.create_agent_token(org.id, "Fast Agent")
|
|
|
|
{:ok, site} =
|
|
Sites.create_site(%{
|
|
name: "Test Site",
|
|
organization_id: org.id,
|
|
agent_token_id: slow_agent.id
|
|
})
|
|
|
|
{:ok, device} =
|
|
Towerops.Devices.create_device(%{
|
|
name: "Router",
|
|
ip_address: "192.168.1.1",
|
|
site_id: site.id,
|
|
snmp_enabled: true,
|
|
snmp_community: "public",
|
|
snmp_version: "2c"
|
|
})
|
|
|
|
# Create only 5 checks (below default minimum of 10)
|
|
for _ <- 1..5 do
|
|
Monitoring.create_check(%{
|
|
device_id: device.id,
|
|
agent_token_id: slow_agent.id,
|
|
status: :success,
|
|
response_time_ms: 100,
|
|
checked_at: DateTime.utc_now()
|
|
})
|
|
|
|
Monitoring.create_check(%{
|
|
device_id: device.id,
|
|
agent_token_id: fast_agent.id,
|
|
status: :success,
|
|
response_time_ms: 50,
|
|
checked_at: DateTime.utc_now()
|
|
})
|
|
end
|
|
|
|
# Trigger evaluation
|
|
AgentLatencyEvaluator.trigger_evaluation()
|
|
|
|
# Wait for async processing
|
|
Process.sleep(100)
|
|
|
|
# Verify site was NOT reassigned (insufficient data)
|
|
updated_site = Sites.get_site!(site.id)
|
|
assert updated_site.agent_token_id == slow_agent.id
|
|
end
|
|
|
|
test "handles multiple devices in single evaluation" do
|
|
user = user_fixture()
|
|
org = organization_fixture(user.id)
|
|
{:ok, slow_agent, _} = Agents.create_agent_token(org.id, "Slow Agent")
|
|
{:ok, fast_agent, _} = Agents.create_agent_token(org.id, "Fast Agent")
|
|
|
|
{:ok, site1} =
|
|
Sites.create_site(%{
|
|
name: "Site 1",
|
|
organization_id: org.id,
|
|
agent_token_id: slow_agent.id
|
|
})
|
|
|
|
{:ok, site2} =
|
|
Sites.create_site(%{
|
|
name: "Site 2",
|
|
organization_id: org.id,
|
|
agent_token_id: slow_agent.id
|
|
})
|
|
|
|
{:ok, device1} =
|
|
Towerops.Devices.create_device(%{
|
|
name: "Router 1",
|
|
ip_address: "192.168.1.1",
|
|
site_id: site1.id,
|
|
snmp_enabled: true,
|
|
snmp_community: "public",
|
|
snmp_version: "2c"
|
|
})
|
|
|
|
{:ok, device2} =
|
|
Towerops.Devices.create_device(%{
|
|
name: "Router 2",
|
|
ip_address: "192.168.2.1",
|
|
site_id: site2.id,
|
|
snmp_enabled: true,
|
|
snmp_community: "public",
|
|
snmp_version: "2c"
|
|
})
|
|
|
|
# Create checks for both devices
|
|
for device_id <- [device1.id, device2.id] do
|
|
for _ <- 1..15 do
|
|
Monitoring.create_check(%{
|
|
device_id: device_id,
|
|
agent_token_id: slow_agent.id,
|
|
status: :success,
|
|
response_time_ms: 100,
|
|
checked_at: DateTime.utc_now()
|
|
})
|
|
|
|
Monitoring.create_check(%{
|
|
device_id: device_id,
|
|
agent_token_id: fast_agent.id,
|
|
status: :success,
|
|
response_time_ms: 50,
|
|
checked_at: DateTime.utc_now()
|
|
})
|
|
end
|
|
end
|
|
|
|
# Trigger evaluation
|
|
AgentLatencyEvaluator.trigger_evaluation()
|
|
|
|
# Wait for async processing
|
|
Process.sleep(100)
|
|
|
|
# Verify both sites were reassigned
|
|
updated_site1 = Sites.get_site!(site1.id)
|
|
updated_site2 = Sites.get_site!(site2.id)
|
|
|
|
assert updated_site1.agent_token_id == fast_agent.id
|
|
assert updated_site2.agent_token_id == fast_agent.id
|
|
end
|
|
end
|
|
|
|
describe "handle_info(:evaluate_latency)" do
|
|
test "worker processes evaluation on schedule" do
|
|
user = user_fixture()
|
|
org = organization_fixture(user.id)
|
|
{:ok, slow_agent, _} = Agents.create_agent_token(org.id, "Slow Agent")
|
|
{:ok, fast_agent, _} = Agents.create_agent_token(org.id, "Fast Agent")
|
|
|
|
{:ok, site} =
|
|
Sites.create_site(%{
|
|
name: "Test Site",
|
|
organization_id: org.id,
|
|
agent_token_id: slow_agent.id
|
|
})
|
|
|
|
{:ok, device} =
|
|
Towerops.Devices.create_device(%{
|
|
name: "Router",
|
|
ip_address: "192.168.1.1",
|
|
site_id: site.id,
|
|
snmp_enabled: true,
|
|
snmp_community: "public",
|
|
snmp_version: "2c"
|
|
})
|
|
|
|
# Create checks
|
|
for _ <- 1..15 do
|
|
Monitoring.create_check(%{
|
|
device_id: device.id,
|
|
agent_token_id: slow_agent.id,
|
|
status: :success,
|
|
response_time_ms: 100,
|
|
checked_at: DateTime.utc_now()
|
|
})
|
|
|
|
Monitoring.create_check(%{
|
|
device_id: device.id,
|
|
agent_token_id: fast_agent.id,
|
|
status: :success,
|
|
response_time_ms: 50,
|
|
checked_at: DateTime.utc_now()
|
|
})
|
|
end
|
|
|
|
# Send the message directly to the worker
|
|
send(Process.whereis(AgentLatencyEvaluator), :evaluate_latency)
|
|
|
|
# Wait for async processing
|
|
Process.sleep(100)
|
|
|
|
# Verify site was reassigned
|
|
updated_site = Sites.get_site!(site.id)
|
|
assert updated_site.agent_token_id == fast_agent.id
|
|
end
|
|
end
|
|
end
|