Skip to content

Commit

Permalink
Native libs tests and fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
pron committed Aug 18, 2014
1 parent 1cfb224 commit 302d05b
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 40 deletions.
24 changes: 11 additions & 13 deletions capsule/src/main/java/Capsule.java
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ public class Capsule implements Runnable {
private static final String ATTR_SECURITY_POLICY_A = "Security-Policy-A";
private static final String ATTR_JAVA_AGENTS = "Java-Agents";
private static final String ATTR_REPOSITORIES = "Repositories";
private static final String ATTR_ALLOW_SNAPSHOTS = "Allow-Snapshots";
private static final String ATTR_DEPENDENCIES = "Dependencies";
private static final String ATTR_NATIVE_DEPENDENCIES_LINUX = "Native-Dependencies-Linux";
private static final String ATTR_NATIVE_DEPENDENCIES_WIN = "Native-Dependencies-Win";
Expand Down Expand Up @@ -958,28 +959,25 @@ private static void addSystemProperty(String p, Map<String, String> ps) {
//<editor-fold desc="Native Dependencies">
/////////// Native Dependencies ///////////////////////////////////
private List<Path> buildNativeLibraryPath() {
final List<Path> libraryPath = new ArrayList<Path>();
final List<Path> libraryPath = new ArrayList<Path>(toPath(Arrays.asList(System.getProperty(PROP_JAVA_LIBRARY_PATH).split(PATH_SEPARATOR))));

resolveNativeDependencies();
if (appCache != null)
libraryPath.addAll(nullToEmpty(toAbsolutePath(appCache, getListAttribute(ATTR_LIBRARY_PATH_P))));
libraryPath.addAll(toPath(Arrays.asList(System.getProperty(PROP_JAVA_LIBRARY_PATH).split(PATH_SEPARATOR))));
if (appCache != null) {
libraryPath.addAll(0, nullToEmpty(toAbsolutePath(appCache, getListAttribute(ATTR_LIBRARY_PATH_P))));
libraryPath.addAll(nullToEmpty(toAbsolutePath(appCache, getListAttribute(ATTR_LIBRARY_PATH_A))));
libraryPath.add(appCache);
}
} else if (hasAttribute(ATTR_LIBRARY_PATH_P) || hasAttribute(ATTR_LIBRARY_PATH_A))
throw new IllegalStateException("Cannot use the " + ATTR_LIBRARY_PATH_P + " or the " + ATTR_LIBRARY_PATH_A
+ " attributes when the " + ATTR_EXTRACT + " attribute is set to false");
return libraryPath;
}

private void resolveNativeDependencies() {
if (!hasAttribute(ATTR_LIBRARY_PATH_P) && !hasAttribute(ATTR_LIBRARY_PATH_A))
return;
if (appCache == null)
throw new IllegalStateException("Cannot use the " + ATTR_LIBRARY_PATH_P + " or the " + ATTR_LIBRARY_PATH_A
+ " attributes when the " + ATTR_EXTRACT + " attribute is set to false");

final List<String> depsAndRename = getNativeDependenciesAndRename();
if (depsAndRename == null || depsAndRename.isEmpty())
return;
if (appCache == null)
throw new IllegalStateException("Cannot have native dependencies when the " + ATTR_EXTRACT + " attribute is set to false");
final List<String> deps = new ArrayList<String>(depsAndRename.size());
final List<String> renames = new ArrayList<String>(depsAndRename.size());
for (String depAndRename : depsAndRename) {
Expand All @@ -990,7 +988,7 @@ private void resolveNativeDependencies() {
verbose("Resolving native libs " + deps);
final List<Path> resolved = resolveDependencies(deps, getNativeLibExtension());
if (resolved.size() != deps.size())
throw new RuntimeException("One of the native artifacts " + deps + " reolved to more than a single file");
throw new RuntimeException("One of the native artifacts " + deps + " reolved to more than a single file or to none");

assert appCache != null;
if (!cacheUpToDate) {
Expand All @@ -1003,7 +1001,7 @@ private void resolveNativeDependencies() {
Files.copy(lib, appCache.resolve(rename != null ? rename : lib.getFileName().toString()));
}
} catch (IOException e) {
throw new RuntimeException("Exception while copying native libs");
throw new RuntimeException("Exception while copying native libs", e);
}
}
}
Expand Down
157 changes: 130 additions & 27 deletions capsule/src/test/java/CapsuleTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public class CapsuleTest {
public void tearDown() throws Exception {
fs.close();
}

@Test
public void testParseJavaVersion() {
int[] ver;
Expand Down Expand Up @@ -101,22 +101,22 @@ public void isJavaDir() {

@Test
public void testDelete() throws Exception {
Files.createDirectories(fs.getPath("a", "b", "c"));
Files.createDirectories(fs.getPath("a", "b1"));
Files.createDirectories(fs.getPath("a", "b", "c1"));
Files.createFile(fs.getPath("a", "x"));
Files.createFile(fs.getPath("a", "b", "x"));
Files.createFile(fs.getPath("a", "b1", "x"));
Files.createFile(fs.getPath("a", "b", "c", "x"));
Files.createFile(fs.getPath("a", "b", "c1", "x"));
Files.createDirectories(path("a", "b", "c"));
Files.createDirectories(path("a", "b1"));
Files.createDirectories(path("a", "b", "c1"));
Files.createFile(path("a", "x"));
Files.createFile(path("a", "b", "x"));
Files.createFile(path("a", "b1", "x"));
Files.createFile(path("a", "b", "c", "x"));
Files.createFile(path("a", "b", "c1", "x"));

assertTrue(Files.exists(fs.getPath("a")));
assertTrue(Files.isDirectory(fs.getPath("a")));
assertTrue(Files.exists(path("a")));
assertTrue(Files.isDirectory(path("a")));

//Files.delete(fs.getPath("a"));
Capsule.delete(fs.getPath("a"));
//Files.delete(path("a"));
Capsule.delete(path("a"));

assertTrue(!Files.exists(fs.getPath("a")));
assertTrue(!Files.exists(path("a")));
}

@Test
Expand All @@ -140,10 +140,10 @@ public void testSimpleExtract() throws Exception {
Path appCache = cache.resolve("apps").resolve("com.acme.Foo");

assertEquals("com.acme.Foo", getProperty(pb, "capsule.app"));
assertEquals(appCache.toString(), getProperty(pb, "capsule.dir"));
assertEquals(getPath("capsule.jar").toString(), getProperty(pb, "capsule.jar"));
assertEquals(appCache.toString(), getEnv(pb, "CAPSULE_DIR"));
assertEquals(getPath("capsule.jar").toString(), getEnv(pb, "CAPSULE_JAR"));
assertEquals(appCache, path(getProperty(pb, "capsule.dir")));
assertEquals(path("capsule.jar"), path(getProperty(pb, "capsule.jar")));
assertEquals(appCache, path(getEnv(pb, "CAPSULE_DIR")));
assertEquals(path("capsule.jar"), path(getEnv(pb, "CAPSULE_JAR")));

assertEquals(list("com.acme.Foo", "hi", "there"), getMainAndArgs(pb));

Expand All @@ -160,7 +160,7 @@ public void testSimpleExtract() throws Exception {
assertTrue(!Files.isDirectory(appCache.resolve("META-INF")));
assertTrue(!Files.isRegularFile(appCache.resolve("META-INF").resolve("x.txt")));

ASSERT.that(getClassPath(pb)).has().item(getPath("capsule.jar"));
ASSERT.that(getClassPath(pb)).has().item(path("capsule.jar"));
ASSERT.that(getClassPath(pb)).has().item(appCache);
ASSERT.that(getClassPath(pb)).has().item(appCache.resolve("foo.jar"));
ASSERT.that(getClassPath(pb)).has().noneOf(appCache.resolve("lib").resolve("a.jar"));
Expand Down Expand Up @@ -228,13 +228,116 @@ public void testClassPath() throws Exception {
assertTrue(Files.isDirectory(appCache.resolve("lib")));
assertTrue(Files.isRegularFile(appCache.resolve("lib").resolve("a.jar")));

ASSERT.that(getClassPath(pb)).has().item(getPath("capsule.jar"));
ASSERT.that(getClassPath(pb)).has().item(path("capsule.jar"));
ASSERT.that(getClassPath(pb)).has().item(appCache);
ASSERT.that(getClassPath(pb)).has().item(appCache.resolve("foo.jar"));
ASSERT.that(getClassPath(pb)).has().item(appCache.resolve("lib").resolve("a.jar"));
ASSERT.that(getClassPath(pb)).has().item(appCache.resolve("lib").resolve("b.jar"));
}

@Test
public void testNatives1() throws Exception {
Jar jar = newCapsuleJar()
.setAttribute("Application-Class", "com.acme.Foo")
.setListAttribute("Library-Path-A", list("lib/a.so"))
.setListAttribute("Library-Path-P", list("lib/b.so"))
.addEntry("foo.jar", Jar.toInputStream("", UTF_8))
.addEntry("lib/a.so", Jar.toInputStream("", UTF_8))
.addEntry("lib/b.so", Jar.toInputStream("", UTF_8))
.addEntry("lib/c.jar", Jar.toInputStream("", UTF_8))
.addEntry("lib/d.jar", Jar.toInputStream("", UTF_8));

String[] args = strings("hi", "there");
List<String> cmdLine = list();

Capsule capsule = newCapsule(jar, null);
ProcessBuilder pb = capsule.prepareForLaunch(cmdLine, args);

Path appCache = cache.resolve("apps").resolve("com.acme.Foo");

int len = paths(getProperty(pb, "java.library.path")).size();
ASSERT.that(paths(getProperty(pb, "java.library.path")).get(0)).isEqualTo(appCache.resolve("lib").resolve("b.so"));
ASSERT.that(paths(getProperty(pb, "java.library.path")).get(len - 2)).isEqualTo(appCache.resolve("lib").resolve("a.so"));
ASSERT.that(paths(getProperty(pb, "java.library.path")).get(len - 1)).isEqualTo(appCache);
}

@Test
public void testNatives2() throws Exception {
final String orig = System.getProperty("java.library.path");
try {
Jar jar = newCapsuleJar()
.setAttribute("Application-Class", "com.acme.Foo")
.setListAttribute("Library-Path-A", list("lib/a.so"))
.setListAttribute("Library-Path-P", list("lib/b.so"))
.addEntry("foo.jar", Jar.toInputStream("", UTF_8))
.addEntry("lib/a.so", Jar.toInputStream("", UTF_8))
.addEntry("lib/b.so", Jar.toInputStream("", UTF_8))
.addEntry("lib/c.jar", Jar.toInputStream("", UTF_8))
.addEntry("lib/d.jar", Jar.toInputStream("", UTF_8));

String[] args = strings("hi", "there");
System.setProperty("java.library.path", "/foo/bar");
List<String> cmdLine = list();

Capsule capsule = newCapsule(jar, null);
ProcessBuilder pb = capsule.prepareForLaunch(cmdLine, args);

Path appCache = cache.resolve("apps").resolve("com.acme.Foo");

ASSERT.that(paths(getProperty(pb, "java.library.path"))).isEqualTo(list(
appCache.resolve("lib").resolve("b.so"),
path("/foo", "bar"),
appCache.resolve("lib").resolve("a.so"),
appCache));
} finally {
System.setProperty("java.library.path", orig);
}
}

@Test
public void testNativesWithDeps() throws Exception {
Jar jar = newCapsuleJar()
.setAttribute("Application-Class", "com.acme.Foo")
.setListAttribute("Native-Dependencies-Linux", list("com.acme:baz-linux:3.4,libbaz.so"))
.setListAttribute("Native-Dependencies-Windows", list("com.acme:baz-win:3.4,libbaz.dll"))
.setListAttribute("Native-Dependencies-Mac", list("com.acme:baz-macos:3.4,libbaz.dylib"))
.addEntry("foo.jar", Jar.toInputStream("", UTF_8))
.addEntry("lib/a.so", Jar.toInputStream("", UTF_8))
.addEntry("lib/b.so", Jar.toInputStream("", UTF_8))
.addEntry("lib/c.jar", Jar.toInputStream("", UTF_8))
.addEntry("lib/d.jar", Jar.toInputStream("", UTF_8));

DependencyManager dm = mock(DependencyManager.class);
Files.createDirectories(cache.resolve("deps").resolve("com.acme").resolve("baz"));
Path bazLinuxPath = cache.resolve("deps").resolve("com.acme").resolve("baz").resolve("baz-linux-3.4.so");
Files.createFile(bazLinuxPath);
when(dm.resolveDependencies(list("com.acme:baz-linux:3.4"), "so")).thenReturn(list(bazLinuxPath));
Path bazWindowsPath = cache.resolve("deps").resolve("com.acme").resolve("baz").resolve("baz-win-3.4.dll");
Files.createFile(bazWindowsPath);
when(dm.resolveDependencies(list("com.acme:baz-win:3.4"), "dll")).thenReturn(list(bazWindowsPath));
Path bazMacPath = cache.resolve("deps").resolve("com.acme").resolve("baz").resolve("baz-macos-3.4.dylib");
Files.createFile(bazMacPath);
when(dm.resolveDependencies(list("com.acme:baz-macos:3.4"), "dylib")).thenReturn(list(bazMacPath));

String[] args = strings("hi", "there");
System.setProperty("java.library.path", "/foo/bar");
List<String> cmdLine = list();

Capsule capsule = newCapsule(jar, dm);
ProcessBuilder pb = capsule.prepareForLaunch(cmdLine, args);

Path appCache = cache.resolve("apps").resolve("com.acme.Foo");

ASSERT.that(paths(getProperty(pb, "java.library.path"))).has().item(appCache);

if (Capsule.isUnix())
assertTrue(Files.isRegularFile(appCache.resolve("libbaz.so")));
else if (Capsule.isWindows())
assertTrue(Files.isRegularFile(appCache.resolve("libbaz.dll")));
else if (Capsule.isMac())
assertTrue(Files.isRegularFile(appCache.resolve("libbaz.dylib")));
}

@Test
public void testBootClassPath1() throws Exception {
Jar jar = newCapsuleJar()
Expand Down Expand Up @@ -305,7 +408,7 @@ public void testBootClassPathWithDeps() throws Exception {
DependencyManager dm = mock(DependencyManager.class);
Path barPath = cache.resolve("deps").resolve("com.acme").resolve("bar").resolve("bar-1.2.jar");
when(dm.resolveDependency("com.acme:bar:1.2", "jar")).thenReturn(list(barPath));
Path bazPath = cache.resolve("deps").resolve("com.acme").resolve("baz").resolve("bar-3.4.jar");
Path bazPath = cache.resolve("deps").resolve("com.acme").resolve("baz").resolve("baz-3.4.jar");
when(dm.resolveDependency("com.acme:baz:3.4", "jar")).thenReturn(list(bazPath));

String[] args = strings("hi", "there");
Expand Down Expand Up @@ -432,7 +535,7 @@ public void testCapsuleInClassPath() throws Exception {
assertTrue(Files.isDirectory(appCache.resolve("lib")));
assertTrue(Files.isRegularFile(appCache.resolve("lib").resolve("a.jar")));

ASSERT.that(getClassPath(pb)).has().noneOf(getPath("capsule.jar"));
ASSERT.that(getClassPath(pb)).has().noneOf(path("capsule.jar"));
ASSERT.that(getClassPath(pb)).has().allOf(
appCache,
appCache.resolve("foo.jar"),
Expand Down Expand Up @@ -548,7 +651,7 @@ public void testReallyExecutableCapsule() throws Exception {
String[] args = strings("hi", "there");
List<String> cmdLine = list("-Dfoo=x", "-Dzzz", "-Xms15");

final Path capsuleJar = getPath("capsule.jar");
final Path capsuleJar = path("capsule.jar");
jar.write(capsuleJar);
Capsule capsule = Capsule.newCapsule(capsuleJar, cache);

Expand All @@ -567,7 +670,7 @@ public void testCustomCapsule() throws Exception {
String[] args = strings("hi", "there");
List<String> cmdLine = list("-Dfoo=x", "-Dzzz", "-Xms15");

final Path capsuleJar = getPath("capsule.jar");
final Path capsuleJar = path("capsule.jar");
jar.write(capsuleJar);
Capsule capsule = Capsule.newCapsule(capsuleJar, cache);

Expand Down Expand Up @@ -649,7 +752,7 @@ public void testEmptyCapsule() throws Exception {
// may be called once per test (always writes jar into /capsule.jar)
private Capsule newCapsule(Jar jar, DependencyManager dependencyManager) {
try {
final Path capsuleJar = getPath("capsule.jar");
final Path capsuleJar = path("capsule.jar");
jar.write(capsuleJar);
Constructor<Capsule> ctor = Capsule.class.getDeclaredConstructor(Path.class, Path.class, Object.class);
ctor.setAccessible(true);
Expand All @@ -667,7 +770,7 @@ private Jar newCapsuleJar() {
.setAttribute("Main-Class", "Capsule");
}

private Path getPath(String first, String... more) {
private Path path(String first, String... more) {
return fs.getPath(first, more);
}

Expand All @@ -690,7 +793,7 @@ private InputStream toInputStream(Model model) {
private List<Path> paths(String cp) {
final List<Path> res = new ArrayList<>();
for (String p : cp.split(":"))
res.add(getPath(p));
res.add(path(p));
return res;
}

Expand Down

0 comments on commit 302d05b

Please sign in to comment.