mirror of
https://github.com/wanderer-industries/wanderer
synced 2026-01-30 10:36:02 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
078e5fc19e | ||
|
|
3877e121c3 | ||
|
|
dcb2a0cdb2 |
@@ -2,6 +2,15 @@
|
||||
|
||||
<!-- changelog -->
|
||||
|
||||
## [v1.90.4](https://github.com/wanderer-industries/wanderer/compare/v1.90.3...v1.90.4) (2025-12-12)
|
||||
|
||||
|
||||
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* core: fixed map scopes & signatures clean up behaviour
|
||||
|
||||
## [v1.90.3](https://github.com/wanderer-industries/wanderer/compare/v1.90.2...v1.90.3) (2025-12-11)
|
||||
|
||||
|
||||
|
||||
@@ -829,7 +829,8 @@ defmodule WandererApp.Map.Server.CharactersImpl do
|
||||
)
|
||||
|> case do
|
||||
true ->
|
||||
# Add new location system
|
||||
# Connection is valid (at least one system matches scopes)
|
||||
# Add BOTH systems including border systems - filtering already done by is_connection_valid
|
||||
case SystemsImpl.maybe_add_system(map_id, location, old_location, map_opts) do
|
||||
:ok ->
|
||||
:ok
|
||||
|
||||
@@ -744,15 +744,33 @@ defmodule WandererApp.Map.Server.ConnectionsImpl do
|
||||
when is_list(scopes) and from_solar_system_id != to_solar_system_id do
|
||||
with {:ok, from_system_static_info} <- get_system_static_info(from_solar_system_id),
|
||||
{:ok, to_system_static_info} <- get_system_static_info(to_solar_system_id) do
|
||||
# Connection is valid if:
|
||||
# 1. Neither system is prohibited
|
||||
# 2. At least one system matches one of the selected scopes
|
||||
not is_prohibited_system_class?(from_system_static_info.system_class) and
|
||||
not is_prohibited_system_class?(to_system_static_info.system_class) and
|
||||
not (@prohibited_systems |> Enum.member?(from_solar_system_id)) and
|
||||
not (@prohibited_systems |> Enum.member?(to_solar_system_id)) and
|
||||
(system_matches_any_scope?(from_system_static_info.system_class, scopes) or
|
||||
system_matches_any_scope?(to_system_static_info.system_class, scopes))
|
||||
# First check: neither system is prohibited
|
||||
not_prohibited =
|
||||
not is_prohibited_system_class?(from_system_static_info.system_class) and
|
||||
not is_prohibited_system_class?(to_system_static_info.system_class) and
|
||||
not (@prohibited_systems |> Enum.member?(from_solar_system_id)) and
|
||||
not (@prohibited_systems |> Enum.member?(to_solar_system_id))
|
||||
|
||||
if not_prohibited do
|
||||
from_is_wormhole = from_system_static_info.system_class in @wh_space
|
||||
to_is_wormhole = to_system_static_info.system_class in @wh_space
|
||||
wormholes_enabled = :wormholes in scopes
|
||||
|
||||
# Wormhole border behavior: if wormholes scope is enabled AND at least one
|
||||
# system is a wormhole, allow the connection (adds border k-space systems)
|
||||
# Otherwise: BOTH systems must match the configured scopes
|
||||
if wormholes_enabled and (from_is_wormhole or to_is_wormhole) do
|
||||
# At least one system matches (wormhole matches :wormholes, or other matches its scope)
|
||||
system_matches_any_scope?(from_system_static_info.system_class, scopes) or
|
||||
system_matches_any_scope?(to_system_static_info.system_class, scopes)
|
||||
else
|
||||
# Non-wormhole movement: both systems must match scopes
|
||||
system_matches_any_scope?(from_system_static_info.system_class, scopes) and
|
||||
system_matches_any_scope?(to_system_static_info.system_class, scopes)
|
||||
end
|
||||
else
|
||||
false
|
||||
end
|
||||
else
|
||||
_ -> false
|
||||
end
|
||||
|
||||
@@ -403,64 +403,76 @@ defmodule WandererApp.Map.Server.SystemsImpl do
|
||||
end)
|
||||
end
|
||||
|
||||
# When destination systems are deleted, unlink signatures instead of destroying them.
|
||||
# This preserves the user's scan data while removing the stale link.
|
||||
defp cleanup_linked_signatures(map_id, removed_solar_system_ids) do
|
||||
removed_solar_system_ids
|
||||
|> Enum.map(fn solar_system_id ->
|
||||
WandererApp.Api.MapSystemSignature.by_linked_system_id!(solar_system_id)
|
||||
end)
|
||||
|> List.flatten()
|
||||
|> Enum.uniq_by(& &1.system_id)
|
||||
|> Enum.each(fn s ->
|
||||
try do
|
||||
{:ok, %{eve_id: eve_id, system: system}} = s |> Ash.load([:system])
|
||||
# Group signatures by their source system for efficient broadcasting
|
||||
signatures_by_system =
|
||||
removed_solar_system_ids
|
||||
|> Enum.flat_map(fn solar_system_id ->
|
||||
WandererApp.Api.MapSystemSignature.by_linked_system_id!(solar_system_id)
|
||||
end)
|
||||
|> Enum.uniq_by(& &1.id)
|
||||
|> Enum.group_by(fn sig -> sig.system_id end)
|
||||
|
||||
# Use Ash.destroy (not destroy!) to handle already-deleted signatures gracefully
|
||||
case Ash.destroy(s) do
|
||||
:ok ->
|
||||
# Handle case where parent system was already deleted
|
||||
case system do
|
||||
nil ->
|
||||
Logger.debug(fn ->
|
||||
"[cleanup_linked_signatures] signature #{eve_id} destroyed (parent system already deleted)"
|
||||
end)
|
||||
signatures_by_system
|
||||
|> Enum.each(fn {_system_id, signatures} ->
|
||||
signatures
|
||||
|> Enum.each(fn sig ->
|
||||
try do
|
||||
{:ok, %{eve_id: eve_id, system: system}} = sig |> Ash.load([:system])
|
||||
|
||||
%{solar_system_id: solar_system_id} ->
|
||||
Logger.debug(fn ->
|
||||
"[cleanup_linked_signatures] for system #{solar_system_id}: #{inspect(eve_id)}"
|
||||
end)
|
||||
# Clear the linked_system_id instead of destroying the signature
|
||||
case WandererApp.Api.MapSystemSignature.update_linked_system(sig, %{
|
||||
linked_system_id: nil
|
||||
}) do
|
||||
{:ok, _updated_sig} ->
|
||||
case system do
|
||||
nil ->
|
||||
Logger.debug(fn ->
|
||||
"[cleanup_linked_signatures] signature #{eve_id} unlinked (parent system already deleted)"
|
||||
end)
|
||||
|
||||
# Audit logging for cascade deletion (no user/character context)
|
||||
WandererApp.User.ActivityTracker.track_map_event(:signatures_removed, %{
|
||||
character_id: nil,
|
||||
user_id: nil,
|
||||
map_id: map_id,
|
||||
solar_system_id: solar_system_id,
|
||||
signatures: [eve_id]
|
||||
})
|
||||
%{solar_system_id: solar_system_id} ->
|
||||
Logger.debug(fn ->
|
||||
"[cleanup_linked_signatures] unlinked signature #{eve_id} in system #{solar_system_id}"
|
||||
end)
|
||||
|
||||
Impl.broadcast!(map_id, :signatures_updated, solar_system_id)
|
||||
end
|
||||
# Audit logging for cascade unlink (no user/character context)
|
||||
WandererApp.User.ActivityTracker.track_map_event(:signatures_unlinked, %{
|
||||
character_id: nil,
|
||||
user_id: nil,
|
||||
map_id: map_id,
|
||||
solar_system_id: solar_system_id,
|
||||
signatures: [eve_id]
|
||||
})
|
||||
end
|
||||
|
||||
{:error, %Ash.Error.Invalid{errors: errors}} ->
|
||||
# Check if this is a StaleRecord error (signature already deleted)
|
||||
if Enum.any?(errors, &match?(%Ash.Error.Changes.StaleRecord{}, &1)) do
|
||||
Logger.debug(fn ->
|
||||
"[cleanup_linked_signatures] signature #{eve_id} already deleted (StaleRecord)"
|
||||
end)
|
||||
else
|
||||
{:error, error} ->
|
||||
Logger.error(
|
||||
"[cleanup_linked_signatures] Failed to destroy signature #{eve_id}: #{inspect(errors)}"
|
||||
"[cleanup_linked_signatures] Failed to unlink signature #{sig.eve_id}: #{inspect(error)}"
|
||||
)
|
||||
end
|
||||
|
||||
{:error, error} ->
|
||||
Logger.error(
|
||||
"[cleanup_linked_signatures] Failed to destroy signature: #{inspect(error)}"
|
||||
)
|
||||
end
|
||||
rescue
|
||||
e ->
|
||||
Logger.error("Failed to cleanup linked signature: #{inspect(e)}")
|
||||
end
|
||||
rescue
|
||||
e ->
|
||||
Logger.error("Failed to cleanup linked signature: #{inspect(e)}")
|
||||
end)
|
||||
|
||||
# Broadcast once per source system after all its signatures are processed
|
||||
case List.first(signatures) do
|
||||
%{system: %{solar_system_id: solar_system_id}} ->
|
||||
Impl.broadcast!(map_id, :signatures_updated, solar_system_id)
|
||||
|
||||
_ ->
|
||||
# Try to get the system info if not preloaded
|
||||
case List.first(signatures) |> Ash.load([:system]) do
|
||||
{:ok, %{system: %{solar_system_id: solar_system_id}}} ->
|
||||
Impl.broadcast!(map_id, :signatures_updated, solar_system_id)
|
||||
|
||||
_ ->
|
||||
:ok
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
@@ -485,8 +497,32 @@ defmodule WandererApp.Map.Server.SystemsImpl do
|
||||
end)
|
||||
end
|
||||
|
||||
def maybe_add_system(map_id, location, old_location, map_opts)
|
||||
def maybe_add_system(map_id, location, old_location, map_opts, scopes \\ nil)
|
||||
|
||||
def maybe_add_system(map_id, location, old_location, map_opts, scopes)
|
||||
when not is_nil(location) do
|
||||
alias WandererApp.Map.Server.ConnectionsImpl
|
||||
|
||||
# Check if the system matches the map's configured scopes before adding
|
||||
should_add =
|
||||
case scopes do
|
||||
nil -> true
|
||||
[] -> true
|
||||
scopes when is_list(scopes) ->
|
||||
ConnectionsImpl.can_add_location(scopes, location.solar_system_id)
|
||||
end
|
||||
|
||||
if should_add do
|
||||
do_add_system_from_location(map_id, location, old_location, map_opts)
|
||||
else
|
||||
# System filtered out by scope settings - this is expected behavior
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
def maybe_add_system(_map_id, _location, _old_location, _map_opts, _scopes), do: :ok
|
||||
|
||||
defp do_add_system_from_location(map_id, location, old_location, map_opts) do
|
||||
:telemetry.execute(
|
||||
[:wanderer_app, :map, :system_addition, :start],
|
||||
%{system_time: System.system_time()},
|
||||
@@ -694,8 +730,6 @@ defmodule WandererApp.Map.Server.SystemsImpl do
|
||||
end
|
||||
end
|
||||
|
||||
def maybe_add_system(_map_id, _location, _old_location, _map_opts), do: :ok
|
||||
|
||||
defp do_add_system(
|
||||
map_id,
|
||||
%{
|
||||
|
||||
@@ -42,12 +42,18 @@ defmodule WandererAppWeb.AuthController do
|
||||
|
||||
WandererApp.Character.update_character(character.id, character_update)
|
||||
|
||||
# Update corporation/alliance data from ESI to ensure access control is current
|
||||
update_character_affiliation(character)
|
||||
|
||||
{:ok, character}
|
||||
|
||||
{:error, _error} ->
|
||||
{:ok, character} = WandererApp.Api.Character.create(character_data)
|
||||
:telemetry.execute([:wanderer_app, :user, :character, :registered], %{count: 1})
|
||||
|
||||
# Fetch initial corporation/alliance data for new characters
|
||||
update_character_affiliation(character)
|
||||
|
||||
{:ok, character}
|
||||
end
|
||||
|
||||
@@ -113,4 +119,102 @@ defmodule WandererAppWeb.AuthController do
|
||||
end
|
||||
|
||||
def maybe_update_character_user_id(_character, _user_id), do: :ok
|
||||
|
||||
# Updates character's corporation and alliance data from ESI.
|
||||
# This ensures ACL-based access control uses current corporation membership,
|
||||
# even for characters not actively being tracked on any map.
|
||||
defp update_character_affiliation(%{id: character_id, eve_id: eve_id} = character) do
|
||||
# Run async to not block the SSO callback
|
||||
Task.start(fn ->
|
||||
character_eve_id = eve_id |> String.to_integer()
|
||||
|
||||
case WandererApp.Esi.post_characters_affiliation([character_eve_id]) do
|
||||
{:ok, [affiliation_info]} when is_map(affiliation_info) ->
|
||||
new_corporation_id = Map.get(affiliation_info, "corporation_id")
|
||||
new_alliance_id = Map.get(affiliation_info, "alliance_id")
|
||||
|
||||
# Check if corporation changed
|
||||
corporation_changed = character.corporation_id != new_corporation_id
|
||||
alliance_changed = character.alliance_id != new_alliance_id
|
||||
|
||||
if corporation_changed or alliance_changed do
|
||||
update_affiliation_data(character_id, character, new_corporation_id, new_alliance_id)
|
||||
end
|
||||
|
||||
{:error, error} ->
|
||||
Logger.warning(
|
||||
"[AuthController] Failed to fetch affiliation for character #{character_id}: #{inspect(error)}"
|
||||
)
|
||||
|
||||
_ ->
|
||||
:ok
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
defp update_character_affiliation(_character), do: :ok
|
||||
|
||||
defp update_affiliation_data(character_id, character, corporation_id, alliance_id) do
|
||||
# Fetch corporation info
|
||||
corporation_update =
|
||||
case WandererApp.Esi.get_corporation_info(corporation_id) do
|
||||
{:ok, %{"name" => corp_name, "ticker" => corp_ticker}} ->
|
||||
%{
|
||||
corporation_id: corporation_id,
|
||||
corporation_name: corp_name,
|
||||
corporation_ticker: corp_ticker
|
||||
}
|
||||
|
||||
_ ->
|
||||
%{corporation_id: corporation_id}
|
||||
end
|
||||
|
||||
# Fetch alliance info if present
|
||||
alliance_update =
|
||||
case alliance_id do
|
||||
nil ->
|
||||
%{alliance_id: nil, alliance_name: nil, alliance_ticker: nil}
|
||||
|
||||
_ ->
|
||||
case WandererApp.Esi.get_alliance_info(alliance_id) do
|
||||
{:ok, %{"name" => alliance_name, "ticker" => alliance_ticker}} ->
|
||||
%{
|
||||
alliance_id: alliance_id,
|
||||
alliance_name: alliance_name,
|
||||
alliance_ticker: alliance_ticker
|
||||
}
|
||||
|
||||
_ ->
|
||||
%{alliance_id: alliance_id}
|
||||
end
|
||||
end
|
||||
|
||||
full_update = Map.merge(corporation_update, alliance_update)
|
||||
|
||||
# Update database
|
||||
case character.corporation_id != corporation_id do
|
||||
true ->
|
||||
{:ok, _} = WandererApp.Api.Character.update_corporation(character, corporation_update)
|
||||
|
||||
false ->
|
||||
:ok
|
||||
end
|
||||
|
||||
case character.alliance_id != alliance_id do
|
||||
true ->
|
||||
{:ok, _} = WandererApp.Api.Character.update_alliance(character, alliance_update)
|
||||
|
||||
false ->
|
||||
:ok
|
||||
end
|
||||
|
||||
# Update cache
|
||||
WandererApp.Character.update_character(character_id, full_update)
|
||||
|
||||
Logger.info(
|
||||
"[AuthController] Updated affiliation for character #{character_id}: " <>
|
||||
"corp #{character.corporation_id} -> #{corporation_id}, " <>
|
||||
"alliance #{character.alliance_id} -> #{alliance_id}"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
2
mix.exs
2
mix.exs
@@ -3,7 +3,7 @@ defmodule WandererApp.MixProject do
|
||||
|
||||
@source_url "https://github.com/wanderer-industries/wanderer"
|
||||
|
||||
@version "1.90.3"
|
||||
@version "1.90.4"
|
||||
|
||||
def project do
|
||||
[
|
||||
|
||||
@@ -206,37 +206,55 @@ defmodule WandererApp.Map.Server.MapScopesTest do
|
||||
assert ConnectionsImpl.is_connection_valid([:hi], @hs_system_id, @hs_system_id) == false
|
||||
end
|
||||
|
||||
test "connection valid when at least one system matches a scope" do
|
||||
# WH to HS: valid if either :wormholes or :hi is selected
|
||||
test "wormhole border behavior: WH connections allow border k-space systems" do
|
||||
# WH to HS with [:wormholes]: valid (wormhole border behavior)
|
||||
# At least one system is WH, :wormholes is enabled -> border k-space allowed
|
||||
assert ConnectionsImpl.is_connection_valid([:wormholes], @wh_system_id, @hs_system_id) ==
|
||||
true
|
||||
|
||||
assert ConnectionsImpl.is_connection_valid([:hi], @wh_system_id, @hs_system_id) == true
|
||||
# WH to HS with [:hi] only: INVALID (no wormhole scope, WH doesn't match :hi)
|
||||
# Neither system matches when we require both to match (no wormhole border behavior)
|
||||
assert ConnectionsImpl.is_connection_valid([:hi], @wh_system_id, @hs_system_id) == false
|
||||
|
||||
# WH to WH: valid only if :wormholes is selected
|
||||
assert ConnectionsImpl.is_connection_valid([:wormholes], @wh_system_id, @c2_system_id) ==
|
||||
true
|
||||
|
||||
assert ConnectionsImpl.is_connection_valid([:hi], @wh_system_id, @c2_system_id) == false
|
||||
|
||||
# HS to LS: valid if :hi or :low is selected
|
||||
assert ConnectionsImpl.is_connection_valid([:hi], @hs_system_id, @ls_system_id) == true
|
||||
assert ConnectionsImpl.is_connection_valid([:low], @hs_system_id, @ls_system_id) == true
|
||||
assert ConnectionsImpl.is_connection_valid([:null], @hs_system_id, @ls_system_id) == false
|
||||
end
|
||||
|
||||
test "connection with multiple scopes allows cross-space movement" do
|
||||
# With [:wormholes, :hi], all of these should be valid:
|
||||
# - WH to WH (wormholes matches)
|
||||
# - HS to HS (hi matches)
|
||||
# - WH to HS (either matches)
|
||||
test "k-space connections require BOTH systems to match scopes" do
|
||||
# HS to LS: requires BOTH to match, so single scope is not enough
|
||||
assert ConnectionsImpl.is_connection_valid([:hi], @hs_system_id, @ls_system_id) == false
|
||||
assert ConnectionsImpl.is_connection_valid([:low], @hs_system_id, @ls_system_id) == false
|
||||
assert ConnectionsImpl.is_connection_valid([:null], @hs_system_id, @ls_system_id) == false
|
||||
|
||||
# HS to LS with [:hi, :low]: valid (both match)
|
||||
assert ConnectionsImpl.is_connection_valid([:hi, :low], @hs_system_id, @ls_system_id) == true
|
||||
|
||||
# HS to HS: valid with [:hi] (both match)
|
||||
assert ConnectionsImpl.is_connection_valid([:hi], @hs_system_id, 30_000_002) == true
|
||||
|
||||
# NS to NS: valid with [:null] (both match)
|
||||
assert ConnectionsImpl.is_connection_valid([:null], @ns_system_id, @ns_system_id) == false
|
||||
# (same system returns false)
|
||||
end
|
||||
|
||||
test "connection with multiple scopes" do
|
||||
# With [:wormholes, :hi]:
|
||||
# - WH to WH: valid (both match :wormholes)
|
||||
# - HS to HS: valid (both match :hi)
|
||||
# - WH to HS: valid (wormhole border behavior - WH is wormhole, :wormholes enabled)
|
||||
scopes = [:wormholes, :hi]
|
||||
assert ConnectionsImpl.is_connection_valid(scopes, @wh_system_id, @c2_system_id) == true
|
||||
assert ConnectionsImpl.is_connection_valid(scopes, @hs_system_id, 30_000_002) == true
|
||||
assert ConnectionsImpl.is_connection_valid(scopes, @wh_system_id, @hs_system_id) == true
|
||||
|
||||
# But LS to NS should not be valid with [:wormholes, :hi]
|
||||
# LS to NS should not be valid with [:wormholes, :hi] (neither is WH, neither matches)
|
||||
assert ConnectionsImpl.is_connection_valid(scopes, @ls_system_id, @ns_system_id) == false
|
||||
|
||||
# HS to LS should not be valid with [:wormholes, :hi] (neither is WH, only HS matches)
|
||||
assert ConnectionsImpl.is_connection_valid(scopes, @hs_system_id, @ls_system_id) == false
|
||||
end
|
||||
|
||||
test "all scopes allows any connection" do
|
||||
@@ -294,4 +312,127 @@ defmodule WandererApp.Map.Server.MapScopesTest do
|
||||
assert ConnectionsImpl.is_prohibited_system_class?(25) == false
|
||||
end
|
||||
end
|
||||
|
||||
describe "maybe_add_system/5 scope filtering" do
|
||||
alias WandererApp.Map.Server.SystemsImpl
|
||||
|
||||
test "returns :ok without filtering when scopes is nil" do
|
||||
# When scopes is nil, should not filter (backward compatibility)
|
||||
result = SystemsImpl.maybe_add_system("map_id", nil, nil, [])
|
||||
assert result == :ok
|
||||
end
|
||||
|
||||
test "returns :ok without filtering when scopes is empty list" do
|
||||
# Empty scopes should not filter (let through)
|
||||
result = SystemsImpl.maybe_add_system("map_id", nil, nil, [], [])
|
||||
assert result == :ok
|
||||
end
|
||||
|
||||
test "filters system when scopes provided and system doesn't match" do
|
||||
# When scopes is [:wormholes] and system is Hi-Sec, should filter (return :ok without adding)
|
||||
location = %{solar_system_id: @hs_system_id}
|
||||
result = SystemsImpl.maybe_add_system("map_id", location, nil, [], [:wormholes])
|
||||
# Returns :ok because system was filtered out (not an error, just skipped)
|
||||
assert result == :ok
|
||||
end
|
||||
|
||||
test "allows system through when scopes match (verified via can_add_location)" do
|
||||
# When scopes is [:wormholes] and system is WH, filtering should allow it
|
||||
# We test this via can_add_location which is what maybe_add_system uses internally
|
||||
assert ConnectionsImpl.can_add_location([:wormholes], @wh_system_id) == true
|
||||
assert ConnectionsImpl.can_add_location([:null], @ns_system_id) == true
|
||||
assert ConnectionsImpl.can_add_location([:wormholes, :null], @wh_system_id) == true
|
||||
assert ConnectionsImpl.can_add_location([:wormholes, :null], @ns_system_id) == true
|
||||
end
|
||||
end
|
||||
|
||||
describe "border system auto-addition behavior" do
|
||||
# Tests that verify bordered systems are correctly auto-added ONLY for wormholes.
|
||||
# Key behavior:
|
||||
# - Wormhole border: WH to Hi-Sec with [:wormholes] -> BOTH added (border behavior)
|
||||
# - K-space only: Null to Hi-Sec with [:wormholes, :null] -> REJECTED (no border for k-space)
|
||||
# - K-space must match: both systems must match scopes when no wormhole involved
|
||||
|
||||
test "WORMHOLE BORDER: WH->Hi-Sec with [:wormholes] is VALID (border k-space added)" do
|
||||
# Border case: moving from WH to k-space
|
||||
# Valid because :wormholes enabled AND one system is WH
|
||||
assert ConnectionsImpl.is_connection_valid([:wormholes], @wh_system_id, @hs_system_id) == true
|
||||
end
|
||||
|
||||
test "WORMHOLE BORDER: Hi-Sec->WH with [:wormholes] is VALID (border k-space added)" do
|
||||
# Border case: moving from k-space to WH
|
||||
# Valid because :wormholes enabled AND one system is WH
|
||||
assert ConnectionsImpl.is_connection_valid([:wormholes], @hs_system_id, @wh_system_id) == true
|
||||
end
|
||||
|
||||
test "K-SPACE ONLY: Hi-Sec->Hi-Sec with [:wormholes] is REJECTED" do
|
||||
# No wormhole involved, neither matches :wormholes
|
||||
assert ConnectionsImpl.is_connection_valid([:wormholes], @hs_system_id, 30_000_002) == false
|
||||
end
|
||||
|
||||
test "K-SPACE ONLY: Null->Hi-Sec with [:wormholes, :null] is REJECTED (no border for k-space)" do
|
||||
# Neither system is a wormhole, so no border behavior
|
||||
# Null matches :null, but Hi-Sec doesn't match any scope -> BOTH must match
|
||||
assert ConnectionsImpl.is_connection_valid([:wormholes, :null], @ns_system_id, @hs_system_id) ==
|
||||
false
|
||||
end
|
||||
|
||||
test "K-SPACE ONLY: Hi-Sec->Low-Sec with [:wormholes, :null] is REJECTED" do
|
||||
# Neither Hi-Sec nor Low-Sec match [:wormholes, :null], no WH involved
|
||||
assert ConnectionsImpl.is_connection_valid([:wormholes, :null], @hs_system_id, @ls_system_id) ==
|
||||
false
|
||||
end
|
||||
|
||||
test "K-SPACE ONLY: Low-Sec->Hi-Sec with [:low] is REJECTED (no border for k-space)" do
|
||||
# Low-Sec matches :low, but Hi-Sec doesn't match
|
||||
# No wormhole involved, so BOTH must match -> rejected
|
||||
assert ConnectionsImpl.is_connection_valid([:low], @ls_system_id, @hs_system_id) == false
|
||||
end
|
||||
|
||||
test "K-SPACE MATCH: Low-Sec->Low-Sec with [:low] is VALID (both match)" do
|
||||
# Both systems match :low
|
||||
assert ConnectionsImpl.is_connection_valid([:low], @ls_system_id, 30_000_101) == true
|
||||
end
|
||||
|
||||
test "K-SPACE MATCH: Null->Null with [:null] is VALID (both match)" do
|
||||
# Would need two different null-sec systems for this test
|
||||
# Using same system returns false (same system check)
|
||||
assert ConnectionsImpl.is_connection_valid([:null], @ns_system_id, @ns_system_id) == false
|
||||
end
|
||||
|
||||
test "WORMHOLE BORDER: Pochven->WH with [:wormholes, :pochven] is VALID" do
|
||||
# WH is wormhole, :wormholes enabled -> border behavior applies
|
||||
assert ConnectionsImpl.is_connection_valid([:wormholes, :pochven], @pochven_id, @wh_system_id) ==
|
||||
true
|
||||
end
|
||||
|
||||
test "WORMHOLE BORDER: WH->Pochven with [:wormholes] is VALID (border k-space)" do
|
||||
# WH is wormhole, :wormholes enabled -> border behavior, Pochven added as border
|
||||
assert ConnectionsImpl.is_connection_valid([:wormholes], @wh_system_id, @pochven_id) == true
|
||||
end
|
||||
|
||||
test "border systems: WH->Hi-Sec->WH path with [:wormholes] scope" do
|
||||
# Simulates a character path through k-space between WHs
|
||||
# First jump: WH to Hi-Sec - valid (wormhole border)
|
||||
assert ConnectionsImpl.is_connection_valid([:wormholes], @wh_system_id, @hs_system_id) == true
|
||||
# Second jump: Hi-Sec to WH - valid (wormhole border)
|
||||
assert ConnectionsImpl.is_connection_valid([:wormholes], @hs_system_id, @c2_system_id) == true
|
||||
end
|
||||
|
||||
test "excluded path: k-space chain with [:wormholes] scope remains excluded" do
|
||||
# If character moves within k-space (no WH involved), should be excluded
|
||||
assert ConnectionsImpl.is_connection_valid([:wormholes], @hs_system_id, 30_000_002) == false
|
||||
assert ConnectionsImpl.is_connection_valid([:wormholes], 30_000_002, @ls_system_id) == false
|
||||
end
|
||||
|
||||
test "excluded path: Null->Hi-Sec->Low-Sec with [:wormholes, :null] - only Null tracked" do
|
||||
# Character in Null (tracked) jumps to Hi-Sec (border - but NO wormhole!) -> REJECTED
|
||||
# This is the key case: k-space to k-space should NOT add border systems
|
||||
assert ConnectionsImpl.is_connection_valid([:wormholes, :null], @ns_system_id, @hs_system_id) ==
|
||||
false
|
||||
# Hi-Sec to Low-Sec also rejected (neither matches)
|
||||
assert ConnectionsImpl.is_connection_valid([:wormholes, :null], @hs_system_id, @ls_system_id) ==
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user