import hashlib import io import tempfile import unittest import zipfile from pathlib import Path from deploy_tool.installer import ( MAVEN_ARCHIVE_NAME, TOMCAT_VERSION, install_maven, install_tomcat, build_install_command, explain_install_failure, format_install_output, recommend_jdk_version, ) from deploy_tool.scanner import scan_project class InstallerTests(unittest.TestCase): def test_recommends_jdk_8_from_maven_source_property(self): with tempfile.TemporaryDirectory() as tmp: root = Path(tmp) backend = root / "server" (backend / "src" / "main" / "java").mkdir(parents=True) (backend / "pom.xml").write_text( """ 1.8 1.8 spring-boot-starter-web """, encoding="utf-8", ) scan = scan_project(root) recommendation = recommend_jdk_version(scan) self.assertEqual(recommendation.version, "8") self.assertIn("maven.compiler.source", recommendation.reason) def test_recommends_jdk_17_for_spring_boot_3(self): with tempfile.TemporaryDirectory() as tmp: root = Path(tmp) backend = root / "server" (backend / "src" / "main" / "java").mkdir(parents=True) (backend / "pom.xml").write_text( """ org.springframework.boot spring-boot-starter-parent 3.2.5 """, encoding="utf-8", ) scan = scan_project(root) recommendation = recommend_jdk_version(scan) self.assertEqual(recommendation.version, "17") self.assertIn("Spring Boot 3", recommendation.reason) def test_defaults_to_jdk_8_without_project_signal(self): recommendation = recommend_jdk_version(None) self.assertEqual(recommendation.version, "8") self.assertIn("默认", recommendation.reason) def test_builds_jdk_winget_install_command(self): command = build_install_command("JDK", version="8") self.assertEqual(command, ["winget", "install", "-e", "--id", "EclipseAdoptium.Temurin.8.JDK"]) def test_builds_node_winget_install_command(self): command = build_install_command("Node.js") self.assertEqual(command, ["winget", "install", "-e", "--id", "OpenJS.NodeJS.LTS"]) def test_maven_is_not_offered_as_an_invalid_winget_package(self): with self.assertRaises(ValueError): build_install_command("Maven") def test_installs_maven_from_verified_apache_archive(self): archive_buffer = io.BytesIO() with zipfile.ZipFile(archive_buffer, "w") as archive: archive.writestr("apache-maven-3.10.0/bin/mvn.cmd", "@echo off") archive_bytes = archive_buffer.getvalue() checksum = hashlib.sha512(archive_bytes).hexdigest().encode("ascii") def opener(url, timeout): return io.BytesIO(checksum if url.endswith(".sha512") else archive_bytes) with tempfile.TemporaryDirectory() as tmp: messages = [] executable = install_maven(messages.append, Path(tmp), opener) self.assertTrue(executable.exists()) self.assertEqual(executable.read_text(), "@echo off") self.assertTrue(any("校验通过" in message for message in messages)) def test_rejects_maven_archive_with_wrong_checksum(self): def opener(url, timeout): payload = ("0" * 128).encode("ascii") if url.endswith(".sha512") else b"not-a-zip" return io.BytesIO(payload) with tempfile.TemporaryDirectory() as tmp: with self.assertRaisesRegex(RuntimeError, "SHA-512"): install_maven(lambda _message: None, Path(tmp), opener) self.assertFalse((Path(tmp) / MAVEN_ARCHIVE_NAME.removesuffix("-bin.zip")).exists()) def test_installs_tomcat_from_verified_apache_archive(self): archive_buffer = io.BytesIO() with zipfile.ZipFile(archive_buffer, "w") as archive: archive.writestr(f"apache-tomcat-{TOMCAT_VERSION}/bin/catalina.bat", "@echo off") archive_bytes = archive_buffer.getvalue() checksum = hashlib.sha512(archive_bytes).hexdigest().encode("ascii") def opener(url, timeout): return io.BytesIO(checksum if url.endswith(".sha512") else archive_bytes) with tempfile.TemporaryDirectory() as tmp: executable = install_tomcat(lambda _message: None, Path(tmp), opener) self.assertTrue(executable.exists()) self.assertEqual(executable.name, "catalina.bat") def test_formats_winget_progress_without_garbled_bar(self): raw = "████████████▒▒▒▒▒▒ 63%\r".encode("utf-8") self.assertEqual(format_install_output(raw), ["安装进度: 63%"]) def test_keeps_readable_winget_text(self): raw = "已找到 Eclipse Temurin JDK [EclipseAdoptium.Temurin.8.JDK]\n".encode("utf-8") self.assertEqual(format_install_output(raw), ["已找到 Eclipse Temurin JDK [EclipseAdoptium.Temurin.8.JDK]"]) def test_explains_missing_maven_winget_package(self): message = explain_install_failure( "Maven", 2316632084, ["找不到与输入条件匹配的程序包。"], ) self.assertIn("winget 当前源找不到 Maven 包", message) self.assertIn("手动下载 Apache Maven", message) self.assertIn("mvn.cmd", message) if __name__ == "__main__": unittest.main()