mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-10 16:04:04 +00:00
78 lines
6.3 KiB
GDScript
78 lines
6.3 KiB
GDScript
extends "res://tests/test_case.gd"
|
|
|
|
const ControlPlaneClient = preload("res://scripts/control_plane_client.gd")
|
|
const RankedProfileState = preload("res://scripts/ranked_profile_state.gd")
|
|
|
|
|
|
func test_base_url_validation_rejects_ambiguous_or_insecure_values() -> void:
|
|
assert_true(ControlPlaneClient.is_valid_base_url("http://127.0.0.1:8080"), "local HTTP endpoint is valid")
|
|
assert_true(ControlPlaneClient.is_valid_base_url("https://match.example"), "HTTPS endpoint is valid")
|
|
assert_true(not ControlPlaneClient.is_valid_base_url("match.example"), "scheme is required")
|
|
assert_true(not ControlPlaneClient.is_valid_base_url("http://match.example/"), "trailing slash is normalized before validation")
|
|
assert_true(not ControlPlaneClient.is_valid_base_url("http://match example"), "whitespace is rejected")
|
|
assert_true(not ControlPlaneClient.is_valid_base_url("https://user:pass@match.example"), "userinfo is rejected")
|
|
assert_true(not ControlPlaneClient.is_valid_base_url("https://match.example?token=secret"), "query strings are rejected")
|
|
|
|
var client := ControlPlaneClient.new()
|
|
assert_true(client.configure("https://match.example", "session-id:opaque-token"), "safe access token configures")
|
|
assert_true(not client.configure("https://match.example", "token\nforged-header"), "header injection is rejected")
|
|
assert_true(ControlPlaneClient.is_valid_web_api_ticket("ticket-value"), "ordinary Steam Web API ticket is accepted")
|
|
assert_true(not ControlPlaneClient.is_valid_web_api_ticket("ticket\nforged"), "ticket header characters are rejected")
|
|
assert_true(not ControlPlaneClient.is_valid_web_api_ticket(""), "empty Steam ticket is rejected")
|
|
assert_true(ControlPlaneClient.is_valid_access_token("session-id:opaque-token"), "opaque session format is accepted")
|
|
assert_true(not ControlPlaneClient.is_valid_access_token(":opaque-token"), "missing session identifier is rejected")
|
|
assert_true(not ControlPlaneClient.is_valid_access_token("session-id:token\nforged"), "session header injection is rejected")
|
|
assert_eq(ControlPlaneClient.websocket_url("https://match.example"), "wss://match.example", "TLS control plane uses secure WebSocket")
|
|
assert_eq(ControlPlaneClient.websocket_url("http://127.0.0.1:8080"), "ws://127.0.0.1:8080", "local control plane uses WebSocket")
|
|
assert_eq(ControlPlaneClient.websocket_url("match.example"), "", "unscoped URL cannot become a WebSocket URL")
|
|
var unconfigured := ControlPlaneClient.new()
|
|
assert_eq(unconfigured.connect_event_stream(), ERR_UNAUTHORIZED, "event stream requires an authenticated session")
|
|
|
|
|
|
func test_ticket_normalization_preserves_payload_and_derives_expiry() -> void:
|
|
var payload := {"ticket_id": "ticket-1", "state": "QUEUED", "expires_at": "2026-08-31T12:00:00Z"}
|
|
var normalized := ControlPlaneClient.normalize_ticket(payload)
|
|
assert_eq(normalized["ticket_id"], "ticket-1", "normalization preserves ticket identity")
|
|
assert_true(normalized.has("expires_at_unix"), "RFC3339 expiry is available to the projection")
|
|
assert_true(int(normalized["expires_at_unix"]) > 0, "expiry is converted to a positive epoch")
|
|
assert_true(not payload.has("expires_at_unix"), "normalization does not mutate the HTTP payload")
|
|
|
|
|
|
func test_websocket_event_validation_requires_contract_specific_fields() -> void:
|
|
var envelope := {"event": "state_changed", "revision": 1, "resource_id": "ticket-1", "occurred_at": "2026-08-31T12:00:00Z", "state": "QUEUED"}
|
|
assert_true(ControlPlaneClient._valid_websocket_event(envelope), "valid state event is accepted")
|
|
var bad_state := envelope.duplicate()
|
|
bad_state["state"] = "SECRET"
|
|
assert_true(not ControlPlaneClient._valid_websocket_event(bad_state), "unknown state event is rejected")
|
|
var assignment := {"event": "assignment_changed", "revision": 0, "resource_id": "match-1", "occurred_at": "2026-08-31T12:00:00Z", "match_id": "match-1", "server_id": "server-1"}
|
|
assert_true(ControlPlaneClient._valid_websocket_event(assignment), "complete assignment event is accepted")
|
|
assignment.erase("server_id")
|
|
assert_true(not ControlPlaneClient._valid_websocket_event(assignment), "incomplete assignment event is rejected")
|
|
|
|
|
|
func test_retryable_mutation_policy_only_retries_safe_failures() -> void:
|
|
assert_true(ControlPlaneClient.is_retryable_mutation_response(0), "transport failure is retryable")
|
|
assert_true(ControlPlaneClient.is_retryable_mutation_response(408), "request timeout is retryable")
|
|
assert_true(ControlPlaneClient.is_retryable_mutation_response(429), "rate limit is retryable")
|
|
assert_true(ControlPlaneClient.is_retryable_mutation_response(503), "server failure is retryable")
|
|
assert_true(not ControlPlaneClient.is_retryable_mutation_response(401), "authentication failure is not blindly replayed")
|
|
assert_true(not ControlPlaneClient.is_retryable_mutation_response(409), "revision/idempotency conflict is not blindly replayed")
|
|
|
|
|
|
func test_assignment_endpoint_split_never_accepts_url_or_bad_port() -> void:
|
|
var endpoint := ControlPlaneClient._split_assignment_endpoint("127.0.0.1:31001")
|
|
assert_eq(endpoint["host"], "127.0.0.1", "assignment host is separated from the port")
|
|
assert_eq(endpoint["port"], 31001, "assignment port is parsed as an integer")
|
|
for unsafe in ["127.0.0.1", "127.0.0.1:0", "127.0.0.1:65536", "127.0.0.1:31001/path", "https://127.0.0.1:31001"]:
|
|
assert_true(ControlPlaneClient._split_assignment_endpoint(unsafe).is_empty(), "unsafe endpoint is rejected: %s" % unsafe)
|
|
|
|
|
|
func test_ranked_profile_is_backend_display_data_and_rejects_unsafe_values() -> void:
|
|
var profile := RankedProfileState.new()
|
|
assert_true(profile.apply({"rating": 1500.0, "rd": 200.0, "volatility": 0.06, "ranked_games": 3, "tier": "GOLD", "provisional": true, "season_id": "s1"}), "valid profile applies")
|
|
assert_eq(profile.display_text(), "Provisional · 3 ranked games", "provisional status overrides tier presentation")
|
|
assert_true(not profile.apply({"rating": -1.0, "rd": 200.0, "volatility": 0.06, "ranked_games": 3, "tier": "GOLD", "provisional": false}), "negative rating is rejected")
|
|
assert_true(not profile.available, "unsafe response is not displayed")
|
|
assert_true(not profile.apply({"rating": 1500.0, "rd": 200.0, "volatility": 0.06, "ranked_games": 3, "tier": "", "provisional": false}), "empty tier is rejected")
|
|
assert_true(not profile.apply({"rating": 1500.0, "rd": 200.0, "volatility": 0.06, "ranked_games": 3, "tier": "GOLD", "provisional": "false"}), "string boolean is rejected")
|