Skip to content

Commit 3657320

Browse files
authored
req_promise() improvements (#639)
Add verbosity argument and improve argument checking (doing it all eagerly). Extract helper out into helper file.
1 parent 0ee28a6 commit 3657320

File tree

6 files changed

+114
-35
lines changed

6 files changed

+114
-35
lines changed

NEWS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747

4848
* `req_perform_connection()` gains a `verbosity` argument, which is useful for
4949
understanding exactly how data is streamed back to you (#599).
50+
`req_perform_promise()` also gains a `verbosity` argument.
5051

5152
* `req_url_query()` can control how spaces are encoded with `.space` (#432).
5253

R/req-promise.R

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,13 @@
6969
#' }
7070
req_perform_promise <- function(req,
7171
path = NULL,
72-
pool = NULL) {
72+
pool = NULL,
73+
verbosity = NULL) {
7374
check_installed(c("promises", "later"))
75+
76+
check_request(req)
7477
check_string(path, allow_null = TRUE)
78+
verbosity <- verbosity %||% httr2_verbosity()
7579

7680
if (missing(pool)) {
7781
if (!identical(later::current_loop(), later::global_loop())) {
@@ -80,7 +84,14 @@ req_perform_promise <- function(req,
8084
i = "Do you need {.code pool = curl::new_pool()}?"
8185
))
8286
}
83-
}
87+
} else {
88+
if (!is.null(pool) && !inherits(pool, "curl_multi")) {
89+
stop_input_type(pool, "a {curl} pool", allow_null = TRUE)
90+
}
91+
}
92+
# verbosity checked by req_verbosity
93+
94+
req <- req_verbosity(req, verbosity)
8495

8596
promises::promise(
8697
function(resolve, reject) {

man/req_perform_promise.Rd

Lines changed: 13 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/testthat/_snaps/req-promise.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,44 @@
1+
# checks its inputs
2+
3+
Code
4+
req_perform_promise(1)
5+
Condition
6+
Error in `req_perform_promise()`:
7+
! `req` must be an HTTP request object, not the number 1.
8+
Code
9+
req_perform_promise(req, path = 1)
10+
Condition
11+
Error in `req_perform_promise()`:
12+
! `path` must be a single string or `NULL`, not the number 1.
13+
Code
14+
req_perform_promise(req, pool = "INVALID")
15+
Condition
16+
Error in `req_perform_promise()`:
17+
! `pool` must be a {curl} pool or `NULL`, not the string "INVALID".
18+
Code
19+
req_perform_promise(req, verbosity = "INVALID")
20+
Condition
21+
Error in `req_perform_promise()`:
22+
! `verbosity` must 0, 1, 2, or 3.
23+
24+
# correctly prepares request
25+
26+
Code
27+
. <- extract_promise(req_perform_promise(req, verbosity = 1))
28+
Output
29+
-> GET /get HTTP/1.1
30+
-> Host: <variable>
31+
-> User-Agent: <variable>
32+
-> Accept: */*
33+
-> Accept-Encoding: <variable>
34+
->
35+
<- HTTP/1.1 200 OK
36+
<- Date: <variable>
37+
<- Content-Type: application/json
38+
<- Content-Length: <variable>
39+
<- ETag: <variable>
40+
<-
41+
142
# req_perform_promise uses the default loop
243

344
Code

tests/testthat/helper-promise.R

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# promises package test helper
2+
extract_promise <- function(promise, timeout = 30) {
3+
promise_value <- NULL
4+
error <- NULL
5+
promises::then(
6+
promise,
7+
onFulfilled = function(value) promise_value <<- value,
8+
onRejected = function(reason) {
9+
error <<- reason
10+
}
11+
)
12+
13+
start <- Sys.time()
14+
while (!later::loop_empty()) {
15+
if (difftime(Sys.time(), start, units = "secs") > timeout) {
16+
stop("Waited too long")
17+
}
18+
later::run_now()
19+
Sys.sleep(0.01)
20+
}
21+
22+
if (!is.null(error)) {
23+
cnd_signal(error)
24+
} else
25+
promise_value
26+
}

tests/testthat/test-req-promise.R

Lines changed: 20 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,13 @@
1-
# promises package test helper
2-
extract_promise <- function(promise, timeout = 30) {
3-
promise_value <- NULL
4-
error <- NULL
5-
promises::then(
6-
promise,
7-
onFulfilled = function(value) promise_value <<- value,
8-
onRejected = function(reason) {
9-
error <<- reason
10-
}
11-
)
12-
13-
start <- Sys.time()
14-
while (!later::loop_empty()) {
15-
if (difftime(Sys.time(), start, units = "secs") > timeout) {
16-
stop("Waited too long")
17-
}
18-
later::run_now()
19-
Sys.sleep(0.01)
20-
}
21-
22-
if (!is.null(error)) {
23-
cnd_signal(error)
24-
} else
25-
promise_value
26-
}
1+
test_that("checks its inputs", {
2+
req <- request_test("/status/:status", status = 200)
3+
4+
expect_snapshot(error = TRUE, {
5+
req_perform_promise(1)
6+
req_perform_promise(req, path = 1)
7+
req_perform_promise(req, pool = "INVALID")
8+
req_perform_promise(req, verbosity = "INVALID")
9+
})
10+
})
2711

2812
test_that("returns a promise that resolves", {
2913
p1 <- req_perform_promise(request_test("/delay/:secs", secs = 0.25))
@@ -42,6 +26,16 @@ test_that("correctly prepares request", {
4226
expect_no_error(extract_promise(prom))
4327
})
4428

29+
test_that("correctly prepares request", {
30+
req <- request_test("/get")
31+
expect_snapshot(
32+
. <- extract_promise(req_perform_promise(req, verbosity = 1)),
33+
transform = function(x) {
34+
gsub("(Date|Host|User-Agent|ETag|Content-Length|Accept-Encoding): .*", "\\1: <variable>", x)
35+
}
36+
)
37+
})
38+
4539
test_that("can promise to download files", {
4640
req <- request_test("/json")
4741
path <- withr::local_tempfile()
@@ -81,12 +75,6 @@ test_that("both curl and HTTP errors in promises are rejected", {
8175
),
8276
class = "httr2_failure"
8377
)
84-
expect_error(
85-
extract_promise(
86-
req_perform_promise(request_test("/status/:status", status = 200), pool = "INVALID")
87-
),
88-
'inherits\\(pool, "curl_multi"\\) is not TRUE'
89-
)
9078
})
9179

9280
test_that("req_perform_promise doesn't leave behind poller", {

0 commit comments

Comments
 (0)