Injects ProcessRunner to simplify testing, tests conda

This commit is contained in:
Guillaume Tâche
2024-08-27 20:50:10 +02:00
parent bf68d0a206
commit ae76707def
24 changed files with 810 additions and 110 deletions

View File

@@ -1,6 +1,7 @@
package com.github.gtache.autosubtitle.setup.conda;
import com.github.gtache.autosubtitle.impl.OS;
import com.github.gtache.autosubtitle.process.ProcessRunner;
import com.github.gtache.autosubtitle.setup.SetupException;
import com.github.gtache.autosubtitle.setup.SetupStatus;
import com.github.gtache.autosubtitle.setup.impl.AbstractSetupManager;
@@ -31,8 +32,8 @@ public class CondaSetupManager extends AbstractSetupManager {
private final CondaSetupConfiguration configuration;
@Inject
CondaSetupManager(final CondaSetupConfiguration configuration, final HttpClient httpClient) {
super(httpClient);
CondaSetupManager(final CondaSetupConfiguration configuration, final ProcessRunner processRunner, final HttpClient httpClient) {
super(processRunner, httpClient);
this.configuration = requireNonNull(configuration);
}
@@ -71,31 +72,28 @@ public class CondaSetupManager extends AbstractSetupManager {
switch (configuration.os()) {
case OS.WINDOWS -> installWindows();
case OS.MAC, OS.LINUX -> installLinux();
default -> throw new SetupException("Unsupported OS: " + configuration.os());
}
}
private void installLinux() throws SetupException {
try {
final var installerPath = configuration.condaInstallerPath();
final var rootPath = configuration.condaRootPath();
logger.info("Installing conda using {}", installerPath);
final var result = run(List.of("bash", installerPath.toString(), "-b", "-p", rootPath.toString()), Duration.ofMinutes(15));
if (result.exitCode() == 0) {
logger.info("Installed conda to {}", rootPath);
} else {
throw new SetupException("Error installing conda: " + result);
}
} catch (final IOException e) {
throw new SetupException(e);
}
final var installerPath = configuration.condaInstallerPath();
final var rootPath = configuration.condaRootPath();
installArgs(List.of("bash", installerPath.toString(), "-b", "-p", rootPath.toString()));
}
private void installWindows() throws SetupException {
final var installerPath = configuration.condaInstallerPath();
final var rootPath = configuration.condaRootPath();
installArgs(List.of(installerPath.toString(), "/InstallationType=JustMe", "/RegisterPython=0", "/S", "/D=" + rootPath));
}
private void installArgs(final List<String> args) throws SetupException {
try {
final var installerPath = configuration.condaInstallerPath();
final var rootPath = configuration.condaRootPath();
logger.info("Installing conda using {}", installerPath);
final var result = run(List.of(installerPath.toString(), "/InstallationType=JustMe", "/RegisterPython=0", "/S", "/D=" + rootPath.toString()), Duration.ofMinutes(15));
final var result = processRunner().run(args, Duration.ofMinutes(15));
if (result.exitCode() == 0) {
logger.info("Installed conda to {}", rootPath);
} else {
@@ -111,6 +109,7 @@ public class CondaSetupManager extends AbstractSetupManager {
case OS.WINDOWS -> downloadCondaWindows();
case OS.MAC -> downloadCondaMac();
case OS.LINUX -> downloadCondaLinux();
default -> throw new SetupException("Unsupported OS: " + configuration.os());
}
logger.info("Downloaded conda to {}", configuration.condaInstallerPath());
}
@@ -154,7 +153,7 @@ public class CondaSetupManager extends AbstractSetupManager {
@Override
public void update() throws SetupException {
try {
final var result = run(List.of(getCondaPath().toString(), "update", "-y", "conda"), Duration.ofMinutes(15));
final var result = processRunner().run(List.of(getCondaPath().toString(), "update", "-y", "conda"), Duration.ofMinutes(15));
if (result.exitCode() == 0) {
logger.info("Conda updated");
} else {
@@ -169,7 +168,7 @@ public class CondaSetupManager extends AbstractSetupManager {
final var args = Stream.concat(Stream.of(getCondaPath().toString(), "create", "-y", "-p", path.toString(), "python=" + pythonVersion), Arrays.stream(packages)).toList();
try {
logger.info("Creating venv {}", path);
final var result = run(args, Duration.ofMinutes(15));
final var result = processRunner().run(args, Duration.ofMinutes(15));
if (result.exitCode() == 0) {
logger.info("Created venv {}", path);
} else {
@@ -181,6 +180,7 @@ public class CondaSetupManager extends AbstractSetupManager {
try (final var files = Files.find(sourceFolder, 1, (p, a) -> p.getFileName().toString().contains("libcrypto") || p.getFileName().toString().contains("libssl"))) {
final var fileList = files.toList();
final var targetFolder = path.resolve("DLLs");
Files.createDirectories(targetFolder);
for (final var s : fileList) {
Files.copy(s, targetFolder.resolve(s.getFileName()));
}
@@ -202,7 +202,7 @@ public class CondaSetupManager extends AbstractSetupManager {
private boolean isSystemCondaInstalled() throws SetupException {
try {
final var result = run(List.of(configuration.condaSystemPath().toString(), "--version"), Duration.ofSeconds(5));
final var result = processRunner().run(List.of(configuration.condaSystemPath().toString(), "--version"), Duration.ofSeconds(5));
if (result.exitCode() == 0) {
final var output = result.output().getFirst();
final var versionString = output.substring(output.indexOf(' ') + 1);
@@ -212,7 +212,7 @@ public class CondaSetupManager extends AbstractSetupManager {
final var minor = Integer.parseInt(version[1]);
return major >= configuration.condaMinimumMajorVersion() && minor >= configuration.condaMinimumMinorVersion();
} else {
throw new SetupException("Unexpected python version: " + versionString);
throw new SetupException("Unexpected conda version: " + versionString);
}
} else {
return false;

View File

@@ -0,0 +1,71 @@
package com.github.gtache.autosubtitle.modules.setup.conda;
import com.github.gtache.autosubtitle.impl.Architecture;
import com.github.gtache.autosubtitle.impl.OS;
import com.github.gtache.autosubtitle.setup.conda.CondaSetupConfiguration;
import org.junit.jupiter.api.Test;
import java.nio.file.Paths;
import static org.junit.jupiter.api.Assertions.assertEquals;
class TestCondaSetupModule {
@Test
void testCondaSetupConfiguration() {
final var rootPath = Paths.get("root");
final var systemPath = Paths.get("system");
final var bundledPath = Paths.get("bundled");
final var condaMinimumMajorVersion = 24;
final var condaMinimumMinorVersion = 5;
final var condaInstallerPath = Paths.get("installer");
final var os = OS.WINDOWS;
final var architecture = Architecture.X86_64;
final var expected = new CondaSetupConfiguration(rootPath, systemPath, bundledPath, condaMinimumMajorVersion, condaMinimumMinorVersion, condaInstallerPath, os, architecture);
assertEquals(expected, CondaSetupModule.providesCondaSetupConfiguration(systemPath, bundledPath, condaMinimumMajorVersion, condaMinimumMinorVersion, condaInstallerPath, rootPath, os, architecture));
}
@Test
void testProvidesCondaSystemPath() {
assertEquals(Paths.get("conda.bat"), CondaSetupModule.providesCondaSystemPath(OS.WINDOWS));
assertEquals(Paths.get("conda"), CondaSetupModule.providesCondaSystemPath(OS.LINUX));
assertEquals(Paths.get("conda"), CondaSetupModule.providesCondaSystemPath(OS.MAC));
}
@Test
void testCondaBundledPath() {
final var root = Paths.get("root");
final var expectedWindows = root.resolve("condabin").resolve(Paths.get("conda.bat"));
final var expectedOther = root.resolve("condabin").resolve(Paths.get("conda"));
assertEquals(expectedWindows, CondaSetupModule.providesCondaBundledPath(root, OS.WINDOWS));
assertEquals(expectedOther, CondaSetupModule.providesCondaBundledPath(root, OS.MAC));
assertEquals(expectedOther, CondaSetupModule.providesCondaBundledPath(root, OS.LINUX));
}
@Test
void testCondaMinimumMajorVersion() {
assertEquals(24, CondaSetupModule.providesCondaMinimumMajorVersion());
}
@Test
void testCondaMinimumMinorVersion() {
assertEquals(5, CondaSetupModule.providesCondaMinimumMinorVersion());
}
@Test
void testCondaRootPath() {
final var root = Paths.get("root");
final var expected = root.resolve("miniconda3");
assertEquals(expected, CondaSetupModule.providesCondaRootPath(root));
}
@Test
void testCondaInstallerPath() {
final var root = Paths.get("root");
final var expectedWindows = root.resolve("conda-install.exe");
final var expectedOther = root.resolve("conda-install.sh");
assertEquals(expectedWindows, CondaSetupModule.providesCondaInstallerPath(root, OS.WINDOWS));
assertEquals(expectedOther, CondaSetupModule.providesCondaInstallerPath(root, OS.MAC));
assertEquals(expectedOther, CondaSetupModule.providesCondaInstallerPath(root, OS.LINUX));
}
}

View File

@@ -0,0 +1,65 @@
package com.github.gtache.autosubtitle.setup.conda;
import com.github.gtache.autosubtitle.impl.Architecture;
import com.github.gtache.autosubtitle.impl.OS;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.nio.file.Path;
import java.util.Objects;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
@ExtendWith(MockitoExtension.class)
class TestCondaSetupConfiguration {
private final Path condaRootPath;
private final Path condaSystemPath;
private final Path condaBundledPath;
private final int condaMinimumMajorVersion;
private final int condaMinimumMinorVersion;
private final Path condaInstallerPath;
private final OS os;
private final Architecture architecture;
TestCondaSetupConfiguration(@Mock final Path condaRootPath, @Mock final Path condaSystemPath,
@Mock final Path condaBundledPath, @Mock final Path condaInstallerPath,
@Mock final OS os, @Mock final Architecture architecture) {
this.condaRootPath = Objects.requireNonNull(condaRootPath);
this.condaSystemPath = Objects.requireNonNull(condaSystemPath);
this.condaBundledPath = Objects.requireNonNull(condaBundledPath);
this.condaMinimumMajorVersion = 3;
this.condaMinimumMinorVersion = 4;
this.condaInstallerPath = Objects.requireNonNull(condaInstallerPath);
this.os = Objects.requireNonNull(os);
this.architecture = Objects.requireNonNull(architecture);
}
@Test
void testCondaSetupConfiguration() {
final var configuration = new CondaSetupConfiguration(condaRootPath, condaSystemPath, condaBundledPath, condaMinimumMajorVersion, condaMinimumMinorVersion, condaInstallerPath, os, architecture);
assertEquals(condaRootPath, configuration.condaRootPath());
assertEquals(condaSystemPath, configuration.condaSystemPath());
assertEquals(condaBundledPath, configuration.condaBundledPath());
assertEquals(condaMinimumMajorVersion, configuration.condaMinimumMajorVersion());
assertEquals(condaMinimumMinorVersion, configuration.condaMinimumMinorVersion());
assertEquals(condaInstallerPath, configuration.condaInstallerPath());
assertEquals(os, configuration.os());
assertEquals(architecture, configuration.architecture());
}
@Test
void testIllegal() {
assertThrows(NullPointerException.class, () -> new CondaSetupConfiguration(null, condaSystemPath, condaBundledPath, condaMinimumMajorVersion, condaMinimumMinorVersion, condaInstallerPath, os, architecture));
assertThrows(NullPointerException.class, () -> new CondaSetupConfiguration(condaRootPath, null, condaBundledPath, condaMinimumMajorVersion, condaMinimumMinorVersion, condaInstallerPath, os, architecture));
assertThrows(NullPointerException.class, () -> new CondaSetupConfiguration(condaRootPath, condaSystemPath, null, condaMinimumMajorVersion, condaMinimumMinorVersion, condaInstallerPath, os, architecture));
assertThrows(IllegalArgumentException.class, () -> new CondaSetupConfiguration(condaRootPath, condaSystemPath, condaBundledPath, 0, condaMinimumMinorVersion, condaInstallerPath, os, architecture));
assertThrows(IllegalArgumentException.class, () -> new CondaSetupConfiguration(condaRootPath, condaSystemPath, condaBundledPath, condaMinimumMajorVersion, -1, condaInstallerPath, os, architecture));
assertThrows(NullPointerException.class, () -> new CondaSetupConfiguration(condaRootPath, condaSystemPath, condaBundledPath, condaMinimumMajorVersion, condaMinimumMinorVersion, null, os, architecture));
assertThrows(NullPointerException.class, () -> new CondaSetupConfiguration(condaRootPath, condaSystemPath, condaBundledPath, condaMinimumMajorVersion, condaMinimumMinorVersion, condaInstallerPath, null, architecture));
assertThrows(NullPointerException.class, () -> new CondaSetupConfiguration(condaRootPath, condaSystemPath, condaBundledPath, condaMinimumMajorVersion, condaMinimumMinorVersion, condaInstallerPath, os, null));
}
}

View File

@@ -0,0 +1,513 @@
package com.github.gtache.autosubtitle.setup.conda;
import com.github.gtache.autosubtitle.impl.Architecture;
import com.github.gtache.autosubtitle.impl.OS;
import com.github.gtache.autosubtitle.process.ProcessResult;
import com.github.gtache.autosubtitle.process.ProcessRunner;
import com.github.gtache.autosubtitle.setup.SetupException;
import com.github.gtache.autosubtitle.setup.SetupStatus;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.io.TempDir;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.io.IOException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
import java.util.List;
import static java.util.Objects.requireNonNull;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
class TestCondaSetupManager {
private static final String PYTHON_VERSION = "3.3";
private static final String[] PACKAGES = {"p1", "p2"};
private final CondaSetupConfiguration configuration;
private final ProcessRunner processRunner;
private final HttpClient httpClient;
private final CondaSetupManager condaSetupManager;
private final ProcessResult systemProcessResult;
private final Path systemPath;
private final HttpResponse<Path> response;
TestCondaSetupManager(@Mock final CondaSetupConfiguration configuration, @Mock final ProcessRunner processRunner,
@Mock final HttpClient httpClient, @Mock final ProcessResult systemProcessResult, @Mock final HttpResponse<Path> response) throws IOException, InterruptedException {
this.configuration = requireNonNull(configuration);
this.processRunner = requireNonNull(processRunner);
this.httpClient = requireNonNull(httpClient);
this.condaSetupManager = new CondaSetupManager(configuration, processRunner, httpClient);
this.systemProcessResult = requireNonNull(systemProcessResult);
this.systemPath = Paths.get("system");
this.response = requireNonNull(response);
when(response.statusCode()).thenReturn(200);
when(configuration.condaSystemPath()).thenReturn(systemPath);
when(systemProcessResult.output()).thenReturn(List.of("conda 99.99.99"));
when(systemProcessResult.exitCode()).thenReturn(0);
when(processRunner.run(List.of(systemPath.toString(), "--version"), Duration.ofSeconds(5))).thenReturn(systemProcessResult);
when(httpClient.send(any(HttpRequest.class), any(HttpResponse.BodyHandler.class))).thenReturn(response);
}
@Test
void testName() {
assertEquals("conda", condaSetupManager.name());
}
@Test
void testGetStatusIsSystemInstalled() throws SetupException {
assertEquals(SetupStatus.SYSTEM_INSTALLED, condaSetupManager.getStatus());
}
@Test
void testGetStatusIsBundledInstalled(@TempDir final Path tempDir) throws SetupException, IOException {
final var path = tempDir.resolve("conda");
Files.createFile(path);
when(configuration.condaBundledPath()).thenReturn(path);
when(systemProcessResult.exitCode()).thenReturn(1);
assertEquals(SetupStatus.BUNDLE_INSTALLED, condaSetupManager.getStatus());
}
@Test
void testGetStatusNotInstalled() throws SetupException {
final var path = Paths.get("conda");
when(configuration.condaBundledPath()).thenReturn(path);
when(systemProcessResult.exitCode()).thenReturn(1);
assertEquals(SetupStatus.NOT_INSTALLED, condaSetupManager.getStatus());
}
@Test
void testInstallIsInstalledSystem() {
assertDoesNotThrow(condaSetupManager::install);
verifyNoInteractions(httpClient);
}
@Test
void testInstallIsInstalledBundled(@TempDir final Path tempDir) throws IOException {
final var path = tempDir.resolve("conda");
Files.createFile(path);
when(configuration.condaBundledPath()).thenReturn(path);
when(systemProcessResult.exitCode()).thenReturn(1);
assertDoesNotThrow(condaSetupManager::install);
verifyNoInteractions(httpClient);
}
@Test
void testInstallDownloadWindows(@TempDir final Path tempDir) throws IOException, InterruptedException {
final var installerPath = tempDir.resolve("conda");
when(configuration.condaInstallerPath()).thenReturn(installerPath);
when(configuration.condaBundledPath()).thenReturn(tempDir);
when(configuration.os()).thenReturn(OS.WINDOWS);
when(systemProcessResult.exitCode()).thenReturn(1);
when(configuration.condaRootPath()).thenReturn(tempDir);
final var args = List.of(installerPath.toString(), "/InstallationType=JustMe", "/RegisterPython=0", "/S", "/D=" + tempDir);
final var result = mock(ProcessResult.class);
when(result.exitCode()).thenReturn(0);
when(processRunner.run(args, Duration.ofMinutes(15))).thenReturn(result);
assertDoesNotThrow(condaSetupManager::install);
final var requestCapture = ArgumentCaptor.forClass(HttpRequest.class);
verify(httpClient).send(requestCapture.capture(), any(HttpResponse.BodyHandler.class));
final var request = requestCapture.getValue();
assertEquals("https://repo.anaconda.com/miniconda/Miniconda3-latest-Windows-x86_64.exe", request.uri().toString());
verify(processRunner).run(args, Duration.ofMinutes(15));
}
@Test
void testInstallDownloadLinuxAMD64(@TempDir final Path tempDir) throws IOException, InterruptedException {
final var installerPath = tempDir.resolve("conda");
when(configuration.condaInstallerPath()).thenReturn(installerPath);
when(configuration.condaBundledPath()).thenReturn(tempDir);
when(configuration.os()).thenReturn(OS.LINUX);
when(configuration.architecture()).thenReturn(Architecture.AMD64);
when(systemProcessResult.exitCode()).thenReturn(1);
when(configuration.condaRootPath()).thenReturn(tempDir);
final var args = List.of("bash", installerPath.toString(), "-b", "-p", tempDir.toString());
final var result = mock(ProcessResult.class);
when(result.exitCode()).thenReturn(0);
when(processRunner.run(args, Duration.ofMinutes(15))).thenReturn(result);
assertDoesNotThrow(condaSetupManager::install);
final var requestCapture = ArgumentCaptor.forClass(HttpRequest.class);
verify(httpClient).send(requestCapture.capture(), any(HttpResponse.BodyHandler.class));
final var request = requestCapture.getValue();
assertEquals("https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh", request.uri().toString());
verify(processRunner).run(args, Duration.ofMinutes(15));
}
@Test
void testInstallDownloadLinuxARM64(@TempDir final Path tempDir) throws IOException, InterruptedException {
final var installerPath = tempDir.resolve("conda");
when(configuration.condaInstallerPath()).thenReturn(installerPath);
when(configuration.condaBundledPath()).thenReturn(tempDir);
when(configuration.os()).thenReturn(OS.LINUX);
when(configuration.architecture()).thenReturn(Architecture.ARM64);
when(systemProcessResult.exitCode()).thenReturn(1);
when(configuration.condaRootPath()).thenReturn(tempDir);
final var args = List.of("bash", installerPath.toString(), "-b", "-p", tempDir.toString());
final var result = mock(ProcessResult.class);
when(result.exitCode()).thenReturn(0);
when(processRunner.run(args, Duration.ofMinutes(15))).thenReturn(result);
assertDoesNotThrow(condaSetupManager::install);
final var requestCapture = ArgumentCaptor.forClass(HttpRequest.class);
verify(httpClient).send(requestCapture.capture(), any(HttpResponse.BodyHandler.class));
final var request = requestCapture.getValue();
assertEquals("https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-aarch64.sh", request.uri().toString());
verify(processRunner).run(args, Duration.ofMinutes(15));
}
@Test
void testInstallDownloadLinuxUnsupported(@TempDir final Path tempDir) throws IOException {
final var installerPath = tempDir.resolve("conda");
when(configuration.condaInstallerPath()).thenReturn(installerPath);
when(configuration.condaBundledPath()).thenReturn(tempDir);
when(configuration.os()).thenReturn(OS.LINUX);
when(configuration.architecture()).thenReturn(Architecture.ARM32);
when(systemProcessResult.exitCode()).thenReturn(1);
when(configuration.condaRootPath()).thenReturn(tempDir);
assertThrows(SetupException.class, condaSetupManager::install);
verifyNoInteractions(httpClient);
}
@Test
void testInstallDownloadMacAMD64(@TempDir final Path tempDir) throws IOException, InterruptedException {
final var installerPath = tempDir.resolve("conda");
when(configuration.condaInstallerPath()).thenReturn(installerPath);
when(configuration.condaBundledPath()).thenReturn(tempDir);
when(configuration.os()).thenReturn(OS.MAC);
when(configuration.architecture()).thenReturn(Architecture.AMD64);
when(systemProcessResult.exitCode()).thenReturn(1);
when(configuration.condaRootPath()).thenReturn(tempDir);
final var args = List.of("bash", installerPath.toString(), "-b", "-p", tempDir.toString());
final var result = mock(ProcessResult.class);
when(result.exitCode()).thenReturn(0);
when(processRunner.run(args, Duration.ofMinutes(15))).thenReturn(result);
assertDoesNotThrow(condaSetupManager::install);
final var requestCapture = ArgumentCaptor.forClass(HttpRequest.class);
verify(httpClient).send(requestCapture.capture(), any(HttpResponse.BodyHandler.class));
final var request = requestCapture.getValue();
assertEquals("https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-x86_64.sh", request.uri().toString());
verify(processRunner).run(args, Duration.ofMinutes(15));
}
@Test
void testInstallDownloadMacARM64(@TempDir final Path tempDir) throws IOException, InterruptedException {
final var installerPath = tempDir.resolve("conda");
when(configuration.condaInstallerPath()).thenReturn(installerPath);
when(configuration.condaBundledPath()).thenReturn(tempDir);
when(configuration.os()).thenReturn(OS.MAC);
when(configuration.architecture()).thenReturn(Architecture.ARM64);
when(systemProcessResult.exitCode()).thenReturn(1);
when(configuration.condaRootPath()).thenReturn(tempDir);
final var args = List.of("bash", installerPath.toString(), "-b", "-p", tempDir.toString());
final var result = mock(ProcessResult.class);
when(result.exitCode()).thenReturn(0);
when(processRunner.run(args, Duration.ofMinutes(15))).thenReturn(result);
assertDoesNotThrow(condaSetupManager::install);
final var requestCapture = ArgumentCaptor.forClass(HttpRequest.class);
verify(httpClient).send(requestCapture.capture(), any(HttpResponse.BodyHandler.class));
final var request = requestCapture.getValue();
assertEquals("https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-arm64.sh", request.uri().toString());
verify(processRunner).run(args, Duration.ofMinutes(15));
}
@Test
void testInstallDownloadMacUnsupported(@TempDir final Path tempDir) throws IOException {
final var installerPath = tempDir.resolve("conda");
when(configuration.condaInstallerPath()).thenReturn(installerPath);
when(configuration.condaBundledPath()).thenReturn(tempDir);
when(configuration.os()).thenReturn(OS.MAC);
when(configuration.architecture()).thenReturn(Architecture.ARM32);
when(systemProcessResult.exitCode()).thenReturn(1);
when(configuration.condaRootPath()).thenReturn(tempDir);
assertThrows(SetupException.class, condaSetupManager::install);
verifyNoInteractions(httpClient);
}
@Test
void testInstallDownloadUnsupported(@TempDir final Path tempDir) throws IOException {
final var installerPath = tempDir.resolve("conda");
when(configuration.condaInstallerPath()).thenReturn(installerPath);
when(configuration.condaBundledPath()).thenReturn(tempDir);
when(configuration.os()).thenReturn(OS.UNKNOWN);
when(systemProcessResult.exitCode()).thenReturn(1);
when(configuration.condaRootPath()).thenReturn(tempDir);
assertThrows(SetupException.class, condaSetupManager::install);
verifyNoInteractions(httpClient);
}
@Test
void testInstallInstallerWindows(@TempDir final Path tempDir) throws IOException {
final var installerPath = tempDir.resolve("conda");
Files.createFile(installerPath);
when(configuration.condaInstallerPath()).thenReturn(installerPath);
when(configuration.condaBundledPath()).thenReturn(tempDir);
when(configuration.os()).thenReturn(OS.WINDOWS);
when(systemProcessResult.exitCode()).thenReturn(1);
when(configuration.condaRootPath()).thenReturn(tempDir);
final var args = List.of(installerPath.toString(), "/InstallationType=JustMe", "/RegisterPython=0", "/S", "/D=" + tempDir.toString());
final var result = mock(ProcessResult.class);
when(result.exitCode()).thenReturn(0);
when(processRunner.run(args, Duration.ofMinutes(15))).thenReturn(result);
assertDoesNotThrow(condaSetupManager::install);
verify(processRunner).run(args, Duration.ofMinutes(15));
verifyNoInteractions(httpClient);
}
@Test
void testInstallInstallerLinux(@TempDir final Path tempDir) throws IOException {
final var installerPath = tempDir.resolve("conda");
Files.createFile(installerPath);
when(configuration.condaInstallerPath()).thenReturn(installerPath);
when(configuration.condaBundledPath()).thenReturn(tempDir);
when(configuration.os()).thenReturn(OS.LINUX);
when(systemProcessResult.exitCode()).thenReturn(1);
when(configuration.condaRootPath()).thenReturn(tempDir);
final var args = List.of("bash", installerPath.toString(), "-b", "-p", tempDir.toString());
final var result = mock(ProcessResult.class);
when(result.exitCode()).thenReturn(0);
when(processRunner.run(args, Duration.ofMinutes(15))).thenReturn(result);
assertDoesNotThrow(condaSetupManager::install);
verify(processRunner).run(args, Duration.ofMinutes(15));
verifyNoInteractions(httpClient);
}
@Test
void testInstallInstallerLinuxIOException(@TempDir final Path tempDir) throws IOException {
final var installerPath = tempDir.resolve("conda");
Files.createFile(installerPath);
when(configuration.condaInstallerPath()).thenReturn(installerPath);
when(configuration.condaBundledPath()).thenReturn(tempDir);
when(configuration.os()).thenReturn(OS.LINUX);
when(systemProcessResult.exitCode()).thenReturn(1);
when(configuration.condaRootPath()).thenReturn(tempDir);
final var args = List.of("bash", installerPath.toString(), "-b", "-p", tempDir.toString());
when(processRunner.run(args, Duration.ofMinutes(15))).thenThrow(IOException.class);
assertThrows(SetupException.class, condaSetupManager::install);
verify(processRunner).run(args, Duration.ofMinutes(15));
verifyNoInteractions(httpClient);
}
@Test
void testInstallInstallerLinuxBadExitCode(@TempDir final Path tempDir) throws IOException {
final var installerPath = tempDir.resolve("conda");
Files.createFile(installerPath);
when(configuration.condaInstallerPath()).thenReturn(installerPath);
when(configuration.condaBundledPath()).thenReturn(tempDir);
when(configuration.os()).thenReturn(OS.LINUX);
when(systemProcessResult.exitCode()).thenReturn(1);
when(configuration.condaRootPath()).thenReturn(tempDir);
final var args = List.of("bash", installerPath.toString(), "-b", "-p", tempDir.toString());
final var result = mock(ProcessResult.class);
when(result.exitCode()).thenReturn(1);
when(processRunner.run(args, Duration.ofMinutes(15))).thenReturn(result);
assertThrows(SetupException.class, condaSetupManager::install);
verify(processRunner).run(args, Duration.ofMinutes(15));
verifyNoInteractions(httpClient);
}
@Test
void testInstallInstallerUnknown(@TempDir final Path tempDir) throws IOException {
final var installerPath = tempDir.resolve("conda");
Files.createFile(installerPath);
when(configuration.condaInstallerPath()).thenReturn(installerPath);
when(configuration.condaBundledPath()).thenReturn(tempDir);
when(configuration.os()).thenReturn(OS.UNKNOWN);
when(systemProcessResult.exitCode()).thenReturn(1);
assertThrows(SetupException.class, condaSetupManager::install);
verifyNoInteractions(httpClient);
}
@Test
void testUninstall(@TempDir final Path tempDir) throws IOException {
when(configuration.condaRootPath()).thenReturn(tempDir);
Files.createDirectories(tempDir.resolve("sub"));
Files.createFile(tempDir.resolve("sub").resolve("conda"));
Files.createFile(tempDir.resolve("python"));
assertDoesNotThrow(condaSetupManager::uninstall);
assertFalse(Files.isDirectory(tempDir));
}
@Test
void testUpdateBundled() throws IOException {
final var path = Path.of("test");
final var args = List.of(path.toString(), "update", "-y", "conda");
final var duration = Duration.ofMinutes(15);
when(configuration.condaBundledPath()).thenReturn(path);
when(systemProcessResult.exitCode()).thenReturn(1);
final var processResult = mock(ProcessResult.class);
when(processResult.exitCode()).thenReturn(0);
when(processRunner.run(args, duration)).thenReturn(processResult);
assertDoesNotThrow(condaSetupManager::update);
verify(processRunner).run(args, duration);
}
@Test
void testUpdateSystemInstalled() throws IOException {
final var args = List.of(systemPath.toString(), "update", "-y", "conda");
final var duration = Duration.ofMinutes(15);
final var processResult = mock(ProcessResult.class);
when(processResult.exitCode()).thenReturn(0);
when(processRunner.run(args, duration)).thenReturn(processResult);
assertDoesNotThrow(condaSetupManager::update);
verify(processRunner).run(args, duration);
verify(processRunner).run(List.of(systemPath.toString(), "--version"), Duration.ofSeconds(5));
}
@Test
void testUpdateSystemIOException() throws IOException {
when(processRunner.run(List.of(systemPath.toString(), "--version"), Duration.ofSeconds(5))).thenThrow(IOException.class);
assertThrows(SetupException.class, condaSetupManager::update);
}
@Test
void testUpdateSystemBadVersion() {
final var path = Path.of("test");
when(systemProcessResult.output()).thenReturn(List.of("conda 9"));
when(configuration.condaBundledPath()).thenReturn(path);
when(configuration.condaSystemPath()).thenReturn(systemPath);
assertThrows(SetupException.class, condaSetupManager::update);
}
@Test
void testUpdateBundleBadResultCode() throws IOException {
final var path = Path.of("test");
final var args = List.of(path.toString(), "update", "-y", "conda");
final var duration = Duration.ofMinutes(15);
when(systemProcessResult.exitCode()).thenReturn(1);
when(configuration.condaBundledPath()).thenReturn(path);
when(processRunner.run(args, duration)).thenReturn(systemProcessResult);
when(systemProcessResult.exitCode()).thenReturn(1);
assertThrows(SetupException.class, condaSetupManager::update);
verify(processRunner).run(args, duration);
}
@Test
void testUpdateBundleIOException() throws IOException {
final var path = Path.of("test");
final var args = List.of(path.toString(), "update", "-y", "conda");
final var duration = Duration.ofMinutes(15);
when(systemProcessResult.exitCode()).thenReturn(1);
when(configuration.condaBundledPath()).thenReturn(path);
when(processRunner.run(args, duration)).thenThrow(IOException.class);
assertThrows(SetupException.class, condaSetupManager::update);
verify(processRunner).run(args, duration);
}
@Test
void testCreateVenv() throws IOException {
final var path = Paths.get("test");
final var args = List.of(systemPath.toString(), "create", "-y", "-p", path.toString(), "python=" + PYTHON_VERSION, "p1", "p2");
final var result = mock(ProcessResult.class);
when(result.exitCode()).thenReturn(0);
when(configuration.os()).thenReturn(OS.LINUX);
when(processRunner.run(args, Duration.ofMinutes(15))).thenReturn(result);
assertDoesNotThrow(() -> condaSetupManager.createVenv(path, PYTHON_VERSION, PACKAGES));
}
@Test
void testCreateVenvWindows(@TempDir final Path tempDir) throws IOException {
final var path = tempDir.resolve("test");
final var bin = path.resolve("Library").resolve("bin");
Files.createDirectories(bin);
final var crypto1 = bin.resolve("libcrypto-1.1.dll");
final var crypto2 = bin.resolve("libcrypto-2.sdf");
final var ssl1 = bin.resolve("libssl-1.1.dll");
final var ssl2 = bin.resolve("libssl-2.sdf");
final var other = bin.resolve("other.dll");
final var dlls = path.resolve("DLLs");
for (final var path1 : List.of(crypto1, crypto2, ssl1, ssl2, other)) {
Files.createFile(path1);
}
final var args = List.of(systemPath.toString(), "create", "-y", "-p", path.toString(), "python=" + PYTHON_VERSION, "p1", "p2");
final var result = mock(ProcessResult.class);
when(result.exitCode()).thenReturn(0);
when(configuration.os()).thenReturn(OS.WINDOWS);
when(processRunner.run(args, Duration.ofMinutes(15))).thenReturn(result);
assertDoesNotThrow(() -> condaSetupManager.createVenv(path, PYTHON_VERSION, PACKAGES));
for (final var path1 : List.of(crypto1, crypto2, ssl1, ssl2)) {
assertTrue(Files.exists(dlls.resolve(path1.getFileName())));
}
assertFalse(Files.exists(dlls.resolve(other.getFileName())));
}
@Test
void testCreateVenvIOException() throws IOException {
final var path = Paths.get("test");
final var args = List.of(systemPath.toString(), "create", "-y", "-p", path.toString(), "python=" + PYTHON_VERSION, "p1", "p2");
when(processRunner.run(args, Duration.ofMinutes(15))).thenThrow(IOException.class);
assertThrows(SetupException.class, () -> condaSetupManager.createVenv(path, PYTHON_VERSION, PACKAGES));
}
@Test
void testCreateVenvBadResultCode() throws IOException {
final var path = Paths.get("test");
final var args = List.of(systemPath.toString(), "create", "-y", "-p", path.toString(), "python=" + PYTHON_VERSION, "p1", "p2");
final var result = mock(ProcessResult.class);
when(result.exitCode()).thenReturn(1);
when(processRunner.run(args, Duration.ofMinutes(15))).thenReturn(result);
assertThrows(SetupException.class, () -> condaSetupManager.createVenv(path, PYTHON_VERSION, PACKAGES));
}
@Test
void testVenvExists(@TempDir final Path tempDirectory) throws IOException {
assertFalse(condaSetupManager.venvExists(tempDirectory));
Files.createDirectories(tempDirectory.resolve("bin"));
when(configuration.os()).thenReturn(OS.WINDOWS);
Files.createFile(tempDirectory.resolve("bin").resolve("python.exe"));
assertTrue(condaSetupManager.venvExists(tempDirectory));
when(configuration.os()).thenReturn(OS.LINUX);
assertFalse(condaSetupManager.venvExists(tempDirectory));
Files.createFile(tempDirectory.resolve("bin").resolve("python"));
assertTrue(condaSetupManager.venvExists(tempDirectory));
when(configuration.os()).thenReturn(OS.MAC);
assertTrue(condaSetupManager.venvExists(tempDirectory));
}
@Test
void testIllegal() {
assertThrows(NullPointerException.class, () -> new CondaSetupManager(null, processRunner, httpClient));
assertThrows(NullPointerException.class, () -> new CondaSetupManager(configuration, null, httpClient));
assertThrows(NullPointerException.class, () -> new CondaSetupManager(configuration, processRunner, null));
}
}