mirror of
https://github.com/wanderer-industries/wanderer
synced 2026-01-06 23:10:20 +00:00
280 lines
8.9 KiB
Elixir
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
|