test_that("create self process", {
expect_error(ps_handle("foobar"), class = "invalid_argument")
expect_error(ps_handle(time = 123), class = "invalid_argument")
ps <- ps_handle()
expect_identical(ps_pid(ps), Sys.getpid())
})
test_that("format", {
ps <- ps_handle()
expect_match(format(ps), format_regexp())
})
test_that("print", {
ps <- ps_handle()
expect_output(print(ps), format_regexp())
})
test_that("pid", {
## Argument check
expect_error(ps_pid(123), class = "invalid_argument")
## Self
ps <- ps_handle()
expect_identical(ps_pid(ps), Sys.getpid())
## Child
p1 <- processx::process$new(px(), c("sleep", "10"))
on.exit(p1$kill(), add = TRUE)
ps <- ps_handle(p1$get_pid())
expect_identical(ps_pid(ps), p1$get_pid())
skip_if_no_processx()
## Even if it has quit already
p2 <- processx::process$new(px(), c("sleep", "10"))
on.exit(p2$kill(), add = TRUE)
pid2 <- p2$get_pid()
ps <- ps_handle(pid2)
p2$kill()
expect_false(p2$is_alive())
expect_identical(ps_pid(ps), pid2)
})
test_that("create_time", {
## Argument check
expect_error(ps_create_time(123), class = "invalid_argument")
skip_if_no_processx()
p1 <- processx::process$new(px(), c("sleep", "10"))
on.exit(p1$kill(), add = TRUE)
ps <- ps_handle(p1$get_pid())
expect_identical(p1$get_start_time(), ps_create_time(ps))
})
test_that("is_running", {
## Argument check
expect_error(ps_is_running(123), class = "invalid_argument")
p1 <- processx::process$new(px(), c("sleep", "10"))
on.exit(p1$kill(), add = TRUE)
ps <- ps_handle(p1$get_pid())
expect_true(ps_is_running(ps))
p1$kill()
timeout <- Sys.time() + 5
while (ps_is_running(ps) && Sys.time() < timeout) Sys.sleep(0.05)
expect_false(ps_is_running(ps))
})
test_that("parent", {
## Argument check
expect_error(ps_parent(123), class = "invalid_argument")
p1 <- processx::process$new(px(), c("sleep", "10"))
on.exit(p1$kill(), add = TRUE)
ps <- ps_handle(p1$get_pid())
expect_true(ps_is_running(ps))
pp <- ps_parent(ps)
expect_equal(ps_pid(pp), Sys.getpid())
})
test_that("ppid", {
## Argument check
expect_error(ps_ppid(123), class = "invalid_argument")
p1 <- processx::process$new(px(), c("sleep", "10"))
on.exit(p1$kill(), add = TRUE)
ps <- ps_handle(p1$get_pid())
expect_true(ps_is_running(ps))
expect_equal(ps_ppid(ps), Sys.getpid())
})
test_that("name", {
## Argument check
expect_error(ps_name(123), class = "invalid_argument")
skip_if_no_processx()
p1 <- processx::process$new(px(), c("sleep", "10"))
on.exit(p1$kill(), add = TRUE)
ps <- ps_handle(p1$get_pid())
expect_true(ps_is_running(ps))
expect_true(ps_name(ps) %in% c("px", "px.exe"))
## Long names are not truncated
file.copy(
px(),
tmp <- paste0(tempfile(pattern = "file1234567890123456"), ".bat"))
on.exit(unlink(tmp), add = TRUE)
Sys.chmod(tmp, "0755")
p2 <- processx::process$new(tmp, c("sleep", "10"))
on.exit(p2$kill(), add = TRUE)
ps <- ps_handle(p2$get_pid())
expect_true(ps_is_running(ps))
expect_equal(ps_name(ps), basename(tmp))
})
test_that("exe", {
## Argument check
expect_error(ps_exe(123), class = "invalid_argument")
p1 <- processx::process$new(px(), c("sleep", "10"))
on.exit(p1$kill(), add = TRUE)
ps <- ps_handle(p1$get_pid())
expect_true(ps_is_running(ps))
exe <- ps_exe(ps)
# In qemu the first entry is qemu, the second entry is the exe
if (!grepl("qemu", exe)) {
expect_equal(ps_exe(ps), realpath(px()))
}
})
test_that("cmdline", {
## Argument check
expect_error(ps_cmdline(123), class = "invalid_argument")
p1 <- processx::process$new(px(), c("sleep", "10"))
on.exit(p1$kill(), add = TRUE)
ps <- ps_handle(p1$get_pid())
expect_true(ps_is_running(ps))
cmd <- ps_cmdline(ps)
# in qemu, need to drop the first two
if (grepl("qemu", cmd[1])) {
cmd <- cmd[-(1:2)]
}
expect_equal(cmd, c(px(), "sleep", "10"))
})
test_that("cwd", {
## Argument check
expect_error(ps_cwd(123), class = "invalid_argument")
p1 <- processx::process$new(px(), c("sleep", "10"), wd = tempdir())
on.exit(p1$kill(), add = TRUE)
ps <- ps_handle(p1$get_pid())
expect_true(ps_is_running(ps))
expect_equal(normalizePath(ps_cwd(ps)), normalizePath(tempdir()))
})
test_that("environ, environ_raw", {
## Argument check
expect_error(ps_environ(123), class = "invalid_argument")
skip_if_no_processx()
rnd <- basename(tempfile())
p1 <- processx::process$new(px(), c("sleep", "10"), env = c(FOO = rnd))
on.exit(p1$kill(), add = TRUE)
ps <- ps_handle(p1$get_pid())
expect_true(ps_is_running(ps))
expect_equal(ps_environ(ps)[["FOO"]], rnd)
expect_true(paste0("FOO=", rnd) %in% ps_environ_raw(ps))
})
test_that("num_threads", {
## Argument check
expect_error(ps_num_threads(123), class = "invalid_argument")
## sleep should be single-threaded
p1 <- processx::process$new(px(), c("sleep", "10"))
on.exit(p1$kill(), add = TRUE)
ps <- ps_handle(p1$get_pid())
expect_true(ps_is_running(ps))
# This is not reliable in qemu
if (!grepl("qemu", ps_exe(ps))) {
expect_equal(ps_num_threads(ps), 1)
}
## TODO: more threads?
})
test_that("suspend, resume", {
## Argument check
expect_error(ps_suspend(123), class = "invalid_argument")
expect_error(ps_resume(123), class = "invalid_argument")
p1 <- processx::process$new(px(), c("sleep", "10"))
on.exit(p1$kill(), add = TRUE)
ps <- ps_handle(p1$get_pid())
ps_suspend(ps)
timeout <- Sys.time() + 60
while (Sys.time() < timeout && ps_status(ps) != "stopped") Sys.sleep(0.05)
expect_equal(ps_status(ps), "stopped")
expect_true(p1$is_alive())
expect_true(ps_is_running(ps))
ps_resume(ps)
timeout <- Sys.time() + 60
while (Sys.time() < timeout && ps_status(ps) == "stopped") Sys.sleep(0.05)
expect_true(ps_status(ps) %in% c("running", "sleeping"))
expect_true(p1$is_alive())
expect_true(ps_is_running(ps))
ps_kill(ps)
})
test_that("kill", {
## Argument check
expect_error(ps_kill(123), class = "invalid_argument")
p1 <- processx::process$new(px(), c("sleep", "10"))
on.exit(p1$kill(), add = TRUE)
ps <- ps_handle(p1$get_pid())
ps_kill(ps)
timeout <- Sys.time() + 5
while (Sys.time() < timeout && ps_is_running(ps)) Sys.sleep(0.05)
expect_false(p1$is_alive())
expect_false(ps_is_running(ps))
if (ps_os_type()[["POSIX"]]) {
expect_equal(p1$get_exit_status(), - signals()$SIGTERM)
}
})
test_that("children", {
## Argument check
expect_error(ps_children(123), class = "invalid_argument")
## This fails on CRAN, and I cannot reproduce it anywhere else
skip_on_cran()
skip_if_no_processx()
p1 <- processx::process$new(px(), c("sleep", "10"))
on.exit(p1$kill(), add = TRUE)
p2 <- processx::process$new(px(), c("sleep", "10"))
on.exit(p2$kill(), add = TRUE)
ch <- ps_children(ps_handle())
expect_true(length(ch) >= 2)
pids <- map_int(ch, ps_pid)
expect_true(p1$get_pid() %in% pids)
expect_true(p2$get_pid() %in% pids)
## We don't do this on Windows, because the parent process might be
## gone by now, and then it fails with no_such_process
if (ps_os_type()[["POSIX"]]) {
ch3 <- ps_children(ps_parent(ps_handle()), recursive = TRUE)
pids3 <- map_int(ch3, ps_pid)
expect_true(Sys.getpid() %in% pids3)
expect_true(p1$get_pid() %in% pids3)
expect_true(p2$get_pid() %in% pids3)
}
})
test_that("num_fds", {
skip_in_rstudio()
skip_on_cran()
tmp <- tempfile()
on.exit(unlink(tmp), add = TRUE)
me <- ps_handle()
orig <- ps_num_fds(me)
f <- file(tmp, open = "w")
on.exit(close(f), add = TRUE)
expect_equal(ps_num_fds(me), orig + 1)
})
test_that("open_files", {
skip_in_rstudio()
skip_on_cran()
tmp <- tempfile()
on.exit(unlink(tmp), add = TRUE)
f <- file(tmp, open = "w")
on.exit(try(close(f), silent = TRUE), add = TRUE)
files <- ps_open_files(ps_handle())
expect_true(basename(tmp) %in% basename(files$path))
close(f)
files <- ps_open_files(ps_handle())
expect_false(basename(tmp) %in% basename(files$path))
})
test_that("interrupt", {
skip_on_cran()
px <- processx::process$new(px(), c("sleep", "10"))
on.exit(px$kill(), add = TRUE)
ps <- ps_handle(px$get_pid())
expect_true(ps_is_running(ps))
ps_interrupt(ps)
deadline <- Sys.time() + 3
while (ps_is_running(ps) && Sys.time() < deadline) Sys.sleep(0.05)
expect_true(Sys.time() < deadline)
expect_false(ps_is_running(ps))
if (ps_os_type()[["POSIX"]]) expect_equal(px$get_exit_status(), -2)
})
test_that("cpu affinity", {
skip_on_cran()
skip_on_covr()
skip_on_os("mac")
orig <- ps::ps_get_cpu_affinity()
expect_true(length(orig) <= ps::ps_cpu_count())
do <- function() {
ps::ps_set_cpu_affinity(affinity = 0:0)
ps::ps_get_cpu_affinity()
}
expect_equal(callr::r(do), 0:0)
})
test_that("kill 2", {
skip_on_cran()
p <- processx::process$new(px(), c("sleep", "3"))
on.exit(p$kill(), add = TRUE)
ph <- p$as_ps_handle()
done <- if (ps_os_type()[["WINDOWS"]]) "killed" else "terminated"
expect_equal(ps_kill(ph), done)
expect_equal(ps_kill(ph), "dead")
# multiple processes
p1 <- processx::process$new(px(), c("sleep", "3"))
on.exit(p1$kill(), add = TRUE)
ph1 <- p1$as_ps_handle()
p2 <- processx::process$new(px(), c("sleep", "3"))
on.exit(p2$kill(), add = TRUE)
ph2 <- p2$as_ps_handle()
expect_equal(ps_kill(list(ph1, ph2)), c(done, done))
expect_equal(ps_kill(list(ph1, ph2)), c("dead", "dead"))
# some dead, some alive
p3 <- processx::process$new(px(), c("sleep", "3"))
on.exit(p3$kill(), add = TRUE)
ph3 <- p3$as_ps_handle()
p4 <- processx::process$new(px(), c("sleep", "3"))
on.exit(p4$kill(), add = TRUE)
ph4 <- p4$as_ps_handle()
expect_equal(ps_kill(ph3), done)
expect_equal(ps_kill(list(ph3, ph4)), c("dead", done))
# error up front for pid 0
if (ps_os_type()[["MACOS"]]) {
p5 <- processx::process$new(px(), c("sleep", "3"))
on.exit(p5$kill(), add = TRUE)
ph5 <- p5$as_ps_handle()
ph6 <- ps_handle(0)
expect_snapshot(error = TRUE, {
ps_kill(list(ph5, ph6))
})
expect_true(p5$is_alive())
p5$kill()
}
# access denied for some processes
if (ps_os_type()[["MACOS"]]) {
p7 <- processx::process$new(px(), c("sleep", "3"))
on.exit(p7$kill(), add = TRUE)
ph7 <- p7$as_ps_handle()
ph8 <- ps_handle(1)
p9 <- processx::process$new(px(), c("sleep", "3"))
on.exit(p9$kill(), add = TRUE)
ph9 <- p9$as_ps_handle()
expect_snapshot(error = TRUE, {
ps_kill(list(ph7, ph8, ph9))
})
expect_false(p7$is_alive())
expect_true(ps_is_running(ph8))
expect_false(p9$is_alive())
}
})
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.