diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index a808d97..89f072d 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -20,7 +20,7 @@ jobs: config: - {os: macos-latest, r: 'release'} - {os: windows-latest, r: 'release'} - - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} + # - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} # TODO: fix with issue #mrc-5693 - {os: ubuntu-latest, r: 'release'} - {os: ubuntu-latest, r: 'oldrel-1'} diff --git a/.github/workflows/build-and-push.yaml b/.github/workflows/build-and-push.yaml index f99e1a4..1b46a92 100644 --- a/.github/workflows/build-and-push.yaml +++ b/.github/workflows/build-and-push.yaml @@ -2,9 +2,9 @@ # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help on: push: - branches: [main, master] + branches: [main, master] pull_request: - branches: [main, master] + branches: [main, master] name: Build-and-push diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7c2feb7 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "editor.formatOnSave": false +} diff --git a/R/api.R b/R/api.R index 34b6e3d..a8ae7cf 100644 --- a/R/api.R +++ b/R/api.R @@ -60,16 +60,16 @@ report_list <- function(root, ref) { last_changed <- function(nm) { max(contents$modified[startsWith(contents$path, sprintf("src/%s", nm))]) } - updated_time <- vnapply(nms, last_changed, USE.NAMES = FALSE) + updatedTime <- vnapply(nms, last_changed, USE.NAMES = FALSE) modified_sources <- git_get_modified(ref, relative_dir = "src/", repo = root) modified_reports <- unique(first_dirname(modified_sources)) - has_modifications <- vlapply(nms, function(report_name) { + hasModifications <- vlapply(nms, function(report_name) { report_name %in% modified_reports }, USE.NAMES = FALSE) data.frame( name = nms, - updated_time = updated_time, - has_modifications = has_modifications + updatedTime = updatedTime, + hasModifications = hasModifications ) } @@ -102,12 +102,15 @@ submit_report_run <- function(root, queue, data) { ref = data$hash, parameters = data$parameters ) - list(task_id = scalar(task_id)) + list(taskId = scalar(task_id)) } ##' @porcelain -##' GET /report/status/ => json(report_run_status_response) +##' POST /report/status => json(report_run_status_response) ##' state queue :: queue -report_run_status <- function(queue, task_id) { - queue$get_status(task_id) +##' query include_logs :: logical +##' body data :: json(report_run_status_request) +report_run_status <- function(queue, include_logs, data) { + task_ids <- jsonlite::fromJSON(data) + queue$get_status(task_ids, include_logs) } diff --git a/R/porcelain.R b/R/porcelain.R index 2079602..c356a2e 100644 --- a/R/porcelain.R +++ b/R/porcelain.R @@ -39,11 +39,13 @@ returning = porcelain::porcelain_returning_json("report_run_response"), validate = validate) }, - "GET /report/status/" = function(state, validate) { + "POST /report/status" = function(state, validate) { porcelain::porcelain_endpoint$new( - "GET", - "/report/status/", + "POST", + "/report/status", report_run_status, + porcelain::porcelain_input_query(include_logs = "logical"), + porcelain::porcelain_input_body_json("data", "report_run_status_request"), porcelain::porcelain_state(queue = state$queue), returning = porcelain::porcelain_returning_json("report_run_status_response"), validate = validate) diff --git a/R/queue.R b/R/queue.R index 984e901..33855d8 100644 --- a/R/queue.R +++ b/R/queue.R @@ -17,7 +17,7 @@ Queue <- R6::R6Class("Queue", # nolint #' @param root Orderly root. #' @param queue_id ID of an existing queue to connect to, creates a new one #' if NULL (default NULL) - #' @param logs_dir directory to store worker logs + #' @param logs_dir directory to store worker logs initialize = function(root, queue_id = NULL, logs_dir = "logs/worker") { self$root <- root self$config <- orderly2::orderly_config(self$root) @@ -75,24 +75,29 @@ Queue <- R6::R6Class("Queue", # nolint #' @description #' Gets status of packet run #' - #' @param task_id Id of redis queue job to get status of. + #' @param task_ids Task ids to get status of. + #' @param include_logs Whether to include logs in response or not #' @return status of redis queue job - get_status = function(task_id) { - if (!rrq::rrq_task_exists(task_id, controller = self$controller)) { - porcelain::porcelain_stop("Job ID does not exist") + get_status = function(task_ids, include_logs = TRUE) { + invalid_task_ids <- task_ids[!rrq::rrq_task_exists(task_ids, controller = self$controller)] + if (length(invalid_task_ids) > 0) { + porcelain::porcelain_stop(sprintf("Job ids [%s] do not exist in the queue", paste(invalid_task_ids, collapse = ", "))) } - status <- rrq::rrq_task_status(task_id, controller = self$controller) - times <- rrq::rrq_task_times(task_id, controller = self$controller) + statuses <- rrq::rrq_task_status(task_ids, controller = self$controller) + tasks_times <- rrq::rrq_task_times(task_ids, controller = self$controller) + queuePositions <- rrq::rrq_task_position(task_ids, controller = self$controller) - list( - status = scalar(status), - queue_position = if (status == "PENDING") scalar(rrq::rrq_task_position(task_id, controller = self$controller)) else NULL, - time_queued = scalar(times[1]), - time_started = scalar(times[2]), - time_complete = scalar(times[3]), - packet_id = if (status == "COMPLETE") scalar(rrq::rrq_task_result(task_id, controller = self$controller)) else NULL, - logs = rrq::rrq_task_log(task_id, controller = self$controller) - ) + lapply(seq_along(task_ids), function(index) { + list( + status = scalar(statuses[index]), + queuePosition = if (statuses[index] == "PENDING") scalar(queuePositions[index]) else NULL, + timeQueued = scalar(tasks_times[task_ids[index], 1]), + timeStarted = scalar(tasks_times[task_ids[index], 2]), + timeComplete = scalar(tasks_times[task_ids[index], 3]), + packetId = if (statuses[index] == "COMPLETE") scalar(rrq::rrq_task_result(task_ids[index], controller = self$controller)) else NULL, + logs = if (include_logs) rrq::rrq_task_log(task_ids[index], controller = self$controller) else NULL + ) + }) }, #' @description Destroy queue diff --git a/inst/schema/report_list.json b/inst/schema/report_list.json index bc85d18..28d8753 100644 --- a/inst/schema/report_list.json +++ b/inst/schema/report_list.json @@ -5,10 +5,10 @@ "type": "object", "properties": { "name": { "type": "string" }, - "updated_time": { "type": "number" }, - "has_modifications": { "type": "boolean" } + "updatedTime": { "type": "number" }, + "hasModifications": { "type": "boolean" } }, "additionalPropertes": false, - "required": [ "name", "updated_time", "has_modifications" ] + "required": [ "name", "updatedTime", "hasModifications" ] } } diff --git a/inst/schema/report_run_response.json b/inst/schema/report_run_response.json index e0043cc..e2cfd34 100644 --- a/inst/schema/report_run_response.json +++ b/inst/schema/report_run_response.json @@ -2,10 +2,10 @@ "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "properties": { - "task_id": { + "taskId": { "type": "string" } }, - "required": ["task_id"], + "required": ["taskId"], "additionalProperties": false } diff --git a/inst/schema/report_run_status_request.json b/inst/schema/report_run_status_request.json new file mode 100644 index 0000000..c9c24dc --- /dev/null +++ b/inst/schema/report_run_status_request.json @@ -0,0 +1,7 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "array", + "items": { + "type": "string" + } +} diff --git a/inst/schema/report_run_status_response.json b/inst/schema/report_run_status_response.json index 9b4bdde..8338063 100644 --- a/inst/schema/report_run_status_response.json +++ b/inst/schema/report_run_status_response.json @@ -1,35 +1,39 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "time_queued": { - "type": "number", - "description": "time queued in UTC time." + "type": "array", + "items": { + "type": "object", + "properties": { + "timeQueued": { + "type": "number", + "description": "time queued in UTC time." + }, + "timeStarted": { + "type": ["number", "null"], + "description": "time started run in UTC time." + }, + "timeComplete": { + "type": ["number", "null"], + "description": "time completed in UTC time." + }, + "queuePosition": { + "type": ["number", "null"] + }, + "logs": { + "type": ["array", "null"], + "items": { + "type": "string" + } + }, + "status": { + "type": "string", + "enum": ["PENDING", "RUNNING","COMPLETE", "ERROR", "CANCELLED", "DIED", "TIMEOUT", "IMPOSSIBLE","DEFERRED", "MOVED"] + }, + "packetId": { + "type": ["string", "null"] + } }, - "time_started": { - "type": ["number", "null"], - "description": "time started run in UTC time." - }, - "time_complete": { - "type": ["number", "null"], - "description": "time completed in UTC time." - }, - "queue_position": { - "type": ["number", "null"] - }, - "logs": { - "type": ["array", "null"], - "items": { - "type": "string" - } - }, - "status": { - "type": "string" - }, - "packet_id": { - "type": ["string", "null"] - } - }, - "required": ["time_queued", "time_started", "queue_position", "logs", "status", "packet_id"], - "additionalProperties": false + "required": ["timeQueued", "timeStarted", "queuePosition", "logs", "status", "packetId"], + "additionalProperties": false + } } diff --git a/man/Queue.Rd b/man/Queue.Rd index e135a52..d93cd27 100644 --- a/man/Queue.Rd +++ b/man/Queue.Rd @@ -36,7 +36,7 @@ Object for managing running jobs on the redis queue \subsection{Method \code{new()}}{ Create object, read configuration and setup Redis connection. \subsection{Usage}{ -\if{html}{\out{
}}\preformatted{Queue$new(root, queue_id = NULL)}\if{html}{\out{
}} +\if{html}{\out{
}}\preformatted{Queue$new(root, queue_id = NULL, logs_dir = "logs/worker")}\if{html}{\out{
}} } \subsection{Arguments}{ @@ -46,6 +46,8 @@ Create object, read configuration and setup Redis connection. \item{\code{queue_id}}{ID of an existing queue to connect to, creates a new one if NULL (default NULL)} + +\item{\code{logs_dir}}{directory to store worker logs} } \if{html}{\out{}} } @@ -90,13 +92,15 @@ We reset hard to this ref and run the report. (default HEAD)} \subsection{Method \code{get_status()}}{ Gets status of packet run \subsection{Usage}{ -\if{html}{\out{
}}\preformatted{Queue$get_status(job_id)}\if{html}{\out{
}} +\if{html}{\out{
}}\preformatted{Queue$get_status(task_ids, include_logs = TRUE)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ -\item{\code{job_id}}{Id of redis queue job to get status of.} +\item{\code{task_ids}}{Task ids to get status of.} + +\item{\code{include_logs}}{Whether to include logs in response or not} } \if{html}{\out{
}} } diff --git a/tests/testthat/test-api.R b/tests/testthat/test-api.R index c16811e..9edb7fb 100644 --- a/tests/testthat/test-api.R +++ b/tests/testthat/test-api.R @@ -29,12 +29,11 @@ test_that("can list orderly reports", { repo$local, skip_queue_creation = TRUE ) - res <- endpoint$run(gert::git_branch(repo$local)) expect_equal(res$status_code, 200) expect_setequal(res$data$name, c("data", "parameters")) - expect_true(all(res$data$updated_time > (Sys.time() - 100))) - expect_false(all(res$data$has_modifications)) + expect_true(all(res$data$updatedTime > (Sys.time() - 100))) + expect_false(all(res$data$hasModifications)) ## Add a report on a 2nd branch gert::git_branch_create("other", repo = repo$local) @@ -56,7 +55,7 @@ test_that("can list orderly reports", { existing <- other_res$data[other_res$data$name != "parameters2", ] expect_equal(existing, res$data) expect_equal(nrow(params2), 1) - expect_true(params2$has_modifications) + expect_true(params2$hasModifications) ## We can still see all reports on main branch commits <- gert::git_log(repo = repo$local)$commit @@ -115,9 +114,9 @@ test_that("can run orderly reports", { ) res <- endpoint$run(jsonlite::toJSON(req)) - rrq::rrq_task_wait(res$data$task_id, controller = queue$controller) + rrq::rrq_task_wait(res$data$taskId, controller = queue$controller) expect_equal( - rrq::rrq_task_status(res$data$task_id, controller = queue$controller), + rrq::rrq_task_status(res$data$taskId, controller = queue$controller), "COMPLETE" ) @@ -129,9 +128,57 @@ test_that("can run orderly reports", { ) res <- endpoint$run(jsonlite::toJSON(req)) - rrq::rrq_task_wait(res$data$task_id, controller = queue$controller) + rrq::rrq_task_wait(res$data$taskId, controller = queue$controller) expect_equal( - rrq::rrq_task_status(res$data$task_id, controller = queue$controller), + rrq::rrq_task_status(res$data$taskId, controller = queue$controller), "COMPLETE" ) }) + +test_that("can get statuses of jobs", { + # run 2 jobs first and wait for finish + skip_if_no_redis() + queue_id <- "orderly.runner:bad-animal" + repo <- test_prepare_orderly_example(c("data", "parameters")) + gert::git_init(repo) + orderly2::orderly_gitignore_update("(root)", root = repo) + git_add_and_commit(repo) + queue <- Queue$new(repo, queue_id = queue_id, logs_dir = tempfile()) + worker_manager <- start_queue_workers_quietly( + 1, queue$controller + ) + make_worker_dirs(repo, worker_manager$id) + endpoint <- withr::with_envvar( + c(ORDERLY_RUNNER_QUEUE_ID = queue_id), + orderly_runner_endpoint("POST", "/report/run", repo) + ) + req <- list( + name = scalar("data"), + branch = scalar(gert::git_branch(repo = repo)), + hash = scalar(gert::git_commit_id(repo = repo)), + parameters = scalar(NULL) + ) + dat1 <- endpoint$run(jsonlite::toJSON(req)) + dat2 <- endpoint$run(jsonlite::toJSON(req)) + task_ids <- c(dat1$data$taskId, dat2$data$taskId) + rrq::rrq_task_wait(task_ids, controller = queue$controller) + + # status endpoint + endpoint <- withr::with_envvar( + c(ORDERLY_RUNNER_QUEUE_ID = queue_id), + orderly_runner_endpoint("POST", "/report/status", repo) + ) + dat <- endpoint$run(TRUE, jsonlite::toJSON(task_ids))$data + + for (i in seq_along(task_ids)) { + task_status <- dat[[i]] + task_times <- get_task_times(task_ids[[i]], queue$controller) + expect_equal(task_status$status, scalar("COMPLETE")) + expect_null(scalar(task_status$queuePosition)) + expect_equal(task_status$packetId, scalar(get_task_result(task_ids[[i]], queue$controller))) + expect_equal(scalar(task_times[1]), task_status$timeQueued) + expect_equal(scalar(task_times[2]), task_status$timeStarted) + expect_equal(scalar(task_times[3]), task_status$timeComplete) + expect_equal(get_task_logs(task_ids[[i]], queue$controller), unlist(task_status$logs)) + } +}) diff --git a/tests/testthat/test-queue.R b/tests/testthat/test-queue.R index 7b729b5..b1b1df9 100644 --- a/tests/testthat/test-queue.R +++ b/tests/testthat/test-queue.R @@ -26,9 +26,13 @@ test_that("creates directory for logs & adds to worker config", { test_that("Errors if not git repo", { root <- create_temporary_root() - expect_error(Queue$new(root), #nolint - paste("Not starting server as orderly root", - "is not version controlled.")) + expect_error( + Queue$new(root), # nolint + paste( + "Not starting server as orderly root", + "is not version controlled." + ) + ) }) @@ -126,33 +130,68 @@ test_that("Can submit 2 tasks on different commit hashes", { }) -test_that("can get status on complete report run", { +test_that("can get statuses on complete report runs with logs", { skip_if_no_redis() root <- test_prepare_orderly_example("data") git_info <- helper_add_git(root, c("src", "orderly_config.yml")) q <- start_queue_with_workers(root, 1) - task_id <- q$submit("data", branch = git_info$branch) - wait_for_task_complete(task_id, q$controller, 5) + task_id1 <- q$submit("data", branch = git_info$branch) + task_id2 <- q$submit("data", branch = git_info$branch) + task_ids <- c(task_id1, task_id2) + wait_for_task_complete(task_ids, q$controller, 5) + + statuses <- q$get_status(task_ids) + + for (i in seq_along(task_ids)) { + status <- statuses[[i]] + expect_equal(status$status, scalar("COMPLETE")) + expect_null(status$queuePosition) + expect_equal(status$packetId, scalar(get_task_result(task_ids[[i]], q$controller))) + expect_equal(status$logs, get_task_logs(task_ids[[i]], q$controller)) + } +}) - status <- q$get_status(task_id) - expect_equal(status$status, scalar("COMPLETE")) - expect_null(status$queue_position) - expect_equal(status$packet_id, scalar(get_task_result(task_id, q$controller))) - expect_equal(status$logs, get_task_logs(task_id, q$controller)) +test_that("can get statuses wihtout logs if include_logs = false", { + # run 2 reports + skip_if_no_redis() + root <- test_prepare_orderly_example("data") + git_info <- helper_add_git(root, c("src", "orderly_config.yml")) + q <- start_queue_with_workers(root, 1) + task_id1 <- q$submit("data", branch = git_info$branch) + task_id2 <- q$submit("data", branch = git_info$branch) + task_ids <- c(task_id1, task_id2) + wait_for_task_complete(task_ids, q$controller, 5) + + statuses <- q$get_status(task_ids, FALSE) + + for (i in seq_along(task_ids)) { + status <- statuses[[i]] + expect_equal(status$status, scalar("COMPLETE")) + expect_null(status$queuePosition) + expect_equal(status$packetId, scalar(get_task_result(task_ids[[i]], q$controller))) + expect_null(status$logs) + } }) test_that("can get status on pending report run", { + # run 2 reports skip_if_no_redis() root <- test_prepare_orderly_example("data") git_info <- helper_add_git(root, c("src", "orderly_config.yml")) q <- new_queue_quietly(root) - task_id <- q$submit("data", branch = git_info$branch) - - status <- q$get_status(task_id) - expect_equal(status$status, scalar("PENDING")) - expect_equal(status$queue_position, scalar(as.integer(1))) - expect_null(status$packet_id) - expect_null(status$logs) + task_id1 <- q$submit("data", branch = git_info$branch) + task_id2 <- q$submit("data", branch = git_info$branch) + task_ids <- c(task_id1, task_id2) + + statuses <- q$get_status(task_ids) + + for (i in seq_along(task_ids)) { + status <- statuses[[i]] + expect_equal(status$status, scalar("PENDING")) + expect_equal(status$queuePosition, scalar(as.integer(i))) + expect_null(status$packetId) + expect_null(status$logs) + } }) test_that("redis_host uses REDIS_CONTAINER_NAME if it exists", { root <- create_temporary_root() diff --git a/tests/testthat/test-zzz-e2e.R b/tests/testthat/test-zzz-e2e.R index 8976bfc..69d5624 100644 --- a/tests/testthat/test-zzz-e2e.R +++ b/tests/testthat/test-zzz-e2e.R @@ -7,7 +7,8 @@ root <- test_prepare_orderly_remote_example( ) queue <- start_queue_with_workers(root$local, 1, queue_id = queue_id) bg <- porcelain::porcelain_background$new( - api, args = list(root$local), + api, + args = list(root$local), env = c(ORDERLY_RUNNER_QUEUE_ID = queue_id) ) bg$start() @@ -20,17 +21,21 @@ test_that("can run server", { dat <- httr::content(r) expect_equal(dat$status, "success") expect_null(dat$errors) - expect_equal(dat$data$orderly2, - package_version_string("orderly2")) - expect_equal(dat$data$orderly.runner, - package_version_string("orderly.runner")) + expect_equal( + dat$data$orderly2, + package_version_string("orderly2") + ) + expect_equal( + dat$data$orderly.runner, + package_version_string("orderly.runner") + ) }) test_that("can list reports", { r <- bg$request("GET", "/report/list?ref=HEAD") expect_equal(httr::status_code(r), 200) - + dat <- httr::content(r) expect_equal(dat$status, "success") expect_null(dat$errors) @@ -80,12 +85,11 @@ test_that("can run report", { expect_equal(httr::status_code(r), 200) dat <- httr::content(r) - expect_equal(dat$status, "success") expect_null(dat$errors) - expect_worker_task_complete(dat$data$task_id, queue$controller, 10) - expect_type(get_task_result(dat$data$task_id, queue$controller), "character") + expect_worker_task_complete(dat$data$taskId, queue$controller, 10) + expect_type(get_task_result(dat$data$taskId, queue$controller), "character") }) test_that("can run report with params", { @@ -110,21 +114,25 @@ test_that("can run report with params", { expect_equal(dat$status, "success") expect_null(dat$errors) - expect_worker_task_complete(dat$data$task_id, queue$controller, 10) - expect_type(get_task_result(dat$data$task_id, queue$controller), "character") + expect_worker_task_complete(dat$data$taskId, queue$controller, 10) + expect_type(get_task_result(dat$data$taskId, queue$controller), "character") }) -test_that("retruns error when getting status of run with invalid task_id", { +test_that("returns error when getting status when not passing in include_logs", { res <- bg$request( - "GET", - sprintf("/report/status/bad_task_id") + "POST", + "/report/status", + body = jsonlite::toJSON(c("invalid_taskId")), + encode = "raw", + httr::content_type("application/json") ) - + errors <- httr::content(res)$errors expect_equal(httr::status_code(res), 400) - expect_equal(errors[[1]]$detail, "Job ID does not exist") + expect_equal(errors[[1]]$detail, "query parameter 'include_logs' is missing but required") }) -test_that("can get status of report run", { + +test_that("can get status of report run with logs", { # run task and wait for finish before getting status data <- list( name = "data", @@ -138,22 +146,96 @@ test_that("can get status of report run", { encode = "raw", httr::content_type("application/json") ) - task_id <- httr::content(r)$data$task_id + task_id <- httr::content(r)$data$taskId task_times <- wait_for_task_complete(task_id, queue$controller, 3) res <- bg$request( - "GET", - sprintf("/report/status/%s", task_id) + "POST", + "/report/status?include_logs=TRUE", + body = jsonlite::toJSON(c(task_id)), + encode = "raw", + httr::content_type("application/json") ) - dat <- httr::content(res)$data + dat <- httr::content(res)$data[[1]] task_times <- get_task_times(task_id, queue$controller) expect_equal(httr::status_code(res), 200) expect_equal(dat$status, "COMPLETE") - expect_null(dat$queue_positionc) - expect_equal(dat$packet_id, get_task_result(task_id, queue$controller)) - expect_equal(task_times[1], dat$time_queued) - expect_equal(task_times[2], dat$time_started) - expect_equal(task_times[3], dat$time_complete) + expect_null(dat$queuePosition) + expect_equal(dat$packetId, get_task_result(task_id, queue$controller)) + expect_equal(task_times[1], dat$timeQueued) + expect_equal(task_times[2], dat$timeStarted) + expect_equal(task_times[3], dat$timeComplete) expect_equal(get_task_logs(task_id, queue$controller), unlist(dat$logs)) }) +test_that("can get status of multiple tasks without logs", { + # run multiple tasks and wait for finish before getting status + data <- list( + name = "data", + branch = gert::git_branch(repo = root$local), + hash = gert::git_commit_id(repo = root$local), + parameters = c(NULL) + ) + r1 <- bg$request( + "POST", "/report/run", + body = jsonlite::toJSON(data, null = "null", auto_unbox = TRUE), + encode = "raw", + httr::content_type("application/json") + ) + r2 <- bg$request( + "POST", "/report/run", + body = jsonlite::toJSON(data, null = "null", auto_unbox = TRUE), + encode = "raw", + httr::content_type("application/json") + ) + task_ids <- c(httr::content(r1)$data$taskId, httr::content(r2)$data$taskId) + task_times <- wait_for_task_complete(task_ids, queue$controller, 3) + + res <- bg$request( + "POST", + "/report/status?include_logs=FALSE", + body = jsonlite::toJSON(task_ids), + encode = "raw", + httr::content_type("application/json") + ) + dat <- httr::content(res)$data + + for (i in seq_along(task_ids)) { + task_status <- dat[[i]] + task_times <- get_task_times(task_ids[[i]], queue$controller) + expect_equal(task_status$status, "COMPLETE") + expect_null(task_status$queuePosition) + expect_equal(task_status$packetId, get_task_result(task_ids[[i]], queue$controller)) + expect_equal(task_times[1], task_status$timeQueued) + expect_equal(task_times[2], task_status$timeStarted) + expect_equal(task_times[3], task_status$timeComplete) + expect_null(task_status$logs) + } +}) + +test_that("returns error with tasks ids of non-extant task ids", { + # run report + data <- list( + name = "data", + branch = gert::git_branch(repo = root$local), + hash = gert::git_commit_id(repo = root$local), + parameters = c(NULL) + ) + r1 <- bg$request( + "POST", "/report/run", + body = jsonlite::toJSON(data, null = "null", auto_unbox = TRUE), + encode = "raw", + httr::content_type("application/json") + ) + task_ids <- c(httr::content(r1)$data$taskId, "non-existant-id") + + res <- bg$request( + "POST", + "/report/status?include_logs=FALSE", + body = jsonlite::toJSON(task_ids), + encode = "raw", + httr::content_type("application/json") + ) + + expect_equal(httr::content(res)$errors[[1]]$detail , "Job ids [non-existant-id] do not exist in the queue") +})