mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-13 22:32:09 +00:00
feat(multiplayer): reject outdated clients with distinct messaging
Closes §8.43's 'version-mismatch-specific client messaging' gap. Per the user's explicit go-ahead to design new server behavior for this (rather than only wiring up something that already existed, the pattern every other fix this session followed): before this, there was no server-side protocol rejection at all. queue_create accepted any protocol_version >= 1 unconditionally, so an outdated client could only ever discover a mismatch by waiting in the queue forever unmatched -- the matcher's own compatibility check requires every formed player to share an identical protocol_version -- with no error and no explanation given to the player. Server: Service.MinProtocolVersion (opt-in, zero by default so every existing caller keeps accepting protocol_version 1 unconditionally) rejects a below-floor queue_create with 426 Upgrade Required / client_outdated before the request ever reaches the candidate provider. Wired via cmd/control-plane's new --min-protocol-version flag (validated non-negative at startup). Client: ControlPlaneClient recognises HTTPClient.RESPONSE_UPGRADE_REQUIRED on queue_create specifically and sets a distinct 'Your client is out of date -- please update to continue searching' message instead of the server's raw generic error string, and clears _last_queue_create so can_retry_queue_create() never offers 'Retry Search' for a failure that retrying with the same build can never fix. Verified: go build/vet/test -race clean across every server package. TestQueueCreateEnforcesMinProtocolVersion covers below-floor rejection (candidate provider never reached), exactly-at-floor acceptance, and the error body naming client_outdated; TestQueueCreateMinProtocolVersionZeroIsDisabled proves the opt-in default doesn't change behavior for every existing caller. Godot: test_outdated_client_receives_a_distinct_message_and_no_retry_offer proves the distinct message and suppressed retry offer. Full Godot suite (217/217, 0 failed, no crash), full make verify-multiplayer-local gate, zero new crash reports.
This commit is contained in:
@@ -338,6 +338,24 @@ func test_queue_conflict_response_handler_defers_ticket_recovery() -> void:
|
||||
client.free()
|
||||
|
||||
|
||||
# Covers §8.43's "version-mismatch-specific client messaging": a 426 Upgrade
|
||||
# Required on queue_create (the server-side floor added alongside this test)
|
||||
# must surface a distinct, actionable message rather than the server's raw
|
||||
# generic error string, and must not offer a futile "Retry Search" -- the
|
||||
# same client build will fail again identically every time.
|
||||
func test_outdated_client_receives_a_distinct_message_and_no_retry_offer() -> void:
|
||||
var client := ControlPlaneClient.new()
|
||||
client._ready()
|
||||
assert_true(client.configure("https://match.example", "session-id:opaque-token"), "client configures")
|
||||
client._operation = "queue_create"
|
||||
client._last_queue_create = {"ticket_id": "ticket-outdated", "playlist": "casual", "client_build": "build-1", "protocol_version": 4, "key": "outdated-key-123456"}
|
||||
client._on_request_completed(HTTPRequest.RESULT_SUCCESS, HTTPClient.RESPONSE_UPGRADE_REQUIRED, PackedStringArray(), JSON.stringify({"error": "client_outdated"}).to_utf8_buffer())
|
||||
assert_eq(client.state.phase, MatchmakingState.FAILED, "outdated client fails the search")
|
||||
assert_true(client.state.message.to_lower().contains("update"), "message tells the player to update rather than repeating the raw server error: %s" % client.state.message)
|
||||
assert_true(not client.can_retry_queue_create(), "retrying with the same outdated client build is never offered")
|
||||
client.free()
|
||||
|
||||
|
||||
func test_rest_responses_reject_malformed_resource_identifiers() -> void:
|
||||
var client := ControlPlaneClient.new()
|
||||
client._ready()
|
||||
|
||||
Reference in New Issue
Block a user