/* * (C) Copyright 2013-2014 Nuxeo SA (http://nuxeo.com/) and others. * * 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. * * Contributors: * Florent Guillaume */ package org.nuxeo.launcher; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.security.GeneralSecurityException; import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.cli.ParseException; import org.apache.commons.io.Charsets; import org.apache.commons.io.FileUtils; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.internal.AssumptionViolatedException; import org.nuxeo.common.Environment; import org.nuxeo.connect.identity.LogicalInstanceIdentifier; import org.nuxeo.connect.identity.LogicalInstanceIdentifier.InvalidCLID; import org.nuxeo.connect.update.PackageException; import org.nuxeo.launcher.config.AbstractConfigurationTest; import org.nuxeo.launcher.config.ConfigurationException; import org.nuxeo.launcher.config.ConfigurationGenerator; import org.nuxeo.launcher.config.TomcatConfigurator; import org.nuxeo.launcher.info.InstanceInfo; import org.nuxeo.launcher.process.SolarisProcessManager; public class TestNuxeoLauncher extends AbstractConfigurationTest { private static final String TEST_INSTANCE_CLID = "/opt/build/hudson/instance.clid"; private static final String NUXEO_PATH = "/opt/nuxeo"; private static final String STARTUP_CLASS = "org.apache.catalina.startup.Bootstrap"; // USER PID %CPU %MEM SZ RSS TT S START TIME COMMAND private static final String SOL_PS1_CMD = "fsflush"; private static final String SOL_PS1 = "root 3 0.2 0.0 0 0 ? S 16:02:16 0:00 " + SOL_PS1_CMD; private static final String SOL_PS2_CMD = "/usr/lib/rad/rad -m /usr/lib/rad/transport -m /usr/lib/rad/protocol -m /usr/lib/rad/module -m /usr/lib/rad/site-modules -t pipe:fd=3,exit -e 180"; private static final String SOL_PS2 = "fguillau 1786 0.0 0.219136 3908 ? S 16:05:41 0:00 " + SOL_PS2_CMD; private static final String SOL_PS3_CMD = "gnome-terminal"; private static final String SOL_PS3 = "fguillau 1921 2.2 0.913130018836 ? S 16:08:28 0:00 " + SOL_PS3_CMD; private static final String SOL_PS4_CMD = "/usr/jdk/instances/jdk1.7.0/jre/bin/java -server -Xms512m -Xmx1024m -XX:MaxPermSize=512m -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 -Dfile.encoding=UTF-8 -Dmail.mime.decodeparameters=true -Xdebug -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n -Djava.net.preferIPv4Stack=true -Djava.awt.headless=true -cp .:/opt/nuxeo/nxserver/lib:/opt/nuxeo/bin/bootstrap.jar:/opt/nuxeo/bin/tomcat-juli.jar -Dnuxeo.home=/opt/nuxeo -Dnuxeo.conf=/opt/nuxeo/bin/nuxeo.conf -Dnuxeo.log.dir=/opt/nuxeo/log -Dnuxeo.data.dir=/opt/nuxeo/nxserver/data -Dnuxeo.tmp.dir=/opt/nuxeo/tmp -Djava.io.tmpdir=/opt/nuxeo/tmp -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Dcatalina.base=/opt/nuxeo -Dcatalina.home=/opt/nuxeo -Djava.endorsed.dirs=/opt/nuxeo/endorsed org.apache.catalina.startup.Bootstrap start"; private static final String SOL_PS4 = "fguillau 2788 1.2 19.5699008405296 pts/2 S 18:54:51 1:26 " + SOL_PS4_CMD; protected class MockSolarisProcessManager extends SolarisProcessManager { protected Map<String, List<String>> commands = new HashMap<>(); public void setLines(String command, List<String> lines) { commands.put(command, lines); } @Override protected List<String> execute(String... command) throws IOException { for (Entry<String, List<String>> es : commands.entrySet()) { String c = es.getKey(); if (command[0].contains(c)) { return es.getValue(); } } fail("Bad command: " + Arrays.toString(command)); return null; } } /** Code from {@link NuxeoLauncher#init} */ protected String getRegex() { return "^(?!/bin/sh).*" + Pattern.quote(NUXEO_PATH) + ".*" + Pattern.quote(STARTUP_CLASS) + ".*$"; } protected static void assertSolarisMatch(MockSolarisProcessManager pm, String expectedPid, String expectedCommand, String line) { Matcher lineMatcher = pm.getLineMatcher(line); assertTrue(lineMatcher.matches()); String pid = lineMatcher.group(1); String command = lineMatcher.group(2); assertEquals(expectedPid, pid); assertEquals(expectedCommand, command); } @Test public void testSolarisProcessManagerParsing() throws Exception { MockSolarisProcessManager pm = new MockSolarisProcessManager(); pm.setLines("uname", Collections.singletonList("5.11")); assertEquals("5.11", pm.getSolarisVersion()); assertSolarisMatch(pm, "3", SOL_PS1_CMD, SOL_PS1); assertSolarisMatch(pm, "1786", SOL_PS2_CMD, SOL_PS2); assertSolarisMatch(pm, "1921", SOL_PS3_CMD, SOL_PS3); assertSolarisMatch(pm, "2788", SOL_PS4_CMD, SOL_PS4); pm.setLines("ps", Arrays.asList(SOL_PS1, SOL_PS2, SOL_PS3, SOL_PS4)); assertEquals("2788", pm.findPid(getRegex())); } @Override @Before public void setUp() throws Exception { Environment.setDefault(null); nuxeoHome = new File("target/launcher"); FileUtils.deleteQuietly(nuxeoHome); nuxeoHome.mkdirs(); File nuxeoConf = getResourceFile("config/nuxeo.conf"); FileUtils.copyFileToDirectory(nuxeoConf, nuxeoHome); FileUtils.copyDirectory(getResourceFile("templates"), new File(nuxeoHome, "templates")); System.setProperty(Environment.NUXEO_HOME, nuxeoHome.getPath()); System.setProperty(ConfigurationGenerator.NUXEO_CONF, new File(nuxeoHome, nuxeoConf.getName()).getPath()); System.setProperty(TomcatConfigurator.TOMCAT_HOME, Environment.getDefault().getServerHome().getPath()); configGenerator = new ConfigurationGenerator(); assertTrue(configGenerator.init()); } @Test public void testClidOption() throws ConfigurationException, ParseException, IOException, PackageException, InvalidCLID { Path instanceClid = Paths.get(TEST_INSTANCE_CLID); if (!Files.exists(instanceClid)) { throw new AssumptionViolatedException("No test CLID available"); } String[] args = new String[] { "--clid", instanceClid.toString(), "showconf" }; final NuxeoLauncher launcher = NuxeoLauncher.createLauncher(args); InstanceInfo info = launcher.getInfo(); assertNotNull("Failed to get instance info", info); List<String> clidLines = Files.readAllLines(instanceClid, Charsets.UTF_8); LogicalInstanceIdentifier expectedClid = new LogicalInstanceIdentifier(clidLines.get(0) + LogicalInstanceIdentifier.ID_SEP + clidLines.get(1), "expected clid"); assertEquals("Not the right instance.clid file: ", expectedClid.getCLID(), info.clid); } /** * NXP-19071: avoid confusion with the command parameters when passing an argument to an option, or when calling * without argument an option which accepts optional arguments. * * @throws Exception * @since 8.2 */ @Test public void testParamSeparator() throws Exception { // failing syntax: "value1" is parsed as an argument to "--encrypt" option NuxeoLauncher launcher = NuxeoLauncher.createLauncher(new String[] { "encrypt", "--encrypt", "value1", "value2" }); assertTrue(launcher.commandIs("encrypt")); assertTrue(launcher.cmdLine.hasOption(NuxeoLauncher.OPTION_ENCRYPT)); assertEquals("value1", launcher.cmdLine.getOptionValue(NuxeoLauncher.OPTION_ENCRYPT)); assertArrayEquals(new String[] { "value2" }, launcher.params); try { launcher.encrypt(); fail("Expected 'java.security.NoSuchAlgorithmException: Cannot find any provider supporting value1'"); } catch (NoSuchAlgorithmException e) { assertEquals("Cannot find any provider supporting value1", e.getMessage()); } // working syntax: "value1" is a parsed as a parameter to "encrypt" command // 1) option without argument placed at the end launcher = NuxeoLauncher.createLauncher(new String[] { "encrypt", "value1", "value2", "--encrypt" }); checkParsing(launcher); // 2) option with an argument launcher = NuxeoLauncher.createLauncher(new String[] { "encrypt", "--encrypt", "AES/ECB/PKCS5Padding", "value1", "value2" }); checkParsing(launcher); // 3) option without argument separated with "--" launcher = NuxeoLauncher.createLauncher(new String[] { "encrypt", "--encrypt", "--", "value1", "value2" }); checkParsing(launcher); // Check specific case of the "--set" option launcher = NuxeoLauncher.createLauncher(new String[] { "config", "--set", "someTemplate", "someKey" }); assertTrue(launcher.commandIs("config")); assertTrue(launcher.cmdLine.hasOption(NuxeoLauncher.OPTION_SET)); assertEquals("someTemplate", launcher.cmdLine.getOptionValue(NuxeoLauncher.OPTION_SET)); assertArrayEquals(new String[] { "someKey" }, launcher.params); launcher = NuxeoLauncher.createLauncher(new String[] { "config", "--set", "--", "someKey" }); assertTrue(launcher.commandIs("config")); assertTrue(launcher.cmdLine.hasOption(NuxeoLauncher.OPTION_SET)); assertEquals(null, launcher.cmdLine.getOptionValue(NuxeoLauncher.OPTION_SET)); assertArrayEquals(new String[] { "someKey" }, launcher.params); launcher = NuxeoLauncher.createLauncher(new String[] { "config", "someKey", "--set" }); assertTrue(launcher.commandIs("config")); assertTrue(launcher.cmdLine.hasOption(NuxeoLauncher.OPTION_SET)); assertEquals(null, launcher.cmdLine.getOptionValue(NuxeoLauncher.OPTION_SET)); assertArrayEquals(new String[] { "someKey" }, launcher.params); } private void checkParsing(NuxeoLauncher launcher) throws ConfigurationException, GeneralSecurityException { assertTrue(launcher.commandIs("encrypt")); assertTrue(launcher.cmdLine.hasOption(NuxeoLauncher.OPTION_ENCRYPT)); assertEquals("AES/ECB/PKCS5Padding", launcher.cmdLine.getOptionValue(NuxeoLauncher.OPTION_ENCRYPT, "AES/ECB/PKCS5Padding")); assertArrayEquals(new String[] { "value1", "value2" }, launcher.params); launcher.encrypt(); } @Override @After public void tearDown() { FileUtils.deleteQuietly(nuxeoHome); System.clearProperty(ConfigurationGenerator.NUXEO_CONF); System.clearProperty(Environment.NUXEO_HOME); System.clearProperty(TomcatConfigurator.TOMCAT_HOME); System.clearProperty(Environment.NUXEO_DATA_DIR); System.clearProperty(Environment.NUXEO_LOG_DIR); } }