Skip to content

Commit

Permalink
merge master changes - update curl adapter for new curl stuff
Browse files Browse the repository at this point in the history
add curl adapter tests
  • Loading branch information
sckott committed Jan 10, 2019
1 parent 802102b commit 3b05bc1
Show file tree
Hide file tree
Showing 64 changed files with 1,771 additions and 197 deletions.
1 change: 1 addition & 0 deletions .Rbuildignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ notes.md
cran-comments.md
^codemeta\.json$
revdep/
appveyor.yml
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
.Rproj.user
.Rhistory
.RData
notes.md
.DS_Store
revdep/checks.noindex
revdep/data.sqlite
revdep/library.noindex
webmockr.Rproj
.Rproj.user
9 changes: 7 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,14 @@ matrix:
env: R_CODECOV=true
- os: linux
r: devel
env: _R_CHECK_LENGTH_1_LOGIC2_=TRUE
- os: osx
osx_image: xcode7.3
r: oldrel

r_github_packages:
- jimhester/covr
r_binary_packages:
- covr
- httr

after_success:
- if [[ "${R_CODECOV}" ]]; then R -e 'covr::codecov()'; fi
Expand Down
14 changes: 8 additions & 6 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Description: Stubbing and setting expectations on 'HTTP' requests.
'HTTP' method, query parameters, request body, headers and
more. Can be used for unit tests or outside of a testing
context.
Version: 0.2.6.9100
Version: 0.3.0.9100
Authors@R: c(
person("Scott", "Chamberlain", role = c("aut", "cre"), email =
"[email protected]", comment = c(ORCID="0000-0003-1444-9135")),
Expand All @@ -17,6 +17,7 @@ URL: https://github.com/ropensci/webmockr (devel)
https://ropensci.github.io/http-testing-book/ (user manual)
BugReports: https://github.com/ropensci/webmockr/issues
LazyData: true
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
Imports:
curl,
Expand All @@ -26,14 +27,15 @@ Imports:
R6 (>= 2.1.3),
urltools (>= 1.6.0),
fauxpas,
crul (>= 0.5.2)
crul (>= 0.7.0)
Suggests:
roxygen2 (>= 6.0.1),
roxygen2 (>= 6.1.1),
testthat,
xml2,
vcr
Remotes: sckott/curl@d97134a235b4abbfb82538c55c7b8f4acd40204d
RoxygenNote: 6.0.1
vcr,
httr
RoxygenNote: 6.1.1
Remotes: sckott/curl@mocking
X-schema.org-applicationCategory: Web
X-schema.org-keywords: http, https, API, web-services, curl, mock, mocking, fakeweb, http-mocking, testing, testing-tools, tdd
X-schema.org-isPartOf: https://ropensci.org
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
YEAR: 2018
YEAR: 2019
COPYRIGHT HOLDER: Scott Chamberlain
5 changes: 5 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export(CurlAdapter)
export(HashCounter)
export(HeadersPattern)
export(HttpLibAdapaterRegistry)
export(HttrAdapter)
export(MethodPattern)
export(RequestPattern)
export(RequestRegistry)
Expand All @@ -20,9 +21,13 @@ export(build_crul_request)
export(build_crul_response)
export(build_curl_request)
export(build_curl_response)
export(build_httr_request)
export(build_httr_response)
export(curl_mock)
export(disable)
export(enable)
export(enabled)
export(httr_mock)
export(remove_request_stub)
export(request_registry)
export(stub_registry)
Expand Down
35 changes: 35 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,38 @@
webmockr 0.3.0
==============

### MINOR IMPROVEMENTS

* returned mocked response headers were retaining case that the user gave - whereas they should be all lowercased to match the output in `crul` and `httr`. now fixed. (#49) thanks @hlapp
* returned mocked response headers were not all of character class, but depended on what class was given by the user on creating the stub. this is now fixed, returning all character class values for response headers (#48) thanks @hlapp
* skip tests that require `vcr` if `vcr` is not available (#53)
* internal change to crul adapter to produce the same http response as a new version of crul returns - adds a `response_headers_all` slot (#51) (#54)


webmockr 0.2.9
==============

### MINOR IMPROVEMENTS

* make `request_registry()` and `stub_registry()` print methods more similar to avoid confusion for users (#35)
* update docs for `enable`/`disable` to indicate that `crul` and `httr` supported (#46) (related to #45)
* wrap httr adapter examples in `requireNamespace` so only run when httr available
* clean up `.onLoad` call, removing commented out code, and add note about creating adapter objects does not load crul and httr packages

### BUG FIXES

* fix to `enable()` and `disable()` methods. even though `httr` is in Suggests, we were loading all adapters (crul, httr) with `stop` when the package was not found. We now give a message and skip when a package not installed. In addition, we `enable()` and `disable()` gain an `adapter` parameter to indicate which package you want to enable or disable. If `adapter` not given we attempt all adapters. Note that this bug shouldn't have affected `vcr` users as `httr` is in Imports in that package, so you'd have to have `httr` installed (#45) thanks to @maelle for uncovering the problem


webmockr 0.2.8
==============

### NEW FEATURES

* Added support for integration with package `httr`; see `HttrAdapter` for the details; `webmockr` now integrates with two HTTP R packages: `crul` and `httr` (#43) (#44)
* Along with `httr` integration is a new method `httr_mock()` to turn on mocking for `httr`; and two methods `build_httr_response` and `build_httr_request` meant for internal use


webmockr 0.2.6
==============

Expand Down
4 changes: 2 additions & 2 deletions R/HttpLibAdapterRegistry.R
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ HttpLibAdapaterRegistry <- R6::R6Class(

register = function(x) {
# FIXME: when other adapters supported, change this inherits test
if (!inherits(x, "CrulAdapter")) {
if (!inherits(x, c("CrulAdapter", "HttrAdapter", "CurlAdapter"))) {
stop("'x' must be an adapter, such as CrulAdapter", call. = FALSE)
}
self$adapters <- cc(list(self$adapters, x))
self$adapters <- c(self$adapters, x)
}
)
)
3 changes: 2 additions & 1 deletion R/RequestPattern.R
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ RequestPattern <- R6::R6Class(
self$body_pattern <- if (!is.null(body)) BodyPattern$new(pattern = body)
self$headers_pattern <- if (!is.null(headers))
HeadersPattern$new(pattern = headers)
#if (length(options)) private$assign_options(options)
# FIXME: all private methods used in the below line, see if needed or remove
# if (length(options)) private$assign_options(options)
},

matches = function(request_signature) {
Expand Down
2 changes: 1 addition & 1 deletion R/RequestRegistry.R
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ RequestRegistry <- R6::R6Class(

print = function(x, ...) {
cat("<webmockr request registry> ", sep = "\n")
cat(" Registered Requests", sep = "\n")
cat(" Registered Requests", sep = "\n")
for (i in seq_along(self$request_signatures$hash)) {
cat(
sprintf(
Expand Down
2 changes: 1 addition & 1 deletion R/RequestSignature.R
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ RequestSignature <- R6::R6Class(

to_s = function() {
gsub("^\\s+|\\s+$", "", paste(
toupper(self$method),
paste0(toupper(self$method), ": "),
self$uri,
if (!is.null(self$body) && length(self$body)) {
paste0(" with body ", to_string(self$body))
Expand Down
2 changes: 1 addition & 1 deletion R/StubbedRequest.R
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ StubbedRequest <- R6::R6Class(
)
gsub("^\\s+|\\s+$", "", sprintf(
" %s: %s %s %s %s %s",
self$method,
toupper(self$method),
url_builder(self$uri, self$query),
make_body(self$body),
make_headers(self$request_headers),
Expand Down
56 changes: 31 additions & 25 deletions R/adapter-crul.R
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,10 @@ CrulAdapter <- R6::R6Class(
crul_resp$content <- ss$responses_sequences$body_raw
}
if (names(toadd)[i] == "headers") {
crul_resp$response_headers <- toadd[[i]]
crul_resp$response_headers <-
names_to_lower(as_character(toadd[[i]]))
crul_resp$response_headers_all <-
list(crul_resp$response_headers)
}
}
}
Expand Down Expand Up @@ -243,37 +246,40 @@ CrulAdapter <- R6::R6Class(
#' @param resp a response
#' @return a crul response
build_crul_response <- function(req, resp) {
# prep headers
if (grepl("^ftp://", resp$url)) {
headers <- list()
} else {
hds <- resp$headers
if (is.null(hds)) {
hds <- resp$response_headers
headers <- if (is.null(hds)) {
list()
} else {
stopifnot(is.list(hds))
stopifnot(is.character(hds[[1]]))
hds
}
} else {
hh <- rawToChar(hds %||% raw(0))
if (is.null(hh) || nchar(hh) == 0) {
headers <- list()
} else {
headers <- lapply(curl::parse_headers(hh, multiple = TRUE),
crul_headers_parse)
}
}
}

crul::HttpResponse$new(
method = req$method,
url = req$url$url,
status_code = resp$status_code,
request_headers = c('User-Agent' = req$options$useragent, req$headers),
response_headers = {
if (grepl("^ftp://", resp$url)) {
list()
} else {
hds <- resp$headers

if (is.null(hds)) {
hds <- resp$response_headers

if (is.null(hds)) {
list()
} else {
stopifnot(is.list(hds))
stopifnot(is.character(hds[[1]]))
hds
}
} else {
hh <- rawToChar(hds %||% raw(0))
if (is.null(hh) || nchar(hh) == 0) {
list()
} else {
crul_headers_parse(curl::parse_headers(hh))
}
}
}
if (all(hz_namez(headers))) headers else last(headers)
},
response_headers_all = headers,
modified = resp$modified %||% NA,
times = resp$times,
content = resp$content,
Expand Down
32 changes: 30 additions & 2 deletions R/adapter-curl.R
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,11 @@
#' curl_fetch_memory("https://httpbin.org/get?cow=brown", h3)
#' ## disable again
#' webmockr_disable_net_connect()
#' stub_request("get", "https://httpbin.org/get?cow=brown")
#' curl_fetch_memory("https://httpbin.org/get?cow=brown", h3)
#' stub_request("get", "https://httpbin.org/get?cow=brown") %>%
#' to_return(headers = list(brown = "cow"))
#' x <- curl_fetch_memory("https://httpbin.org/get?cow=brown", h3)
#' x
#' rawToChar(x$headers)
#' }
CurlAdapter <- R6::R6Class(
'CurlAdapter',
Expand Down Expand Up @@ -249,13 +252,19 @@ build_curl_response <- function(req, resp) {
list(
url = req$url,
status_code = resp$status_code,
type = ctype_fetch(resp$response_headers) %||% NA,
headers = headers %||% raw(0),
modified = resp$modified %||% NA,
times = resp$times %||% numeric(0),
content = resp$content
)
}

ctype_fetch <- function(x) {
match_ctype <- which("content-type" == tolower(names(x)))
if (length(match_ctype) > 0) x[[match_ctype]]
}

#' Build a curl request
#' @export
#' @param x an unexecuted curl request object
Expand Down Expand Up @@ -286,3 +295,22 @@ make_curl_headers <- function(x) {
), "\r\n\r\n")
}
# "HTTP/1.1 405 METHOD NOT ALLOWED\r\nConnection: keep-alive\r\nServer: gunicorn/19.8.1\r\nDate: Fri, 18 May 2018 18:37:00 GMT\r\nContent-Type: text/html\r\nAllow: OPTIONS, PUT\r\nContent-Length: 178\r\nAccess-Control-Allow-Origin: *\r\nAccess-Control-Allow-Credentials: true\r\nVia: 1.1 vegur\r\n\r\n"

#' Turn on curl mocking
#' @export
#' @param on (logical) set to `TRUE` to turn on, and `FALSE`
#' to turn off. default: `TRUE`
#' @return sets a env var to TRUE
curl_mock <- function(on = TRUE) {
check_for_pkg("curl")
curl::mock()
enable()
# webmockr_handle <- function(req) {
# webmockr::CurlAdapter$new()$handle_request(req)
# }
# if (on) {
# httr::set_callback("request", webmockr_handle)
# } else {
# httr::set_callback("request", NULL)
# }
}
Loading

0 comments on commit 3b05bc1

Please sign in to comment.