extends SceneTree ## The update check (scripts/core/updates.gd): comparing versions, a plain ## version.json feed, a Gitea/GitHub release feed (its version.json asset and ## downloads by name), "you're up to date", broken feeds, the setting, the ## title screen's banner, and the advice on a "Different game version" ## refusal. No network: a fake feed answers. ## Run: godot --headless --path . --script res://tests/test_updates.gd var _fails := 0 var _finished := false var U: Node var pages: Dictionary = {} func check(cond: bool, what: String) -> void: print((" ok " if cond else " FAIL ") + what) if not cond: _fails += 1 func _initialize() -> void: _run.call_deferred() func _run() -> void: U = root.get_node("Updates") U.prefs_path = "user://test_updates.json" DirAccess.remove_absolute(U.prefs_path) U.load_prefs() await _body() check(_finished, "test ran to the end (no script errors)") DirAccess.remove_absolute(U.prefs_path) print("RESULT: %s (%d failures)" % ["PASS" if _fails == 0 else "FAIL", _fails]) quit(1 if _fails > 0 else 0) func _fake(url: String) -> String: return String(pages.get(url, "404")) func _check_now() -> String: U.check() while U.state == "checking": await process_frame return U.state func _body() -> void: print("versions") var C: Script = load("res://scripts/core/updates.gd") check(C.compare_versions("0.2.0", "0.1.0") == 1 and C.compare_versions("0.1.0", "0.2.0") == -1, "0.2.0 is newer than 0.1.0") check(C.compare_versions("v0.10.0", "0.9.5") == 1, "0.10 beats 0.9 (numbers, not letters), and a v in front is fine") check(C.compare_versions("1.0", "1.0.0") == 0 and C.compare_versions("1.0.0-beta", "1.0.0") == 0, "1.0 = 1.0.0 = 1.0.0-beta") check(U.version == ProjectSettings.get_setting("application/config/version") and not U.version.is_empty(), "this game knows its own version (%s)" % U.version) check(U.feed.begins_with("https://"), "and where to ask: %s" % U.feed) print("headless, no fake feed") U.fetch_override = Callable() check(await _check_now() == "off", "tests and bots never touch the network") U.fetch_override = _fake U.feed = "https://example.test/version.json" var plat: String = C.platform_key() print("a version.json feed") pages[U.feed] = JSON.stringify({"version": "9.1.0", "protocol": 99, "notes": "The Cove.", "page": "https://example.test/r/9.1.0", "downloads": {plat: {"file": "Emberwild-9.1.0-%s.zip" % plat, "url": "https://example.test/dl/%s.zip" % plat, "sha256": "ab"}}}) check(await _check_now() == "available", "9.1.0 is out: available") check(U.latest_version() == "9.1.0" and U.latest_protocol() == 99, "its version and protocol") check(U.download_url() == "https://example.test/dl/%s.zip" % plat and U.download().sha256 == "ab", "this platform's download (%s), with its checksum" % plat) print("a release feed (Gitea / Forgejo / GitHub)") U.feed = "https://example.test/api/releases/latest" pages[U.feed] = JSON.stringify({"tag_name": "v9.2.0", "html_url": "https://example.test/releases/v9.2.0", "assets": [ {"name": "version.json", "browser_download_url": "https://example.test/a/version.json"}, {"name": "Emberwild-9.2.0-%s.zip" % plat, "browser_download_url": "https://example.test/a/game-%s.zip" % plat}]}) pages["https://example.test/a/version.json"] = JSON.stringify({"version": "9.2.0", "protocol": 99, "downloads": {plat: {"file": "Emberwild-9.2.0-%s.zip" % plat, "sha256": "cd"}}, "windows_only_key": true}) check(await _check_now() == "available" and U.latest_version() == "9.2.0", "the release's version.json is read: 9.2.0") check(U.download_url() == "https://example.test/a/game-%s.zip" % plat, "the download is the release asset with that file name") check(U.page == "https://example.test/releases/v9.2.0", "and the release page is kept") U.latest.downloads.erase(plat) check(U.download_url() == U.page, "no package for this platform: the release page instead") print("up to date, and broken feeds") pages[U.feed] = JSON.stringify({"version": U.version, "protocol": 12}) check(await _check_now() == "current", "the same version: up to date") pages[U.feed] = JSON.stringify({"version": "0.0.1"}) check(await _check_now() == "current", "an older one: up to date") pages[U.feed] = "Bad gateway" check(await _check_now() == "failed" and U.error.contains("JSON"), "a 502 page: failed, and says why (%s)" % U.error) pages[U.feed] = JSON.stringify({"tag_name": "v1", "assets": []}) check(await _check_now() == "failed" and U.error.contains("version.json"), "a release with no version.json: failed") print("the setting") U.set_enabled(false) pages[U.feed] = JSON.stringify({"version": "9.3.0"}) check(await _check_now() == "off", "off: no check") U.load_prefs() check(not U.enabled, "and it's remembered") U.set_enabled(true) check(await _check_now() == "available", "on again: 9.3.0") print("the title screen") var TS: Script = load("res://scripts/ui/title_screen.gd") var msg := "Different game version: this server runs Emberwild 9.3.0 (protocol 99), you have protocol 12. Update the game to join." check(TS.version_advice(msg).contains("9.3.0 is out"), "refused for an old version: it says the new one is out") check(TS.version_advice("Server is full").is_empty(), "(other refusals: nothing added)") pages[U.feed] = JSON.stringify({"version": "9.4.0", "notes": "Sea fishing."}) U.state = "idle" var title: Node = load("res://scenes/title.tscn").instantiate() root.add_child(title) for _i in range(5): await process_frame while U.state == "checking": await process_frame await process_frame check(title.version_label != null and title.version_label.text.ends_with(U.version), "the version, bottom left (%s)" % title.version_label.text) check(title.update_banner.visible and title._update_text.text.contains("9.4.0 is out") and title._update_text.text.contains("Sea fishing."), "a banner: 9.4.0 is out, with its notes") check(title._update_text.text.contains("git pull"), "(running from the source: it says git pull)") title.queue_free() await process_frame U.fetch_override = Callable() _finished = true