extends "res://tests/test_case.gd" # Task 6.3. The behaviour that matters is not "it parses a port" — it is the # precedence order an operator relies on, and the refusal to run on a typo. const ServerConfigScript = preload("res://scripts/server_config.gd") func _parse(args: Array) -> Variant: var argv := PackedStringArray() for a in args: argv.append(a) return ServerConfigScript.parse(argv) func _temp_config(body: String) -> String: var path := "user://test_server_%d.cfg" % Time.get_ticks_usec() var f := FileAccess.open(path, FileAccess.WRITE) f.store_string(body) f.close() return path func test_defaults_apply_when_nothing_is_given() -> void: var config = _parse([]) assert_true(config.is_valid(), "an empty command line is valid") assert_eq(config.get_value("port"), 7777, "default port") assert_eq(config.get_value("max-matches"), 0, "0 means run forever") assert_eq(config.get_value("log-level"), "info", "default log level") func test_command_line_values_are_typed_not_strings() -> void: var config = _parse(["--port=7000", "--match-length=90.5", "--fill-bots"]) assert_true(config.is_valid(), "valid: %s" % str(config.errors)) assert_eq(config.get_value("port"), 7000, "int stays an int") assert_almost_eq(config.get_value("match-length"), 90.5, 0.001, "float stays a float") assert_eq(config.get_value("fill-bots"), true, "a bare bool flag is true") func test_an_unknown_flag_is_an_error_not_a_shrug() -> void: # The whole reason this class exists: `--max-clientss=8` used to run a # server on the default cap and say nothing at all. var config = _parse(["--max-clientss=8"]) assert_true(not config.is_valid(), "a typo'd flag is rejected") assert_true("max-clientss" in " ".join(config.errors), "and the error names it: %s" % str(config.errors)) func test_a_value_that_is_not_the_declared_type_is_rejected() -> void: var config = _parse(["--port=seven"]) assert_true(not config.is_valid(), "a non-numeric port is rejected") var config_ok = _parse(["--port=7000"]) assert_true(config_ok.is_valid(), "control: a numeric port is accepted") func test_a_non_bool_flag_without_a_value_is_rejected() -> void: # Silently defaulting here would hide a shell-quoting mistake. var config = _parse(["--port"]) assert_true(not config.is_valid(), "--port with no value is an error") func test_no_prefix_turns_a_bool_off() -> void: var config = _parse(["--no-fill-bots"]) assert_true(config.is_valid(), "valid: %s" % str(config.errors)) assert_eq(config.get_value("fill-bots"), false, "--no- inverts it") # And it must not be listed separately, or --help doubles in length. var help: String = ServerConfigScript.help_text() assert_eq(help.count("--no-fill-bots"), 1, "--no- form appears once, in the default hint") func test_the_command_line_beats_the_config_file() -> void: var path := _temp_config("[server]\nport=8100\nmax-clients=4\n") var config = _parse(["--config=%s" % path, "--port=9200"]) assert_true(config.is_valid(), "valid: %s" % str(config.errors)) assert_eq(config.get_value("port"), 9200, "the command line wins") assert_eq(config.get_value("max-clients"), 4, "the file still supplies what the command line omits") DirAccess.remove_absolute(ProjectSettings.globalize_path(path)) func test_the_config_file_beats_the_default() -> void: var path := _temp_config("[server]\nport=8100\n") var config = _parse(["--config=%s" % path]) assert_true(config.is_valid(), "valid: %s" % str(config.errors)) assert_eq(config.get_value("port"), 8100, "the file overrides the default") DirAccess.remove_absolute(ProjectSettings.globalize_path(path)) func test_a_missing_or_malformed_config_file_is_an_error() -> void: var config = _parse(["--config=user://definitely_not_here_%d.cfg" % Time.get_ticks_usec()]) assert_true(not config.is_valid(), "a config file that cannot be read is an error, not silence") var path := _temp_config("[server]\nnonsense=1\n") var unknown_key = _parse(["--config=%s" % path]) assert_true(not unknown_key.is_valid(), "an unknown key in the file is rejected too") DirAccess.remove_absolute(ProjectSettings.globalize_path(path)) func test_out_of_range_values_are_rejected_with_their_own_message() -> void: assert_true(not _parse(["--port=0"]).is_valid(), "port 0 is out of range") assert_true(not _parse(["--port=70000"]).is_valid(), "port 70000 is out of range") assert_true(not _parse(["--max-clients=0"]).is_valid(), "a server for nobody is rejected") assert_true(not _parse(["--match-length=0"]).is_valid(), "a zero-length match is rejected") assert_true(not _parse(["--log-level=chatty"]).is_valid(), "an undefined log level is rejected") assert_true(not _parse(["--arena-rotation=spiral"]).is_valid(), "an undefined rotation mode is rejected") assert_true(not _parse(["--arena-path=res://scenes/arena_01_elevated.tscn"]).is_valid(), "an elevated arena cannot be selected for allocated ranked play") assert_true(_parse(["--arena-path=res://scenes/arena_01.tscn"]).is_valid(), "a ranked-eligible arena path is accepted") assert_true(not _parse(["--smoke-force-goal-after=-2"]).is_valid(), "only -1 disables the deterministic smoke goal") # Control: the same flags at legal values all pass together. var ok = _parse(["--port=7000", "--max-clients=6", "--match-length=90", "--log-level=warn", "--arena-rotation=random"]) assert_true(ok.is_valid(), "control: legal values pass (%s)" % str(ok.errors)) func test_a_repeated_flag_is_rejected_rather_than_last_wins() -> void: # Last-wins hides a duplicated line in a generated systemd unit. var config = _parse(["--port=7000", "--port=8000"]) assert_true(not config.is_valid(), "the same flag twice is an error") func test_help_documents_every_declared_flag() -> void: # The acceptance criterion is literally "--help documents every flag", so # assert it against the declaration rather than against a hand-kept list. var help: String = ServerConfigScript.help_text() for spec in ServerConfigScript.specs(): assert_true("--%s" % spec.key in help, "--%s appears in --help" % spec.key) assert_true(spec.help in help, "and so does its description") func test_help_is_requested_without_needing_a_valid_command_line() -> void: var config = _parse(["--help"]) assert_true(config.help_requested, "--help is recognised") var short = _parse(["-h"]) assert_true(short.help_requested, "-h too") func test_allocated_mode_is_opt_in_and_requires_compatibility_manifest() -> void: var community = _parse([]) assert_true(community.is_valid(), "community defaults remain valid") assert_eq(community.get_value("allocated-mode"), false, "allocation is opt-in") var incomplete = _parse(["--allocated-mode", "--transport=enet"]) assert_true(not incomplete.is_valid(), "allocated mode cannot start without its manifest") var valid = _parse([ "--allocated-mode", "--match-id=match_1234567890123456", "--server-id=server_1234567890123456", "--playlist-version=2026-08-31", "--client-build=client-2026-08-31", "--assignment-expiry-unix=%d" % (Time.get_unix_time_from_system() + 3600), "--server-image-digest=sha256:" + "a".repeat(64), "--playlist=casual", "--transport=enet", "--region=EU", "--join-authorisations-file=/run/secrets/join-authorisations.json", "--join-authorisations-key-file=/run/secrets/join-authorisations.key" ]) assert_true(valid.is_valid(), "a complete allocated compatibility manifest is accepted: %s" % str(valid.errors)) func test_allocated_mode_rejects_invalid_transport_region_or_digest() -> void: var args := [ "--allocated-mode", "--match-id=m", "--server-id=s", "--playlist-version=v", "--client-build=client", "--assignment-expiry-unix=%d" % (Time.get_unix_time_from_system() + 3600), "--server-image-digest=sha256:" + "g".repeat(64), "--transport=udp", "--region=AP" ] var config = _parse(args) assert_true(not config.is_valid(), "invalid compatibility values are rejected") var unsafe_id = _parse([ "--allocated-mode", "--match-id=short", "--server-id=server/unsafe", "--playlist-version=v", "--client-build=client", "--assignment-expiry-unix=%d" % (Time.get_unix_time_from_system() + 3600), "--server-image-digest=sha256:" + "a".repeat(64), "--playlist=casual", "--transport=enet", "--region=EU", "--join-authorisations-file=/run/secrets/join-authorisations.json", "--join-authorisations-key-file=/run/secrets/join-authorisations.key" ]) assert_true(not unsafe_id.is_valid(), "short or unsafe allocated identifiers are rejected") func test_allocated_mode_rejects_missing_or_expired_assignment_manifest_fields() -> void: var missing = _parse(["--allocated-mode", "--match-id=m", "--server-id=s", "--playlist-version=v", "--server-image-digest=sha256:" + "a".repeat(64), "--transport=enet", "--region=EU"]) assert_true(not missing.is_valid(), "client build and expiry are required") var expired = _parse(["--allocated-mode", "--match-id=m", "--server-id=s", "--playlist-version=v", "--client-build=client", "--assignment-expiry-unix=1", "--server-image-digest=sha256:" + "a".repeat(64), "--transport=enet", "--region=EU"]) assert_true(not expired.is_valid(), "expired assignment is rejected") func test_allocated_start_floor_is_the_verified_roster_size() -> void: var boot = preload("res://scripts/server_boot.gd") 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")