Files
wanderer/test/integration/api/map_audit_api_controller_test.exs
2025-11-25 12:28:31 +01:00

280 lines
8.9 KiB
Elixir

defmodule WandererAppWeb.MapAuditAPIControllerIntegrationTest do
use WandererAppWeb.ApiCase, async: false
alias WandererAppWeb.Factory
describe "GET /api/map/audit (index)" do
setup :setup_map_authentication
test "returns audit events for a map by slug", %{conn: conn, map: map} do
# Create a character for the audit events
character =
Factory.insert(:character, %{
eve_id: "123456789",
name: "Test Character"
})
# Create a user for the audit events
user = Factory.insert(:user)
# Create audit events
_audit1 =
Factory.insert(:map_audit_event, %{
entity_id: map.id,
user_id: user.id,
character_id: character.id,
entity_type: :map,
event_type: :system_added,
event_data: %{"solar_system_id" => 30_000_142, "name" => "Jita"}
})
_audit2 =
Factory.insert(:map_audit_event, %{
entity_id: map.id,
user_id: user.id,
character_id: character.id,
entity_type: :map,
event_type: :map_connection_added,
event_data: %{"source" => 30_000_142, "target" => 30_000_143}
})
conn = get(conn, "/api/map/audit", %{"slug" => map.slug, "period" => "1D"})
assert %{"data" => events} = json_response(conn, 200)
assert length(events) == 2
# Verify event structure
event = hd(events)
assert Map.has_key?(event, "entity_type")
assert Map.has_key?(event, "event_name")
assert Map.has_key?(event, "event_data")
assert Map.has_key?(event, "character")
assert Map.has_key?(event, "inserted_at")
# Verify character information
assert event["character"]["eve_id"] == "123456789"
assert event["character"]["name"] == "Test Character"
end
test "returns audit events for a map by map_id", %{conn: conn, map: map} do
character = Factory.insert(:character, %{eve_id: "123456789"})
user = Factory.insert(:user)
Factory.insert(:map_audit_event, %{
entity_id: map.id,
user_id: user.id,
character_id: character.id,
entity_type: :map,
event_type: :system_updated
})
conn = get(conn, "/api/map/audit", %{"map_id" => map.id, "period" => "1H"})
assert %{"data" => events} = json_response(conn, 200)
assert length(events) == 1
end
test "filters events by period", %{conn: conn, map: map} do
character = Factory.insert(:character, %{eve_id: "123456789"})
user = Factory.insert(:user)
# Create events at different times
Factory.insert(:map_audit_event, %{
entity_id: map.id,
user_id: user.id,
character_id: character.id,
entity_type: :map,
event_type: :system_added
})
Factory.insert(:map_audit_event, %{
entity_id: map.id,
user_id: user.id,
character_id: character.id,
entity_type: :map,
event_type: :systems_removed
})
# Request events for last 1 day
conn = get(conn, "/api/map/audit", %{"slug" => map.slug, "period" => "1D"})
assert %{"data" => events} = json_response(conn, 200)
# Should only return recent events based on period filter
# Number depends on period filtering logic
assert length(events) >= 0
end
test "supports different period values", %{conn: conn, map: map} do
character = Factory.insert(:character, %{eve_id: "123456789"})
user = Factory.insert(:user)
Factory.insert(:map_audit_event, %{
entity_id: map.id,
user_id: user.id,
character_id: character.id,
entity_type: :map,
event_type: :system_added
})
# Test different period values
periods = ["1H", "1D", "1W", "1M", "2M", "3M"]
for period <- periods do
conn = get(conn, "/api/map/audit", %{"slug" => map.slug, "period" => period})
assert %{"data" => _events} = json_response(conn, 200)
end
end
test "returns empty array when no audit events exist", %{conn: conn, map: map} do
conn = get(conn, "/api/map/audit", %{"slug" => map.slug, "period" => "1D"})
assert %{"data" => []} = json_response(conn, 200)
end
test "requires period parameter", %{conn: conn, map: map} do
conn = get(conn, "/api/map/audit", %{"slug" => map.slug})
assert %{"error" => _} = json_response(conn, 400)
end
test "requires either map_id or slug parameter", %{conn: conn} do
conn = get(conn, "/api/map/audit", %{"period" => "1D"})
assert %{"error" => _} = json_response(conn, 400)
end
test "returns error when both map_id and slug provided", %{conn: conn, map: map} do
conn =
get(conn, "/api/map/audit", %{
"map_id" => map.id,
"slug" => map.slug,
"period" => "1D"
})
assert %{"error" => _} = json_response(conn, 400)
end
test "returns 404 for non-existent map", %{conn: conn} do
conn = get(conn, "/api/map/audit", %{"slug" => "non-existent", "period" => "1D"})
assert %{"error" => _} = json_response(conn, 404)
end
test "returns 401 without API key", %{map: map} do
conn = build_conn()
conn = get(conn, "/api/map/audit", %{"slug" => map.slug, "period" => "1D"})
assert json_response(conn, 401)
end
test "includes different entity types", %{conn: conn, map: map} do
character = Factory.insert(:character, %{eve_id: "123456789"})
user = Factory.insert(:user)
# Create different types of audit events
Factory.insert(:map_audit_event, %{
entity_id: map.id,
user_id: user.id,
character_id: character.id,
entity_type: :map,
event_type: :system_added
})
Factory.insert(:map_audit_event, %{
entity_id: map.id,
user_id: user.id,
character_id: character.id,
entity_type: :map,
event_type: :map_connection_added
})
Factory.insert(:map_audit_event, %{
entity_id: map.id,
user_id: user.id,
character_id: character.id,
entity_type: :map,
event_type: :signatures_added
})
conn = get(conn, "/api/map/audit", %{"slug" => map.slug, "period" => "1D"})
assert %{"data" => events} = json_response(conn, 200)
assert length(events) == 3
entity_types = Enum.map(events, & &1["entity_type"])
assert "map" in entity_types
# All should be map entity type
assert Enum.all?(entity_types, &(&1 == "map"))
end
test "handles events without character information", %{conn: conn, map: map} do
user = Factory.insert(:user)
# Create audit event without character
Factory.insert(:map_audit_event, %{
entity_id: map.id,
user_id: user.id,
character_id: nil,
entity_type: :map,
event_type: :custom
})
conn = get(conn, "/api/map/audit", %{"slug" => map.slug, "period" => "1D"})
assert %{"data" => events} = json_response(conn, 200)
assert length(events) == 1
event = hd(events)
# Should handle missing character gracefully
assert Map.has_key?(event, "character")
end
test "orders events by insertion time", %{conn: conn, map: map} do
character = Factory.insert(:character, %{eve_id: "123456789"})
user = Factory.insert(:user)
# Create events with specific timestamps
Factory.insert(:map_audit_event, %{
entity_id: map.id,
user_id: user.id,
character_id: character.id,
entity_type: :map,
event_type: :system_added,
event_data: %{"name" => "first_event"}
})
# Sleep to ensure second event has later timestamp
Process.sleep(100)
Factory.insert(:map_audit_event, %{
entity_id: map.id,
user_id: user.id,
character_id: character.id,
entity_type: :map,
event_type: :system_updated,
event_data: %{"name" => "second_event"}
})
conn = get(conn, "/api/map/audit", %{"slug" => map.slug, "period" => "1D"})
assert %{"data" => events} = json_response(conn, 200)
assert length(events) == 2
# Verify events are ordered by insertion time (should be descending - newest first)
timestamps = Enum.map(events, & &1["inserted_at"])
assert length(timestamps) == 2
# Convert to DateTime for comparison
[first_timestamp, second_timestamp] =
Enum.map(timestamps, fn ts ->
{:ok, dt, _} = DateTime.from_iso8601(ts)
dt
end)
# Verify descending order (newest first)
assert DateTime.compare(first_timestamp, second_timestamp) == :gt,
"Events should be ordered by insertion time (newest first)"
# Also verify the event names to confirm correct ordering
event_names = Enum.map(events, & &1["event_name"])
# The exact names depend on the get_event_name function
assert length(event_names) == 2
end
end
end