Repository: maven-surefire Updated Branches: refs/heads/SUREFIRE-1302_4 c7e0582bb -> 9354c3100 (forced update)
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/9354c310/surefire-booter/src/main/java/org/apache/maven/surefire/booter/PpidChecker.java ---------------------------------------------------------------------- diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/PpidChecker.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/PpidChecker.java new file mode 100644 index 0000000..f7eb1df --- /dev/null +++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/PpidChecker.java @@ -0,0 +1,295 @@ +package org.apache.maven.surefire.booter; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import java.io.File; +import java.io.IOException; +import java.util.Queue; +import java.util.Scanner; +import java.util.StringTokenizer; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static java.lang.Long.parseLong; +import static java.util.concurrent.TimeUnit.DAYS; +import static java.util.concurrent.TimeUnit.HOURS; +import static java.util.concurrent.TimeUnit.MINUTES; +import static java.util.regex.Pattern.compile; +import static org.apache.commons.io.IOUtils.closeQuietly; +import static org.apache.commons.lang3.SystemUtils.IS_OS_UNIX; +import static org.apache.commons.lang3.SystemUtils.IS_OS_WINDOWS; +import static org.apache.maven.surefire.booter.ProcessInfo.ERR_PROCESS_INFO; +import static org.apache.maven.surefire.booter.ProcessInfo.INVALID_PROCESS_INFO; + +/** + * Recognizes PID of Plugin process and determines lifetime. + * + * @author <a href="mailto:[email protected]">Tibor Digana (tibor17)</a> + * @since 2.20.1 + */ +final class PpidChecker +{ + private static final String WMIC_CREATION_DATE = "CreationDate"; + + private final Queue<Process> destroyableCommands = new ConcurrentLinkedQueue<Process>(); + + /** + * The etime is in the form of [[dd-]hh:]mm:ss on Unix like systems. + */ + static final Pattern UNIX_CMD_OUT_PATTERN = compile( "^(((\\d+)-)?(\\d{2}):)?(\\d{2}):(\\d{2})$" ); + + private final long pluginPid; + + private volatile ProcessInfo pluginProcessInfo; + private volatile boolean stopped; + + PpidChecker( long pluginPid ) + { + this.pluginPid = pluginPid; + } + + boolean canUse() + { + return pluginProcessInfo == null + ? IS_OS_WINDOWS || IS_OS_UNIX + : pluginProcessInfo.isValid() && !pluginProcessInfo.isError(); + } + + /** + * This method can be called only after {@link #canUse()} has returned {@code true}. + * + * @return {@code true} if parent process is alive; {@code false} otherwise + * @throws IllegalStateException if {@link #canUse()} returns {@code false} + * or the object has been {@link #destroyActiveCommands() destroyed} + */ + @SuppressWarnings( "unchecked" ) + boolean isProcessAlive() + { + if ( !canUse() ) + { + throw new IllegalStateException( "irrelevant to call isProcessAlive()" ); + } + + if ( IS_OS_WINDOWS ) + { + ProcessInfo previousPluginProcessInfo = pluginProcessInfo; + pluginProcessInfo = windows(); + if ( isStopped() || pluginProcessInfo.isError() ) + { + throw new IllegalStateException( "error to read process" ); + } + // let's compare creation time, should be same unless killed or PID is reused by OS into another process + return pluginProcessInfo.isValid() + && ( previousPluginProcessInfo == null + || pluginProcessInfo.isTimeEqualTo( previousPluginProcessInfo ) ); + } + else if ( IS_OS_UNIX ) + { + ProcessInfo previousPluginProcessInfo = pluginProcessInfo; + pluginProcessInfo = unix(); + if ( isStopped() || pluginProcessInfo.isError() ) + { + throw new IllegalStateException( "error to read process" ); + } + // let's compare elapsed time, should be greater or equal if parent process is the same and still alive + return pluginProcessInfo.isValid() + && ( previousPluginProcessInfo == null + || pluginProcessInfo.isTimeEqualTo( previousPluginProcessInfo ) + || pluginProcessInfo.isTimeAfter( previousPluginProcessInfo ) ); + } + + throw new IllegalStateException(); + } + + // https://www.freebsd.org/cgi/man.cgi?ps(1) + // etimes elapsed running time, in decimal integer seconds + + // http://manpages.ubuntu.com/manpages/xenial/man1/ps.1.html + // etimes elapsed time since the process was started, in seconds. + + // http://hg.openjdk.java.net/jdk7/jdk7/jdk/file/9b8c96f96a0f/test/java/lang/ProcessBuilder/Basic.java#L167 + ProcessInfo unix() + { + ProcessInfoConsumer reader = new ProcessInfoConsumer() + { + @Override + ProcessInfo consumeLine( String line, ProcessInfo previousProcessInfo ) + { + if ( !previousProcessInfo.isValid() ) + { + Matcher matcher = UNIX_CMD_OUT_PATTERN.matcher( line ); + if ( matcher.matches() ) + { + long pidUptime = fromDays( matcher ) + + fromHours( matcher ) + + fromMinutes( matcher ) + + fromSeconds( matcher ); + return ProcessInfo.unixProcessInfo( pluginPid, pidUptime ); + } + } + return previousProcessInfo; + } + }; + + return reader.execute( "/bin/sh", "-c", unixPathToPS() + " -o etime= -p " + pluginPid ); + } + + ProcessInfo windows() + { + ProcessInfoConsumer reader = new ProcessInfoConsumer() + { + private boolean hasHeader; + + @Override + ProcessInfo consumeLine( String line, ProcessInfo previousProcessInfo ) + { + if ( !previousProcessInfo.isValid() ) + { + StringTokenizer args = new StringTokenizer( line ); + if ( args.countTokens() == 1 ) + { + if ( hasHeader ) + { + String startTimestamp = args.nextToken(); + return ProcessInfo.windowsProcessInfo( pluginPid, startTimestamp ); + } + else + { + hasHeader = WMIC_CREATION_DATE.equals( args.nextToken() ); + } + } + } + return previousProcessInfo; + } + }; + String pid = String.valueOf( pluginPid ); + return reader.execute( "CMD", "/A", "/X", "/C", + "wmic process where (ProcessId=" + pid + ") get " + WMIC_CREATION_DATE + ); + } + + void destroyActiveCommands() + { + stopped = true; + for ( Process p = destroyableCommands.poll(); p != null; p = destroyableCommands.poll() ) + { + p.destroy(); + } + } + + private boolean isStopped() + { + return stopped; + } + + static String unixPathToPS() + { + return new File( "/usr/bin/ps" ).canExecute() ? "/usr/bin/ps" : "/bin/ps"; + } + + static long fromDays( Matcher matcher ) + { + String s = matcher.group( 3 ); + return s == null ? 0L : DAYS.toSeconds( parseLong( s ) ); + } + + static long fromHours( Matcher matcher ) + { + String s = matcher.group( 4 ); + return s == null ? 0L : HOURS.toSeconds( parseLong( s ) ); + } + + static long fromMinutes( Matcher matcher ) + { + String s = matcher.group( 5 ); + return s == null ? 0L : MINUTES.toSeconds( parseLong( s ) ); + } + + static long fromSeconds( Matcher matcher ) + { + String s = matcher.group( 6 ); + return s == null ? 0L : parseLong( s ); + } + + private static void checkValid( Scanner scanner ) + throws IOException + { + IOException exception = scanner.ioException(); + if ( exception != null ) + { + throw exception; + } + } + + /** + * Reads standard output from {@link Process}. + * <br> + * The artifact maven-shared-utils has non-daemon Threads which is an issue in Surefire to satisfy System.exit. + * This implementation is taylor made without using any Thread. + * It's easy to destroy Process from other Thread. + */ + private abstract class ProcessInfoConsumer + { + abstract ProcessInfo consumeLine( String line, ProcessInfo previousProcessInfo ); + + ProcessInfo execute( String... command ) + { + ProcessBuilder processBuilder = new ProcessBuilder( command ); + processBuilder.redirectErrorStream( true ); + Process process = null; + ProcessInfo processInfo = INVALID_PROCESS_INFO; + try + { + process = processBuilder.start(); + destroyableCommands.add( process ); + Scanner scanner = new Scanner( process.getInputStream() ); + while ( scanner.hasNextLine() ) + { + String line = scanner.nextLine().trim(); + processInfo = consumeLine( line, processInfo ); + } + checkValid( scanner ); + int exitCode = process.waitFor(); + return exitCode == 0 ? processInfo : INVALID_PROCESS_INFO; + } + catch ( IOException e ) + { + return ERR_PROCESS_INFO; + } + catch ( InterruptedException e ) + { + return ERR_PROCESS_INFO; + } + finally + { + if ( process != null ) + { + destroyableCommands.remove( process ); + process.destroy(); + closeQuietly( process.getInputStream() ); + closeQuietly( process.getErrorStream() ); + closeQuietly( process.getOutputStream() ); + } + } + } + } + +} http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/9354c310/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ProcessInfo.java ---------------------------------------------------------------------- diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ProcessInfo.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ProcessInfo.java new file mode 100644 index 0000000..212e221 --- /dev/null +++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ProcessInfo.java @@ -0,0 +1,109 @@ +package org.apache.maven.surefire.booter; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import static org.apache.maven.surefire.util.internal.ObjectUtils.requireNonNull; + +/** + * Immutable object which encapsulates PID and elapsed time (Unix) or start time (Windows). + * <br> + * Methods + * ({@link #getPID()}, {@link #getTime()}, {@link #isTimeAfter(ProcessInfo)}, {@link #isTimeEqualTo(ProcessInfo)}) + * throw {@link IllegalStateException} + * if {@link #isValid()} returns {@code false} or {@link #isError()} returns {@code true}. + * + * @author <a href="mailto:[email protected]">Tibor Digana (tibor17)</a> + * @since 2.20.1 + */ +final class ProcessInfo +{ + static final ProcessInfo INVALID_PROCESS_INFO = new ProcessInfo( null, null ); + static final ProcessInfo ERR_PROCESS_INFO = new ProcessInfo( null, null ); + + /** + * On Unix we do not get PID due to the command is interested only to etime of PPID: + * <br> + * <pre>/bin/ps -o etime= -p 123</pre> + */ + static ProcessInfo unixProcessInfo( long pid, long etime ) + { + return new ProcessInfo( pid, etime ); + } + + static ProcessInfo windowsProcessInfo( long pid, String startTimestamp ) + { + return new ProcessInfo( pid, requireNonNull( startTimestamp, "startTimestamp is NULL" ) ); + } + + private final Long pid; + private final Comparable time; + + private ProcessInfo( Long pid, Comparable time ) + { + this.pid = pid; + this.time = time; + } + + boolean isValid() + { + return this != INVALID_PROCESS_INFO; + } + + boolean isError() + { + return this == ERR_PROCESS_INFO; + } + + long getPID() + { + checkValid(); + return pid; + } + + Comparable getTime() + { + checkValid(); + return time; + } + + @SuppressWarnings( "unchecked" ) + boolean isTimeEqualTo( ProcessInfo that ) + { + checkValid(); + that.checkValid(); + return this.time.compareTo( that.time ) == 0; + } + + @SuppressWarnings( "unchecked" ) + boolean isTimeAfter( ProcessInfo that ) + { + checkValid(); + that.checkValid(); + return this.time.compareTo( that.time ) > 0; + } + + private void checkValid() + { + if ( !isValid() || isError() ) + { + throw new IllegalStateException( "invalid process info" ); + } + } +} http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/9354c310/surefire-booter/src/main/java/org/apache/maven/surefire/booter/PropertiesWrapper.java ---------------------------------------------------------------------- diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/PropertiesWrapper.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/PropertiesWrapper.java index 41b4850..d94be71 100644 --- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/PropertiesWrapper.java +++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/PropertiesWrapper.java @@ -70,6 +70,12 @@ public class PropertiesWrapper return Integer.parseInt( properties.get( propertyName ) ); } + public Long getLongProperty( String propertyName ) + { + String number = getProperty( propertyName ); + return number == null ? null : Long.parseLong( number ); + } + public File getFileProperty( String key ) { final String property = getProperty( key ); http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/9354c310/surefire-booter/src/main/java/org/apache/maven/surefire/booter/SystemUtils.java ---------------------------------------------------------------------- diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/SystemUtils.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/SystemUtils.java new file mode 100644 index 0000000..75f7fac --- /dev/null +++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/SystemUtils.java @@ -0,0 +1,180 @@ +package org.apache.maven.surefire.booter; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.maven.surefire.util.ReflectionUtils; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.lang.management.ManagementFactory; +import java.lang.reflect.Method; + +import static java.lang.Thread.currentThread; +import static org.apache.commons.lang3.JavaVersion.JAVA_9; +import static org.apache.commons.lang3.JavaVersion.JAVA_RECENT; +import static org.apache.commons.lang3.SystemUtils.IS_OS_FREE_BSD; +import static org.apache.commons.lang3.SystemUtils.IS_OS_LINUX; +import static org.apache.commons.lang3.SystemUtils.IS_OS_NET_BSD; +import static org.apache.commons.lang3.SystemUtils.IS_OS_OPEN_BSD; +import static org.apache.maven.surefire.util.ReflectionUtils.invokeMethodChain; +import static org.apache.maven.surefire.util.ReflectionUtils.tryLoadClass; + +/** + * JDK 9 support. + * + * @author <a href="mailto:[email protected]">Tibor Digana (tibor17)</a> + * @since 2.20.1 + */ +public final class SystemUtils +{ + private static final int PROC_STATUS_PID_FIRST_CHARS = 20; + + public SystemUtils() + { + throw new IllegalStateException( "no instantiable constructor" ); + } + + public static ClassLoader platformClassLoader() + { + if ( JAVA_RECENT.atLeast( JAVA_9 ) ) + { + return reflectClassLoader( ClassLoader.class, "getPlatformClassLoader" ); + } + return null; + } + + public static Long pid() + { + if ( JAVA_RECENT.atLeast( JAVA_9 ) ) + { + Long pid = pidOnJava9(); + if ( pid != null ) + { + return pid; + } + } + + if ( IS_OS_LINUX ) + { + try + { + return pidStatusOnLinux(); + } + catch ( Exception e ) + { + // examine PID via JMX + } + } + else if ( IS_OS_FREE_BSD || IS_OS_NET_BSD || IS_OS_OPEN_BSD ) + { + try + { + return pidStatusOnBSD(); + } + catch ( Exception e ) + { + // examine PID via JMX + } + } + + return pidOnJMX(); + } + + static Long pidOnJMX() + { + String processName = ManagementFactory.getRuntimeMXBean().getName(); + if ( processName.contains( "@" ) ) + { + String pid = processName.substring( 0, processName.indexOf( '@' ) ).trim(); + try + { + return Long.parseLong( pid ); + } + catch ( NumberFormatException e ) + { + return null; + } + } + + return null; + } + + static Long pidStatusOnLinux() throws Exception + { + FileReader input = new FileReader( "/proc/self/stat" ); + try + { + // Reading and encoding 20 characters is bit faster than whole line. + // size of (long) = 19, + 1 space + char[] buffer = new char[PROC_STATUS_PID_FIRST_CHARS]; + String startLine = new String( buffer, 0, input.read( buffer ) ); + return Long.parseLong( startLine.substring( 0, startLine.indexOf( ' ' ) ) ); + } + finally + { + input.close(); + } + } + + /** + * The process status. This file is read-only and returns a single + * line containing multiple space-separated fields. + * See <a href="https://www.freebsd.org/cgi/man.cgi?query=procfs&sektion=5">procfs status</a> + * + * @return current PID + * @throws Exception if could not read /proc/curproc/status + */ + static Long pidStatusOnBSD() throws Exception + { + BufferedReader input = new BufferedReader( new FileReader( "/proc/curproc/status" ) ); + try + { + String line = input.readLine(); + int i1 = 1 + line.indexOf( ' ' ); + int i2 = line.indexOf( ' ', i1 ); + return Long.parseLong( line.substring( i1, i2 ) ); + } + finally + { + input.close(); + } + } + + static Long pidOnJava9() + { + ClassLoader classLoader = currentThread().getContextClassLoader(); + Class<?> processHandle = tryLoadClass( classLoader, "java.lang.ProcessHandle" ); + String[] methodChain = { "current", "pid" }; + return (Long) invokeMethodChain( processHandle, methodChain, null ); + } + + static ClassLoader reflectClassLoader( Class<?> target, String getterMethodName ) + { + try + { + Method getter = ReflectionUtils.getMethod( target, getterMethodName ); + return (ClassLoader) ReflectionUtils.invokeMethodWithArray( null, getter ); + } + catch ( RuntimeException e ) + { + return null; + } + } +} http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/9354c310/surefire-booter/src/test/java/org/apache/maven/surefire/booter/JUnit4SuiteTest.java ---------------------------------------------------------------------- diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/JUnit4SuiteTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/JUnit4SuiteTest.java index 2bdcf21..f073a8b 100644 --- a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/JUnit4SuiteTest.java +++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/JUnit4SuiteTest.java @@ -34,7 +34,9 @@ import org.junit.runners.Suite; ClasspathTest.class, CommandReaderTest.class, PropertiesWrapperTest.class, - SurefireReflectorTest.class + SurefireReflectorTest.class, + PpidCheckerTest.class, + SystemUtilsTest.class } ) @RunWith( Suite.class ) public class JUnit4SuiteTest http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/9354c310/surefire-booter/src/test/java/org/apache/maven/surefire/booter/PpidCheckerTest.java ---------------------------------------------------------------------- diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/PpidCheckerTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/PpidCheckerTest.java new file mode 100644 index 0000000..b0153ac --- /dev/null +++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/PpidCheckerTest.java @@ -0,0 +1,144 @@ +package org.apache.maven.surefire.booter; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.junit.Test; + +import java.lang.management.ManagementFactory; +import java.util.regex.Matcher; + +import static org.apache.commons.lang3.SystemUtils.IS_OS_UNIX; +import static org.apache.commons.lang3.SystemUtils.IS_OS_WINDOWS; +import static org.fest.assertions.Assertions.assertThat; +import static org.junit.Assume.assumeTrue; + +/** + * Testing {@link PpidChecker} on a platform. + * + * @author <a href="mailto:[email protected]">Tibor Digana (tibor17)</a> + * @since 2.20.1 + */ +public class PpidCheckerTest +{ + @Test + public void shouldHavePpidAsWindows() + { + assumeTrue( IS_OS_WINDOWS ); + + long expectedPid = Long.parseLong( ManagementFactory.getRuntimeMXBean().getName().split( "@" )[0].trim() ); + + PpidChecker checker = new PpidChecker( expectedPid ); + ProcessInfo processInfo = checker.windows(); + + assertThat( processInfo ) + .isNotNull(); + + assertThat( checker.canUse() ) + .isTrue(); + + assertThat( checker.isProcessAlive() ) + .isTrue(); + + assertThat( processInfo.getPID() ) + .isEqualTo( expectedPid ); + + assertThat( processInfo.getTime() ) + .isNotNull(); + } + + @Test + public void shouldHavePpidAsUnix() + { + assumeTrue( IS_OS_UNIX ); + + long expectedPid = Long.parseLong( ManagementFactory.getRuntimeMXBean().getName().split( "@" )[0].trim() ); + + PpidChecker checker = new PpidChecker( expectedPid ); + ProcessInfo processInfo = checker.unix(); + + assertThat( processInfo ) + .isNotNull(); + + assertThat( checker.canUse() ) + .isTrue(); + + assertThat( checker.isProcessAlive() ) + .isTrue(); + + assertThat( processInfo.getPID() ) + .isEqualTo( expectedPid ); + + assertThat( processInfo.getTime() ) + .isNotNull(); + } + + @Test + public void shouldNotFindSuchPID() + { + PpidChecker checker = new PpidChecker( 1000000L ); + assertThat( checker.canUse() ) + .isTrue(); + + boolean isAlive = checker.isProcessAlive(); + + assertThat( isAlive ) + .isFalse(); + } + + @Test + public void shouldParseEtime() + { + Matcher m = PpidChecker.UNIX_CMD_OUT_PATTERN.matcher( "38" ); + assertThat( m.matches() ) + .isFalse(); + + m = PpidChecker.UNIX_CMD_OUT_PATTERN.matcher( "05:38" ); + assertThat( m.matches() ) + .isTrue(); + assertThat( PpidChecker.fromDays( m ) ).isEqualTo( 0L ); + assertThat( PpidChecker.fromHours( m ) ).isEqualTo( 0L ); + assertThat( PpidChecker.fromMinutes( m ) ).isEqualTo( 300L ); + assertThat( PpidChecker.fromSeconds( m ) ).isEqualTo( 38L ); + + m = PpidChecker.UNIX_CMD_OUT_PATTERN.matcher( "00:05:38" ); + assertThat( m.matches() ) + .isTrue(); + assertThat( PpidChecker.fromDays( m ) ).isEqualTo( 0L ); + assertThat( PpidChecker.fromHours( m ) ).isEqualTo( 0L ); + assertThat( PpidChecker.fromMinutes( m ) ).isEqualTo( 300L ); + assertThat( PpidChecker.fromSeconds( m ) ).isEqualTo( 38L ); + + m = PpidChecker.UNIX_CMD_OUT_PATTERN.matcher( "01:05:38" ); + assertThat( m.matches() ) + .isTrue(); + assertThat( PpidChecker.fromDays( m ) ).isEqualTo( 0L ); + assertThat( PpidChecker.fromHours( m ) ).isEqualTo( 3600L ); + assertThat( PpidChecker.fromMinutes( m ) ).isEqualTo( 300L ); + assertThat( PpidChecker.fromSeconds( m ) ).isEqualTo( 38L ); + + m = PpidChecker.UNIX_CMD_OUT_PATTERN.matcher( "02-01:05:38" ); + assertThat( m.matches() ) + .isTrue(); + assertThat( PpidChecker.fromDays( m ) ).isEqualTo( 2 * 24 * 3600L ); + assertThat( PpidChecker.fromHours( m ) ).isEqualTo( 3600L ); + assertThat( PpidChecker.fromMinutes( m ) ).isEqualTo( 300L ); + assertThat( PpidChecker.fromSeconds( m ) ).isEqualTo( 38L ); + } +} http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/9354c310/surefire-booter/src/test/java/org/apache/maven/surefire/booter/SystemUtilsTest.java ---------------------------------------------------------------------- diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/SystemUtilsTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/SystemUtilsTest.java new file mode 100644 index 0000000..12aff99 --- /dev/null +++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/SystemUtilsTest.java @@ -0,0 +1,131 @@ +package org.apache.maven.surefire.booter; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.junit.Test; + +import java.lang.management.ManagementFactory; + +import static org.apache.commons.lang3.JavaVersion.JAVA_9; +import static org.apache.commons.lang3.JavaVersion.JAVA_RECENT; +import static org.apache.commons.lang3.SystemUtils.IS_OS_FREE_BSD; +import static org.apache.commons.lang3.SystemUtils.IS_OS_LINUX; +import static org.apache.commons.lang3.SystemUtils.IS_OS_NET_BSD; +import static org.apache.commons.lang3.SystemUtils.IS_OS_OPEN_BSD; +import static org.fest.assertions.Assertions.assertThat; +import static org.junit.Assume.assumeTrue; + +/** + * Test of {@link SystemUtils}. + * + * @author <a href="mailto:[email protected]">Tibor Digana (tibor17)</a> + * @since 2.20.1 + */ +public class SystemUtilsTest +{ + @Test + public void shouldBePlatformClassLoader() + { + ClassLoader cl = SystemUtils.platformClassLoader(); + if ( JAVA_RECENT.atLeast( JAVA_9 ) ) + { + assertThat( cl ).isNotNull(); + } + else + { + assertThat( cl ).isNull(); + } + } + + @Test + public void shouldNotFindClassLoader() + { + ClassLoader cl = SystemUtils.reflectClassLoader( getClass(), "_getPlatformClassLoader_" ); + assertThat( cl ).isNull(); + } + + @Test + public void shouldFindClassLoader() + { + ClassLoader cl = SystemUtils.reflectClassLoader( getClass(), "getPlatformClassLoader" ); + assertThat( cl ).isSameAs( ClassLoader.getSystemClassLoader() ); + } + + @Test + public void shouldBePidOnJigsaw() + { + assumeTrue( JAVA_RECENT.atLeast( JAVA_9 ) ); + + Long actualPid = SystemUtils.pidOnJava9(); + String expectedPid = ManagementFactory.getRuntimeMXBean().getName().split( "@" )[0].trim(); + + assertThat( actualPid + "" ) + .isEqualTo( expectedPid ); + } + + @Test + public void shouldBePidStatusOnLinux() throws Exception + { + assumeTrue( IS_OS_LINUX ); + + Long actualPid = SystemUtils.pidStatusOnLinux(); + String expectedPid = ManagementFactory.getRuntimeMXBean().getName().split( "@" )[0].trim(); + + assertThat( actualPid + "" ) + .isEqualTo( expectedPid ); + } + + @Test + public void shouldBePidStatusOnBSD() throws Exception + { + assumeTrue( IS_OS_FREE_BSD || IS_OS_NET_BSD || IS_OS_OPEN_BSD ); + + Long actualPid = SystemUtils.pidStatusOnBSD(); + String expectedPid = ManagementFactory.getRuntimeMXBean().getName().split( "@" )[0].trim(); + + assertThat( actualPid + "" ) + .isEqualTo( expectedPid ); + } + + @Test + public void shouldBePidOnJMX() + { + Long actualPid = SystemUtils.pidOnJMX(); + String expectedPid = ManagementFactory.getRuntimeMXBean().getName().split( "@" )[0].trim(); + + assertThat( actualPid + "" ) + .isEqualTo( expectedPid ); + } + + @Test + public void shouldBePid() + { + Long actualPid = SystemUtils.pid(); + String expectedPid = ManagementFactory.getRuntimeMXBean().getName().split( "@" )[0].trim(); + + assertThat( actualPid + "" ) + .isEqualTo( expectedPid ); + } + + public static ClassLoader getPlatformClassLoader() + { + return ClassLoader.getSystemClassLoader(); + } +} http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/9354c310/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1295AttributeJvmCrashesToTestsIT.java ---------------------------------------------------------------------- diff --git a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1295AttributeJvmCrashesToTestsIT.java b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1295AttributeJvmCrashesToTestsIT.java index 1fa88f6..f051c1c 100644 --- a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1295AttributeJvmCrashesToTestsIT.java +++ b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1295AttributeJvmCrashesToTestsIT.java @@ -27,8 +27,9 @@ import org.junit.Before; import org.junit.Test; import java.util.Iterator; -import java.util.Locale; +import static org.apache.commons.lang.SystemUtils.IS_OS_LINUX; +import static org.apache.commons.lang.SystemUtils.IS_OS_MAC_OSX; import static org.fest.assertions.Assertions.assertThat; import static org.junit.Assert.fail; import static org.junit.Assume.assumeTrue; @@ -46,8 +47,7 @@ public class Surefire1295AttributeJvmCrashesToTestsIT @Before public void skipWindows() { - String os = System.getProperty( "os.name" ).toLowerCase( Locale.ROOT ); - assumeTrue( os.equals( "mac os x" ) || os.equals( "linux" ) /*|| os.contains( "windows" )*/ ); + assumeTrue( IS_OS_LINUX || IS_OS_MAC_OSX ); } @Test
