extends SceneTree var failures := 0 var auth func _initialize() -> void: call_deferred("_run") func _run() -> void: auth = load("res://scripts/autoload/auth_state.gd").new() root.add_child(auth) await process_frame _test_expiration_parsing() _test_warning_and_expiration() _test_refresh_preserves_identity() _test_refresh_in_flight_has_expiry_grace() _test_stale_responses_cannot_restore_or_end_session() auth.queue_free() await process_frame quit(1 if failures > 0 else 0) func _test_expiration_parsing() -> void: var iso_expiration: float = float(auth._parse_expiration("2030-01-02T03:04:05Z")) var expected_iso := float(Time.get_unix_time_from_datetime_string("2030-01-02T03:04:05")) _assert(is_equal_approx(iso_expiration, expected_iso), "session expiry should parse the Auth API ISO timestamp") var jwt_expiration := 1893456000 var payload: String = Marshalls.raw_to_base64(JSON.stringify({"exp": jwt_expiration}).to_utf8_buffer()) payload = payload.replace("+", "-").replace("/", "_").trim_suffix("=") var token := "header.%s.signature" % payload _assert(int(auth._parse_expiration("", token)) == jwt_expiration, "session expiry should fall back to the JWT exp claim") func _test_warning_and_expiration() -> void: var observed := {"warning_seconds": -1, "expiration_reason": ""} var warning_callback := func(seconds: int): observed["warning_seconds"] = seconds var expiration_callback := func(reason: String): observed["expiration_reason"] = reason auth.session_warning.connect(warning_callback) auth.session_expired.connect(expiration_callback) auth.set_session("tester", "warning-token", "refresh-token", "USER", str(Time.get_unix_time_from_system() + 90.0)) auth._evaluate_expiry() _assert(int(observed["warning_seconds"]) > 0 and int(observed["warning_seconds"]) <= 90, "session should warn inside the two-minute renewal window") auth.expiration_unix = Time.get_unix_time_from_system() - 1.0 auth._evaluate_expiry() _assert(str(observed["expiration_reason"]) == "expired" and not auth.is_logged_in, "an unanswered warning should clear the session at expiry") auth.session_warning.disconnect(warning_callback) auth.session_expired.disconnect(expiration_callback) func _test_refresh_preserves_identity() -> void: var observed := {"refreshed": false} var refreshed_callback := func(): observed["refreshed"] = true auth.session_refreshed.connect(refreshed_callback) auth.set_session("tester", "old-token", "persistent-refresh", "SUPER", str(Time.get_unix_time_from_system() + 60.0)) auth.refresh_in_progress = true auth.refresh_revision = auth.session_revision var next_expiration := Time.get_unix_time_from_system() + 900.0 var body := JSON.stringify({"accessToken": "new-token", "exp": next_expiration}).to_utf8_buffer() auth._on_refresh_completed(HTTPRequest.RESULT_SUCCESS, 200, PackedStringArray(), body) _assert(bool(observed["refreshed"]) and auth.access_token == "new-token", "successful renewal should install the replacement access token") _assert(auth.refresh_token == "persistent-refresh" and auth.username == "tester" and auth.role == "SUPER", "renewal should preserve identity and the non-rotating refresh token") _assert(not auth.warning_active and auth.expiration_unix > Time.get_unix_time_from_system(), "renewal should reset the warning window") auth.session_refreshed.disconnect(refreshed_callback) func _test_refresh_in_flight_has_expiry_grace() -> void: auth.set_session("tester", "old-token", "refresh-token", "USER", str(Time.get_unix_time_from_system() + 60.0)) auth.expiration_unix = Time.get_unix_time_from_system() - 1.0 auth.refresh_in_progress = true auth._evaluate_expiry() _assert(auth.is_logged_in, "a submitted renewal should be allowed to finish after the old access token expires") _assert(not auth.can_send_authenticated_request(), "expired access tokens should not be used while renewal is in progress") auth.refresh_in_progress = false auth.clear_session() func _test_stale_responses_cannot_restore_or_end_session() -> void: auth.set_session("tester", "old-token", "refresh-token", "USER", str(Time.get_unix_time_from_system() + 60.0)) auth.refresh_in_progress = true auth.refresh_revision = auth.session_revision auth.clear_session() var body := JSON.stringify({"accessToken": "stale-token", "exp": Time.get_unix_time_from_system() + 900.0}).to_utf8_buffer() auth._on_refresh_completed(HTTPRequest.RESULT_SUCCESS, 200, PackedStringArray(), body) _assert(auth.access_token.is_empty(), "a delayed refresh response must not restore a logged-out session") auth.set_session("tester", "current-token", "refresh-token", "USER", str(Time.get_unix_time_from_system() + 900.0)) auth.handle_unauthorized("old-token") _assert(auth.is_logged_in and auth.access_token == "current-token", "a stale 401 must not end a newer session") auth.handle_unauthorized("current-token") _assert(not auth.is_logged_in, "a 401 for the active token should end the invalid session") func _assert(condition: bool, message: String) -> void: if condition: return failures += 1 push_error(message)