diff --git a/src/main/java/org/kiwiproject/base/DefaultEnvironment.java b/src/main/java/org/kiwiproject/base/DefaultEnvironment.java index 6cec09ec..2e1fa2c6 100644 --- a/src/main/java/org/kiwiproject/base/DefaultEnvironment.java +++ b/src/main/java/org/kiwiproject/base/DefaultEnvironment.java @@ -14,6 +14,7 @@ import java.time.ZonedDateTime; import java.util.Date; import java.util.Map; +import java.util.Optional; import java.util.OptionalLong; import java.util.Properties; import java.util.concurrent.TimeUnit; @@ -143,6 +144,11 @@ public ProcessHandle currentProcessHandle() { return ProcessHandle.current(); } + @Override + public Optional processHandleOfPid(long pid) { + return ProcessHandle.of(pid); + } + @Override public void sleep(long milliseconds) throws InterruptedException { Thread.sleep(milliseconds); diff --git a/src/main/java/org/kiwiproject/base/KiwiEnvironment.java b/src/main/java/org/kiwiproject/base/KiwiEnvironment.java index dacf876f..755847c4 100644 --- a/src/main/java/org/kiwiproject/base/KiwiEnvironment.java +++ b/src/main/java/org/kiwiproject/base/KiwiEnvironment.java @@ -11,6 +11,7 @@ import java.time.ZonedDateTime; import java.util.Date; import java.util.Map; +import java.util.Optional; import java.util.OptionalLong; import java.util.Properties; import java.util.concurrent.TimeUnit; @@ -189,6 +190,19 @@ public interface KiwiEnvironment { */ ProcessHandle currentProcessHandle(); + /** + * Tries to obtain a {@link ProcessHandle} for a process with the given ID. If the process does not exist, then + * an empty Optional is returned. + * + * @param pid the process ID + * @return an Optional containing a ProcessHandle for the given process ID, or an empty Optional if the process + * does not exist + * @see ProcessHandle#of(long) + * @implNote Implementations may throw the same exceptions as {@link ProcessHandle#of(long)}, but are not required + * to do so. + */ + Optional processHandleOfPid(long pid); + /** * Sleep for the given number of milliseconds. * diff --git a/src/test/java/org/kiwiproject/base/DefaultEnvironmentTest.java b/src/test/java/org/kiwiproject/base/DefaultEnvironmentTest.java index c236ec73..5fac1059 100644 --- a/src/test/java/org/kiwiproject/base/DefaultEnvironmentTest.java +++ b/src/test/java/org/kiwiproject/base/DefaultEnvironmentTest.java @@ -3,6 +3,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatCode; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assumptions.assumeTrue; +import static org.kiwiproject.base.KiwiStrings.format; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; @@ -13,6 +15,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.RepeatedTest; import org.junit.jupiter.api.Test; import org.kiwiproject.collect.KiwiMaps; @@ -30,6 +33,7 @@ import java.util.Map; import java.util.Properties; import java.util.Set; +import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; @DisplayName("DefaultKiwiEnvironment") @@ -263,6 +267,27 @@ void shouldAllowUnsupportedExceptionsToEscape() { } } + @Nested + class ProcessHandleOfPid { + + @Test + void shouldReturnProcessHandle_ForAnExistingProcess() { + var pid = ProcessHandle.current().pid(); + var processHandle = env.processHandleOfPid(pid).orElseThrow(); + assertThat(processHandle).isEqualTo(ProcessHandle.current()); + } + + @RepeatedTest(5) + void shouldReturnEmptyOptional_WhenProcessDoesNotExist() { + // use a range for pids that should never exist + var randomPid = ThreadLocalRandom.current().nextLong(100_000, 200_001); + assumeTrue(ProcessHandle.of(randomPid).isEmpty(), + () -> format("Expected process having pid {} not to exist, but it does", randomPid)); + + assertThat(env.processHandleOfPid(randomPid)).isEmpty(); + } + } + @Test void testSleep() throws InterruptedException { long sleepTime = 50; @@ -429,4 +454,4 @@ void testGetProperties() { assertThat(props).isEqualTo(System.getProperties()); } -} \ No newline at end of file +}