blob: c6eb3d1f7722fb06c79fe6abcc5f4d7ede88da6b [file] [log] [blame]
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.build.gradle.internal.dependency
import com.android.SdkConstants
import com.android.ide.common.process.CachedProcessOutputHandler
import com.android.ide.common.process.DefaultProcessExecutor
import com.android.ide.common.process.LoggedProcessOutputHandler
import com.android.ide.common.process.ProcessInfoBuilder
import com.android.testutils.TestResources
import com.android.testutils.TestUtils
import com.android.testutils.truth.PathSubject.assertThat
import com.android.testutils.truth.ZipFileSubject
import com.android.utils.FileUtils
import com.android.utils.ILogger
import com.android.utils.StdLogger
import com.google.common.truth.Truth
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
import java.io.File
class JdkImageTransformDelegateTest {
@JvmField
@Rule
val tmp = TemporaryFolder()
val javaHome = TestUtils.getJava11Jdk().toFile()
fun copyCfsmJarToTempFolder(): File {
val originalCfsmJar =
TestUtils.resolvePlatformPath(
SdkConstants.FN_CORE_FOR_SYSTEM_MODULES, TestUtils.TestType.AGP
).toFile()
val cfsmJar = tmp.newFile(originalCfsmJar.name)
FileUtils.copyFile(originalCfsmJar, cfsmJar)
return cfsmJar
}
@Test
fun testGenerateModuleDescriptorMethod() {
val cfsmJar = copyCfsmJarToTempFolder()
val result = generateModuleDescriptor("java.base", listOf(cfsmJar))
Truth.assertThat(result).isEqualTo(
"""
module java.base {
exports android.icu.lang;
exports android.icu.math;
exports android.icu.number;
exports android.icu.text;
exports android.icu.util;
exports android.net.ssl;
exports android.system;
exports dalvik.annotation;
exports dalvik.annotation.optimization;
exports dalvik.bytecode;
exports dalvik.system;
exports java.awt.font;
exports java.beans;
exports java.io;
exports java.lang;
exports java.lang.annotation;
exports java.lang.invoke;
exports java.lang.ref;
exports java.lang.reflect;
exports java.lang.runtime;
exports java.math;
exports java.net;
exports java.nio;
exports java.nio.channels;
exports java.nio.channels.spi;
exports java.nio.charset;
exports java.nio.charset.spi;
exports java.nio.file;
exports java.nio.file.attribute;
exports java.nio.file.spi;
exports java.security;
exports java.security.acl;
exports java.security.cert;
exports java.security.interfaces;
exports java.security.spec;
exports java.sql;
exports java.text;
exports java.time;
exports java.time.chrono;
exports java.time.format;
exports java.time.temporal;
exports java.time.zone;
exports java.util;
exports java.util.concurrent;
exports java.util.concurrent.atomic;
exports java.util.concurrent.locks;
exports java.util.function;
exports java.util.jar;
exports java.util.logging;
exports java.util.prefs;
exports java.util.regex;
exports java.util.stream;
exports java.util.zip;
exports javax.annotation.processing;
exports javax.crypto;
exports javax.crypto.interfaces;
exports javax.crypto.spec;
exports javax.net;
exports javax.net.ssl;
exports javax.security.auth;
exports javax.security.auth.callback;
exports javax.security.auth.login;
exports javax.security.auth.x500;
exports javax.security.cert;
exports javax.sql;
exports javax.xml;
exports javax.xml.datatype;
exports javax.xml.namespace;
exports javax.xml.parsers;
exports javax.xml.transform;
exports javax.xml.transform.dom;
exports javax.xml.transform.sax;
exports javax.xml.transform.stream;
exports javax.xml.validation;
exports javax.xml.xpath;
exports org.json;
exports org.w3c.dom;
exports org.w3c.dom.ls;
exports org.xml.sax;
exports org.xml.sax.ext;
exports org.xml.sax.helpers;
exports org.xmlpull.v1;
exports org.xmlpull.v1.sax2;
}
""".trimIndent().replace("\n", System.lineSeparator())
)
}
@Test
fun testModuleDescriptorCompilation() {
val cfsmJar = copyCfsmJarToTempFolder()
val logger = StdLogger(StdLogger.Level.VERBOSE)
val outDir = FileUtils.join(tmp.newFolder(), "system")
val delegate =
JdkImageTransformDelegate(
cfsmJar,
tmp.newFolder(),
outDir,
JdkTools(
javaHome,
DefaultProcessExecutor(logger),
logger
)
)
val moduleInfoClass = delegate.makeModuleInfoClass()
// validate moduleInfoClass content via "javap" command
val pib = ProcessInfoBuilder().apply {
setExecutable(javaHome.resolve("bin").resolve("javap".optionalExe()))
addArgs(moduleInfoClass.absolutePath)
}
val processHandler = CachedProcessOutputHandler()
DefaultProcessExecutor(logger).execute(
pib.createProcess(),
processHandler
).rethrowFailure().assertNormalExitValue()
Truth.assertThat(processHandler.processOutput.standardOutputAsString).apply {
startsWith("Compiled from \"module-info.java\"")
contains("exports java.lang;")
contains("exports android.icu.lang;")
}
}
@Test
fun testModuleJarCreation() {
val cfsmJar = copyCfsmJarToTempFolder()
val logger = StdLogger(StdLogger.Level.VERBOSE)
val outDir = FileUtils.join(tmp.newFolder(), "system")
val delegate =
JdkImageTransformDelegate(
cfsmJar,
tmp.newFolder(),
outDir,
JdkTools(
javaHome,
DefaultProcessExecutor(logger),
logger
)
)
val moduleJar = delegate.makeModuleJar()
assertThat(moduleJar).exists()
ZipFileSubject.assertThat(moduleJar) {
it.contains("module-info.class")
it.contains("java/lang")
it.contains("android/icu")
}
}
@Test
fun testJmodFileCreation() {
val cfsmJar = copyCfsmJarToTempFolder()
val logger = StdLogger(StdLogger.Level.VERBOSE)
val outDir = FileUtils.join(tmp.newFolder(), "system")
val delegate =
JdkImageTransformDelegate(
cfsmJar,
tmp.newFolder(),
outDir,
JdkTools(
javaHome,
DefaultProcessExecutor(logger),
logger
)
)
val jmodFile = delegate.makeJmodFile()
// validate jmodFile content via "jmod describe" command
val pib = ProcessInfoBuilder().apply {
setExecutable(javaHome.resolve("bin").resolve("jmod"))
addArgs("describe")
addArgs(jmodFile.absolutePath)
}
val processHandler = CachedProcessOutputHandler()
DefaultProcessExecutor(logger).execute(
pib.createProcess(),
processHandler
).rethrowFailure().assertNormalExitValue()
Truth.assertThat(processHandler.processOutput.standardOutputAsString).apply {
startsWith("java.base@11")
contains("exports java.lang")
contains("exports android.icu.lang")
contains("exports dalvik.system")
contains("platform LINUX-OTHER")
}
}
@Test
fun testDelegateRunMethod() {
val cfsmJar = copyCfsmJarToTempFolder()
val logger = StdLogger(StdLogger.Level.VERBOSE)
val outDir = FileUtils.join(tmp.newFolder(), "system")
val delegate =
JdkImageTransformDelegate(
cfsmJar,
tmp.newFolder(),
outDir,
JdkTools(
javaHome,
DefaultProcessExecutor(logger),
logger
)
)
delegate.run()
Truth.assertThat(outDir.list()).asList().containsExactly("release", "lib")
val jrtFsJar = outDir.resolve("lib").resolve(JRT_FS_JAR)
assertThat(jrtFsJar).exists()
ZipFileSubject.assertThat(jrtFsJar) {
it.doesNotContain("META-INF/MANIFEST.MF")
}
val compiledJava11Dir = tmp.newFolder("compiledJava11")
compileTestClass(
outDir, logger, TestResources.getFile(
JdkImageTransformDelegateTest::class.java,
"Java11Class.java"
), compiledJava11Dir
)
compileTestClass(
outDir, logger, TestResources.getFile(
JdkImageTransformDelegateTest::class.java,
"Java11ClassWithAndroidApis.java"
), compiledJava11Dir
)
}
private fun compileTestClass(
systemImageDir: File,
logger: ILogger,
java11SourceFile: File,
compiledJava11Dir: File
) {
//compile a java 11 source file against the system image
assertThat(java11SourceFile).exists()
val androidJar =
TestUtils.resolvePlatformPath(SdkConstants.FN_FRAMEWORK_LIBRARY, TestUtils.TestType.AGP)
val pib = ProcessInfoBuilder().apply {
setExecutable(javaHome.resolve("bin").resolve("javac".optionalExe()))
addArgs("--system", systemImageDir.absolutePath)
addArgs("-d", compiledJava11Dir.absolutePath)
addArgs("-cp", androidJar.toString())
addArgs(java11SourceFile.absolutePath)
}
DefaultProcessExecutor(logger).execute(
pib.createProcess(),
LoggedProcessOutputHandler(logger)
).rethrowFailure().assertNormalExitValue()
val compiledJava11File = FileUtils.join(
compiledJava11Dir,
"${java11SourceFile.nameWithoutExtension}.class"
)
assertThat(compiledJava11File).exists()
}
}