package org.graalvm.component.installer.commands;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.graalvm.component.installer.CommandInput;
import org.graalvm.component.installer.remote.CatalogIterable;
import org.graalvm.component.installer.CommandTestBase;
import org.graalvm.component.installer.Commands;
import org.graalvm.component.installer.CommonConstants;
import org.graalvm.component.installer.ComponentCatalog;
import org.graalvm.component.installer.ComponentParam;
import org.graalvm.component.installer.DependencyException;
import org.graalvm.component.installer.FailedOperationException;
import org.graalvm.component.installer.FileIterable;
import org.graalvm.component.installer.IncompatibleException;
import org.graalvm.component.installer.SoftwareChannelSource;
import org.graalvm.component.installer.model.CatalogContents;
import org.graalvm.component.installer.model.ComponentInfo;
import org.graalvm.component.installer.model.ComponentRegistry;
import org.graalvm.component.installer.model.GraalEdition;
import org.graalvm.component.installer.persist.ProxyResource;
import org.graalvm.component.installer.remote.RemoteCatalogDownloader;
import org.graalvm.component.installer.persist.test.Handler;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TestName;
public class CatalogInstallTest extends CommandTestBase {
private static final String TEST_CATALOG_URL = "test://release/catalog.properties";
@Rule public TestName name = new TestName();
@Rule public ExpectedException exception = ExpectedException.none();
@Rule public ProxyResource proxyResource = new ProxyResource();
protected InstallCommand inst;
private RemoteCatalogDownloader downloader;
private void setupVersion(String v) {
String version = v == null ? "0.33" : v;
storage.graalInfo.put(CommonConstants.CAP_GRAALVM_VERSION, version);
}
private void setupCatalog(String rel) throws Exception {
String relSpec;
if (rel == null) {
relSpec = "catalog-" + name.getMethodName() + ".properties";
if (getClass().getResource(relSpec) == null) {
if (name.getMethodName().contains("Deps")) {
relSpec = "cataloginstallDeps.properties";
} else {
relSpec = "catalogInstallTest.properties";
}
}
} else {
relSpec = rel;
}
URL u = getClass().getResource(relSpec);
if (u == null) {
u = getClass().getResource("catalogInstallTest.properties");
}
Handler.bind(TEST_CATALOG_URL, u);
downloader = new RemoteCatalogDownloader(this, this, new URL(TEST_CATALOG_URL));
this.registry = new CatalogContents(this, downloader.getStorage(), getLocalRegistry());
}
private void setupCatalog2(String rel) throws IOException {
Path p = dataFile(rel);
URL u = p.toUri().toURL();
downloader = new RemoteCatalogDownloader(this, this, u);
this.registry = new CatalogContents(this, downloader.getStorage(), getLocalRegistry());
}
@Test
public void testRejectMismatchingCatalog() throws Exception {
setupVersion("1.0.0-rc1");
URL rubyURL = new URL("test://release/graalvm-ruby.zip");
Handler.bind(rubyURL.toString(), new URLConnection(rubyURL) {
@Override
public void connect() throws IOException {
throw new UnsupportedOperationException("Should not be touched");
}
});
exception.expect(IncompatibleException.class);
exception.expectMessage("REMOTE_UnsupportedGraalVersion");
setupCatalog(null);
textParams.add("ruby");
paramIterable = new CatalogIterable(this, this);
paramIterable.iterator().next();
}
@Test
public void testRejectMetaDontDownloadPackage() throws Exception {
setupVersion("0.33-dev");
URL rubyURL = new URL("test://release/graalvm-ruby.zip");
Handler.bind(rubyURL.toString(), new URLConnection(rubyURL) {
@Override
public void connect() throws IOException {
throw new UnsupportedOperationException(
"Should not be touched");
}
});
exception.expect(DependencyException.Mismatch.class);
exception.expectMessage("VERIFY_ObsoleteGraalVM");
setupCatalog(null);
paramIterable = new CatalogIterable(this, this);
textParams.add("ruby");
InstallCommand cmd = new InstallCommand();
cmd.init(this,
withBundle(InstallCommand.class));
cmd.execute();
}
@Test
public void testCheckPostinstMessageLoaded() throws Exception {
setupVersion("0.33");
URL x = getClass().getResource("postinst2.jar");
URL rubyURL = new URL("test://release/postinst2.jar");
Handler.bind(rubyURL.toString(), x);
setupCatalog(null);
paramIterable = new CatalogIterable(this, this);
textParams.add("ruby");
InstallCommand cmd = new InstallCommand();
cmd.init(this, withBundle(InstallCommand.class));
cmd.prepareInstallation();
cmd.completeInstallers();
assertFalse(cmd.realInstallers.isEmpty());
for (Installer i : cmd.realInstallers.values()) {
assertNotNull(i.getComponentInfo().getPostinstMessage());
}
}
@Test
public void testPostinstMessagePrinted() throws Exception {
setupVersion("0.33");
URL x = getClass().getResource("postinst2.jar");
URL rubyURL = new URL("test://release/postinst2.jar");
Handler.bind(rubyURL.toString(), x);
setupCatalog(null);
paramIterable = new CatalogIterable(this, this);
textParams.add("ruby");
InstallCommand cmd = new InstallCommand();
cmd.init(this, withBundle(InstallCommand.class));
String[] formatted = new String[1];
delegateFeedback(new FeedbackAdapter() {
@Override
public boolean verbatimOut(String aMsg, boolean beVerbose) {
if (aMsg.contains("Ruby openssl")) {
formatted[0] = aMsg;
}
return super.verbatimOut(aMsg, beVerbose);
}
});
cmd.execute();
assertNotNull(formatted[0]);
}
@Test
public void testInstallWithDepsSingleLevel() throws Exception {
setupVersion("19.3-dev");
setupCatalog(null);
paramIterable = new CatalogIterable(this, this);
textParams.add("r");
InstallCommand cmd = new InstallCommand();
cmd.init(this, withBundle(InstallCommand.class));
cmd.executionInit();
cmd.executeStep(cmd::prepareInstallation, false);
List<ComponentParam> deps = cmd.getDependencies();
assertEquals(1, deps.size());
assertEquals("org.graalvm.llvm-toolchain", deps.get(0).createMetaLoader().getComponentInfo().getId());
}
@Test
public void testInstallWithIgnoredDeps() throws Exception {
setupVersion("19.3-dev");
setupCatalog(null);
paramIterable = new CatalogIterable(this, this);
textParams.add("r");
options.put(Commands.OPTION_NO_DEPENDENCIES, "");
InstallCommand cmd = new InstallCommand();
cmd.init(this, withBundle(InstallCommand.class));
cmd.executionInit();
cmd.executeStep(cmd::prepareInstallation, false);
List<ComponentParam> deps = cmd.getDependencies();
assertTrue(deps.isEmpty());
}
@Test
public void testInstallWithBrokenDeps() throws Exception {
setupVersion("19.3-dev");
setupCatalog(null);
paramIterable = new CatalogIterable(this, this);
textParams.add("additional");
InstallCommand cmd = new InstallCommand();
cmd.init(this, withBundle(InstallCommand.class));
cmd.executionInit();
exception.expect(FailedOperationException.class);
exception.expectMessage("INSTALL_UnresolvedDependencies");
try {
cmd.executeStep(cmd::prepareInstallation, false);
} catch (FailedOperationException ex) {
Set<String> u = cmd.getUnresolvedDependencies();
assertFalse(u.isEmpty());
assertEquals("org.graalvm.unknown", u.iterator().next());
throw ex;
}
}
@Test
public void testInstallWithBrokenIgnoredDeps() throws Exception {
setupVersion("19.3-dev");
setupCatalog(null);
paramIterable = new CatalogIterable(this, this);
textParams.add("additional");
options.put(Commands.OPTION_NO_DEPENDENCIES, "");
InstallCommand cmd = new InstallCommand();
cmd.init(this, withBundle(InstallCommand.class));
cmd.executionInit();
cmd.executeStep(cmd::prepareInstallation, false);
}
@Test
public void testInstallDepsWithDependecnyInstalled() throws Exception {
setupVersion("19.3-dev");
setupCatalog(null);
testInstallDepsWithDependecnyInstalledCommon();
}
private void testInstallDepsWithDependecnyInstalledCommon() throws Exception {
ComponentInfo fakeInfo = new ComponentInfo("org.graalvm.llvm-toolchain", "Fake Toolchain", "19.3-dev");
fakeInfo.setInfoPath("");
storage.installed.add(fakeInfo);
paramIterable = new CatalogIterable(this, this);
textParams.add("r");
InstallCommand cmd = new InstallCommand();
cmd.init(this, withBundle(InstallCommand.class));
cmd.executionInit();
cmd.executeStep(cmd::prepareInstallation, false);
assertTrue(cmd.getDependencies().isEmpty());
}
@Test
public void testInstallDepsOnCommandLine() throws Exception {
setupVersion("19.3-dev");
setupCatalog2("cataloginstallDeps.properties");
testInstallDepsOnCommandLineCommon();
}
private void testInstallDepsOnCommandLineCommon() throws Exception {
paramIterable = new CatalogIterable(this, this);
textParams.add("r");
textParams.add("llvm-toolchain");
InstallCommand cmd = new InstallCommand();
cmd.init(this, withBundle(InstallCommand.class));
cmd.executionInit();
cmd.executeStep(cmd::prepareInstallation, false);
cmd.executeStep(cmd::completeInstallers, false);
List<Installer> instSequence = cmd.getInstallers();
assertEquals(2, instSequence.size());
ComponentInfo ci = instSequence.get(0).getComponentInfo();
assertEquals("org.graalvm.llvm-toolchain", ci.getId());
ci = instSequence.get(1).getComponentInfo();
assertEquals("org.graalvm.r", ci.getId());
}
@Test
public void testInstallDepsOnCommandLine2() throws Exception {
setupVersion("19.3-dev");
setupCatalog2("cataloginstallDeps2.properties");
testInstallDepsOnCommandLineCommon();
}
@Test
public void testDepsBeforeUsage() throws Exception {
setupVersion("19.3-dev");
setupCatalog2("cataloginstallDeps.properties");
testDepsBeforeUsageCommon();
}
@Test
public void testDepsBeforeUsage2() throws Exception {
setupVersion("19.3-dev");
setupCatalog2("cataloginstallDeps2.properties");
testDepsBeforeUsageCommon();
}
private void testDepsBeforeUsageCommon() throws Exception {
paramIterable = new CatalogIterable(this, this);
textParams.add("ruby");
InstallCommand cmd = new InstallCommand();
cmd.init(this, withBundle(InstallCommand.class));
cmd.executionInit();
cmd.executeStep(cmd::prepareInstallation, false);
cmd.executeStep(cmd::completeInstallers, false);
List<Installer> instSequence = cmd.getInstallers();
assertEquals(3, instSequence.size());
ComponentInfo ci = instSequence.get(0).getComponentInfo();
assertEquals("org.graalvm.llvm-toolchain", ci.getId());
ci = instSequence.get(1).getComponentInfo();
assertEquals("org.graalvm.native-image", ci.getId());
ci = instSequence.get(2).getComponentInfo();
assertEquals("org.graalvm.ruby", ci.getId());
}
@Test
public void testTwoSameComponentsCommandLineDeps() throws Exception {
setupVersion("19.3-dev");
setupCatalog2("cataloginstallDeps.properties");
testTwoSameComponentsCommandLineDepsCommon();
}
@Test
public void testTwoSameComponentsCommandLineDeps2() throws Exception {
setupVersion("19.3-dev");
setupCatalog2("cataloginstallDeps2.properties");
testTwoSameComponentsCommandLineDepsCommon();
}
private void testTwoSameComponentsCommandLineDepsCommon() throws Exception {
paramIterable = new CatalogIterable(this, this);
textParams.add("r");
textParams.add("r");
InstallCommand cmd = new InstallCommand();
cmd.init(this, withBundle(InstallCommand.class));
cmd.executionInit();
cmd.executeStep(cmd::prepareInstallation, false);
cmd.executeStep(cmd::completeInstallers, false);
List<Installer> instSequence = cmd.getInstallers();
assertEquals(2, instSequence.size());
ComponentInfo ci = instSequence.get(0).getComponentInfo();
assertEquals("org.graalvm.llvm-toolchain", ci.getId());
ci = instSequence.get(1).getComponentInfo();
assertEquals("org.graalvm.r", ci.getId());
}
CatalogFactory catalogFactory = null;
@Override
public CatalogFactory getCatalogFactory() {
if (catalogFactory == null) {
return super.getCatalogFactory();
} else {
return catalogFactory;
}
}
@Test
public void testInstallDependencyFromSameDirectory() throws Exception {
Path ruby193Source = dataFile("../repo/19.3.0.0/r");
Path llvm193Source = dataFile("../repo/19.3.0.0/llvm-toolchain");
assertEquals(ruby193Source.getParent(), llvm193Source.getParent());
files.add(ruby193Source.toFile());
setupVersion("19.3.0.0");
downloader = new RemoteCatalogDownloader(this, this, (URL) null);
downloader.addLocalChannelSource(
new SoftwareChannelSource(ruby193Source.getParent().toFile().toURI().toString()));
catalogFactory = new CatalogFactory() {
@Override
public ComponentCatalog createComponentCatalog(CommandInput input) {
return new CatalogContents(CatalogInstallTest.this, downloader.getStorage(), input.getLocalRegistry());
}
@Override
public List<GraalEdition> listEditions(ComponentRegistry targetGraalVM) {
return Collections.emptyList();
}
};
FileIterable fit = new FileIterable(this, this);
fit.setCatalogFactory(catalogFactory);
paramIterable = fit;
InstallCommand cmd = new InstallCommand();
cmd.init(this, withBundle(InstallCommand.class));
cmd.executionInit();
cmd.executeStep(cmd::prepareInstallation, false);
assertFalse(cmd.getDependencies().isEmpty());
}
@Test
public void testInstallCorrectJavaVersion8() throws Exception {
storage.graalInfo.put(CommonConstants.CAP_JAVA_VERSION, "8");
setupVersion("1.0.0.0");
setupCatalog("catalogMultiFlavours.properties");
paramIterable = new CatalogIterable(this, this);
textParams.add("ruby");
InstallCommand cmd = new InstallCommand();
cmd.init(this, withBundle(InstallCommand.class));
cmd.executionInit();
cmd.executeStep(cmd::prepareInstallation, false);
List<Installer> installers = cmd.getInstallers();
assertEquals(1, installers.size());
}
@Test
public void testInstallCorrectJavaVersion11() throws Exception {
storage.graalInfo.put(CommonConstants.CAP_JAVA_VERSION, "11");
setupVersion("1.0.0.0");
setupCatalog("catalogMultiFlavours.properties");
paramIterable = new CatalogIterable(this, this);
textParams.add("ruby");
InstallCommand cmd = new InstallCommand();
cmd.init(this, withBundle(InstallCommand.class));
cmd.executionInit();
cmd.executeStep(cmd::prepareInstallation, false);
List<Installer> installers = cmd.getInstallers();
assertEquals(1, installers.size());
}
}