mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-11 08:23:45 +00:00
fix(multiplayer): reconcile authoritative initial connections
This commit is contained in:
@@ -173,3 +173,12 @@ func test_allocated_start_floor_is_the_verified_roster_size() -> void:
|
||||
assert_eq(boot.required_min_players(true, 6, 1), 6, "allocated six-player roster cannot start with one player")
|
||||
assert_eq(boot.required_min_players(true, 2, 6), 2, "allocated casual roster uses its complete size")
|
||||
assert_eq(boot.required_min_players(false, 1, 1), 1, "direct server keeps its configured floor")
|
||||
|
||||
|
||||
func test_connection_reporting_requires_safe_workload_configuration() -> void:
|
||||
var boot = preload("res://scripts/server_boot.gd")
|
||||
assert_true(boot.valid_connection_report_configuration("http://control-plane:8080", "signed-token", "match-1234567890", "server-123456789", "player-123456789"), "allocated workload configuration is accepted")
|
||||
assert_true(not boot.valid_connection_report_configuration("http://control-plane:8080?token=leak", "signed-token", "match-1234567890", "server-123456789", "player-123456789"), "query-bearing control-plane URL is rejected")
|
||||
assert_true(not boot.valid_connection_report_configuration("http://control-plane:8080", "token\nforged", "match-1234567890", "server-123456789", "player-123456789"), "header injection token is rejected")
|
||||
assert_true(not boot.valid_connection_report_configuration("http://control-plane:8080", "signed-token", "short", "server-123456789", "player-123456789"), "non-opaque match identity is rejected")
|
||||
assert_true(not boot.valid_connection_report_configuration("http://control-plane:8080", "signed-token", "match-1234567890", "server-123456789", "short"), "non-opaque player identity is rejected")
|
||||
|
||||
@@ -6,6 +6,14 @@ func test_allocated_initial_connect_policy_has_explicit_boundaries() -> void:
|
||||
assert_eq(loop.allocated_initial_connect_action("ranked", 30000, 5, 6, true, true), loop.ALLOCATED_CANCEL, "ranked cancels at 30 seconds")
|
||||
assert_eq(loop.allocated_initial_connect_action("casual", 59999, 2, 6, true, true), loop.ALLOCATED_WAIT, "casual waits before 60 seconds")
|
||||
assert_eq(loop.allocated_initial_connect_action("casual", 60000, 2, 6, true, true), loop.ALLOCATED_START_WITH_BOTS, "casual starts with bots when both teams are represented")
|
||||
assert_eq(loop.allocated_initial_connect_action("casual", 1000, 2, 2, true, true), loop.ALLOCATED_START_WITH_BOTS, "complete relaxed casual roster starts with disclosed bots immediately")
|
||||
assert_eq(loop.allocated_initial_connect_action("casual", 1000, 2, 2, true, false), loop.ALLOCATED_CANCEL, "malformed relaxed casual roster fails closed")
|
||||
assert_eq(loop.allocated_initial_connect_action("casual", 60000, 2, 6, true, false), loop.ALLOCATED_CANCEL, "casual cancels when one team is empty")
|
||||
assert_eq(loop.allocated_initial_connect_action("casual", 1000, 6, 6, true, true), loop.ALLOCATED_READY, "complete roster is ready immediately")
|
||||
assert_eq(loop.allocated_initial_connect_action("ranked", 1000, 5, 5, true, true), loop.ALLOCATED_CANCEL, "ranked cannot shrink its expected roster")
|
||||
assert_eq(loop.allocated_initial_connect_action("other", 0, 1, 6, true, true), loop.ALLOCATED_CANCEL, "unknown allocated playlist fails closed")
|
||||
var instance = loop.new()
|
||||
instance.allocated_admission_armed = false
|
||||
instance.arm_allocated_admission()
|
||||
assert_true(instance.allocated_admission_armed, "durable readiness signal arms the local timeout")
|
||||
instance.free()
|
||||
|
||||
@@ -12,6 +12,8 @@ func _init() -> void:
|
||||
quit(1)
|
||||
return
|
||||
control.set_process_ready(true)
|
||||
control.set_meta("admission_armed", false)
|
||||
control.initial_connect_ready.connect(func() -> void: control.set_meta("admission_armed", true))
|
||||
await process_frame
|
||||
var ready_response := await _request("GET", "/ready", [])
|
||||
if ready_response != 200:
|
||||
@@ -23,6 +25,16 @@ func _init() -> void:
|
||||
printerr("unauthorized drain response was %d" % unauthorized)
|
||||
quit(1)
|
||||
return
|
||||
var unauthorized_admission := await _request("POST", "/initial-connect-ready", ["Authorization: Bearer wrong"])
|
||||
if unauthorized_admission != 401 or bool(control.get_meta("admission_armed")):
|
||||
printerr("unauthorized initial-connect response/state was %d/%s" % [unauthorized_admission, control.get_meta("admission_armed")])
|
||||
quit(1)
|
||||
return
|
||||
var admitted := await _request("POST", "/initial-connect-ready", ["Authorization: Bearer drain-secret"])
|
||||
if admitted != 202 or not bool(control.get_meta("admission_armed")):
|
||||
printerr("authorized initial-connect response/state was %d/%s" % [admitted, control.get_meta("admission_armed")])
|
||||
quit(1)
|
||||
return
|
||||
var drained := await _request("POST", "/drain", ["Authorization: Bearer drain-secret"])
|
||||
if drained != 202 or not control.is_draining():
|
||||
printerr("authorized drain response/state was %d/%s" % [drained, control.is_draining()])
|
||||
|
||||
Reference in New Issue
Block a user