diff --git a/cli/src/test/java/com/devonfw/tools/ide/commandlet/CheckCommandletTest.java b/cli/src/test/java/com/devonfw/tools/ide/commandlet/CheckCommandletTest.java index 798d66223d..ed899db160 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/commandlet/CheckCommandletTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/commandlet/CheckCommandletTest.java @@ -48,7 +48,8 @@ void testCheckMissingGitignoreWithoutFix(@TempDir Path tempDir) throws IOExcepti CheckCommandlet check = new CheckCommandlet(context); assertThrows(CliException.class, check::run); - Path gitignore = tempDir.resolve(".gitignore"); + // findRepositoryRoot resolves symlinks, so /var and /private/var must not be compared as different paths. + Path gitignore = context.getFileAccess().toRealPath(tempDir).resolve(".gitignore"); assertThat(gitignore).doesNotExist(); assertThat(context).log().hasEntries(IdeLogEntry.ofWarning(gitignore + ": No .gitignore found in repository root.")); } diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/CveCheckInstallTest.java b/cli/src/test/java/com/devonfw/tools/ide/tool/CveCheckInstallTest.java index ff92570855..792c74e4a9 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/tool/CveCheckInstallTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/tool/CveCheckInstallTest.java @@ -44,8 +44,8 @@ class CveCheckInstallTest extends AbstractIdeContextTest { /** - * + * Install Intellij with a configured version for which a version above it is the nearest safe upgrade. Ensures the documented "nearest" suggestion (see - * + * {@code documentation/security.adoc}) also offers versions greater than the configured one. + + * Install Intellij with a configured version for which a version above it is the nearest safe upgrade. Ensures the documented "nearest" suggestion (see + * {@code documentation/security.adoc}) also offers versions greater than the configured one. */ @Test void testInstallToolNearestSuggestsMinimalSafeUpgrade() { @@ -58,10 +58,10 @@ void testInstallToolNearestSuggestsMinimalSafeUpgrade() { context.setAnswers("nearest"); //act - commandlet.install(); + ToolInstallation installation = commandlet.install(); //assert - assertThat(context.getSoftwarePath().resolve("intellij").resolve(IdeTestContext.FILE_SOFTWARE_VERSION)).exists().hasContent("2022.3.2"); + assertInstalledVersion(installation, "2022.3.2"); } /** @@ -100,10 +100,10 @@ void testInstallToolCurrent() { context.setAnswers("current"); //act - commandlet.install(); + ToolInstallation installation = commandlet.install(); //assert - assertThat(context.getSoftwarePath().resolve("intellij").resolve(IdeTestContext.FILE_SOFTWARE_VERSION)).exists().hasContent("2023.3.3"); + assertInstalledVersion(installation, "2023.3.3"); assertThat(context.getSoftwarePath().resolve("java").resolve(IdeTestContext.FILE_SOFTWARE_VERSION)).exists().hasContent("17.0.10_7"); } @@ -115,10 +115,10 @@ void testInstallToolNearest() { context.setAnswers("nearest"); //act - commandlet.install(); + ToolInstallation installation = commandlet.install(); //assert - assertThat(context.getSoftwarePath().resolve("intellij").resolve(IdeTestContext.FILE_SOFTWARE_VERSION)).exists().hasContent("2022.3.2"); + assertInstalledVersion(installation, "2022.3.2"); assertThat(context.getSoftwarePath().resolve("java").resolve(IdeTestContext.FILE_SOFTWARE_VERSION)).exists().hasContent("17.0.10_7"); } @@ -133,12 +133,24 @@ void testInstallToolLatest() { context.setAnswers("latest"); //act - commandlet.install(); + ToolInstallation installation = commandlet.install(); //assert - assertThat(context.getSoftwarePath().resolve("intellij").resolve(IdeTestContext.FILE_SOFTWARE_VERSION)).exists().hasContent("2025.1.1.1"); + assertInstalledVersion(installation, "2025.1.1.1"); assertThat(context.getSoftwareRepositoryPath().resolve(ToolRepository.ID_DEFAULT).resolve("java").resolve("java").resolve("21.0.6_7") .resolve(IdeTestContext.FILE_SOFTWARE_VERSION)).exists().hasContent("21.0.6_7"); } + /** + * Asserts {@link IdeTestContext#FILE_SOFTWARE_VERSION} on the installation root. On macOS {@code software/intellij} links into the {@code .app} bundle, and + * the version file is not written there because changing a bundle after codesign breaks the seal. + * + * @param installation the installation returned by {@link Intellij#install()}. + * @param version the expected version file content. + */ + private static void assertInstalledVersion(ToolInstallation installation, String version) { + + assertThat(installation.rootDir().resolve(IdeTestContext.FILE_SOFTWARE_VERSION)).exists().hasContent(version); + } + } diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/repository/ToolRepositoryMock.java b/cli/src/test/java/com/devonfw/tools/ide/tool/repository/ToolRepositoryMock.java index 8933cf8870..6a2de51c3a 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/tool/repository/ToolRepositoryMock.java +++ b/cli/src/test/java/com/devonfw/tools/ide/tool/repository/ToolRepositoryMock.java @@ -17,9 +17,11 @@ import org.slf4j.LoggerFactory; import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.io.TarCompression; import com.devonfw.tools.ide.tool.AbstractToolCommandlet; import com.devonfw.tools.ide.url.model.file.UrlDownloadFile; import com.devonfw.tools.ide.url.model.file.UrlDownloadFileMetadata; +import com.devonfw.tools.ide.util.FilenameUtil; import com.devonfw.tools.ide.version.GenericVersionRange; import com.devonfw.tools.ide.version.VersionIdentifier; import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; @@ -107,18 +109,20 @@ public Path download(String tool, String edition, VersionIdentifier version, Abs UrlDownloadFileMetadata metadata = getMetadata(tool, edition, version, toolCommandlet); String url = metadata.getUrls().iterator().next(); if (url.startsWith(VARIABLE_TESTBASEURL)) { + // FileAccess.compress builds tar and zip only. Fixtures named .dmg or .pkg are served as tgz. + String archiveUrl = toCompressibleArchiveUrl(url); try (ByteArrayOutputStream baos = new ByteArrayOutputStream(1024)) { - this.context.getFileAccess().compress(archiveFolder, baos, url); + this.context.getFileAccess().compress(archiveFolder, baos, archiveUrl); byte[] body = baos.toByteArray(); - String path = url.substring(VARIABLE_TESTBASEURL.length()); + String path = archiveUrl.substring(VARIABLE_TESTBASEURL.length()); stubFor(get(urlMatching(path)).willReturn( aResponse().withStatus(200).withBody(body))); - String resolvedUrl = url.replace(VARIABLE_TESTBASEURL, this.wmRuntimeInfo.getHttpBaseUrl()); + String resolvedUrl = archiveUrl.replace(VARIABLE_TESTBASEURL, this.wmRuntimeInfo.getHttpBaseUrl()); UrlDownloadFile urlDownloadFile = (UrlDownloadFile) metadata; metadata = new UrlDownloadFile(urlDownloadFile.getParent(), urlDownloadFile.getName(), Set.of(resolvedUrl)); return super.download(metadata); } catch (IOException e) { - throw new IllegalStateException("Failed to create mock archive for " + url, e); + throw new IllegalStateException("Failed to create mock archive for " + archiveUrl, e); } } else { throw new IllegalStateException("Invalid URL: " + url); @@ -127,4 +131,20 @@ public Path download(String tool, String edition, VersionIdentifier version, Abs return archiveFolder; } + /** + * Returns a URL that {@code FileAccess.compress} can build. Fixtures for {@code dmg} and {@code pkg} cannot be created by the test infrastructure, so + * their extension is rewritten to {@code tgz}. + * + * @param url the download URL from the test fixture. + * @return {@code url} unchanged, or the same URL with a {@code tgz} extension for {@code dmg} and {@code pkg}. + */ + private static String toCompressibleArchiveUrl(String url) { + + String extension = FilenameUtil.getExtension(url); + if (!"dmg".equals(extension) && !"pkg".equals(extension)) { + return url; + } + return url.substring(0, url.lastIndexOf('.')) + "." + TarCompression.GZ.getCombinedExtension(); + } + }