package org.graalvm.component.installer.remote;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import org.graalvm.component.installer.BundleConstants;
import org.graalvm.component.installer.CommonConstants;
import org.graalvm.component.installer.MetadataException;
import org.graalvm.component.installer.SystemUtils;
import org.graalvm.component.installer.TestBase;
import org.graalvm.component.installer.Version;
import org.graalvm.component.installer.commands.MockStorage;
import org.graalvm.component.installer.model.ComponentInfo;
import org.graalvm.component.installer.model.ComponentRegistry;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
public class RemoteStorageTest extends TestBase {
private static final String TEST_GRAAL_FLAVOUR = "linux_amd64";
private static final String TEST_BASE_URL_DIR = "https://graalvm.io/";
private static final String TEST_BASE_URL = TEST_BASE_URL_DIR + "download/catalog";
private RemotePropertiesStorage remStorage;
private MockStorage storage;
private ComponentRegistry localRegistry;
private Properties catalogProps = new Properties();
private String graalVersion = "0.33-dev";
private String graalSelector = TEST_GRAAL_FLAVOUR;
@Rule public ExpectedException exception = ExpectedException.none();
@Before
public void setUp() throws Exception {
storage = new MockStorage();
remStorage = new RemotePropertiesStorage(this, localRegistry, catalogProps, graalSelector,
Version.fromString(graalVersion), new URL(TEST_BASE_URL));
try (InputStream is = getClass().getResourceAsStream("catalog.properties")) {
catalogProps.load(is);
}
}
private void loadCatalog(String s) throws IOException {
catalogProps.clear();
localRegistry = new ComponentRegistry(this, storage);
try (InputStream is = getClass().getResourceAsStream(s)) {
catalogProps.load(is);
}
}
private void forceLoadCatalog(String s) throws IOException {
loadCatalog(s);
remStorage = new RemotePropertiesStorage(this, localRegistry, catalogProps, graalSelector,
Version.fromString(graalVersion), new URL(TEST_BASE_URL));
}
@Test
public void testListIDs() throws Exception {
Set<String> ids = remStorage.listComponentIDs();
List<String> l = new ArrayList<>(ids);
Collections.sort(l);
assertEquals(Arrays.asList("r", "ruby"), l);
}
private ComponentInfo loadLastComponent(String id) throws IOException {
Set<ComponentInfo> infos = remStorage.loadComponentMetadata(id);
if (infos == null || infos.isEmpty()) {
return null;
}
List<ComponentInfo> sorted = new ArrayList<>(infos);
Collections.sort(sorted, ComponentInfo.versionComparator());
return sorted.get(sorted.size() - 1);
}
@Test
public void testLoadMetadata() throws Exception {
ComponentInfo rInfo = loadLastComponent("r");
assertEquals("FastR 0.33-dev", rInfo.getName());
assertEquals("R", rInfo.getId());
}
@Test
public void testRelativeRemoteURL() throws Exception {
ComponentInfo rInfo = loadLastComponent("r");
assertEquals(new URL(TEST_BASE_URL_DIR + "0.33-dev/graalvm-fastr.zip"), rInfo.getRemoteURL());
}
@Test
public void testInvalidRemoteURL() throws Exception {
loadCatalog("catalog.bad1.properties");
ComponentInfo rInfo = loadLastComponent("ruby");
assertEquals("ruby", rInfo.getId());
exception.expect(MalformedURLException.class);
rInfo = loadLastComponent("r");
}
@Test
public void testLoadMetadataMalformed() throws Exception {
loadCatalog("catalog.bad2.properties");
ComponentInfo rInfo = loadLastComponent("r");
assertEquals("R", rInfo.getId());
exception.expect(MetadataException.class);
exception.expectMessage("ERROR_InvalidVersion");
rInfo = loadLastComponent("ruby");
}
static byte[] truffleruby2Hash = {
(byte) 0xae,
(byte) 0xd6,
0x7c,
0x4d,
0x3c,
0x04,
0x01,
0x15,
0x13,
(byte) 0xf8,
(byte) 0x94,
0x0b,
(byte) 0xf6,
(byte) 0xe6,
(byte) 0xea,
0x22,
0x5d,
0x34,
0x5c,
0x27,
(byte) 0xa1,
(byte) 0xa3,
(byte) 0xcd,
(byte) 0xe4,
(byte) 0xdd,
0x0c,
0x46,
0x36,
0x45,
0x3f,
0x42,
(byte) 0xba
};
static String truffleruby2HashString = "aed67c4d3c04011513f8940bf6e6ea225d345c27a1a3cde4dd0c4636453f42ba";
static String truffleruby2HashString2 = "ae:d6:7c:4d:3c:04:01:15:13:f8:94:0b:f6:e6:ea:22:5d:34:5c:27:a1:a3:cd:e4:dd:0c:46:36:45:3f:42:ba";
@Test
public void testHashString() throws Exception {
byte[] bytes = SystemUtils.toHashBytes(truffleruby2HashString);
assertArrayEquals(truffleruby2Hash, bytes);
}
@Test
public void testHashStringDivided() throws Exception {
byte[] bytes = SystemUtils.toHashBytes(truffleruby2HashString2);
assertArrayEquals(truffleruby2Hash, bytes);
}
@Test
public void loadMultipleVersions() throws Exception {
loadCatalog("catalogMultiVersions.properties");
Set<String> ids = remStorage.listComponentIDs();
assertEquals(3, ids.size());
assertTrue(ids.contains("python"));
}
@Test
public void obsoleteVersionsNotIncluded() throws Exception {
loadCatalog("catalogMultiVersions.properties");
remStorage = new RemotePropertiesStorage(this, localRegistry, catalogProps, TEST_GRAAL_FLAVOUR,
Version.fromString("1.0.0.0"), new URL(TEST_BASE_URL));
Set<ComponentInfo> rubies = remStorage.loadComponentMetadata("ruby");
assertEquals(2, rubies.size());
Set<ComponentInfo> rs = remStorage.loadComponentMetadata("r");
assertEquals(1, rs.size());
Set<ComponentInfo> pythons = remStorage.loadComponentMetadata("python");
assertEquals(1, pythons.size());
}
@Test
public void checkMultipleGraalVMDependencies() throws Exception {
loadCatalog("catalogMultiVersions.properties");
Set<ComponentInfo> rubies = remStorage.loadComponentMetadata("ruby");
Set<Version> versions = new HashSet<>();
for (ComponentInfo ci : rubies) {
Version compVersion = ci.getVersion();
assertTrue(versions.add(compVersion));
String gv = ci.getRequiredGraalValues().get(BundleConstants.GRAAL_VERSION);
assertEquals(gv, compVersion.toString());
}
}
@Test
public void loadMultipleComponentFlavours() throws Exception {
storage.graalInfo.put(CommonConstants.CAP_GRAALVM_VERSION, "1.0.0.0");
loadCatalog("catalogMultiFlavours.properties");
Set<String> ids = remStorage.listComponentIDs();
assertEquals(3, ids.size());
assertTrue(ids.contains("python"));
List<ComponentInfo> infos = new ArrayList<>(remStorage.loadComponentMetadata("ruby"));
assertEquals(4, infos.size());
Collections.sort(infos, (a, b) -> compare(
a.getRequiredGraalValues().get(CommonConstants.CAP_JAVA_VERSION),
b.getRequiredGraalValues().get(CommonConstants.CAP_JAVA_VERSION)));
ComponentInfo ci;
ci = infos.get(2);
assertEquals("ruby", ci.getId());
assertEquals("11", ci.getRequiredGraalValues().get(CommonConstants.CAP_JAVA_VERSION));
ci = infos.get(3);
assertEquals("ruby", ci.getId());
assertEquals("8", ci.getRequiredGraalValues().get(CommonConstants.CAP_JAVA_VERSION));
}
private void setSelector(String os, String arch) {
String s = SystemUtils.patternOsName(os) + "_" + SystemUtils.patternOsArch(arch);
graalSelector = s;
}
private void assertComponentHasNormalizedValues(String cid) throws IOException {
Set<ComponentInfo> infos = remStorage.loadComponentMetadata(cid);
assertEquals(1, infos.size());
ComponentInfo ci = infos.iterator().next();
String os = ci.getRequiredGraalValues().get(CommonConstants.CAP_OS_NAME);
String arch = ci.getRequiredGraalValues().get(CommonConstants.CAP_OS_ARCH);
String nos = SystemUtils.normalizeOSName(os, arch);
String narch = SystemUtils.normalizeArchitecture(os, arch);
assertEquals(nos, os);
assertEquals(narch, arch);
}
private void assertAllComponentsLoaded() throws IOException {
Set<String> ids = remStorage.listComponentIDs();
assertEquals(2, ids.size());
assertTrue(ids.contains("ruby"));
assertTrue(ids.contains("r"));
assertComponentHasNormalizedValues("r");
}
@Test
public void testMixedLinuxArchitetures() throws Exception {
storage.graalInfo.put(CommonConstants.CAP_GRAALVM_VERSION, "0.33-dev");
setSelector("linux", "x86_64");
forceLoadCatalog("catalogWithDifferentOsArch.properties");
assertAllComponentsLoaded();
graalVersion = "0.34-dev";
setSelector("Linux", "amd64");
forceLoadCatalog("catalogWithDifferentOsArch.properties");
assertAllComponentsLoaded();
graalVersion = "0.35-dev";
setSelector("Darwin", "amd64");
forceLoadCatalog("catalogWithDifferentOsArch.properties");
assertAllComponentsLoaded();
storage.graalInfo.put(CommonConstants.CAP_GRAALVM_VERSION, "0.35-dev");
setSelector("macos", "x86_64");
forceLoadCatalog("catalogWithDifferentOsArch.properties");
assertAllComponentsLoaded();
}
static int compare(String a, String b) {
if (a == b) {
return 0;
}
if (a == null) {
return -1;
} else if (b == null) {
return 1;
}
return a.compareTo(b);
}
}