/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.portal.security.pacl; import com.liferay.portal.kernel.process.ProcessCallable; import com.liferay.portal.kernel.process.ProcessChannel; import com.liferay.portal.kernel.process.ProcessConfig; import com.liferay.portal.kernel.process.ProcessConfig.Builder; import com.liferay.portal.kernel.process.ProcessException; import com.liferay.portal.kernel.process.local.LocalProcessExecutor; import com.liferay.portal.kernel.process.local.LocalProcessLauncher.ProcessContext; import com.liferay.portal.kernel.process.log.ProcessOutputStream; import com.liferay.portal.kernel.resiliency.mpi.MPIHelperUtil; import com.liferay.portal.kernel.test.ReflectionTestUtil; import com.liferay.portal.kernel.test.ci.AutoBalanceTestCase; import com.liferay.portal.kernel.test.junit.BridgeJUnitTestRunner; import com.liferay.portal.kernel.test.junit.BridgeJUnitTestRunner.BridgeRunListener; import com.liferay.portal.kernel.util.PropsKeys; import com.liferay.portal.kernel.util.ReflectionUtil; import com.liferay.portal.kernel.util.StringPool; import com.liferay.portal.kernel.util.StringUtil; import com.liferay.portal.kernel.util.SystemProperties; import com.liferay.portal.test.log.CaptureAppender; import com.liferay.portal.test.rule.ExpectedLogs; import com.liferay.portal.test.rule.HypersonicServerTestRule; import com.liferay.portal.test.rule.PACLTestRule; import com.liferay.portal.test.rule.callback.LogAssertionTestCallback; import com.liferay.portal.util.InitUtil; import com.liferay.portal.util.PropsImpl; import com.liferay.portal.util.PropsValues; import com.liferay.util.log4j.Log4JUtil; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.io.Serializable; import java.net.InetSocketAddress; import java.net.Proxy; import java.net.Proxy.Type; import java.net.ProxySelector; import java.net.SocketAddress; import java.net.URI; import java.net.URL; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; 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 java.util.concurrent.Future; import javax.naming.Context; import org.junit.Assume; import org.junit.ClassRule; import org.junit.Test; import org.junit.runner.Result; import org.junit.runner.RunWith; /** * @author Shuyang Zhou */ @RunWith(BridgeJUnitTestRunner.class) public class PACLAggregateTest extends AutoBalanceTestCase { @ClassRule public static final HypersonicServerTestRule hypersonicServerTestRule = HypersonicServerTestRule.INSTANCE; @Test public void testPACLTests() throws Exception { LocalProcessExecutor localProcessExecutor = new LocalProcessExecutor(); try { List<Class<?>> classes = scanTestClasses(); Assume.assumeFalse("No PACL tests available", classes.isEmpty()); ProcessChannel<Result> processChannel = localProcessExecutor.execute( createProcessConfig(), new PACLTestsProcessCallable(classes)); Future<Result> future = processChannel.getProcessNoticeableFuture(); future.get(); } finally { localProcessExecutor.destroy(); } } protected ProcessConfig createProcessConfig() { Builder builder = new Builder(); List<String> arguments = new ArrayList<>(); arguments.add(_JVM_XMX); arguments.add(_JVM_MAX_PERM_SIZE); arguments.add("-Djava.security.manager"); URL url = PACLAggregateTest.class.getResource("security.policy"); arguments.add("-Djava.security.policy==" + url.getFile()); boolean junitDebug = Boolean.getBoolean("jvm.debug"); if (junitDebug) { arguments.add(_JPDA_OPTIONS); arguments.add("-Djvm.debug=true"); } arguments.add("-Dliferay.mode=test"); arguments.add("-Dsun.zip.disableMemoryMapping=true"); String aspectjAgent = System.getProperty("aspectj.agent"); if (aspectjAgent != null) { arguments.add(aspectjAgent); arguments.add("-Daspectj.agent=" + aspectjAgent); String aspectjConfiguration = System.getProperty( "org.aspectj.weaver.loadtime.configuration"); if (aspectjConfiguration != null) { arguments.add( "-Dorg.aspectj.weaver.loadtime.configuration=" + aspectjConfiguration); } } arguments.add( "-D" + PropsKeys.LIFERAY_LIB_PORTAL_DIR + "=" + PropsValues.LIFERAY_LIB_PORTAL_DIR); arguments.add( "-Dportal:" + PropsKeys.CLUSTER_LINK_AUTODETECT_ADDRESS + StringPool.EQUAL); arguments.add( "-Dportal:" + PropsKeys.MODULE_FRAMEWORK_PROPERTIES + _OSGI_CONSOLE); for (String property : hypersonicServerTestRule.getJdbcProperties()) { arguments.add("-D" + property); } builder.setArguments(arguments); builder.setBootstrapClassPath(System.getProperty("java.class.path")); builder.setReactClassLoader(PACLAggregateTest.class.getClassLoader()); return builder.build(); } protected List<Class<?>> scanTestClasses() throws ClassNotFoundException { URL url = PACLAggregateTest.class.getResource("test"); File folder = new File(url.getFile()); File[] files = folder.listFiles( new FileFilter() { @Override public boolean accept(File file) { if (!file.isFile()) { return false; } String fileName = file.getName(); if (fileName.indexOf('$') != -1) { return false; } return fileName.endsWith(".class"); } }); Arrays.sort(files); if (isCIMode()) { files = slice(files); } Package pkg = PACLAggregateTest.class.getPackage(); String packageName = pkg.getName(); packageName = packageName.concat(".test."); ClassLoader classLoader = PACLAggregateTest.class.getClassLoader(); List<Class<?>> classes = new ArrayList<>(); for (File file : files) { String fileName = file.getName(); classes.add( classLoader.loadClass( packageName.concat( fileName.substring(0, fileName.lastIndexOf('.'))))); } return classes; } private static final String _JPDA_OPTIONS = "-agentlib:jdwp=transport=dt_socket,address=8001,server=y,suspend=y"; private static final String _JVM_MAX_PERM_SIZE = "-XX:MaxPermSize=256m"; private static final String _JVM_XMX = "-Xmx1024m"; private static final String _OSGI_CONSOLE = "osgi.console=localhost:11312"; private static class DummySocksProxySelector extends ProxySelector { @Override public void connectFailed( URI uri, SocketAddress socketAddress, IOException ioe) { } @Override public List<Proxy> select(URI uri) { if (_socketAddresses.contains( uri.getHost() + StringPool.COLON + uri.getPort())) { return Collections.singletonList( new Proxy(Type.HTTP, new InetSocketAddress(0))); } return Collections.singletonList(Proxy.NO_PROXY); } private DummySocksProxySelector() throws ProcessException { Properties properties = new Properties(); try { properties.load( PACLTestsProcessCallable.class.getResourceAsStream( "test/dependencies/WEB-INF/liferay-plugin-package." + "properties")); } catch (IOException ioe) { throw new ProcessException(ioe); } for (String socketAddress : StringUtil.split( properties.getProperty( "security-manager-sockets-connect"))) { if (!socketAddress.startsWith("localhost")) { _socketAddresses.add(socketAddress); } } } private final Set<String> _socketAddresses = new HashSet<>(); } private static class PACLTestsProcessCallable implements ProcessCallable<Result> { @Override public Result call() throws ProcessException { ProxySelector.setDefault(new DummySocksProxySelector()); URL resource = PACLTestRule.class.getResource( "pacl-test.properties"); if (resource != null) { System.setProperty("external-properties", resource.getPath()); } System.setProperty( Context.INITIAL_CONTEXT_FACTORY, "org.apache.naming.java.javaURLContextFactory"); System.setProperty("catalina.base", "."); List<CaptureAppender> captureAppenders = null; Path tempStatePath = null; try { tempStatePath = Files.createTempDirectory(null); System.setProperty( "portal:" + PropsKeys.MODULE_FRAMEWORK_STATE_DIR, tempStatePath.toString()); com.liferay.portal.kernel.util.PropsUtil.setProps( new PropsImpl()); SystemProperties.set( "log4j.configure.on.startup", StringPool.FALSE); Log4JUtil.configureLog4J( PACLTestsProcessCallable.class.getClassLoader()); captureAppenders = LogAssertionTestCallback.startAssert( Collections.<ExpectedLogs>emptyList()); return BridgeJUnitTestRunner.runBridgeTests( new ProcessBridgeRunListener(PACLAggregateTest.class), _classes.toArray(new Class<?>[_classes.size()])); } catch (IOException ioe) { throw new ProcessException(ioe); } finally { InitUtil.stopRuntime(); InitUtil.stopModuleFramework(); MPIHelperUtil.shutdown(); if (tempStatePath != null) { try { Files.walkFileTree( tempStatePath, new SimpleFileVisitor<Path>() { @Override public FileVisitResult postVisitDirectory( Path path, IOException ioe) throws IOException { Files.delete(path); return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFile( Path path, BasicFileAttributes basicFileAttributes) throws IOException { Files.delete(path); return FileVisitResult.CONTINUE; } }); } catch (IOException ioe) { throw new ProcessException(ioe); } LogAssertionTestCallback.endAssert( Collections.<ExpectedLogs>emptyList(), captureAppenders); } } } @Override public String toString() { return "PACLTestSuite"; } private PACLTestsProcessCallable(List<Class<?>> classes) { _classes = classes; } private static final long serialVersionUID = 1L; private final List<Class<?>> _classes; } private static class ProcessBridgeRunListener extends BridgeRunListener { @Override protected void bridge(final String methodName, final Object argument) { ProcessOutputStream processOutputStream = ProcessContext.getProcessOutputStream(); try { processOutputStream.writeProcessCallable( new ProcessCallable<Serializable>() { @Override public Serializable call() { ReflectionTestUtil.invoke( BridgeJUnitTestRunner.getRunNotifier(testClass), methodName, new Class<?>[] {argument.getClass()}, argument); return null; } private static final long serialVersionUID = 1L; }); } catch (IOException ioe) { ReflectionUtil.throwException(ioe); } } private ProcessBridgeRunListener(Class<?> testClass) { super(testClass); } private static final long serialVersionUID = 1L; } }