Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix build_mock_url() for requests with multipart body with string and raw values #40

Merged
merged 7 commits into from
Jun 19, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# httptest2 1.1.0.9000

* `build_mock_url()` now works with multipart body request containing character strings or raw data (#40, @jmaspons)

# httptest2 1.1.0

* `request` is now removed when saving `httr2_response` objects. In earlier versions of `httr2`, requests were not included in responses, but in httr2 1.0.0, [they were added](https://github.com/r-lib/httr2/pull/359) in order to improve error messages. *If you recorded any responses with httr2 >= 1.0 and httptest2 prior to this version, you may have leaked auth secrets: this would happen if your requests included auth information (as in an `Authentication` header), and the response was saved in a .R file, not simplified to .json or other response-body-only formats. Please inspect your recorded responses and invalidate any tokens that were exposed.*
Expand Down Expand Up @@ -38,4 +40,4 @@ Changes to function signatures:

* The `path` argument to `capture_requests()` and `start_capturing()` has been removed; instead set the mock path explicitly with `.mockPaths()` or use `with_mock_dir()`.
* Internal function `save_response()` requires a `file` path argument because `httr2_response` objects do not contain their `request`, which is needed to construct the mock file path
* Internal function `build_mock_url()` no longer accepts a string URL as an input; it only accepts `request` objects
* Internal function `build_mock_url()` no longer accepts a string URL as an input; it only accepts `request` objects
6 changes: 4 additions & 2 deletions R/build-mock-url.R
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,11 @@ get_string_request_body <- function(req) {
if (inherits(x, "form_file")) {
# hash the file contents
paste("File:", digest(x$path, serialize = FALSE, file = TRUE))
} else {
# assume form_data
} else if (inherits(x, "form_data")) {
rawToChar(x$value)
} else {
# assume character string or raw
x
}
})
b <- paste(c(
Expand Down
23 changes: 23 additions & 0 deletions tests/testthat/test-capture-requests.R
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
d <- tempfile()
dl_file <- tempfile()
webp_file <- tempfile()
file_path <- tempfile()
writeLines(letters[1:6], file_path)

# The webfake URL will be something like 127.0.0.1:port, and port may vary
# so the mock paths will be different every time it runs
Expand Down Expand Up @@ -31,6 +33,15 @@ test_that("We can record a series of requests (a few ways)", {
req_perform(path = webp_file)
r8 <<- request(httpbin$url("/status/202")) %>% req_perform()
r9 <<- request(httpbin$url("/status/200")) %>% req_perform()
r10 <<- request(httpbin$url("/post")) %>%
req_body_multipart(
file = curl::form_file(file_path),
string = "some text",
form_data = curl::form_data("form data"),
raw_data = charToRaw("raw data")
) %>%
req_method("POST") %>%
req_perform()
stop_capturing()
})

Expand All @@ -41,13 +52,15 @@ test_that("We can record a series of requests (a few ways)", {
"httpbin.org/get.json",
"httpbin.org/image/webp.R", # Not a simplifiable format, so .R
"httpbin.org/image/webp.R-FILE", # The `write_disk` location
"httpbin.org/post-4f024d-POST.json",
"httpbin.org/put-PUT.json", # Not a GET, but returns 200
"httpbin.org/response-headers-ac4928.json",
"httpbin.org/status/200.txt", # empty 200 response "text/plain", so .txt
"httpbin.org/status/202.R", # Not 200 response, so .R
"httpbin.org/status/418.R" # Not 200 response, so .R
)
# But since we don't use httpbin anymore, they're in the localhost-port dir
skip_on_os("windows") # TODO: remove after #42 is fixed
expected_files <- sub("httpbin.org", httpbin_mock_url, expected_files)
expect_identical(sort(dir(d, recursive = TRUE)), expected_files)

Expand Down Expand Up @@ -94,6 +107,15 @@ test_that("We can then load the mocks it stores", {
req_perform(path = mock_webp_file)
m8 <- request(httpbin$url("/status/202")) %>% req_perform()
m9 <- request(httpbin$url("/status/200")) %>% req_perform()
m10 <- request(httpbin$url("/post")) %>%
req_body_multipart(
file = curl::form_file(file_path),
string = "some text",
form_data = curl::form_data("form data"),
raw_data = charToRaw("raw data")
) %>%
req_method("POST") %>%
req_perform()
})
})
expect_identical(resp_body_json(m1), resp_body_json(r1))
Expand All @@ -114,6 +136,7 @@ test_that("We can then load the mocks it stores", {
expect_equal(resp_status(m9), 200)
expect_equal(resp_content_type(m9), "text/plain")
expect_false(resp_has_body(m9))
expect_identical(resp_body_json(m10), resp_body_json(r10))
})

test_that("write_disk mocks can be reloaded even if the mock directory moves", {
Expand Down
Loading