diff --git a/.Rbuildignore b/.Rbuildignore index a9276ac..7a289cb 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -22,3 +22,4 @@ inst/ignore ^use_vcr_notes.txt$ ^docs$ ^make_readme.R$ +^LICENSE\.md$ diff --git a/.github/workflows/R-check.yaml b/.github/workflows/R-check.yaml index 9645b8b..932cd2d 100644 --- a/.github/workflows/R-check.yaml +++ b/.github/workflows/R-check.yaml @@ -13,78 +13,38 @@ jobs: matrix: config: - { os: windows-latest, r: 'release'} - - { os: windows-latest, r: 'devel'} - { os: macOS-latest, r: 'release'} - - { os: macOS-latest, r: 'devel'} - - { os: ubuntu-16.04, r: 'release', rspm: "https://packagemanager.rstudio.com/cran/__linux__/xenial/latest"} - - { os: ubuntu-16.04, r: 'devel', rspm: "https://packagemanager.rstudio.com/cran/__linux__/xenial/latest"} + - { os: ubuntu-22.04, r: 'release'} + - { os: ubuntu-22.04, r: 'devel'} env: R_REMOTES_NO_ERRORS_FROM_WARNINGS: true - RSPM: ${{ matrix.config.rspm }} + CRAN: ${{ matrix.config.rspm }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - uses: r-lib/actions/setup-r@v1 + - uses: r-lib/actions/setup-r@v2 with: r-version: ${{ matrix.config.r }} - - uses: r-lib/actions/setup-pandoc@v1 + - uses: r-lib/actions/setup-pandoc@v2 - - name: Cache R packages - uses: actions/cache@v2 + - uses: r-lib/actions/setup-r-dependencies@v2 with: - path: ${{ env.R_LIBS_USER }} - key: ${{ runner.os }}-r-${{ matrix.config.r }}-${{ steps.install-r.outputs.installed-r-version }}-1- + extra-packages: any::rcmdcheck + needs: check - - name: Install pak - run: | - install.packages("pak", repos = "https://r-lib.github.io/p/pak/dev/") - shell: Rscript {0} - - - name: Install system dependencies - if: runner.os == 'Linux' - env: - RHUB_PLATFORM: linux-x86_64-ubuntu-gcc - run: | - while read -r cmd - do - eval sudo $cmd - done < <(Rscript -e 'writeLines(pak::local_system_requirements("ubuntu", "16.04"))') - - - name: Install dependencies - run: | - pak::local_install_dev_deps() - pak::pkg_install(c("rcmdcheck", "jpeg")) - shell: Rscript {0} - - - name: Session info - run: | - options(width = 100) - pkgs <- installed.packages()[, "Package"] - sessioninfo::session_info(pkgs, include_base = TRUE) - shell: Rscript {0} - - - name: Check - env: - _R_CHECK_CRAN_INCOMING_: false - run: rcmdcheck::rcmdcheck(args = c("--no-manual", "--as-cran"), error_on = "warning", check_dir = "check") - shell: Rscript {0} + - uses: r-lib/actions/check-r-package@v2 + with: + upload-snapshots: true - name: Show testthat output if: always() run: find check -name 'test-all.Rout*' -exec cat '{}' \; || true shell: bash - - name: Upload check results - if: failure() - uses: actions/upload-artifact@v2 - with: - name: ${{ runner.os }}-r${{ matrix.config.r }}-results - path: check - - name: Test coverage - if: matrix.config.os == 'macOS-latest' && matrix.config.r == 'release' + if: matrix.config.os == 'ubuntu-22.04' && matrix.config.r == 'release' run: | Rscript -e 'install.packages("covr")' -e 'covr::codecov(token = "${{secrets.CODECOV_TOKEN}}")' diff --git a/.github/workflows/revdep-check.yaml b/.github/workflows/revdep-check.yaml index 0cb8daa..321978f 100644 --- a/.github/workflows/revdep-check.yaml +++ b/.github/workflows/revdep-check.yaml @@ -1,45 +1,34 @@ on: push - name: revdep jobs: revdep: - runs-on: ${{ matrix.config.os }} + runs-on: ubuntu-22.04 if: startsWith(github.event.head_commit.message, 'REVDEPCHECK') - name: ${{ matrix.config.os }} (${{ matrix.config.r }}) + name: ubuntu-22.04 (release) strategy: fail-fast: false - matrix: - config: - - { os: macOS-latest, r: 'latest'} env: R_REMOTES_NO_ERRORS_FROM_WARNINGS: true - CRAN: ${{ matrix.config.cran }} + GITHUB_PAT: ${{ secrets.GH_PAT }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - uses: r-lib/actions/setup-r@v1 + - uses: r-lib/actions/setup-r@v2 with: - r-version: ${{ matrix.config.r }} + r-version: release - - uses: r-lib/actions/setup-pandoc@v1 + - uses: r-lib/actions/setup-pandoc@v2 - - name: Cache R packages - uses: actions/cache@v2 - with: - path: ${{ env.R_LIBS_USER }} - key: ${{ runner.os }}-r-${{ matrix.config.r }}-${{ hashFiles('DESCRIPTION') }} - - - name: Install dependencies - run: Rscript -e "install.packages('remotes')" -e "remotes::install_deps(dependencies = TRUE)" -e "remotes::install_github('r-lib/revdepcheck')" + - uses: r-lib/actions/setup-r-dependencies@v2 - name: Revdepcheck - run: Rscript -e "revdepcheck::revdep_reset()" -e "revdepcheck::revdep_check(num_workers=4)" + run: Rscript -e "install.packages('remotes')" -e "remotes::install_github('r-lib/revdepcheck')" -e "revdepcheck::revdep_reset()" -e "revdepcheck::revdep_check(num_workers=4)" - name: Upload revdepcheck results - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: - name: ${{ runner.os }}-r${{ matrix.config.r }}-results + name: ubuntu-22-04-r-release-results path: revdep/*.md diff --git a/DESCRIPTION b/DESCRIPTION index e134ff0..b424bca 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -8,17 +8,20 @@ Description: Record test suite 'HTTP' requests and replays them during real 'HTTP' responses on disk in 'cassettes'. Subsequent 'HTTP' requests matching any previous requests in the same 'cassette' use a cached 'HTTP' response. -Version: 0.6.4.91 +Version: 1.6.0.91 Authors@R: c(person("Scott", "Chamberlain", role = c("aut", "cre"), email = "sckott@protonmail.com", comment = c(ORCID="0000-0003-1444-9135")), - person("Aaron", "Wolen", role = "ctb", + person("Aaron", "Wolen", role = "aut", comment = c(ORCID="0000-0003-2542-2202")), - person("Maëlle", "Salmon", role = "ctb", + person("Maëlle", "Salmon", role = "aut", comment = c(ORCID="0000-0002-2815-0399")), + person("Daniel", "Possenriede", role = "aut", + comment = c(ORCID="0000-0002-6738-9845")), person("rOpenSci", role = "fnd", comment = "https://ropensci.org")) -URL: https://github.com/ropensci/vcr/ (devel) - https://books.ropensci.org/http-testing/ (user manual) +URL: https://github.com/ropensci/vcr/, + https://books.ropensci.org/http-testing/, + https://docs.ropensci.org/vcr/ BugReports: https://github.com/ropensci/vcr/issues License: MIT + file LICENSE Encoding: UTF-8 @@ -26,21 +29,19 @@ Language: en-US LazyData: true VignetteBuilder: knitr Roxygen: list(markdown = TRUE) -SystemRequirements: C++11 -LinkingTo: - cpp11 Imports: curl, crul (>= 0.8.4), httr, - webmockr (>= 0.7.4.95), + httr2, + webmockr (>= 0.8.0), urltools, yaml, R6, base64enc, - here + rprojroot Suggests: - roxygen2 (>= 7.0.2), + roxygen2 (>= 7.2.1), jsonlite, testthat, knitr, @@ -48,9 +49,10 @@ Suggests: desc, crayon, cli, - withr -Remotes: ropensci/webmockr@httr-url-redirects + withr, + webfakes +Remotes: ropensci/webmockr@redirects X-schema.org-applicationCategory: Web X-schema.org-keywords: http, https, API, web-services, curl, mock, mocking, http-mocking, testing, testing-tools, tdd X-schema.org-isPartOf: https://ropensci.org -RoxygenNote: 7.1.1 +RoxygenNote: 7.3.2 diff --git a/LICENSE b/LICENSE index d99b2f4..f2a8228 100644 --- a/LICENSE +++ b/LICENSE @@ -1,2 +1,2 @@ -YEAR: 2020 +YEAR: 2022 COPYRIGHT HOLDER: Scott Chamberlain diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..f7f1cdf --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +# MIT License + +Copyright (c) 2022 Scott Chamberlain + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile index 2dc999a..398b0cb 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ doc: ${RSCRIPT} -e "devtools::document()" eg: - ${RSCRIPT} -e "devtools::run_examples()" + ${RSCRIPT} -e "devtools::run_examples(run_dontrun=TRUE)" test: ${RSCRIPT} -e "devtools::test()" diff --git a/NAMESPACE b/NAMESPACE index 1cba3e6..791634b 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -16,6 +16,7 @@ export(Request) export(RequestHandler) export(RequestHandlerCrul) export(RequestHandlerHttr) +export(RequestHandlerHttr2) export(RequestMatcherRegistry) export(Serializers) export(UnhandledHTTPRequestError) @@ -56,6 +57,8 @@ importFrom(crul,mock) importFrom(curl,handle_setopt) importFrom(httr,content) importFrom(httr,http_status) +importFrom(httr2,req_perform) +importFrom(httr2,resp_status_desc) importFrom(urltools,url_compose) importFrom(urltools,url_parse) importFrom(utils,getParseData) @@ -63,4 +66,3 @@ importFrom(webmockr,pluck_body) importFrom(yaml,as.yaml) importFrom(yaml,yaml.load) importFrom(yaml,yaml.load_file) -useDynLib(vcr, .registration = TRUE) diff --git a/NEWS.md b/NEWS.md index 3dfceb2..fb06582 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,98 @@ +vcr 1.6.0 +========= + +### NEW FEATURES + +* `vcr` now supports `httr2` in addition to `httr` and `crul`. (#237) (#268) +* `vcr` now supports async http requests with `crul` (w/ `crul` v1.5 or greater). no change was required in `vcr` for this to happen. a PR was merged in `crul` to hook into `vcr`. there's no support for async in `httr` as that package does not do any async and no support in `httr2` because `req_perform_parallel` does not have a mocking hook as does `req_perform` (#246) + +### BUG FIXES + +* Ports in URLs (e.g., 8000) were being accidentally stripped. Fixed now (#264) (#266) + +### MINOR IMPROVEMENTS + +* Add link to DESCRIPTION file for packge documentation. thanks @olivroy (#265) +* Use `_PACKAGE` syntax for package level doc (#263) + + +vcr 1.2.2 +========= + +* change tests to use more reliable test servers + +vcr 1.2.0 +========= + +### NEW FEATURES + +* Added @dpprdan as an author; changed all ctb to aut (#258) + +### MINOR IMPROVEMENTS + +* `use_vcr()` now creates a test helper file called `helper-vcr.R` instead of `setup-pkgname.R`. + We are reverting the change from version 0.6.0 and now recommend the use of `helper-*.R` again, so that the vcr setup [is loaded with `devtools::load_all()`](https://testthat.r-lib.org/reference/test_dir.html#special-files). + That way your vcr-enabled tests also work when run interactively (#244) (#256) +* default git branch changed from master to main (#253) +* update example packages in the README (#257) +* vcr no longer requires compilation because replaced the single C++ function with a pure R equivalent + +### BUG FIXES + +* roll back a change from the previous CRAN version that removed use of an internal function (`body_from`) (#249) (#252) + +vcr 1.1.0 +========= + +### MINOR IMPROVEMENTS + +* request matching was sensitive to escaping special characters, that's been fixed (#240) (#247) thanks to @KevCaz +* fix broken link given in error suggestion (#239) thanks to @maelle +* using `preserve_exact_body_bytes = TRUE` now writes a base64 encoded string into a field in yaml or json on disk called `base64_string`. When `preserve_exact_body_bytes = FALSE` (the default) the response body goes into a field called `string` + +### BUG FIXES + +* `vcr_test_path` fix to find root package path correctly with R 4.2 on Windows (#242) (#243) thanks to @dpprdan + +vcr 1.0.2 +========= + +### BUG FIXES + +* fix to `vcr_test_path()` to find root package path correctly (#235) (#236) + +vcr 1.0.0 +========= + +### NEW FEATURES + +* `check_cassette_names()` gains `allowed_duplicates` parameter to allow duplicate cassette names; we typically advise users not to use duplicate cassette names, but there are cases where you may want to share cassettes across tests (#227) +* `vcr_configure()` gains `filter_query_parameters` parameter for filtering out query parameters so they don't show up in the recorded request on disk (#212) +* `use_vcr()`: now sets a mimimum vcr version, which is usually the latest (stable) version on CRAN. You can of course easily remove or change the version requirement yourself after running it (#214) +* `vcr_configure()` gains `warn_on_empty_cassette` parameter: Should a warning be thrown when an empty cassette is detected? Empty cassettes are cleaned up (deleted) either way (#224) thanks @llrs and @dpprdan +* `vcr_configure()` gains `quiet` parameter: suppress any messages from both vcr and webmockr (#226) (#25) +* `vcr_configure()` gains new option `filter_sensitive_data_regex`; now `filter_sensitive_data` is for fixed string matching, while `filter_sensitive_data_regex` is for regex based matching (#222) thanks @tomsing1 for reporting +* gains package import `rprojroot` + +### MINOR IMPROVEMENTS + +* `filter_sensitive_data` option now strips leading and trailing single and double quotes from strings before being used IN CASE a user accidentally quotes a secret - logic being that even though a secret may have a single or double quote in it, its very unlikely that it would have both a leading and trailing quote (single or double) (#221) + +### Documentation + +* new vignette explaining the design of the vcr package (also can be found in the HTTP Testing book) (#232) (#233) +* no user facing change - but vignettes moved into man/rmdhunks so that they can be pulled into the HTTP Testing book easily (#209) (#216) +* fix in configuration vignette to clarify a `filter_request_headers` example (#215) thanks @maelle +* docs update (#33) (#217) + +### BUG FIXES + +* `filter_request_headers` was unfortunately adding a request header to the request written to disk when the header did not exist; now fixed (#213) +* bug in internal function `is_base64()`; `strsplit()` needed `useBytes=TRUE` (#219) +* `filter_sensitive_data` was not working when strings contained regex characters; fixed, and see also above new config variable for regex specific filtering (#222) thanks @tomsing1 for reporting +* `vcr_test_path()` should now correctly set paths (#225) (#228) (#229) (#230) + + vcr 0.6.0 ========= @@ -132,12 +227,12 @@ vcr 0.2.6 ## NEW FEATURES * gains function `use_vcr()` to setup `vcr` for your package. This requires 3 pkgs all in Suggests; so are not required if you don't need to use `use_vcr()` (#52) (#95) thanks @maelle for the feedback! -* `vcr` actually supports all four recording modes: `none`, `once`, `new_episodes`, and `all`. `once` is what's used by default. See `?recording` for description of the recording modes. For now [the test file test-ause_cassette_record_modes.R](https://github.com/ropensci/vcr/blob/master/tests/testthat/test-ause_cassette_record_modes.R) gives some examples and what to expect for each record mode; in the future the http testing book will have much more information in the _Record modes_ chapter ([commit](https://github.com/ropensci/vcr/commit/04aa5f784b18308d8f62d1b6b0be2f3e140f2a5a)) +* `vcr` actually supports all four recording modes: `none`, `once`, `new_episodes`, and `all`. `once` is what's used by default. See `?recording` for description of the recording modes. For now [the test file test-ause_cassette_record_modes.R](https://github.com/ropensci/vcr/blob/main/tests/testthat/test-ause_cassette_record_modes.R) gives some examples and what to expect for each record mode; in the future the http testing book will have much more information in the _Record modes_ chapter ([commit](https://github.com/ropensci/vcr/commit/04aa5f784b18308d8f62d1b6b0be2f3e140f2a5a)) ### MINOR IMPROVEMENTS * lots of tidying for better/consistent style -* fix for a partial argument call in `as.list()`: `all` to `all.names` ([commit](https://github.com/ropensci/vcr/commit/b20a2d5ffd0f65175dee4d84aa9573f3652df1d2)) +* fix for a partial argument call in `as.list()`: `all` to `all.names` ### BUG FIXES diff --git a/R/cassette_class.R b/R/cassette_class.R index 433a3cc..01bca06 100644 --- a/R/cassette_class.R +++ b/R/cassette_class.R @@ -26,7 +26,7 @@ #' [webmockr::Response] are used to build a request and response, #' respectively, then passed to [webmockr::build_crul_response()] #' to make a complete `crul` HTTP response object -#' @examples +#' @examples \dontrun{ #' library(vcr) #' vcr_configure(dir = tempdir()) #' @@ -51,7 +51,8 @@ #' vcr_configure(dir = tempdir()) #' res <- Cassette$new(name = "jane") #' library(crul) -#' HttpClient$new("https://httpbin.org")$get("get") +#' # HttpClient$new("https://hb.opencpu.org")$get("get") +#' } Cassette <- R6::R6Class( "Cassette", public = list( @@ -521,7 +522,7 @@ Cassette <- R6::R6Class( #' @description get http interactions from the cassette via the serializer #' @return list deserialized_hash = function() { - tmp <- self$serializer$deserialize() + tmp <- self$serializer$deserialize(self) if (inherits(tmp, "list")) { return(tmp) } else { @@ -538,7 +539,7 @@ Cassette <- R6::R6Class( response <- VcrResponse$new( z$response$status, z$response$headers, - z$response$body$string, + z$response$body$string %||% z$response$body$base64_string, opts = self$cassette_opts, disk = z$response$body$file ) @@ -572,7 +573,7 @@ Cassette <- R6::R6Class( }, #' @description record an http interaction (doesn't write to disk) - #' @param x an crul or httr response object, with the request at `$request` + #' @param x a crul, httr, or httr2 response object, with the request at `$request` #' @return nothing returned record_http_interaction = function(x) { int <- self$make_http_interaction(x) @@ -635,9 +636,12 @@ Cassette <- R6::R6Class( }, #' @description Make an `HTTPInteraction` object - #' @param x an crul or httr response object, with the request at `$request` + #' @param x A crul, httr, or httr2 response object, with the request at `$request` #' @return an object of class [HTTPInteraction] make_http_interaction = function(x) { + # for httr2, duplicate `body` slot in `content` + if (inherits(x, "httr2_response")) x$content <- x$body + # content must be raw or character assert(unclass(x$content), c('raw', 'character')) new_file_path <- "" @@ -662,21 +666,30 @@ Cassette <- R6::R6Class( } else { # crul webmockr::pluck_body(x$request) }, - headers = if (inherits(x, "response")) { + headers = if (inherits(x, c("response", "httr2_response"))) { as.list(x$request$headers) } else { x$request_headers }, opts = self$cassette_opts, - disk = is_disk + disk = is_disk, + skip_port_stripping = TRUE ) response <- VcrResponse$new( status = if (inherits(x, "response")) { c(list(status_code = x$status_code), httr::http_status(x)) - } else unclass(x$status_http()), - headers = if (inherits(x, "response")) x$headers else x$response_headers, - body = if (is.raw(x$content)) { + } else if (inherits(x, "httr2_response")) { + list(status_code = x$status_code, message = httr2::resp_status_desc(x)) + } else { + unclass(x$status_http()) + }, + headers = if (inherits(x, c("response", "httr2_response"))) { + x$headers + } else { + x$response_headers + }, + body = if (is.raw(x$content) || is.null(x$content)) { if (can_rawToChar(x$content)) rawToChar(x$content) else x$content } else { stopifnot(inherits(unclass(x$content), "character")) @@ -787,6 +800,6 @@ empty_cassette_message <- function(x) { c( sprintf("Empty cassette (%s) deleted; consider the following:\n", x), " - If an error occurred resolve that first, then check:\n", - " - vcr only supports crul & httr; requests w/ curl, download.file, etc. are not supported\n", - " - If you are using crul/httr, are you sure you made an HTTP request?\n") + " - vcr only supports crul, httr & httr2; requests w/ curl, download.file, etc. are not supported\n", + " - If you are using crul/httr/httr2, are you sure you made an HTTP request?\n") } diff --git a/R/configuration.R b/R/configuration.R index 53aa10b..1c18a9d 100644 --- a/R/configuration.R +++ b/R/configuration.R @@ -129,7 +129,7 @@ #' - `quiet` (logical) Suppress any messages from both vcr and webmockr. #' Default: `TRUE` #' - `warn_on_empty_cassette` (logical) Should a warning be thrown when an -#' empty cassette is detected? Empty cassettes are claned up (deleted) either +#' empty cassette is detected? Empty cassettes are cleaned up (deleted) either #' way. This option only determines whether a warning is thrown or not. #' Default: `FALSE` #' - `record_separate_redirects` (logical) If http redirects are diff --git a/R/cpp11.R b/R/cpp11.R deleted file mode 100644 index 5ffbb32..0000000 --- a/R/cpp11.R +++ /dev/null @@ -1,5 +0,0 @@ -# Generated by cpp11: do not edit by hand - -split_str <- function(str, splitLength) { - .Call("_vcr_split_str", str, splitLength, PACKAGE = "vcr") -} diff --git a/R/error_suggestions.R b/R/error_suggestions.R index 4922126..f1b92ae 100644 --- a/R/error_suggestions.R +++ b/R/error_suggestions.R @@ -59,6 +59,6 @@ error_suggestions <- list( text = c("If you're surprised vcr is raising this error", "and want insight about how vcr attempted to handle the request,", "you can use 'logging' to see more details"), - url = "https://books.ropensci.org/http-testing/logging" + url = "https://books.ropensci.org/http-testing/debugging-your-tests-that-use-vcr.html#logging-1" ) ) diff --git a/R/errors.R b/R/errors.R index 35733f3..5006e9f 100644 --- a/R/errors.R +++ b/R/errors.R @@ -23,11 +23,11 @@ #' - but if record != once, then allow it, unless record == none #' - others? #' -#' @examples +#' @examples \dontrun{ #' vcr_configure(dir = tempdir()) #' cassettes() #' insert_cassette("turtle") -#' request <- Request$new("post", 'https://eu.httpbin.org/post?a=5', +#' request <- Request$new("post", 'https://hb.opencpu.org/post?a=5', #' "", list(foo = "bar")) #' #' err <- UnhandledHTTPRequestError$new(request) @@ -53,6 +53,7 @@ #' # cleanup #' eject_cassette("turtle") #' unlink(tempdir()) +#' } UnhandledHTTPRequestError <- R6::R6Class( "UnhandledHTTPRequestError", public = list( diff --git a/R/http_interaction.R b/R/http_interaction.R index bd746e1..f5a0d9c 100644 --- a/R/http_interaction.R +++ b/R/http_interaction.R @@ -14,7 +14,7 @@ #' @examples \dontrun{ #' # make the request #' library(vcr) -#' url <- "https://eu.httpbin.org/post" +#' url <- "https://hb.opencpu.org/post" #' body <- list(foo = "bar") #' cli <- crul::HttpClient$new(url = url) #' res <- cli$post(body = body) diff --git a/R/http_interaction_list.R b/R/http_interaction_list.R index b54b91b..29fa396 100644 --- a/R/http_interaction_list.R +++ b/R/http_interaction_list.R @@ -49,7 +49,7 @@ NullList <- R6::R6Class( #' ## make the request #' ### turn off mocking #' crul::mock(FALSE) -#' url <- "https://eu.httpbin.org/post" +#' url <- "https://hb.opencpu.org/post" #' cli <- crul::HttpClient$new(url = url) #' res <- cli$post(body = list(a = 5)) #' @@ -115,7 +115,6 @@ HTTPInteractionList <- R6::R6Class( self$allow_playback_repeats <- allow_playback_repeats self$parent_list <- parent_list self$used_interactions <- used_interactions - interaction_summaries <- vapply(interactions, function(x) { sprintf("%s => %s", request_summary(Request$new()$from_hash(x$request)), diff --git a/R/http_interactions.R b/R/http_interactions.R index 9e650ac..79a5728 100644 --- a/R/http_interactions.R +++ b/R/http_interactions.R @@ -8,7 +8,7 @@ #' insert_cassette("foo_bar") #' webmockr::webmockr_allow_net_connect() #' library(crul) -#' cli <- crul::HttpClient$new("https://eu.httpbin.org/get") +#' cli <- crul::HttpClient$new("https://hb.opencpu.org/get") #' one <- cli$get(query = list(a = 5)) #' z <- http_interactions() #' z diff --git a/R/insert_cassette.R b/R/insert_cassette.R index bdd0d81..4945607 100644 --- a/R/insert_cassette.R +++ b/R/insert_cassette.R @@ -18,7 +18,7 @@ vcr__env <- new.env() #' current_cassette() #' x$new_recorded_interactions #' x$previously_recorded_interactions() -#' cli <- crul::HttpClient$new(url = "https://httpbin.org") +#' cli <- crul::HttpClient$new(url = "https://hb.opencpu.org") #' cli$get("get") #' x$new_recorded_interactions # 1 interaction #' x$previously_recorded_interactions() # empty diff --git a/R/lightswitch.R b/R/lightswitch.R index ee2add5..2515ab6 100644 --- a/R/lightswitch.R +++ b/R/lightswitch.R @@ -18,7 +18,7 @@ #' # turn off for duration of a block #' library(crul) #' turned_off({ -#' res <- HttpClient$new(url = "https://eu.httpbin.org/get")$get() +#' res <- HttpClient$new(url = "https://hb.opencpu.org/get")$get() #' }) #' res #' @@ -26,7 +26,7 @@ #' turn_off() #' library(webmockr) #' crul::mock() -#' # HttpClient$new(url = "https://eu.httpbin.org/get")$get(verbose = TRUE) +#' # HttpClient$new(url = "https://hb.opencpu.org/get")$get(verbose = TRUE) #' turn_on() #' } turned_off <- function(..., ignore_cassettes = FALSE) { diff --git a/R/request_class.R b/R/request_class.R index 1c2411f..cf81fce 100644 --- a/R/request_class.R +++ b/R/request_class.R @@ -3,7 +3,7 @@ #' @export #' @keywords internal #' @examples -#' url <- "https://eu.httpbin.org/post" +#' url <- "https://hb.opencpu.org/post" #' body <- list(foo = "bar") #' headers <- list( #' `User-Agent` = "libcurl/7.54.0 r-curl/3.2 crul/0.5.2", @@ -39,7 +39,7 @@ Request <- R6::R6Class( body = NULL, #' @field headers (character) named list headers = NULL, - #' @field skip_port_stripping (logical) whether to strip thhe port + #' @field skip_port_stripping (logical) whether to strip the port skip_port_stripping = FALSE, #' @field hash (character) a named list - internal use hash = NULL, @@ -51,6 +51,8 @@ Request <- R6::R6Class( fields = NULL, #' @field output (various) request output details, disk, memory, etc output = NULL, + #' @field policies (various) http policies, used in httr2 only + policies = NULL, #' @description Create a new `Request` object #' @param method (character) the HTTP method (i.e. head, options, get, @@ -62,10 +64,12 @@ Request <- R6::R6Class( #' @param disk (boolean), is body a file on disk #' @param fields (various) post fields #' @param output (various) output details + #' @param policies (various) http policies, used in httr2 only + #' @param skip_port_stripping (logical) whether to strip the port. + #' default: `FALSE` #' @return A new `Request` object initialize = function(method, uri, body, headers, opts, disk, - fields, output) { - + fields, output, policies, skip_port_stripping = FALSE) { if (!missing(method)) self$method <- tolower(method) if (!missing(body)) { if (inherits(body, "list")) { @@ -75,7 +79,7 @@ Request <- R6::R6Class( } if (!missing(headers)) self$headers <- headers if (!missing(uri)) { - if (!self$skip_port_stripping) { + if (!skip_port_stripping) { self$uri <- private$without_standard_port(uri) } else { self$uri <- uri @@ -91,6 +95,7 @@ Request <- R6::R6Class( if (!missing(disk)) self$disk <- disk if (!missing(fields)) self$fields <- fields if (!missing(output)) self$output <- output + if (!missing(policies)) self$policies <- policies }, #' @description Convert the request to a list @@ -113,6 +118,7 @@ Request <- R6::R6Class( Request$new( method = hash[['method']], uri = hash[['uri']], + # body = hash[['body']], body = body_from(hash[['body']]), headers = hash[['headers']], disk = hash[['disk']] @@ -155,7 +161,8 @@ serializable_body <- function(x, preserve_exact_body_bytes = FALSE) { body_from <- function(x) { if (is.null(x)) x <- "" if ( - (!is.null(attr(x, "base64")) && attr(x, "base64")) || all(is_base64(x)) + (!is.null(attr(x, "base64")) && attr(x, "base64")) + # (!is.null(attr(x, "base64")) && attr(x, "base64")) || all(is_base64(x)) ) { b64dec <- base64enc::base64decode(x) b64dec_r2c <- tryCatch(rawToChar(b64dec), error = function(e) e) @@ -168,7 +175,8 @@ body_from <- function(x) { b64dec_r2c } } else { - try_encode_string(x, Encoding_safe(x)) + x + # try_encode_string(x, Encoding_safe(x)) } } @@ -178,14 +186,28 @@ try_encoding <- function(x) { if (inherits(z, "error")) "ASCII-8BIT" else z } -is_base64 <- function(x) { - if (inherits(x, "form_file")) return(FALSE) - as_num <- tryCatch(as.numeric(x), warning = function(w) w) - if (!inherits(as_num, "warning")) return(FALSE) - # split string by newlines b/c base64 w/ newlines won't be - # recognized as valid base64 - x <- strsplit(x, "\r|\n", useBytes = TRUE)[[1]] - all(grepl(b64_pattern, x)) +is_base64 <- function(x, cassette) { + if (!is.list(x)) { + if ("base64" %in% names(attributes(x))) { + return(attr(x, 'base64')) + } + return(FALSE) + } + + # new base64 setup where it is stored in "base64_string" + hasb64str <- "base64_string" %in% names(x) + if (hasb64str) return(TRUE) + + if ( + cassette$preserve_exact_body_bytes && "string" %in% names(x) + ) { + # old base64 setup where it was stored in "string" + message("re-record cassettes using 'preserve_exact_body_bytes = TRUE'") + return(TRUE) + } else { + # not using base64 + return(FALSE) + } } Encoding_safe <- function(x) { diff --git a/R/request_handler-crul.R b/R/request_handler-crul.R index 6994f38..d8dec05 100644 --- a/R/request_handler-crul.R +++ b/R/request_handler-crul.R @@ -21,7 +21,7 @@ #' library(crul) #' vcr_configure(dir = tempdir(), log = TRUE, #' log_opts = list(file = file.path(tempdir(), "vcr.log"))) -#' cli <- HttpClient$new(url = "https://httpbin.org") +#' cli <- HttpClient$new(url = "https://hb.opencpu.org") #' #' ## testing, same uri and method, changed body in 2nd block #' use_cassette(name = "apple7", { diff --git a/R/request_handler-httr.R b/R/request_handler-httr.R index c687b37..0106a1d 100644 --- a/R/request_handler-httr.R +++ b/R/request_handler-httr.R @@ -23,7 +23,7 @@ sac <- new.env() #' mydir <- file.path(tempdir(), "testing_httr") #' invisible(vcr_configure(dir = mydir)) #' use_cassette(name = "testing2", { -#' res <- POST("https://httpbin.org/post", body = list(foo = "bar")) +#' res <- POST("https://hb.opencpu.org/post", body = list(foo = "bar")) #' }, match_requests_on = c("method", "uri", "body")) #' #' load("~/httr_req_post.rda") diff --git a/R/request_handler-httr2.R b/R/request_handler-httr2.R new file mode 100644 index 0000000..e92d0d0 --- /dev/null +++ b/R/request_handler-httr2.R @@ -0,0 +1,115 @@ +#' @title RequestHandlerHttr2 +#' @description Methods for the httr2 package, building on [RequestHandler] +#' @export +#' @param request The request from an object of class `HttpInteraction` +#' @examples \dontrun{ +#' # GET request +#' library(httr2) +#' req <- request("https://hb.opencpu.org/post") %>% +#' req_body_json(list(foo = "bar")) +#' x <- RequestHandlerHttr2$new(req) +#' # x$handle() +#' +#' # POST request +#' library(httr2) +#' mydir <- file.path(tempdir(), "testing_httr2") +#' invisible(vcr_configure(dir = mydir)) +#' req <- request("https://hb.opencpu.org/post") %>% +#' req_body_json(list(foo = "bar")) +#' use_cassette(name = "testing3", { +#' response <- req_perform(req) +#' }, match_requests_on = c("method", "uri", "body")) +#' use_cassette(name = "testing3", { +#' response2 <- req_perform(req) +#' }, match_requests_on = c("method", "uri", "body")) +#' } +RequestHandlerHttr2 <- R6::R6Class( + "RequestHandlerHttr2", + inherit = RequestHandler, + + public = list( + #' @description Create a new `RequestHandlerHttr2` object + #' @param request The request from an object of class `HttpInteraction` + #' @return A new `RequestHandlerHttr2` object + initialize = function(request) { + if (!length(request$method)) { + request$method <- webmockr:::req_method_get_w(request) + } + self$request_original <- request + self$request <- { + Request$new(request$method, request$url, + webmockr::pluck_body(request), request$headers, + fields = request$fields, opts = request$options, + policies = request$policies) + } + self$cassette <- tryCatch(current_cassette(), error = function(e) e) + } + ), + + private = list( + # make a `vcr` response + response_for = function(x) { + VcrResponse$new( + list(status_code = x$status_code, description = httr2::resp_status_desc(x)), + x$headers, + x$body, + "", + super$cassette$cassette_opts + ) + }, + + # these will replace those in + on_ignored_request = function(request) { + # perform and return REAL http response + # * make real request + # * run through response_for() to make vcr response, store vcr response + # * give back real response + + # real request + webmockr::httr2_mock(FALSE) + on.exit(webmockr::httr2_mock(TRUE), add = TRUE) + tmp2 <- httr2::req_perform(request) + + # run through response_for() + self$vcr_response <- private$response_for(tmp2) + + # return real response + return(response) + }, + + on_stubbed_by_vcr_request = function(request) { + # print("------- on_stubbed_by_vcr_request -------") + # return stubbed vcr response - no real response to do + serialize_to_httr2(request, super$get_stubbed_response(request)) + }, + + on_recordable_request = function(request) { + # print("------- on_recordable_request -------") + # do real request - then stub response - then return stubbed vcr response + # real request + webmockr::httr2_mock(FALSE) + on.exit(webmockr::httr2_mock(TRUE), add = TRUE) + xx <- self$request_original %>% + httr2::req_error(is_error = function(resp) FALSE) + # print(xx) + tryCatch(httr2::req_perform(xx), error = function(e) e) + tmp2 <- httr2::last_response() + # print("------- after the req_perform -------") + + response <- webmockr::build_httr2_response(self$request_original, tmp2) + + # make vcr response | then record interaction + self$vcr_response <- private$response_for(response) + cas <- tryCatch(current_cassette(), error = function(e) e) + if (inherits(cas, "error")) stop("no cassette in use") + response$request <- self$request_original + response$request$method <- webmockr:::req_method_get_w(response$request) + cas$record_http_interaction(response) + + # return real response + # print("------- before return -------") + return(response) + } + ) +) + diff --git a/R/request_matcher_registry.R b/R/request_matcher_registry.R index 979ecbb..d2bf16d 100644 --- a/R/request_matcher_registry.R +++ b/R/request_matcher_registry.R @@ -45,13 +45,17 @@ RequestMatcherRegistry <- R6::R6Class( #' @note r1=from new request; r2=from recorded interaction register_built_ins = function() { self$register("method", function(r1, r2) r1$method == r2$method) - self$register("uri", function(r1, r2) query_params_remove_str(r1$uri) == r2$uri) + self$register("uri", function(r1, r2) + identical( + curl::curl_unescape(query_params_remove_str(r1$uri)), curl::curl_unescape(r2$uri)) + ) self$register("body", function(r1, r2) identical(r1$body, r2$body)) self$register('headers', function(r1, r2) identical(r1$headers, r2$headers)) self$register("host", function(r1, r2) identical(r1$host, r2$host)) self$register("path", function(r1, r2) identical(sub("/$", "", r1$path), sub("/$", "", r2$path))) - self$register("query", function(r1, r2) identical(r1$query, r2$query)) + self$register("query", function(r1, r2) + identical(curl::curl_unescape(r1$query), curl::curl_unescape(r2$query))) self$try_to_register_body_as_json() }, diff --git a/R/request_response.R b/R/request_response.R index fa1f4e3..7bc8c7f 100644 --- a/R/request_response.R +++ b/R/request_response.R @@ -22,7 +22,7 @@ #' your data/etc. as this is only for printing a summary of the response #' @examples #' # request -#' url <- "https://httpbin.org" +#' url <- "https://hb.opencpu.org" #' body <- list(foo = "bar") #' headers <- list( #' `User-Agent` = "r-curl/3.2", diff --git a/R/response_class.R b/R/response_class.R index 8090190..2436f88 100644 --- a/R/response_class.R +++ b/R/response_class.R @@ -42,7 +42,7 @@ #' x$headers$`content-length` # = NULL #' x$update_content_length_header() # no change, b/c header doesn't exist #' x$headers$`content-length` # = NULL -#' +#' #' ## example 3 #' ### content-length header present, and does change #' body <- " Hello World " @@ -109,7 +109,8 @@ VcrResponse <- R6::R6Class( if (inherits(body, "list")) { body <- paste(names(body), body, sep = "=", collapse = ",") } - self$body <- if (is.character(body)) enc2utf8(body) else body + # self$body <- if (is.character(body)) enc2utf8(body) else body + self$body <- body } if (!missing(http_version)) { self$http_version <- extract_http_version(http_version) @@ -119,6 +120,11 @@ VcrResponse <- R6::R6Class( if (!missing(disk)) self$disk <- disk }, + #' @description print method for the `VcrResponse` class + #' @param x self + #' @param ... ignored + print = function(x, ...) cat(" ", sep = "\n"), + #' @description Create a hash #' @return a list to_hash = function() { @@ -141,6 +147,7 @@ VcrResponse <- R6::R6Class( VcrResponse$new( hash[["status"]], hash[["headers"]], + # hash[["body"]], body_from(hash[["body"]]), hash[["http_version"]], hash[["adapater_metadata"]], diff --git a/R/serialize_to_httr2.R b/R/serialize_to_httr2.R new file mode 100644 index 0000000..a72fd52 --- /dev/null +++ b/R/serialize_to_httr2.R @@ -0,0 +1,37 @@ +# generate actual httr2 response +# request <- httr2::request("https://hb.opencpu.org/301") +# +serialize_to_httr2 <- function(request, response) { + # request + req <- webmockr::RequestSignature$new( + method = request$method, + uri = request$uri, + options = list( + body = request$body %||% NULL, + headers = request$headers %||% NULL, + proxies = NULL, + auth = NULL, + disk = if (inherits(response$body, "httr2_path")) response$body %||% NULL, + fields = request$fields %||% NULL, + output = request$output %||% NULL + ) + ) + + # response + resp <- webmockr::Response$new() + resp$set_url(request$uri) + resp$set_body(response$body, inherits(response$body, "httr2_path")) + resp$set_request_headers(request$headers, capitalize = FALSE) + resp$set_response_headers(response$headers, capitalize = FALSE) + resp$set_status(status = response$status$status_code %||% 200) + + # generate httr2 response + webmockr::build_httr2_response(as_httr2_request(req), resp) +} + +as_httr2_request <- function(x) { + structure(list(url = x$url$url, method = toupper(x$method), + headers = x$headers, body = x$body, fields = x$fields, + options = x$options, policies = x$policies), + class = "httr2_request") +} diff --git a/R/serializer.R b/R/serializer.R index 1b322cb..09c8dd9 100644 --- a/R/serializer.R +++ b/R/serializer.R @@ -34,18 +34,22 @@ Serializer <- R6::R6Class("Serializer", if (!inherits(x, "character")) return(x) gsub("[\r\n]", "", x) }, - process_body = function(x) { + process_body = function(x, cassette) { if (is.null(x)) { return(list()) } else { # check for base64 encoding x$http_interactions <- lapply(x$http_interactions, function(z) { - if (is_base64(z$response$body$string)) { + if (is_base64(z$response$body, cassette)) { + # string or base64_string? + str_slots <- c('string', 'base64_string') + slot <- str_slots[str_slots %in% names(z$response$body)] + # if character and newlines detected, remove newlines - z$response$body$string <- private$strip_newlines(z$response$body$string) - b64dec <- base64enc::base64decode(z$response$body$string) + z$response$body[[slot]] <- private$strip_newlines(z$response$body[[slot]]) + b64dec <- base64enc::base64decode(z$response$body[[slot]]) b64dec_r2c <- tryCatch(rawToChar(b64dec), error = function(e) e) - z$response$body$string <- if (inherits(b64dec_r2c, "error")) { + z$response$body[[slot]] <- if (inherits(b64dec_r2c, "error")) { # probably is binary (e.g., pdf), so can't be converted to char. b64dec } else { @@ -53,8 +57,9 @@ Serializer <- R6::R6Class("Serializer", # can convert to character from binary b64dec_r2c } - z$response$body$encoding <- - sup_mssg(vcr_c$quiet, encoding_guess(z$response$body$string, TRUE)) + + # set encoding to empty string, we're ignoring it for now + z$response$body$encoding <- "" } return(z) }) diff --git a/R/serializers-json.R b/R/serializers-json.R index cb7e277..60a05f1 100644 --- a/R/serializers-json.R +++ b/R/serializers-json.R @@ -32,12 +32,14 @@ JSON <- R6::R6Class("JSON", #' @description Deserializes the content at the file path using #' jsonlite::fromJSON + #' @param cassette the current cassette object so it's properties can + #' be retrieved #' @return (list) the deserialized object, an R list - deserialize = function() { + deserialize = function(cassette) { str <- sensitive_put_back(readLines(self$path)) tmp <- jsonlite::fromJSON(str, FALSE) tmp <- query_params_put_back(tmp) - private$process_body(tmp) + private$process_body(tmp, cassette) } ) ) diff --git a/R/serializers-yaml.R b/R/serializers-yaml.R index 0f8e2f0..051370d 100644 --- a/R/serializers-yaml.R +++ b/R/serializers-yaml.R @@ -35,10 +35,12 @@ YAML <- R6::R6Class("YAML", #' @description Deserializes the content at the path using #' yaml::yaml.load_file + #' @param cassette the current cassette object so it's properties can + #' be retrieved #' @return (list) the deserialized object, an R list - deserialize = function() { + deserialize = function(cassette) { tmp <- yaml_load_desecret(self$path) - private$process_body(tmp) + private$process_body(tmp, cassette) } ) ) diff --git a/R/split_string.R b/R/split_string.R new file mode 100644 index 0000000..d13a445 --- /dev/null +++ b/R/split_string.R @@ -0,0 +1,11 @@ +#' split string every N characters +#' @param str (character) a string +#' @param length (integer) number of characters to split by +#' @examples \dontrun{ +#' str = "XOVEWVJIEWNIGOIWENVOIWEWVWEW" +#' str_splitter(str, 5) +#' str_splitter(str, 5L) +#' } +str_splitter <- function(str, length) { + gsub(sprintf("(.{%s})", length), "\\1 ", str) +} diff --git a/R/use_cassette.R b/R/use_cassette.R index aa4ba71..73615df 100644 --- a/R/use_cassette.R +++ b/R/use_cassette.R @@ -107,14 +107,14 @@ #' vcr_configure(dir = tempdir()) #' #' use_cassette(name = "apple7", { -#' cli <- HttpClient$new(url = "https://httpbin.org") +#' cli <- HttpClient$new(url = "https://hb.opencpu.org") #' resp <- cli$get("get") #' }) #' readLines(file.path(tempdir(), "apple7.yml")) #' #' # preserve exact body bytes - records in base64 encoding #' use_cassette("things4", { -#' cli <- crul::HttpClient$new(url = "https://httpbin.org") +#' cli <- crul::HttpClient$new(url = "https://hb.opencpu.org") #' bbb <- cli$get("get") #' }, preserve_exact_body_bytes = TRUE) #' ## see the body string value in the output here @@ -130,7 +130,7 @@ #' vcr_configure(dir = tempdir(), log = TRUE, log_opts = list(file = file.path(tempdir(), "vcr.log"))) #' #' use_cassette(name = "stuff350", { -#' res <- GET("https://httpbin.org/get") +#' res <- GET("https://hb.opencpu.org/get") #' }) #' readLines(file.path(tempdir(), "stuff350.yml")) #' diff --git a/R/vcr-package.R b/R/vcr-package.R index 9d7c56e..7674d9f 100644 --- a/R/vcr-package.R +++ b/R/vcr-package.R @@ -1,11 +1,3 @@ -#' vcr: Record HTTP Calls to Disk -#' -#' \pkg{vcr} records test suite 'HTTP' requests and replay them during -#' future runs. -#' -#' Check out the [http testing book](https://books.ropensci.org/http-testing/) -#' for a lot more documentation on `vcr`, `webmockr`, and `crul` -#' #' @section Backstory: #' A Ruby gem of the same name (`VCR`, ) was #' created many years ago and is the original. Ports in many languages @@ -29,7 +21,17 @@ #' #' @section Request matching: #' See [request-matching] for help on the many request matching options. -#' +#' +#' @section Async: +#' As of \pkg{crul} v1.5, `vcr` will work for async http requests with +#' \pkg{crul}. \pkg{httr} does not do async requests, and \pkg{httr2} +#' async plumbing does not have any hooks for mocking via \pkg{webmockr} +#' or recording real requests via this package +#' +#' @keywords internal +"_PACKAGE" + +## usethis namespace: start #' @importFrom R6 R6Class #' @importFrom utils getParseData #' @importFrom yaml yaml.load yaml.load_file as.yaml @@ -37,13 +39,10 @@ #' @importFrom urltools url_parse url_compose #' @importFrom crul HttpClient mock #' @importFrom httr http_status content +#' @importFrom httr2 resp_status_desc req_perform #' @importFrom webmockr pluck_body #' @importFrom curl handle_setopt -#' @useDynLib vcr, .registration = TRUE -#' @author Scott Chamberlain \email{myrmecocystus@@gmail.com} -#' @docType package -#' @aliases vcr-package -#' @name vcr +## usethis namespace: end NULL #' An HTTP request as prepared by the \pkg{crul} package diff --git a/R/vcr_setup.R b/R/vcr_setup.R index d6adba6..f4609bf 100644 --- a/R/vcr_setup.R +++ b/R/vcr_setup.R @@ -7,7 +7,7 @@ invisible(vcr::vcr_configure( ))\nvcr::check_cassette_names()\n", example_test = "# EXAMPLE VCR USAGE: RUN AND DELETE ME -foo <- function() crul::ok('https://httpbin.org/get') +foo <- function() crul::ok('https://hb.opencpu.org/get') test_that(\"foo works\", { vcr::use_cassette(\"testing\", { @@ -93,7 +93,7 @@ use_vcr <- function(dir = ".", verbose = TRUE) { dir.create(file.path(dir, "tests/testthat"), recursive = TRUE) } if (verbose) vcr_cat_info("Looking for testthat.R file or similar") - tall <- file.path(dir, sprintf("tests/testthat.R", pkg)) + tall <- file.path(dir, "tests/testthat.R") if (!test_r_file_exists(dir)) { if (verbose) vcr_cat_line(paste0(crayon::blue("tests/testthat.R:" ), " added")) @@ -106,17 +106,18 @@ use_vcr <- function(dir = ".", verbose = TRUE) { } # add helper-pkgname.R to tests/testthat/ - hf <- file.path(dir, sprintf("tests/testthat/setup-%s.R", pkg)) - if (!file.exists(hf)) { - file.create(hf, showWarnings = FALSE) + rel_hf <- "tests/testthat/helper-vcr.R" + abs_hf <- file.path(dir, rel_hf) + if (!file.exists(abs_hf)) { + file.create(abs_hf, showWarnings = FALSE) } - if (!any(grepl("vcr_configure", readLines(hf)))) { + if (!any(grepl("vcr_configure", readLines(abs_hf)))) { if (verbose) vcr_cat_line(paste0("Adding vcr config to ", - crayon::blue(sprintf("tests/testthat/setup-%s.R", pkg)))) - cat(vcr_text$config, file = hf, append = TRUE) + crayon::blue(rel_hf))) + cat(vcr_text$config, file = abs_hf, append = TRUE) } else { if (verbose) vcr_cat_info(paste0("vcr config appears to be already setup in ", - crayon::blue(sprintf("tests/testthat/setup-%s.R", pkg)))) + crayon::blue(rel_hf))) } # add dummy test file with example of use_cassette() diff --git a/R/vcr_test_path.R b/R/vcr_test_path.R index 95e132d..42bede6 100644 --- a/R/vcr_test_path.R +++ b/R/vcr_test_path.R @@ -3,9 +3,11 @@ #' This function, similar to `testthat::test_path()`, is designed to work both #' interactively and during tests, locating files in the `tests/` directory. #' +#' @note `vcr_test_path()` assumes you are using testthat for your unit tests. +#' #' @param ... Character vectors giving path component. each character string #' gets added on to the path, e.g., `vcr_test_path("a", "b")` becomes -#' `tests/a/b` when run from the root of the package. +#' `tests/a/b` relative to the root of the package. #' #' @return A character vector giving the path #' @export @@ -13,22 +15,16 @@ #' if (interactive()) { #' vcr_test_path("fixtures") #' } -# Adapted from https://github.com/r-lib/testthat/blob/45a9c705402bd51af29b9d999e587ba789f6203f/R/test-path.R#L1 vcr_test_path <- function(...) { - if (any(!nzchar(...))) { - stop("Please use non empty path elements.") - } + if (missing(...)) stop("Please provide a directory name.") + if (any(!nzchar(...))) stop("Please use non empty path elements.") - if (identical(Sys.getenv("TESTTHAT"), "true") && - !isTRUE(getOption("testthat_interactive"))) { - if (missing(...)) { - "../." - } else { - here::here("..", ...) - } - } else { - path <- here::here("tests", ...) - if (!dir.exists(path)) message("could not find ", path, "; creating it") - path + # dirname () moves up one level from testthat dir + root <- dirname(rprojroot::find_testthat_root_file()) + path <- file.path(root, ...) + if (!dir.exists(path)){ + message("could not find ", path, "; creating it") + dir.create(path) } + path } diff --git a/R/write.R b/R/write.R index 117b64f..224102f 100644 --- a/R/write.R +++ b/R/write.R @@ -34,7 +34,7 @@ dedup_keys <- function(x) { } str_breaks <- function(x) { - z <- split_str(x, 80L) # from src/split_str.cpp + z <- str_splitter(x, 80L) paste0(z, collapse = "\n") } @@ -50,10 +50,8 @@ prep_interaction <- function(x, file, bytes) { } else { get_body(x$response$body) } - body_nchar <- tryCatch(nchar(body), error = function(e) e) - body <- enc2utf8(body) if (length(body) == 0 || !nzchar(body)) body <- "" - list( + res = list( list( request = list( method = x$request$method, @@ -68,7 +66,7 @@ prep_interaction <- function(x, file, bytes) { status = x$response$status, headers = dedup_keys(x$response$headers), body = list( - encoding = sup_mssg(vcr_c$quiet, encoding_guess(x$response$body, bytes)), + encoding = "", file = x$response$disk, string = body ) @@ -77,6 +75,11 @@ prep_interaction <- function(x, file, bytes) { recorded_with = pkg_versions() ) ) + if (bytes) { + str_index <- which(grepl("string", names(res[[1]]$response$body))) + names(res[[1]]$response$body)[str_index] <- "base64_string" + } + return(res) } # param x: a list with "request" and "response" slots diff --git a/README.Rmd b/README.Rmd index ab8c1c0..6908d16 100644 --- a/README.Rmd +++ b/README.Rmd @@ -16,10 +16,10 @@ knitr::opts_chunk$set( -[![cran checks](https://cranchecks.info/badges/worst/vcr)](https://cranchecks.info/pkgs/vcr) +[![cran checks](https://badges.cranchecks.info/worst/vcr.svg)](https://cloud.r-project.org/web/checks/check_results_vcr.html) [![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active) [![R-check](https://github.com/ropensci/vcr/workflows/R-check/badge.svg)](https://github.com/ropensci/vcr/actions/) -[![codecov](https://codecov.io/gh/ropensci/vcr/branch/master/graph/badge.svg)](https://codecov.io/gh/ropensci/vcr) +[![codecov](https://codecov.io/gh/ropensci/vcr/branch/main/graph/badge.svg)](https://app.codecov.io/gh/ropensci/vcr) [![rstudio mirror downloads](https://cranlogs.r-pkg.org/badges/vcr)](https://github.com/r-hub/cranlogs.app) [![cran version](https://www.r-pkg.org/badges/version/vcr)](https://cran.r-project.org/package=vcr) @@ -42,7 +42,8 @@ install.packages("vcr") Development version: ```{r eval=FALSE} -remotes::install_github("ropensci/vcr") +# install.packages("pak") +pak::pak("ropensci/vcr") ``` ```{r} @@ -53,12 +54,13 @@ library("crul") ## Docs -Check out the [HTTP testing book](https://books.ropensci.org/http-testing) and the [vcr vignettes](https://docs.ropensci.org/vcr/articles/). +Check out the [HTTP testing book](https://books.ropensci.org/http-testing/) and the [vcr vignettes](https://docs.ropensci.org/vcr/articles/). ## Supported HTTP libraries -* [crul](https://docs.ropensci.org/crul/) +* [crul][] * [httr](https://httr.r-lib.org/) +* [httr2](https://httr2.r-lib.org/) ## Getting Started @@ -111,21 +113,23 @@ The canonical `vcr` (in Ruby) lists ports in other languages at -[![cran checks](https://cranchecks.info/badges/worst/vcr)](https://cranchecks.info/pkgs/vcr) +[![cran checks](https://badges.cranchecks.info/worst/vcr.svg)](https://cloud.r-project.org/web/checks/check_results_vcr.html) [![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active) [![R-check](https://github.com/ropensci/vcr/workflows/R-check/badge.svg)](https://github.com/ropensci/vcr/actions/) -[![codecov](https://codecov.io/gh/ropensci/vcr/branch/master/graph/badge.svg)](https://codecov.io/gh/ropensci/vcr) +[![codecov](https://codecov.io/gh/ropensci/vcr/branch/main/graph/badge.svg)](https://app.codecov.io/gh/ropensci/vcr) [![rstudio mirror downloads](https://cranlogs.r-pkg.org/badges/vcr)](https://github.com/r-hub/cranlogs.app) [![cran version](https://www.r-pkg.org/badges/version/vcr)](https://cran.r-project.org/package=vcr) @@ -25,26 +25,27 @@ Easier HTTP testing! Record HTTP requests and responses on disk and replay them Now your tests can work without any internet connection! -[Demo of adding vcr testing to an R package](https://github.com/maelle/exemplighratia/pull/2/files) +[Demo of adding vcr testing to an R package](https://github.com/ropensci-books/exemplighratia/pull/2/files), [corresponding narrative](https://books.ropensci.org/http-testing/vcr.html). ## Installation CRAN version: -```r +``` r install.packages("vcr") ``` Development version: -```r -remotes::install_github("ropensci/vcr") +``` r +# install.packages("pak") +pak::pak("ropensci/vcr") ``` -```r +``` r library("vcr") library("crul") ``` @@ -52,12 +53,13 @@ library("crul") ## Docs -Check out the [HTTP testing book](https://books.ropensci.org/http-testing) and the [vcr vignettes](https://docs.ropensci.org/vcr/articles/). +Check out the [HTTP testing book](https://books.ropensci.org/http-testing/) and the [vcr vignettes](https://docs.ropensci.org/vcr/articles/). ## Supported HTTP libraries -* [crul](https://docs.ropensci.org/crul) +* [crul][] * [httr](https://httr.r-lib.org/) +* [httr2](https://httr2.r-lib.org/) ## Getting Started @@ -81,7 +83,7 @@ This will: * setup a config file for `vcr` * add an example test file for `vcr` * make a `.gitattributes` file with settings for `vcr` -* make a `./tests/testthat/setup-vcr.R` file +* make a `./tests/testthat/helper-vcr.R` file What you will see in the R console: @@ -92,10 +94,10 @@ What you will see in the R console: ✓ Creating directory: ./tests/testthat ◉ Looking for testthat.R file or similar ✓ tests/testthat.R: added -✓ Adding vcr config to tests/testthat/setup-vcr.example.R +✓ Adding vcr config to tests/testthat/helper-vcr.example.R ✓ Adding example test file tests/testthat/test-vcr_example.R ✓ .gitattributes: added -◉ Learn more about `vcr`: https://books.ropensci.org/http-testing +◉ Learn more about `vcr`: https://books.ropensci.org/http-testing/ ``` ### Protecting secrets @@ -104,7 +106,7 @@ Secrets often turn up in API work. A common example is an API key. `vcr` saves responses from APIs as YAML files, and this will include your secrets unless you indicate to `vcr` what they are and how to protect them. The `vcr_configure` function has the `filter_sensitive_data` argument function for just this situation. The `filter_sensitive_data` argument takes a named list where the _name_ of the list is the string that will be used in the recorded cassettes _instead of_ the secret, which is the list _item_. -`vcr` will manage the replacement of that for you, so all you need to do is to edit your `setup-vcr.R` file like this: +`vcr` will manage the replacement of that for you, so all you need to do is to edit your [`helper-vcr.R` file](https://testthat.r-lib.org/reference/test_dir.html#special-files) like this: ```r library("vcr") # *Required* as vcr is set up on loading @@ -152,7 +154,7 @@ Furthermore, as by default requests matching does not include the API key, thing E.g. to have tests pass on continuous integration for external pull requests to your code repository. * vcr does not need an actual API key for requests once the cassettes are created, as no real requests will be made. -* you still need to fool your _package_ into believing there is an API key as it will construct requests with it. So add the following lines to a testthat setup file (e.g. `tests/testthat/setup-vcr.R`) +* you still need to fool your _package_ into believing there is an API key as it will construct requests with it. So add the following lines to a testthat setup file (e.g. `tests/testthat/helper-vcr.R`) ```r if (!nzchar(Sys.getenv("APIKEY"))) { @@ -223,7 +225,7 @@ If you want to get a feel for how vcr works, although you don't need too. -```r +``` r library(vcr) library(crul) @@ -238,7 +240,7 @@ system.time( The request gets recorded, and all subsequent requests of the same form used the cached HTTP response, and so are much faster -```r +``` r system.time( use_cassette(name = "helloworld", { cli$get("get") @@ -359,10 +361,14 @@ We set the following defaults: * log = `FALSE` * log_opts = `list(file = "vcr.log", log_prefix = "Cassette", date = TRUE)` * filter_sensitive_data = `NULL` + * filter_sensitive_data_regex = `NULL` * filter_request_headers = `NULL` * filter_response_headers = `NULL` + * filter_query_parameters = `NULL` * write_disk_path = `NULL` * verbose_errors = `FALSE` + * quiet = `TRUE` + * warn_on_empty_cassette = `TRUE` You can get the defaults programmatically with @@ -380,7 +386,7 @@ vcr_configure() Calling `vcr_configuration()` gives you some of the more important configuration parameters in a nice tidy print out -```r +``` r vcr_configuration() #> #> Cassette Dir: . @@ -427,7 +433,7 @@ You can set your own options by tweaking the `match_requests_on` parameter: -```r +``` r use_cassette(name = "one", { cli$post("post", body = list(a = 5)) }, @@ -450,21 +456,23 @@ We've tried to make sure the parameters that are ignored are marked as such. Kee ## Example packages using vcr +* [allcontributors][] +* [bold][] +* [qualtRics][] * [rgbif][] +* [ritis][] * [rredlist][] -* [bold][] +* [rtoot][] +* [rtweet][] * [wikitaxa][] * [worrms][] -* [microdemic][] -* [zbank][] -* [rplos][] -* [ritis][] ## Contributors * [Scott Chamberlain](https://github.com/sckott) * [Aaron Wolen](https://github.com/aaronwolen) * [Maëlle Salmon](https://github.com/maelle) +* [Daniel Possenriede](https://github.com/dpprdan) ## Meta @@ -473,14 +481,15 @@ We've tried to make sure the parameters that are ignored are marked as such. Kee * Get citation information for `vcr` in R doing `citation(package = 'vcr')` * Please note that this package is released with a [Contributor Code of Conduct](https://ropensci.org/code-of-conduct/). By contributing to this project, you agree to abide by its terms. -[webmockr]: https://docs.ropensci.org/webmockr -[crul]: https://docs.ropensci.org/crul +[allcontributors]: https://github.com/ropenscilabs/allcontributors +[bold]: https://github.com/ropensci/bold +[crul]: https://docs.ropensci.org/crul/ +[qualtRics]: https://github.com/ropensci/qualtRics [rgbif]: https://github.com/ropensci/rgbif +[ritis]: https://github.com/ropensci/ritis [rredlist]: https://github.com/ropensci/rredlist -[bold]: https://github.com/ropensci/bold +[rtoot]: https://github.com/gesistsa/rtoot +[rtweet]: https://github.com/ropensci/rtweet +[webmockr]: https://docs.ropensci.org/webmockr/ [wikitaxa]: https://github.com/ropensci/wikitaxa [worrms]: https://github.com/ropensci/worrms -[microdemic]: https://github.com/ropensci/microdemic -[zbank]: https://github.com/ropenscilabs/zbank -[rplos]: https://github.com/ropensci/rplos -[ritis]: https://github.com/ropensci/ritis diff --git a/_pkgdown.yml b/_pkgdown.yml index e858107..0ba9598 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -60,6 +60,7 @@ reference: - RequestHandler - RequestHandlerCrul - RequestHandlerHttr + - RequestHandlerHttr2 - RequestMatcherRegistry - Serializers - serializer_fetch @@ -70,6 +71,7 @@ reference: - vcr_log_file - vcr_log_info - crul_request + - str_splitter articles: - title: All vignettes @@ -84,3 +86,4 @@ articles: - '`record-modes`' - '`lightswitch`' - '`internals`' + - '`design`' diff --git a/codemeta.json b/codemeta.json index 9aba644..6999164 100644 --- a/codemeta.json +++ b/codemeta.json @@ -1,22 +1,26 @@ { - "@context": [ - "http://purl.org/codemeta/2.0", - "http://schema.org" - ], + "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "identifier": "vcr", - "description": "Record test suite 'HTTP' requests and replays them during\n future runs. A port of the Ruby gem of the same name\n (). Works by hooking into the 'webmockr'\n R package for matching 'HTTP' requests by various rules ('HTTP' method,\n 'URL', query parameters, headers, body, etc.), and then caching\n real 'HTTP' responses on disk in 'cassettes'. Subsequent 'HTTP' requests\n matching any previous requests in the same 'cassette' use a cached\n 'HTTP' response.", + "description": "Record test suite 'HTTP' requests and replays them during future runs. A port of the Ruby gem of the same name (). Works by hooking into the 'webmockr' R package for matching 'HTTP' requests by various rules ('HTTP' method, 'URL', query parameters, headers, body, etc.), and then caching real 'HTTP' responses on disk in 'cassettes'. Subsequent 'HTTP' requests matching any previous requests in the same 'cassette' use a cached 'HTTP' response.", "name": "vcr: Record 'HTTP' Calls to Disk", + "relatedLink": ["https://books.ropensci.org/http-testing/", "https://docs.ropensci.org/vcr/"], "codeRepository": "https://github.com/ropensci/vcr/", "issueTracker": "https://github.com/ropensci/vcr/issues", "license": "https://spdx.org/licenses/MIT", - "version": "0.6.0", + "version": "1.6.0", "programmingLanguage": { "@type": "ComputerLanguage", "name": "R", "url": "https://r-project.org" }, - "runtimePlatform": "R version 4.0.3 Patched (2020-12-04 r79565)", + "runtimePlatform": "R version 4.4.1 Patched (2024-06-25 r86831)", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, "author": [ { "@type": "Person", @@ -24,6 +28,30 @@ "familyName": "Chamberlain", "email": "sckott@protonmail.com", "@id": "https://orcid.org/0000-0003-1444-9135" + }, + { + "@type": "Person", + "givenName": "Aaron", + "familyName": "Wolen", + "@id": "https://orcid.org/0000-0003-2542-2202" + }, + { + "@type": "Person", + "givenName": "Maëlle", + "familyName": "Salmon", + "@id": "https://orcid.org/0000-0002-2815-0399" + }, + { + "@type": "Person", + "givenName": "Daniel", + "familyName": "Possenriede", + "@id": "https://orcid.org/0000-0002-6738-9845" + } + ], + "funder": [ + { + "@type": "Organization", + "name": "rOpenSci" } ], "maintainer": [ @@ -40,7 +68,7 @@ "@type": "SoftwareApplication", "identifier": "roxygen2", "name": "roxygen2", - "version": ">= 7.0.2", + "version": ">= 7.2.1", "provider": { "@id": "https://cran.r-project.org", "@type": "Organization", @@ -156,10 +184,22 @@ "url": "https://cran.r-project.org" }, "sameAs": "https://CRAN.R-project.org/package=withr" + }, + { + "@type": "SoftwareApplication", + "identifier": "webfakes", + "name": "webfakes", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=webfakes" } ], - "softwareRequirements": [ - { + "softwareRequirements": { + "1": { "@type": "SoftwareApplication", "identifier": "crul", "name": "crul", @@ -172,7 +212,7 @@ }, "sameAs": "https://CRAN.R-project.org/package=crul" }, - { + "2": { "@type": "SoftwareApplication", "identifier": "httr", "name": "httr", @@ -184,11 +224,23 @@ }, "sameAs": "https://CRAN.R-project.org/package=httr" }, - { + "3": { + "@type": "SoftwareApplication", + "identifier": "httr2", + "name": "httr2", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=httr2" + }, + "4": { "@type": "SoftwareApplication", "identifier": "webmockr", "name": "webmockr", - "version": ">= 0.7.4", + "version": ">= 0.8.0", "provider": { "@id": "https://cran.r-project.org", "@type": "Organization", @@ -197,7 +249,7 @@ }, "sameAs": "https://CRAN.R-project.org/package=webmockr" }, - { + "5": { "@type": "SoftwareApplication", "identifier": "urltools", "name": "urltools", @@ -209,7 +261,7 @@ }, "sameAs": "https://CRAN.R-project.org/package=urltools" }, - { + "6": { "@type": "SoftwareApplication", "identifier": "yaml", "name": "yaml", @@ -221,7 +273,7 @@ }, "sameAs": "https://CRAN.R-project.org/package=yaml" }, - { + "7": { "@type": "SoftwareApplication", "identifier": "R6", "name": "R6", @@ -233,7 +285,7 @@ }, "sameAs": "https://CRAN.R-project.org/package=R6" }, - { + "8": { "@type": "SoftwareApplication", "identifier": "base64enc", "name": "base64enc", @@ -245,48 +297,22 @@ }, "sameAs": "https://CRAN.R-project.org/package=base64enc" }, - { + "9": { "@type": "SoftwareApplication", - "identifier": "https://sysreqs.r-hub.io/get/cxx11" - } - ], + "identifier": "rprojroot", + "name": "rprojroot", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=rprojroot" + }, + "SystemRequirements": null + }, "applicationCategory": "Web", "isPartOf": "https://ropensci.org", - "keywords": ["http", "https", "API", "web-services", "curl", "mock", "mocking", "http-mocking", "testing", "testing-tools", "tdd", "unit-testing", "rstats", "vcr", "r", "r-package"], - "contIntegration": "https://codecov.io/gh/ropensci/vcr", - "readme": "https://github.com/ropensci/vcr/blob/master/README.md", - "fileSize": "1354.543KB", - "relatedLink": [ - "https://ropenscilabs.github.io/http-testing-book/", - "https://books.ropensci.org/http-testing/" - ], - "developmentStatus": "https://www.repostatus.org/#active", - "provider": { - "@id": "https://cran.r-project.org", - "@type": "Organization", - "name": "Comprehensive R Archive Network (CRAN)", - "url": "https://cran.r-project.org" - }, - "contributor": [ - { - "@type": "Person", - "givenName": "Aaron", - "familyName": "Wolen", - "@id": "https://orcid.org/0000-0003-2542-2202" - }, - { - "@type": "Person", - "givenName": "Maëlle", - "familyName": "Salmon", - "@id": "https://orcid.org/0000-0002-2815-0399" - } - ], - "copyrightHolder": {}, - "funder": [ - { - "@type": "Organization", - "name": "rOpenSci" - } - ], - "releaseNotes": "https://github.com/ropensci/vcr/blob/master/NEWS.md" + "keywords": ["http", "https", "API", "web-services", "curl", "mock", "mocking", "http-mocking", "testing", "testing-tools", "tdd"], + "fileSize": "922.454KB" } diff --git a/cran-comments.md b/cran-comments.md index 655b1de..67674b1 100644 --- a/cran-comments.md +++ b/cran-comments.md @@ -1,20 +1,20 @@ ## Test environments -* local OS X install, R 4.0.3 Patched -* ubuntu 16.04 (on GitHub Actions), R 4.0.3 +* local macOS, R 4.4.1 +* ubuntu 22.04 (on GitHub Actions), R 4.4.1 * win-builder (devel and release) ## R CMD check results 0 errors | 0 warnings | 0 notes -## Reverse dependencies +## Revdep check results -* I have run R CMD check on the 43 reverse dependencies. Summary at https://github.com/ropensci/vcr/actions?query=workflow%3Arevdep Problems were found in checks, but were not related to vcr. +We checked all 53 reverse dependencies, comparing R CMD check results across CRAN and dev verions of this package. We saw zero new problems. -------- -This version adds new features, and improves documentation. +This version adds support for httr2. Thanks very much, Scott Chamberlain diff --git a/man/Cassette.Rd b/man/Cassette.Rd index c16c065..f1b0f4b 100644 --- a/man/Cassette.Rd +++ b/man/Cassette.Rd @@ -37,6 +37,7 @@ to make a complete \code{crul} HTTP response object } \examples{ +\dontrun{ library(vcr) vcr_configure(dir = tempdir()) @@ -61,7 +62,8 @@ library(vcr) vcr_configure(dir = tempdir()) res <- Cassette$new(name = "jane") library(crul) -HttpClient$new("https://httpbin.org")$get("get") +# HttpClient$new("https://hb.opencpu.org")$get("get") +} } \seealso{ \code{\link[=vcr_configure]{vcr_configure()}}, \code{\link[=use_cassette]{use_cassette()}}, \code{\link[=insert_cassette]{insert_cassette()}} @@ -136,43 +138,43 @@ be recorded back to file} \section{Methods}{ \subsection{Public methods}{ \itemize{ -\item \href{#method-new}{\code{Cassette$new()}} -\item \href{#method-print}{\code{Cassette$print()}} -\item \href{#method-call_block}{\code{Cassette$call_block()}} -\item \href{#method-eject}{\code{Cassette$eject()}} -\item \href{#method-file}{\code{Cassette$file()}} -\item \href{#method-recording}{\code{Cassette$recording()}} -\item \href{#method-is_empty}{\code{Cassette$is_empty()}} -\item \href{#method-originally_recorded_at}{\code{Cassette$originally_recorded_at()}} -\item \href{#method-serializable_hash}{\code{Cassette$serializable_hash()}} -\item \href{#method-interactions_to_record}{\code{Cassette$interactions_to_record()}} -\item \href{#method-merged_interactions}{\code{Cassette$merged_interactions()}} -\item \href{#method-up_to_date_interactions}{\code{Cassette$up_to_date_interactions()}} -\item \href{#method-should_re_record}{\code{Cassette$should_re_record()}} -\item \href{#method-should_stub_requests}{\code{Cassette$should_stub_requests()}} -\item \href{#method-should_remove_matching_existing_interactions}{\code{Cassette$should_remove_matching_existing_interactions()}} -\item \href{#method-storage_key}{\code{Cassette$storage_key()}} -\item \href{#method-raw_cassette_bytes}{\code{Cassette$raw_cassette_bytes()}} -\item \href{#method-make_dir}{\code{Cassette$make_dir()}} -\item \href{#method-deserialized_hash}{\code{Cassette$deserialized_hash()}} -\item \href{#method-previously_recorded_interactions}{\code{Cassette$previously_recorded_interactions()}} -\item \href{#method-write_recorded_interactions_to_disk}{\code{Cassette$write_recorded_interactions_to_disk()}} -\item \href{#method-record_http_interaction}{\code{Cassette$record_http_interaction()}} -\item \href{#method-any_new_recorded_interactions}{\code{Cassette$any_new_recorded_interactions()}} -\item \href{#method-make_args}{\code{Cassette$make_args()}} -\item \href{#method-write_metadata}{\code{Cassette$write_metadata()}} -\item \href{#method-http_interactions}{\code{Cassette$http_interactions()}} -\item \href{#method-make_http_interaction}{\code{Cassette$make_http_interaction()}} -\item \href{#method-serialize_to_crul}{\code{Cassette$serialize_to_crul()}} -\item \href{#method-set_request}{\code{Cassette$set_request()}} -\item \href{#method-set_handler}{\code{Cassette$set_handler()}} -\item \href{#method-add_redirect}{\code{Cassette$add_redirect()}} -\item \href{#method-clone}{\code{Cassette$clone()}} -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-new}{}}} +\item \href{#method-Cassette-new}{\code{Cassette$new()}} +\item \href{#method-Cassette-print}{\code{Cassette$print()}} +\item \href{#method-Cassette-call_block}{\code{Cassette$call_block()}} +\item \href{#method-Cassette-eject}{\code{Cassette$eject()}} +\item \href{#method-Cassette-file}{\code{Cassette$file()}} +\item \href{#method-Cassette-recording}{\code{Cassette$recording()}} +\item \href{#method-Cassette-is_empty}{\code{Cassette$is_empty()}} +\item \href{#method-Cassette-originally_recorded_at}{\code{Cassette$originally_recorded_at()}} +\item \href{#method-Cassette-serializable_hash}{\code{Cassette$serializable_hash()}} +\item \href{#method-Cassette-interactions_to_record}{\code{Cassette$interactions_to_record()}} +\item \href{#method-Cassette-merged_interactions}{\code{Cassette$merged_interactions()}} +\item \href{#method-Cassette-up_to_date_interactions}{\code{Cassette$up_to_date_interactions()}} +\item \href{#method-Cassette-should_re_record}{\code{Cassette$should_re_record()}} +\item \href{#method-Cassette-should_stub_requests}{\code{Cassette$should_stub_requests()}} +\item \href{#method-Cassette-should_remove_matching_existing_interactions}{\code{Cassette$should_remove_matching_existing_interactions()}} +\item \href{#method-Cassette-storage_key}{\code{Cassette$storage_key()}} +\item \href{#method-Cassette-raw_cassette_bytes}{\code{Cassette$raw_cassette_bytes()}} +\item \href{#method-Cassette-make_dir}{\code{Cassette$make_dir()}} +\item \href{#method-Cassette-deserialized_hash}{\code{Cassette$deserialized_hash()}} +\item \href{#method-Cassette-previously_recorded_interactions}{\code{Cassette$previously_recorded_interactions()}} +\item \href{#method-Cassette-write_recorded_interactions_to_disk}{\code{Cassette$write_recorded_interactions_to_disk()}} +\item \href{#method-Cassette-record_http_interaction}{\code{Cassette$record_http_interaction()}} +\item \href{#method-Cassette-any_new_recorded_interactions}{\code{Cassette$any_new_recorded_interactions()}} +\item \href{#method-Cassette-make_args}{\code{Cassette$make_args()}} +\item \href{#method-Cassette-write_metadata}{\code{Cassette$write_metadata()}} +\item \href{#method-Cassette-http_interactions}{\code{Cassette$http_interactions()}} +\item \href{#method-Cassette-make_http_interaction}{\code{Cassette$make_http_interaction()}} +\item \href{#method-Cassette-serialize_to_crul}{\code{Cassette$serialize_to_crul()}} +\item \href{#method-Cassette-set_request}{\code{Cassette$set_request()}} +\item \href{#method-Cassette-set_handler}{\code{Cassette$set_handler()}} +\item \href{#method-Cassette-add_redirect}{\code{Cassette$add_redirect()}} +\item \href{#method-Cassette-clone}{\code{Cassette$clone()}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Cassette-new}{}}} \subsection{Method \code{new()}}{ Create a new \code{Cassette} object \subsection{Usage}{ @@ -254,8 +256,8 @@ A new \code{Cassette} object } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-print}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Cassette-print}{}}} \subsection{Method \code{print()}}{ print method for \code{Cassette} objects \subsection{Usage}{ @@ -273,8 +275,8 @@ print method for \code{Cassette} objects } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-call_block}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Cassette-call_block}{}}} \subsection{Method \code{call_block()}}{ run code \subsection{Usage}{ @@ -293,8 +295,8 @@ various } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-eject}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Cassette-eject}{}}} \subsection{Method \code{eject()}}{ ejects the current cassette \subsection{Usage}{ @@ -306,8 +308,8 @@ self } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-file}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Cassette-file}{}}} \subsection{Method \code{file()}}{ get the file path for the cassette \subsection{Usage}{ @@ -319,8 +321,8 @@ character } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-recording}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Cassette-recording}{}}} \subsection{Method \code{recording()}}{ is the cassette in recording mode? \subsection{Usage}{ @@ -332,8 +334,8 @@ logical } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-is_empty}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Cassette-is_empty}{}}} \subsection{Method \code{is_empty()}}{ is the cassette on disk empty \subsection{Usage}{ @@ -345,8 +347,8 @@ logical } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-originally_recorded_at}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Cassette-originally_recorded_at}{}}} \subsection{Method \code{originally_recorded_at()}}{ timestamp the cassette was originally recorded at \subsection{Usage}{ @@ -358,8 +360,8 @@ POSIXct date } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-serializable_hash}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Cassette-serializable_hash}{}}} \subsection{Method \code{serializable_hash()}}{ Get a list of the http interactions to record + recorded_with \subsection{Usage}{ @@ -371,8 +373,8 @@ list } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-interactions_to_record}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Cassette-interactions_to_record}{}}} \subsection{Method \code{interactions_to_record()}}{ Get the list of http interactions to record \subsection{Usage}{ @@ -384,8 +386,8 @@ list } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-merged_interactions}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Cassette-merged_interactions}{}}} \subsection{Method \code{merged_interactions()}}{ Get interactions to record \subsection{Usage}{ @@ -397,8 +399,8 @@ list } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-up_to_date_interactions}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Cassette-up_to_date_interactions}{}}} \subsection{Method \code{up_to_date_interactions()}}{ Cleans out any old interactions based on the re_record_interval and clean_outdated_http_interactions settings @@ -418,8 +420,8 @@ list of interactions to record } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-should_re_record}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Cassette-should_re_record}{}}} \subsection{Method \code{should_re_record()}}{ Should re-record interactions? \subsection{Usage}{ @@ -431,8 +433,8 @@ logical } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-should_stub_requests}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Cassette-should_stub_requests}{}}} \subsection{Method \code{should_stub_requests()}}{ Is record mode NOT "all"? \subsection{Usage}{ @@ -444,8 +446,8 @@ logical } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-should_remove_matching_existing_interactions}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Cassette-should_remove_matching_existing_interactions}{}}} \subsection{Method \code{should_remove_matching_existing_interactions()}}{ Is record mode "all"? \subsection{Usage}{ @@ -457,8 +459,8 @@ logical } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-storage_key}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Cassette-storage_key}{}}} \subsection{Method \code{storage_key()}}{ Get the serializer path \subsection{Usage}{ @@ -470,8 +472,8 @@ character } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-raw_cassette_bytes}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Cassette-raw_cassette_bytes}{}}} \subsection{Method \code{raw_cassette_bytes()}}{ Get character string of entire cassette; bytes is a misnomer \subsection{Usage}{ @@ -483,8 +485,8 @@ character } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-make_dir}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Cassette-make_dir}{}}} \subsection{Method \code{make_dir()}}{ Create the directory that holds the cassettes, if not present \subsection{Usage}{ @@ -496,8 +498,8 @@ no return; creates a directory recursively, if missing } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-deserialized_hash}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Cassette-deserialized_hash}{}}} \subsection{Method \code{deserialized_hash()}}{ get http interactions from the cassette via the serializer \subsection{Usage}{ @@ -509,8 +511,8 @@ list } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-previously_recorded_interactions}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Cassette-previously_recorded_interactions}{}}} \subsection{Method \code{previously_recorded_interactions()}}{ get all previously recorded interactions \subsection{Usage}{ @@ -522,8 +524,8 @@ list } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-write_recorded_interactions_to_disk}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Cassette-write_recorded_interactions_to_disk}{}}} \subsection{Method \code{write_recorded_interactions_to_disk()}}{ write recorded interactions to disk \subsection{Usage}{ @@ -535,8 +537,8 @@ nothing returned } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-record_http_interaction}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Cassette-record_http_interaction}{}}} \subsection{Method \code{record_http_interaction()}}{ record an http interaction (doesn't write to disk) \subsection{Usage}{ @@ -546,7 +548,7 @@ record an http interaction (doesn't write to disk) \subsection{Arguments}{ \if{html}{\out{
}} \describe{ -\item{\code{x}}{an crul or httr response object, with the request at \verb{$request}} +\item{\code{x}}{a crul, httr, or httr2 response object, with the request at \verb{$request}} } \if{html}{\out{
}} } @@ -555,8 +557,8 @@ nothing returned } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-any_new_recorded_interactions}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Cassette-any_new_recorded_interactions}{}}} \subsection{Method \code{any_new_recorded_interactions()}}{ Are there any new recorded interactions? \subsection{Usage}{ @@ -568,8 +570,8 @@ logical } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-make_args}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Cassette-make_args}{}}} \subsection{Method \code{make_args()}}{ make list of all options \subsection{Usage}{ @@ -581,8 +583,8 @@ nothing returned } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-write_metadata}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Cassette-write_metadata}{}}} \subsection{Method \code{write_metadata()}}{ write metadata to the cassette \subsection{Usage}{ @@ -594,8 +596,8 @@ nothing returned } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-http_interactions}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Cassette-http_interactions}{}}} \subsection{Method \code{http_interactions()}}{ make \link{HTTPInteractionList} object, assign to http_interactions_ var \subsection{Usage}{ @@ -607,8 +609,8 @@ nothing returned } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-make_http_interaction}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Cassette-make_http_interaction}{}}} \subsection{Method \code{make_http_interaction()}}{ Make an \code{HTTPInteraction} object \subsection{Usage}{ @@ -618,7 +620,7 @@ Make an \code{HTTPInteraction} object \subsection{Arguments}{ \if{html}{\out{
}} \describe{ -\item{\code{x}}{an crul or httr response object, with the request at \verb{$request}} +\item{\code{x}}{A crul, httr, or httr2 response object, with the request at \verb{$request}} } \if{html}{\out{
}} } @@ -627,8 +629,8 @@ an object of class \link{HTTPInteraction} } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-serialize_to_crul}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Cassette-serialize_to_crul}{}}} \subsection{Method \code{serialize_to_crul()}}{ Make a crul response object \subsection{Usage}{ @@ -640,8 +642,8 @@ a crul response } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-set_request}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Cassette-set_request}{}}} \subsection{Method \code{set_request()}}{ Set original HTTP request in the cassette in case needed for redirect handling @@ -661,8 +663,8 @@ case needed for redirect handling } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-set_handler}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Cassette-set_handler}{}}} \subsection{Method \code{set_handler()}}{ Set RequestHandler in the cassette in case needed for redirect handling @@ -682,8 +684,8 @@ case needed for redirect handling } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-add_redirect}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Cassette-add_redirect}{}}} \subsection{Method \code{add_redirect()}}{ Add an http request to a pool \subsection{Usage}{ @@ -702,8 +704,8 @@ Add an http request to a pool } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-clone}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Cassette-clone}{}}} \subsection{Method \code{clone()}}{ The objects of this class are cloneable with this method. \subsection{Usage}{ diff --git a/man/FileSystem.Rd b/man/FileSystem.Rd index 10e53fc..1c93db2 100644 --- a/man/FileSystem.Rd +++ b/man/FileSystem.Rd @@ -37,16 +37,16 @@ Get absolute path to the \code{storage_location} \section{Methods}{ \subsection{Public methods}{ \itemize{ -\item \href{#method-new}{\code{FileSystem$new()}} -\item \href{#method-get_cassette}{\code{FileSystem$get_cassette()}} -\item \href{#method-is_empty}{\code{FileSystem$is_empty()}} -\item \href{#method-set_cassette}{\code{FileSystem$set_cassette()}} -\item \href{#method-clone}{\code{FileSystem$clone()}} +\item \href{#method-FileSystem-new}{\code{FileSystem$new()}} +\item \href{#method-FileSystem-get_cassette}{\code{FileSystem$get_cassette()}} +\item \href{#method-FileSystem-is_empty}{\code{FileSystem$is_empty()}} +\item \href{#method-FileSystem-set_cassette}{\code{FileSystem$set_cassette()}} +\item \href{#method-FileSystem-clone}{\code{FileSystem$clone()}} } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-new}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-FileSystem-new}{}}} \subsection{Method \code{new()}}{ Create a new \code{FileSystem} object \subsection{Usage}{ @@ -80,8 +80,8 @@ A new \code{FileSystem} object } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-get_cassette}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-FileSystem-get_cassette}{}}} \subsection{Method \code{get_cassette()}}{ Gets the cassette for the given storage key (file name) \subsection{Usage}{ @@ -100,8 +100,8 @@ named list, from \code{yaml::yaml.load_file} } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-is_empty}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-FileSystem-is_empty}{}}} \subsection{Method \code{is_empty()}}{ Checks if a cassette is empty or not \subsection{Usage}{ @@ -113,8 +113,8 @@ logical } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-set_cassette}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-FileSystem-set_cassette}{}}} \subsection{Method \code{set_cassette()}}{ Sets the cassette for the given storage key (file name) \subsection{Usage}{ @@ -135,8 +135,8 @@ no return; writes to disk } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-clone}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-FileSystem-clone}{}}} \subsection{Method \code{clone()}}{ The objects of this class are cloneable with this method. \subsection{Usage}{ diff --git a/man/HTTPInteraction.Rd b/man/HTTPInteraction.Rd index 7d6f38b..326be11 100644 --- a/man/HTTPInteraction.Rd +++ b/man/HTTPInteraction.Rd @@ -21,7 +21,7 @@ Create a HTTPInteraction object from a hash \dontrun{ # make the request library(vcr) -url <- "https://eu.httpbin.org/post" +url <- "https://hb.opencpu.org/post" body <- list(foo = "bar") cli <- crul::HttpClient$new(url = url) res <- cli$post(body = body) @@ -63,15 +63,15 @@ HTTPInteraction$new()$from_hash(my_hash) \section{Methods}{ \subsection{Public methods}{ \itemize{ -\item \href{#method-new}{\code{HTTPInteraction$new()}} -\item \href{#method-to_hash}{\code{HTTPInteraction$to_hash()}} -\item \href{#method-from_hash}{\code{HTTPInteraction$from_hash()}} -\item \href{#method-clone}{\code{HTTPInteraction$clone()}} +\item \href{#method-HTTPInteraction-new}{\code{HTTPInteraction$new()}} +\item \href{#method-HTTPInteraction-to_hash}{\code{HTTPInteraction$to_hash()}} +\item \href{#method-HTTPInteraction-from_hash}{\code{HTTPInteraction$from_hash()}} +\item \href{#method-HTTPInteraction-clone}{\code{HTTPInteraction$clone()}} } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-new}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-HTTPInteraction-new}{}}} \subsection{Method \code{new()}}{ Create a new \code{HTTPInteraction} object \subsection{Usage}{ @@ -94,8 +94,8 @@ A new \code{HTTPInteraction} object } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-to_hash}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-HTTPInteraction-to_hash}{}}} \subsection{Method \code{to_hash()}}{ Create a hash from the HTTPInteraction object \subsection{Usage}{ @@ -107,8 +107,8 @@ a named list } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-from_hash}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-HTTPInteraction-from_hash}{}}} \subsection{Method \code{from_hash()}}{ Create a HTTPInteraction object from a hash \subsection{Usage}{ @@ -127,8 +127,8 @@ a new \code{HttpInteraction} object } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-clone}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-HTTPInteraction-clone}{}}} \subsection{Method \code{clone()}}{ The objects of this class are cloneable with this method. \subsection{Usage}{ diff --git a/man/HTTPInteractionList.Rd b/man/HTTPInteractionList.Rd index bc491a6..2914dc5 100644 --- a/man/HTTPInteractionList.Rd +++ b/man/HTTPInteractionList.Rd @@ -43,7 +43,7 @@ vcr_configure( ## make the request ### turn off mocking crul::mock(FALSE) -url <- "https://eu.httpbin.org/post" +url <- "https://hb.opencpu.org/post" cli <- crul::HttpClient$new(url = url) res <- cli$post(body = list(a = 5)) @@ -94,18 +94,18 @@ x$response_for(request) \section{Methods}{ \subsection{Public methods}{ \itemize{ -\item \href{#method-new}{\code{HTTPInteractionList$new()}} -\item \href{#method-response_for}{\code{HTTPInteractionList$response_for()}} -\item \href{#method-has_interaction_matching}{\code{HTTPInteractionList$has_interaction_matching()}} -\item \href{#method-has_used_interaction_matching}{\code{HTTPInteractionList$has_used_interaction_matching()}} -\item \href{#method-remaining_unused_interaction_count}{\code{HTTPInteractionList$remaining_unused_interaction_count()}} -\item \href{#method-assert_no_unused_interactions}{\code{HTTPInteractionList$assert_no_unused_interactions()}} -\item \href{#method-clone}{\code{HTTPInteractionList$clone()}} +\item \href{#method-HTTPInteractionList-new}{\code{HTTPInteractionList$new()}} +\item \href{#method-HTTPInteractionList-response_for}{\code{HTTPInteractionList$response_for()}} +\item \href{#method-HTTPInteractionList-has_interaction_matching}{\code{HTTPInteractionList$has_interaction_matching()}} +\item \href{#method-HTTPInteractionList-has_used_interaction_matching}{\code{HTTPInteractionList$has_used_interaction_matching()}} +\item \href{#method-HTTPInteractionList-remaining_unused_interaction_count}{\code{HTTPInteractionList$remaining_unused_interaction_count()}} +\item \href{#method-HTTPInteractionList-assert_no_unused_interactions}{\code{HTTPInteractionList$assert_no_unused_interactions()}} +\item \href{#method-HTTPInteractionList-clone}{\code{HTTPInteractionList$clone()}} } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-new}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-HTTPInteractionList-new}{}}} \subsection{Method \code{new()}}{ Create a new \code{HTTPInteractionList} object \subsection{Usage}{ @@ -140,8 +140,8 @@ A new \code{HTTPInteractionList} object } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-response_for}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-HTTPInteractionList-response_for}{}}} \subsection{Method \code{response_for()}}{ Check if there's a matching interaction, returns a response object @@ -158,8 +158,8 @@ response object } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-has_interaction_matching}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-HTTPInteractionList-has_interaction_matching}{}}} \subsection{Method \code{has_interaction_matching()}}{ Check if has a matching interaction \subsection{Usage}{ @@ -178,8 +178,8 @@ logical } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-has_used_interaction_matching}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-HTTPInteractionList-has_used_interaction_matching}{}}} \subsection{Method \code{has_used_interaction_matching()}}{ check if has used interactions matching a given request \subsection{Usage}{ @@ -198,8 +198,8 @@ logical } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-remaining_unused_interaction_count}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-HTTPInteractionList-remaining_unused_interaction_count}{}}} \subsection{Method \code{remaining_unused_interaction_count()}}{ Number of unused interactions \subsection{Usage}{ @@ -211,8 +211,8 @@ integer } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-assert_no_unused_interactions}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-HTTPInteractionList-assert_no_unused_interactions}{}}} \subsection{Method \code{assert_no_unused_interactions()}}{ Checks if there are no unused interactions left. \subsection{Usage}{ @@ -224,8 +224,8 @@ various } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-clone}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-HTTPInteractionList-clone}{}}} \subsection{Method \code{clone()}}{ The objects of this class are cloneable with this method. \subsection{Usage}{ diff --git a/man/Hooks.Rd b/man/Hooks.Rd index 4633f09..10fa35e 100644 --- a/man/Hooks.Rd +++ b/man/Hooks.Rd @@ -29,15 +29,15 @@ Make a hook. \section{Methods}{ \subsection{Public methods}{ \itemize{ -\item \href{#method-invoke_hook}{\code{Hooks$invoke_hook()}} -\item \href{#method-clear_hooks}{\code{Hooks$clear_hooks()}} -\item \href{#method-define_hook}{\code{Hooks$define_hook()}} -\item \href{#method-clone}{\code{Hooks$clone()}} +\item \href{#method-Hooks-invoke_hook}{\code{Hooks$invoke_hook()}} +\item \href{#method-Hooks-clear_hooks}{\code{Hooks$clear_hooks()}} +\item \href{#method-Hooks-define_hook}{\code{Hooks$define_hook()}} +\item \href{#method-Hooks-clone}{\code{Hooks$clone()}} } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-invoke_hook}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Hooks-invoke_hook}{}}} \subsection{Method \code{invoke_hook()}}{ invoke a hook \subsection{Usage}{ @@ -58,8 +58,8 @@ executes hook } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-clear_hooks}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Hooks-clear_hooks}{}}} \subsection{Method \code{clear_hooks()}}{ clear all hooks \subsection{Usage}{ @@ -71,8 +71,8 @@ no return } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-define_hook}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Hooks-define_hook}{}}} \subsection{Method \code{define_hook()}}{ define a hook \subsection{Usage}{ @@ -96,8 +96,8 @@ no return; defines hook internally } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-clone}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Hooks-clone}{}}} \subsection{Method \code{clone()}}{ The objects of this class are cloneable with this method. \subsection{Usage}{ diff --git a/man/JSON.Rd b/man/JSON.Rd index 11923a8..8987950 100644 --- a/man/JSON.Rd +++ b/man/JSON.Rd @@ -13,21 +13,15 @@ class with methods for serializing via \pkg{jsonlite} \section{Methods}{ \subsection{Public methods}{ \itemize{ -\item \href{#method-new}{\code{JSON$new()}} -\item \href{#method-serialize}{\code{JSON$serialize()}} -\item \href{#method-deserialize}{\code{JSON$deserialize()}} -\item \href{#method-clone}{\code{JSON$clone()}} +\item \href{#method-JSON-new}{\code{JSON$new()}} +\item \href{#method-JSON-serialize}{\code{JSON$serialize()}} +\item \href{#method-JSON-deserialize}{\code{JSON$deserialize()}} +\item \href{#method-JSON-clone}{\code{JSON$clone()}} } } -\if{html}{ -\out{
Inherited methods} -\itemize{ -} -\out{
} -} \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-new}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-JSON-new}{}}} \subsection{Method \code{new()}}{ Create a new \code{JSON} object \subsection{Usage}{ @@ -46,8 +40,8 @@ A new \code{JSON} object } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-serialize}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-JSON-serialize}{}}} \subsection{Method \code{serialize()}}{ Serializes the given hash using internal fxn write_json \subsection{Usage}{ @@ -70,22 +64,30 @@ Serializes the given hash using internal fxn write_json } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-deserialize}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-JSON-deserialize}{}}} \subsection{Method \code{deserialize()}}{ Deserializes the content at the file path using jsonlite::fromJSON \subsection{Usage}{ -\if{html}{\out{
}}\preformatted{JSON$deserialize()}\if{html}{\out{
}} +\if{html}{\out{
}}\preformatted{JSON$deserialize(cassette)}\if{html}{\out{
}} } +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{cassette}}{the current cassette object so it's properties can +be retrieved} +} +\if{html}{\out{
}} +} \subsection{Returns}{ (list) the deserialized object, an R list } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-clone}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-JSON-clone}{}}} \subsection{Method \code{clone()}}{ The objects of this class are cloneable with this method. \subsection{Usage}{ diff --git a/man/Persisters.Rd b/man/Persisters.Rd index b9c1bf9..bfa6685 100644 --- a/man/Persisters.Rd +++ b/man/Persisters.Rd @@ -39,13 +39,13 @@ yaml_serializer \section{Methods}{ \subsection{Public methods}{ \itemize{ -\item \href{#method-new}{\code{Persisters$new()}} -\item \href{#method-clone}{\code{Persisters$clone()}} +\item \href{#method-Persisters-new}{\code{Persisters$new()}} +\item \href{#method-Persisters-clone}{\code{Persisters$clone()}} } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-new}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Persisters-new}{}}} \subsection{Method \code{new()}}{ Create a new \code{Persisters} object \subsection{Usage}{ @@ -67,8 +67,8 @@ A new \code{Persisters} object } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-clone}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Persisters-clone}{}}} \subsection{Method \code{clone()}}{ The objects of this class are cloneable with this method. \subsection{Usage}{ diff --git a/man/Request.Rd b/man/Request.Rd index 307b775..f743cc5 100644 --- a/man/Request.Rd +++ b/man/Request.Rd @@ -7,7 +7,7 @@ object that handled all aspects of a request } \examples{ -url <- "https://eu.httpbin.org/post" +url <- "https://hb.opencpu.org/post" body <- list(foo = "bar") headers <- list( `User-Agent` = "libcurl/7.54.0 r-curl/3.2 crul/0.5.2", @@ -45,7 +45,7 @@ x$from_hash(h) \item{\code{headers}}{(character) named list} -\item{\code{skip_port_stripping}}{(logical) whether to strip thhe port} +\item{\code{skip_port_stripping}}{(logical) whether to strip the port} \item{\code{hash}}{(character) a named list - internal use} @@ -56,25 +56,38 @@ x$from_hash(h) \item{\code{fields}}{(various) request body details} \item{\code{output}}{(various) request output details, disk, memory, etc} + +\item{\code{policies}}{(various) http policies, used in httr2 only} } \if{html}{\out{}} } \section{Methods}{ \subsection{Public methods}{ \itemize{ -\item \href{#method-new}{\code{Request$new()}} -\item \href{#method-to_hash}{\code{Request$to_hash()}} -\item \href{#method-from_hash}{\code{Request$from_hash()}} -\item \href{#method-clone}{\code{Request$clone()}} +\item \href{#method-Request-new}{\code{Request$new()}} +\item \href{#method-Request-to_hash}{\code{Request$to_hash()}} +\item \href{#method-Request-from_hash}{\code{Request$from_hash()}} +\item \href{#method-Request-clone}{\code{Request$clone()}} } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-new}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Request-new}{}}} \subsection{Method \code{new()}}{ Create a new \code{Request} object \subsection{Usage}{ -\if{html}{\out{
}}\preformatted{Request$new(method, uri, body, headers, opts, disk, fields, output)}\if{html}{\out{
}} +\if{html}{\out{
}}\preformatted{Request$new( + method, + uri, + body, + headers, + opts, + disk, + fields, + output, + policies, + skip_port_stripping = FALSE +)}\if{html}{\out{
}} } \subsection{Arguments}{ @@ -96,6 +109,11 @@ post, put, patch or delete)} \item{\code{fields}}{(various) post fields} \item{\code{output}}{(various) output details} + +\item{\code{policies}}{(various) http policies, used in httr2 only} + +\item{\code{skip_port_stripping}}{(logical) whether to strip the port. +default: \code{FALSE}} } \if{html}{\out{}} } @@ -104,8 +122,8 @@ A new \code{Request} object } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-to_hash}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Request-to_hash}{}}} \subsection{Method \code{to_hash()}}{ Convert the request to a list \subsection{Usage}{ @@ -117,8 +135,8 @@ list } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-from_hash}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Request-from_hash}{}}} \subsection{Method \code{from_hash()}}{ Convert the request to a list \subsection{Usage}{ @@ -137,8 +155,8 @@ a new \code{Request} object } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-clone}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Request-clone}{}}} \subsection{Method \code{clone()}}{ The objects of this class are cloneable with this method. \subsection{Usage}{ diff --git a/man/RequestHandler.Rd b/man/RequestHandler.Rd index edf2b37..b33cbb6 100644 --- a/man/RequestHandler.Rd +++ b/man/RequestHandler.Rd @@ -95,14 +95,14 @@ eject_cassette("testing_record_mode_none") \section{Methods}{ \subsection{Public methods}{ \itemize{ -\item \href{#method-new}{\code{RequestHandler$new()}} -\item \href{#method-handle}{\code{RequestHandler$handle()}} -\item \href{#method-clone}{\code{RequestHandler$clone()}} +\item \href{#method-RequestHandler-new}{\code{RequestHandler$new()}} +\item \href{#method-RequestHandler-handle}{\code{RequestHandler$handle()}} +\item \href{#method-RequestHandler-clone}{\code{RequestHandler$clone()}} } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-new}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-RequestHandler-new}{}}} \subsection{Method \code{new()}}{ Create a new \code{RequestHandler} object \subsection{Usage}{ @@ -121,8 +121,8 @@ A new \code{RequestHandler} object } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-handle}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-RequestHandler-handle}{}}} \subsection{Method \code{handle()}}{ Handle the request (\code{request} given in \verb{$initialize()}) \subsection{Usage}{ @@ -134,8 +134,8 @@ handles a request, outcomes vary } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-clone}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-RequestHandler-clone}{}}} \subsection{Method \code{clone()}}{ The objects of this class are cloneable with this method. \subsection{Usage}{ diff --git a/man/RequestHandlerCrul.Rd b/man/RequestHandlerCrul.Rd index 0c46654..9b1af89 100644 --- a/man/RequestHandlerCrul.Rd +++ b/man/RequestHandlerCrul.Rd @@ -24,7 +24,7 @@ library(vcr) library(crul) vcr_configure(dir = tempdir(), log = TRUE, log_opts = list(file = file.path(tempdir(), "vcr.log"))) -cli <- HttpClient$new(url = "https://httpbin.org") +cli <- HttpClient$new(url = "https://hb.opencpu.org") ## testing, same uri and method, changed body in 2nd block use_cassette(name = "apple7", { @@ -69,20 +69,20 @@ use_cassette(name = "apple8", { \section{Methods}{ \subsection{Public methods}{ \itemize{ -\item \href{#method-clone}{\code{RequestHandlerCrul$clone()}} +\item \href{#method-RequestHandlerCrul-clone}{\code{RequestHandlerCrul$clone()}} } } -\if{html}{ -\out{
Inherited methods} -\itemize{ -\item \out{}\href{../../vcr/html/RequestHandler.html#method-handle}{\code{vcr::RequestHandler$handle()}}\out{} -\item \out{}\href{../../vcr/html/RequestHandler.html#method-initialize}{\code{vcr::RequestHandler$initialize()}}\out{} -} -\out{
} -} +\if{html}{\out{ +
Inherited methods + +
+}} \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-clone}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-RequestHandlerCrul-clone}{}}} \subsection{Method \code{clone()}}{ The objects of this class are cloneable with this method. \subsection{Usage}{ diff --git a/man/RequestHandlerHttr.Rd b/man/RequestHandlerHttr.Rd index 57fb594..9eeeee6 100644 --- a/man/RequestHandlerHttr.Rd +++ b/man/RequestHandlerHttr.Rd @@ -26,7 +26,7 @@ webmockr::httr_mock() mydir <- file.path(tempdir(), "testing_httr") invisible(vcr_configure(dir = mydir)) use_cassette(name = "testing2", { - res <- POST("https://httpbin.org/post", body = list(foo = "bar")) + res <- POST("https://hb.opencpu.org/post", body = list(foo = "bar")) }, match_requests_on = c("method", "uri", "body")) load("~/httr_req_post.rda") @@ -45,20 +45,20 @@ self=x \section{Methods}{ \subsection{Public methods}{ \itemize{ -\item \href{#method-new}{\code{RequestHandlerHttr$new()}} -\item \href{#method-clone}{\code{RequestHandlerHttr$clone()}} +\item \href{#method-RequestHandlerHttr-new}{\code{RequestHandlerHttr$new()}} +\item \href{#method-RequestHandlerHttr-clone}{\code{RequestHandlerHttr$clone()}} } } -\if{html}{ -\out{
Inherited methods} -\itemize{ -\item \out{}\href{../../vcr/html/RequestHandler.html#method-handle}{\code{vcr::RequestHandler$handle()}}\out{} -} -\out{
} -} +\if{html}{\out{ +
Inherited methods + +
+}} \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-new}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-RequestHandlerHttr-new}{}}} \subsection{Method \code{new()}}{ Create a new \code{RequestHandlerHttr} object \subsection{Usage}{ @@ -77,8 +77,8 @@ A new \code{RequestHandlerHttr} object } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-clone}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-RequestHandlerHttr-clone}{}}} \subsection{Method \code{clone()}}{ The objects of this class are cloneable with this method. \subsection{Usage}{ diff --git a/man/RequestHandlerHttr2.Rd b/man/RequestHandlerHttr2.Rd new file mode 100644 index 0000000..26e53de --- /dev/null +++ b/man/RequestHandlerHttr2.Rd @@ -0,0 +1,86 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/request_handler-httr2.R +\name{RequestHandlerHttr2} +\alias{RequestHandlerHttr2} +\title{RequestHandlerHttr2} +\description{ +Methods for the httr2 package, building on \link{RequestHandler} +} +\examples{ +\dontrun{ +# GET request +library(httr2) +req <- request("https://hb.opencpu.org/post") \%>\% + req_body_json(list(foo = "bar")) +x <- RequestHandlerHttr2$new(req) +# x$handle() + +# POST request +library(httr2) +mydir <- file.path(tempdir(), "testing_httr2") +invisible(vcr_configure(dir = mydir)) +req <- request("https://hb.opencpu.org/post") \%>\% + req_body_json(list(foo = "bar")) +use_cassette(name = "testing3", { + response <- req_perform(req) +}, match_requests_on = c("method", "uri", "body")) +use_cassette(name = "testing3", { + response2 <- req_perform(req) +}, match_requests_on = c("method", "uri", "body")) +} +} +\section{Super class}{ +\code{\link[vcr:RequestHandler]{vcr::RequestHandler}} -> \code{RequestHandlerHttr2} +} +\section{Methods}{ +\subsection{Public methods}{ +\itemize{ +\item \href{#method-RequestHandlerHttr2-new}{\code{RequestHandlerHttr2$new()}} +\item \href{#method-RequestHandlerHttr2-clone}{\code{RequestHandlerHttr2$clone()}} +} +} +\if{html}{\out{ +
Inherited methods + +
+}} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-RequestHandlerHttr2-new}{}}} +\subsection{Method \code{new()}}{ +Create a new \code{RequestHandlerHttr2} object +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{RequestHandlerHttr2$new(request)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{request}}{The request from an object of class \code{HttpInteraction}} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +A new \code{RequestHandlerHttr2} object +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-RequestHandlerHttr2-clone}{}}} +\subsection{Method \code{clone()}}{ +The objects of this class are cloneable with this method. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{RequestHandlerHttr2$clone(deep = FALSE)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{deep}}{Whether to make a deep clone.} +} +\if{html}{\out{
}} +} +} +} diff --git a/man/RequestIgnorer.Rd b/man/RequestIgnorer.Rd index 3af6c4f..dd22122 100644 --- a/man/RequestIgnorer.Rd +++ b/man/RequestIgnorer.Rd @@ -20,18 +20,18 @@ and '0.0.0.0'} \section{Methods}{ \subsection{Public methods}{ \itemize{ -\item \href{#method-new}{\code{RequestIgnorer$new()}} -\item \href{#method-ignore_request}{\code{RequestIgnorer$ignore_request()}} -\item \href{#method-ignore_localhost}{\code{RequestIgnorer$ignore_localhost()}} -\item \href{#method-ignore_localhost_value}{\code{RequestIgnorer$ignore_localhost_value()}} -\item \href{#method-ignore_hosts}{\code{RequestIgnorer$ignore_hosts()}} -\item \href{#method-should_be_ignored}{\code{RequestIgnorer$should_be_ignored()}} -\item \href{#method-clone}{\code{RequestIgnorer$clone()}} +\item \href{#method-RequestIgnorer-new}{\code{RequestIgnorer$new()}} +\item \href{#method-RequestIgnorer-ignore_request}{\code{RequestIgnorer$ignore_request()}} +\item \href{#method-RequestIgnorer-ignore_localhost}{\code{RequestIgnorer$ignore_localhost()}} +\item \href{#method-RequestIgnorer-ignore_localhost_value}{\code{RequestIgnorer$ignore_localhost_value()}} +\item \href{#method-RequestIgnorer-ignore_hosts}{\code{RequestIgnorer$ignore_hosts()}} +\item \href{#method-RequestIgnorer-should_be_ignored}{\code{RequestIgnorer$should_be_ignored()}} +\item \href{#method-RequestIgnorer-clone}{\code{RequestIgnorer$clone()}} } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-new}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-RequestIgnorer-new}{}}} \subsection{Method \code{new()}}{ Create a new \code{RequestIgnorer} object \subsection{Usage}{ @@ -43,8 +43,8 @@ A new \code{RequestIgnorer} object } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-ignore_request}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-RequestIgnorer-ignore_request}{}}} \subsection{Method \code{ignore_request()}}{ Will ignore any request for which the given function returns \code{TRUE} @@ -57,8 +57,8 @@ no return; defines request ignorer hook } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-ignore_localhost}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-RequestIgnorer-ignore_localhost}{}}} \subsection{Method \code{ignore_localhost()}}{ ignore all localhost values (localhost, 127.0.0.1, 0.0.0.0) \subsection{Usage}{ @@ -70,8 +70,8 @@ no return; sets to ignore all localhost aliases } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-ignore_localhost_value}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-RequestIgnorer-ignore_localhost_value}{}}} \subsection{Method \code{ignore_localhost_value()}}{ ignore a specific named localhost \subsection{Usage}{ @@ -90,8 +90,8 @@ no return; defines request ignorer hook } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-ignore_hosts}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-RequestIgnorer-ignore_hosts}{}}} \subsection{Method \code{ignore_hosts()}}{ ignore any named host \subsection{Usage}{ @@ -110,8 +110,8 @@ no return; adds host to ignore } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-should_be_ignored}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-RequestIgnorer-should_be_ignored}{}}} \subsection{Method \code{should_be_ignored()}}{ method to determine whether to ignore a request \subsection{Usage}{ @@ -130,8 +130,8 @@ no return; defines request ignorer hook } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-clone}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-RequestIgnorer-clone}{}}} \subsection{Method \code{clone()}}{ The objects of this class are cloneable with this method. \subsection{Usage}{ diff --git a/man/RequestMatcherRegistry.Rd b/man/RequestMatcherRegistry.Rd index 0dcef08..21f7673 100644 --- a/man/RequestMatcherRegistry.Rd +++ b/man/RequestMatcherRegistry.Rd @@ -28,16 +28,16 @@ x$registry \section{Methods}{ \subsection{Public methods}{ \itemize{ -\item \href{#method-new}{\code{RequestMatcherRegistry$new()}} -\item \href{#method-register}{\code{RequestMatcherRegistry$register()}} -\item \href{#method-register_built_ins}{\code{RequestMatcherRegistry$register_built_ins()}} -\item \href{#method-try_to_register_body_as_json}{\code{RequestMatcherRegistry$try_to_register_body_as_json()}} -\item \href{#method-clone}{\code{RequestMatcherRegistry$clone()}} +\item \href{#method-RequestMatcherRegistry-new}{\code{RequestMatcherRegistry$new()}} +\item \href{#method-RequestMatcherRegistry-register}{\code{RequestMatcherRegistry$register()}} +\item \href{#method-RequestMatcherRegistry-register_built_ins}{\code{RequestMatcherRegistry$register_built_ins()}} +\item \href{#method-RequestMatcherRegistry-try_to_register_body_as_json}{\code{RequestMatcherRegistry$try_to_register_body_as_json()}} +\item \href{#method-RequestMatcherRegistry-clone}{\code{RequestMatcherRegistry$clone()}} } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-new}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-RequestMatcherRegistry-new}{}}} \subsection{Method \code{new()}}{ Create a new RequestMatcherRegistry object \subsection{Usage}{ @@ -61,8 +61,8 @@ A new \code{RequestMatcherRegistry} object } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-register}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-RequestMatcherRegistry-register}{}}} \subsection{Method \code{register()}}{ Register a custom matcher \subsection{Usage}{ @@ -84,8 +84,8 @@ no return; registers the matcher } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-register_built_ins}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-RequestMatcherRegistry-register_built_ins}{}}} \subsection{Method \code{register_built_ins()}}{ Register all built in matchers \subsection{Usage}{ @@ -97,8 +97,8 @@ no return; registers all built in matchers } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-try_to_register_body_as_json}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-RequestMatcherRegistry-try_to_register_body_as_json}{}}} \subsection{Method \code{try_to_register_body_as_json()}}{ Try to register body as JSON \subsection{Usage}{ @@ -117,8 +117,8 @@ no return; registers the matcher } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-clone}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-RequestMatcherRegistry-clone}{}}} \subsection{Method \code{clone()}}{ The objects of this class are cloneable with this method. \subsection{Usage}{ diff --git a/man/Serializer.Rd b/man/Serializer.Rd index df5890e..c5856fc 100644 --- a/man/Serializer.Rd +++ b/man/Serializer.Rd @@ -21,15 +21,15 @@ Serializer class - base class for JSON/YAML serializers \section{Methods}{ \subsection{Public methods}{ \itemize{ -\item \href{#method-new}{\code{Serializer$new()}} -\item \href{#method-serialize}{\code{Serializer$serialize()}} -\item \href{#method-deserialize}{\code{Serializer$deserialize()}} -\item \href{#method-clone}{\code{Serializer$clone()}} +\item \href{#method-Serializer-new}{\code{Serializer$new()}} +\item \href{#method-Serializer-serialize}{\code{Serializer$serialize()}} +\item \href{#method-Serializer-deserialize}{\code{Serializer$deserialize()}} +\item \href{#method-Serializer-clone}{\code{Serializer$clone()}} } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-new}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Serializer-new}{}}} \subsection{Method \code{new()}}{ Create a new YAML object \subsection{Usage}{ @@ -51,8 +51,8 @@ A new \code{YAML} object } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-serialize}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Serializer-serialize}{}}} \subsection{Method \code{serialize()}}{ Serializes a hash - REPLACED BY YAML/JSON METHODS \subsection{Usage}{ @@ -75,8 +75,8 @@ Serializes a hash - REPLACED BY YAML/JSON METHODS } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-deserialize}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Serializer-deserialize}{}}} \subsection{Method \code{deserialize()}}{ Serializes a file - REPLACED BY YAML/JSON METHODS \subsection{Usage}{ @@ -85,8 +85,8 @@ Serializes a file - REPLACED BY YAML/JSON METHODS } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-clone}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Serializer-clone}{}}} \subsection{Method \code{clone()}}{ The objects of this class are cloneable with this method. \subsection{Usage}{ diff --git a/man/Serializers.Rd b/man/Serializers.Rd index 37603bf..190bdda 100644 --- a/man/Serializers.Rd +++ b/man/Serializers.Rd @@ -45,13 +45,13 @@ json_serializer \section{Methods}{ \subsection{Public methods}{ \itemize{ -\item \href{#method-new}{\code{Serializers$new()}} -\item \href{#method-clone}{\code{Serializers$clone()}} +\item \href{#method-Serializers-new}{\code{Serializers$new()}} +\item \href{#method-Serializers-clone}{\code{Serializers$clone()}} } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-new}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Serializers-new}{}}} \subsection{Method \code{new()}}{ Create a new Serializers object \subsection{Usage}{ @@ -72,8 +72,8 @@ A new \code{Serializers} object } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-clone}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Serializers-clone}{}}} \subsection{Method \code{clone()}}{ The objects of this class are cloneable with this method. \subsection{Usage}{ diff --git a/man/UnhandledHTTPRequestError.Rd b/man/UnhandledHTTPRequestError.Rd index 19cec93..e96bcff 100644 --- a/man/UnhandledHTTPRequestError.Rd +++ b/man/UnhandledHTTPRequestError.Rd @@ -41,10 +41,11 @@ error with UnhandledHTTPRequestError } \examples{ +\dontrun{ vcr_configure(dir = tempdir()) cassettes() insert_cassette("turtle") -request <- Request$new("post", 'https://eu.httpbin.org/post?a=5', +request <- Request$new("post", 'https://hb.opencpu.org/post?a=5', "", list(foo = "bar")) err <- UnhandledHTTPRequestError$new(request) @@ -70,6 +71,7 @@ err$match_requests_on_suggestion() # cleanup eject_cassette("turtle") unlink(tempdir()) +} \dontrun{ # vcr_last_error() } @@ -86,32 +88,32 @@ unlink(tempdir()) \section{Methods}{ \subsection{Public methods}{ \itemize{ -\item \href{#method-new}{\code{UnhandledHTTPRequestError$new()}} -\item \href{#method-run}{\code{UnhandledHTTPRequestError$run()}} -\item \href{#method-construct_message}{\code{UnhandledHTTPRequestError$construct_message()}} -\item \href{#method-request_description}{\code{UnhandledHTTPRequestError$request_description()}} -\item \href{#method-current_matchers}{\code{UnhandledHTTPRequestError$current_matchers()}} -\item \href{#method-match_request_on_headers}{\code{UnhandledHTTPRequestError$match_request_on_headers()}} -\item \href{#method-match_request_on_body}{\code{UnhandledHTTPRequestError$match_request_on_body()}} -\item \href{#method-formatted_headers}{\code{UnhandledHTTPRequestError$formatted_headers()}} -\item \href{#method-cassettes_description}{\code{UnhandledHTTPRequestError$cassettes_description()}} -\item \href{#method-cassettes_list}{\code{UnhandledHTTPRequestError$cassettes_list()}} -\item \href{#method-get_help}{\code{UnhandledHTTPRequestError$get_help()}} -\item \href{#method-formatted_suggestions}{\code{UnhandledHTTPRequestError$formatted_suggestions()}} -\item \href{#method-format_bullet_point}{\code{UnhandledHTTPRequestError$format_bullet_point()}} -\item \href{#method-format_foot_note}{\code{UnhandledHTTPRequestError$format_foot_note()}} -\item \href{#method-suggestion_for}{\code{UnhandledHTTPRequestError$suggestion_for()}} -\item \href{#method-suggestions}{\code{UnhandledHTTPRequestError$suggestions()}} -\item \href{#method-no_cassette_suggestions}{\code{UnhandledHTTPRequestError$no_cassette_suggestions()}} -\item \href{#method-record_mode_suggestion}{\code{UnhandledHTTPRequestError$record_mode_suggestion()}} -\item \href{#method-has_used_interaction_matching}{\code{UnhandledHTTPRequestError$has_used_interaction_matching()}} -\item \href{#method-match_requests_on_suggestion}{\code{UnhandledHTTPRequestError$match_requests_on_suggestion()}} -\item \href{#method-clone}{\code{UnhandledHTTPRequestError$clone()}} +\item \href{#method-UnhandledHTTPRequestError-new}{\code{UnhandledHTTPRequestError$new()}} +\item \href{#method-UnhandledHTTPRequestError-run}{\code{UnhandledHTTPRequestError$run()}} +\item \href{#method-UnhandledHTTPRequestError-construct_message}{\code{UnhandledHTTPRequestError$construct_message()}} +\item \href{#method-UnhandledHTTPRequestError-request_description}{\code{UnhandledHTTPRequestError$request_description()}} +\item \href{#method-UnhandledHTTPRequestError-current_matchers}{\code{UnhandledHTTPRequestError$current_matchers()}} +\item \href{#method-UnhandledHTTPRequestError-match_request_on_headers}{\code{UnhandledHTTPRequestError$match_request_on_headers()}} +\item \href{#method-UnhandledHTTPRequestError-match_request_on_body}{\code{UnhandledHTTPRequestError$match_request_on_body()}} +\item \href{#method-UnhandledHTTPRequestError-formatted_headers}{\code{UnhandledHTTPRequestError$formatted_headers()}} +\item \href{#method-UnhandledHTTPRequestError-cassettes_description}{\code{UnhandledHTTPRequestError$cassettes_description()}} +\item \href{#method-UnhandledHTTPRequestError-cassettes_list}{\code{UnhandledHTTPRequestError$cassettes_list()}} +\item \href{#method-UnhandledHTTPRequestError-get_help}{\code{UnhandledHTTPRequestError$get_help()}} +\item \href{#method-UnhandledHTTPRequestError-formatted_suggestions}{\code{UnhandledHTTPRequestError$formatted_suggestions()}} +\item \href{#method-UnhandledHTTPRequestError-format_bullet_point}{\code{UnhandledHTTPRequestError$format_bullet_point()}} +\item \href{#method-UnhandledHTTPRequestError-format_foot_note}{\code{UnhandledHTTPRequestError$format_foot_note()}} +\item \href{#method-UnhandledHTTPRequestError-suggestion_for}{\code{UnhandledHTTPRequestError$suggestion_for()}} +\item \href{#method-UnhandledHTTPRequestError-suggestions}{\code{UnhandledHTTPRequestError$suggestions()}} +\item \href{#method-UnhandledHTTPRequestError-no_cassette_suggestions}{\code{UnhandledHTTPRequestError$no_cassette_suggestions()}} +\item \href{#method-UnhandledHTTPRequestError-record_mode_suggestion}{\code{UnhandledHTTPRequestError$record_mode_suggestion()}} +\item \href{#method-UnhandledHTTPRequestError-has_used_interaction_matching}{\code{UnhandledHTTPRequestError$has_used_interaction_matching()}} +\item \href{#method-UnhandledHTTPRequestError-match_requests_on_suggestion}{\code{UnhandledHTTPRequestError$match_requests_on_suggestion()}} +\item \href{#method-UnhandledHTTPRequestError-clone}{\code{UnhandledHTTPRequestError$clone()}} } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-new}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-UnhandledHTTPRequestError-new}{}}} \subsection{Method \code{new()}}{ Create a new \code{UnhandledHTTPRequestError} object \subsection{Usage}{ @@ -130,8 +132,8 @@ A new \code{UnhandledHTTPRequestError} object } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-run}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-UnhandledHTTPRequestError-run}{}}} \subsection{Method \code{run()}}{ Run unhandled request handling \subsection{Usage}{ @@ -143,8 +145,8 @@ various } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-construct_message}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-UnhandledHTTPRequestError-construct_message}{}}} \subsection{Method \code{construct_message()}}{ Construct and execute stop message for why request failed \subsection{Usage}{ @@ -156,8 +158,8 @@ a stop message } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-request_description}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-UnhandledHTTPRequestError-request_description}{}}} \subsection{Method \code{request_description()}}{ construct request description \subsection{Usage}{ @@ -169,8 +171,8 @@ character } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-current_matchers}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-UnhandledHTTPRequestError-current_matchers}{}}} \subsection{Method \code{current_matchers()}}{ get current request matchers \subsection{Usage}{ @@ -182,8 +184,8 @@ character } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-match_request_on_headers}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-UnhandledHTTPRequestError-match_request_on_headers}{}}} \subsection{Method \code{match_request_on_headers()}}{ are headers included in current matchers? \subsection{Usage}{ @@ -195,8 +197,8 @@ logical } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-match_request_on_body}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-UnhandledHTTPRequestError-match_request_on_body}{}}} \subsection{Method \code{match_request_on_body()}}{ is body includled in current matchers? \subsection{Usage}{ @@ -208,8 +210,8 @@ logical } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-formatted_headers}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-UnhandledHTTPRequestError-formatted_headers}{}}} \subsection{Method \code{formatted_headers()}}{ get request headers \subsection{Usage}{ @@ -221,8 +223,8 @@ character } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-cassettes_description}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-UnhandledHTTPRequestError-cassettes_description}{}}} \subsection{Method \code{cassettes_description()}}{ construct description of current or lack thereof cassettes \subsection{Usage}{ @@ -234,8 +236,8 @@ character } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-cassettes_list}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-UnhandledHTTPRequestError-cassettes_list}{}}} \subsection{Method \code{cassettes_list()}}{ cassette details \subsection{Usage}{ @@ -247,8 +249,8 @@ character } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-get_help}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-UnhandledHTTPRequestError-get_help}{}}} \subsection{Method \code{get_help()}}{ get help message for non-verbose error \subsection{Usage}{ @@ -260,8 +262,8 @@ character } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-formatted_suggestions}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-UnhandledHTTPRequestError-formatted_suggestions}{}}} \subsection{Method \code{formatted_suggestions()}}{ make suggestions for what to do \subsection{Usage}{ @@ -273,8 +275,8 @@ character } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-format_bullet_point}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-UnhandledHTTPRequestError-format_bullet_point}{}}} \subsection{Method \code{format_bullet_point()}}{ add bullet point to beginning of a line \subsection{Usage}{ @@ -295,8 +297,8 @@ character } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-format_foot_note}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-UnhandledHTTPRequestError-format_foot_note}{}}} \subsection{Method \code{format_foot_note()}}{ make a foot note \subsection{Usage}{ @@ -317,8 +319,8 @@ character } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-suggestion_for}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-UnhandledHTTPRequestError-suggestion_for}{}}} \subsection{Method \code{suggestion_for()}}{ get a suggestion by key \subsection{Usage}{ @@ -337,8 +339,8 @@ character } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-suggestions}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-UnhandledHTTPRequestError-suggestions}{}}} \subsection{Method \code{suggestions()}}{ get all suggestions \subsection{Usage}{ @@ -350,8 +352,8 @@ list } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-no_cassette_suggestions}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-UnhandledHTTPRequestError-no_cassette_suggestions}{}}} \subsection{Method \code{no_cassette_suggestions()}}{ get all no cassette suggestions \subsection{Usage}{ @@ -363,8 +365,8 @@ list } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-record_mode_suggestion}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-UnhandledHTTPRequestError-record_mode_suggestion}{}}} \subsection{Method \code{record_mode_suggestion()}}{ get the appropriate record mode suggestion \subsection{Usage}{ @@ -376,8 +378,8 @@ character } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-has_used_interaction_matching}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-UnhandledHTTPRequestError-has_used_interaction_matching}{}}} \subsection{Method \code{has_used_interaction_matching()}}{ are there any used interactions \subsection{Usage}{ @@ -389,8 +391,8 @@ logical } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-match_requests_on_suggestion}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-UnhandledHTTPRequestError-match_requests_on_suggestion}{}}} \subsection{Method \code{match_requests_on_suggestion()}}{ match requests on suggestion \subsection{Usage}{ @@ -402,8 +404,8 @@ list } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-clone}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-UnhandledHTTPRequestError-clone}{}}} \subsection{Method \code{clone()}}{ The objects of this class are cloneable with this method. \subsection{Usage}{ diff --git a/man/VcrResponse.Rd b/man/VcrResponse.Rd index 3b44e7e..b6f84c7 100644 --- a/man/VcrResponse.Rd +++ b/man/VcrResponse.Rd @@ -103,21 +103,22 @@ f <- tempfile() \section{Methods}{ \subsection{Public methods}{ \itemize{ -\item \href{#method-new}{\code{VcrResponse$new()}} -\item \href{#method-to_hash}{\code{VcrResponse$to_hash()}} -\item \href{#method-from_hash}{\code{VcrResponse$from_hash()}} -\item \href{#method-update_content_length_header}{\code{VcrResponse$update_content_length_header()}} -\item \href{#method-get_header}{\code{VcrResponse$get_header()}} -\item \href{#method-edit_header}{\code{VcrResponse$edit_header()}} -\item \href{#method-delete_header}{\code{VcrResponse$delete_header()}} -\item \href{#method-content_encoding}{\code{VcrResponse$content_encoding()}} -\item \href{#method-is_compressed}{\code{VcrResponse$is_compressed()}} -\item \href{#method-clone}{\code{VcrResponse$clone()}} +\item \href{#method-VcrResponse-new}{\code{VcrResponse$new()}} +\item \href{#method-VcrResponse-print}{\code{VcrResponse$print()}} +\item \href{#method-VcrResponse-to_hash}{\code{VcrResponse$to_hash()}} +\item \href{#method-VcrResponse-from_hash}{\code{VcrResponse$from_hash()}} +\item \href{#method-VcrResponse-update_content_length_header}{\code{VcrResponse$update_content_length_header()}} +\item \href{#method-VcrResponse-get_header}{\code{VcrResponse$get_header()}} +\item \href{#method-VcrResponse-edit_header}{\code{VcrResponse$edit_header()}} +\item \href{#method-VcrResponse-delete_header}{\code{VcrResponse$delete_header()}} +\item \href{#method-VcrResponse-content_encoding}{\code{VcrResponse$content_encoding()}} +\item \href{#method-VcrResponse-is_compressed}{\code{VcrResponse$is_compressed()}} +\item \href{#method-VcrResponse-clone}{\code{VcrResponse$clone()}} } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-new}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-VcrResponse-new}{}}} \subsection{Method \code{new()}}{ Create a new VcrResponse object \subsection{Usage}{ @@ -156,8 +157,27 @@ A new \code{VcrResponse} object } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-to_hash}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-VcrResponse-print}{}}} +\subsection{Method \code{print()}}{ +print method for the \code{VcrResponse} class +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{VcrResponse$print(x, ...)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{x}}{self} + +\item{\code{...}}{ignored} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-VcrResponse-to_hash}{}}} \subsection{Method \code{to_hash()}}{ Create a hash \subsection{Usage}{ @@ -169,8 +189,8 @@ a list } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-from_hash}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-VcrResponse-from_hash}{}}} \subsection{Method \code{from_hash()}}{ Get a hash back to an R list \subsection{Usage}{ @@ -189,8 +209,8 @@ an \code{VcrResponse} object } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-update_content_length_header}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-VcrResponse-update_content_length_header}{}}} \subsection{Method \code{update_content_length_header()}}{ Updates the Content-Length response header so that it is accurate for the response body @@ -203,8 +223,8 @@ no return; modifies the content length header } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-get_header}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-VcrResponse-get_header}{}}} \subsection{Method \code{get_header()}}{ Get a header by name \subsection{Usage}{ @@ -223,8 +243,8 @@ the header value (if it exists) } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-edit_header}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-VcrResponse-edit_header}{}}} \subsection{Method \code{edit_header()}}{ Edit a header \subsection{Usage}{ @@ -245,8 +265,8 @@ no return; modifies the header in place } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-delete_header}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-VcrResponse-delete_header}{}}} \subsection{Method \code{delete_header()}}{ Delete a header \subsection{Usage}{ @@ -265,8 +285,8 @@ no return; the header is deleted if it exists } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-content_encoding}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-VcrResponse-content_encoding}{}}} \subsection{Method \code{content_encoding()}}{ Get the content-encoding header value \subsection{Usage}{ @@ -278,8 +298,8 @@ Get the content-encoding header value } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-is_compressed}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-VcrResponse-is_compressed}{}}} \subsection{Method \code{is_compressed()}}{ Checks if the encoding is one of "gzip" or "deflate" \subsection{Usage}{ @@ -291,8 +311,8 @@ logical } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-clone}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-VcrResponse-clone}{}}} \subsection{Method \code{clone()}}{ The objects of this class are cloneable with this method. \subsection{Usage}{ diff --git a/man/YAML.Rd b/man/YAML.Rd index 5527d84..ff20a45 100644 --- a/man/YAML.Rd +++ b/man/YAML.Rd @@ -13,21 +13,15 @@ class with methods for serializing via the \pkg{yaml} package \section{Methods}{ \subsection{Public methods}{ \itemize{ -\item \href{#method-new}{\code{YAML$new()}} -\item \href{#method-serialize}{\code{YAML$serialize()}} -\item \href{#method-deserialize}{\code{YAML$deserialize()}} -\item \href{#method-clone}{\code{YAML$clone()}} +\item \href{#method-YAML-new}{\code{YAML$new()}} +\item \href{#method-YAML-serialize}{\code{YAML$serialize()}} +\item \href{#method-YAML-deserialize}{\code{YAML$deserialize()}} +\item \href{#method-YAML-clone}{\code{YAML$clone()}} } } -\if{html}{ -\out{
Inherited methods} -\itemize{ -} -\out{
} -} \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-new}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-YAML-new}{}}} \subsection{Method \code{new()}}{ Create a new YAML object \subsection{Usage}{ @@ -47,8 +41,8 @@ A new \code{YAML} object } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-serialize}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-YAML-serialize}{}}} \subsection{Method \code{serialize()}}{ Serializes the given hash using internal fxn write_yaml \subsection{Usage}{ @@ -71,22 +65,30 @@ Serializes the given hash using internal fxn write_yaml } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-deserialize}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-YAML-deserialize}{}}} \subsection{Method \code{deserialize()}}{ Deserializes the content at the path using yaml::yaml.load_file \subsection{Usage}{ -\if{html}{\out{
}}\preformatted{YAML$deserialize()}\if{html}{\out{
}} +\if{html}{\out{
}}\preformatted{YAML$deserialize(cassette)}\if{html}{\out{
}} } +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{cassette}}{the current cassette object so it's properties can +be retrieved} +} +\if{html}{\out{
}} +} \subsection{Returns}{ (list) the deserialized object, an R list } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-clone}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-YAML-clone}{}}} \subsection{Method \code{clone()}}{ The objects of this class are cloneable with this method. \subsection{Usage}{ diff --git a/man/check_cassette_names.Rd b/man/check_cassette_names.Rd index 346c72d..4b1cf2d 100644 --- a/man/check_cassette_names.Rd +++ b/man/check_cassette_names.Rd @@ -28,18 +28,17 @@ Check cassette names Cassette names: \itemize{ \item Should be meaningful so that it is obvious to you what test/function -they relate to. Meaningful names are important so that you can -quickly determine to what test file or test block a cassette -belongs. Note that vcr cannot check that your cassette names are -meaningful. +they relate to. Meaningful names are important so that you can quickly +determine to what test file or test block a cassette belongs. Note +that vcr cannot check that your cassette names are meaningful. \item Should not be duplicated. Duplicated cassette names would lead to a test using the wrong cassette. \item Should not have spaces. Spaces can lead to problems in using file paths. \item Should not include a file extension. vcr handles file extensions for the user. -\item Should not have illegal characters that can lead to problems in -using file paths: \code{/}, \verb{?}, \code{<}, \code{>}, \verb{\\}, \code{:}, \code{*}, \code{|}, and \verb{\"} +\item Should not have illegal characters that can lead to problems in using +file paths: \code{/}, \verb{?}, \code{<}, \code{>}, \verb{\\}, \code{:}, \code{*}, \code{|}, and \verb{\"} \item Should not have control characters, e.g., \verb{\n} \item Should not have just dots, e.g., \code{.} or \code{..} \item Should not have Windows reserved words, e.g., \code{com1} @@ -48,11 +47,12 @@ using file paths: \code{/}, \verb{?}, \code{<}, \code{>}, \verb{\\}, \code{:}, \ } \code{vcr::check_cassette_names()} is meant to be run during your tests, from -a \code{setup-pkgname.R} file inside the \code{tests/testthat} directory. It only -checks that cassette names are not duplicated. Note that if you do need -to have duplicated cassette names you can do so by using the -\code{allowed_duplicates} parameter in \code{check_cassette_names()}. A helper -function \code{check_cassette_names()} runs inside -\code{\link[=insert_cassette]{insert_cassette()}} that checks that cassettes -do not have: spaces, file extensions, unaccepted characters (slashes) +a \href{https://testthat.r-lib.org/reference/test_dir.html#special-files}{\verb{helper-*.R} file} +inside the \code{tests/testthat} directory. It only checks that cassette +names are not duplicated. Note that if you do need to have duplicated +cassette names you can do so by using the \code{allowed_duplicates} parameter +in \code{check_cassette_names()}. A helper function \code{check_cassette_names()} +runs inside \code{\link[=insert_cassette]{insert_cassette()}} that checks that +cassettes do not have: spaces, file extensions, unaccepted characters +(slashes). } diff --git a/man/http_interactions.Rd b/man/http_interactions.Rd index a9c5bb0..9560d0e 100644 --- a/man/http_interactions.Rd +++ b/man/http_interactions.Rd @@ -19,7 +19,7 @@ vcr_configure(dir = tempdir()) insert_cassette("foo_bar") webmockr::webmockr_allow_net_connect() library(crul) -cli <- crul::HttpClient$new("https://eu.httpbin.org/get") +cli <- crul::HttpClient$new("https://hb.opencpu.org/get") one <- cli$get(query = list(a = 5)) z <- http_interactions() z diff --git a/man/insert_cassette.Rd b/man/insert_cassette.Rd index 72d6763..061e061 100644 --- a/man/insert_cassette.Rd +++ b/man/insert_cassette.Rd @@ -78,18 +78,17 @@ Insert a cassette to record HTTP requests Cassette names: \itemize{ \item Should be meaningful so that it is obvious to you what test/function -they relate to. Meaningful names are important so that you can -quickly determine to what test file or test block a cassette -belongs. Note that vcr cannot check that your cassette names are -meaningful. +they relate to. Meaningful names are important so that you can quickly +determine to what test file or test block a cassette belongs. Note +that vcr cannot check that your cassette names are meaningful. \item Should not be duplicated. Duplicated cassette names would lead to a test using the wrong cassette. \item Should not have spaces. Spaces can lead to problems in using file paths. \item Should not include a file extension. vcr handles file extensions for the user. -\item Should not have illegal characters that can lead to problems in -using file paths: \code{/}, \verb{?}, \code{<}, \code{>}, \verb{\\}, \code{:}, \code{*}, \code{|}, and \verb{\"} +\item Should not have illegal characters that can lead to problems in using +file paths: \code{/}, \verb{?}, \code{<}, \code{>}, \verb{\\}, \code{:}, \code{*}, \code{|}, and \verb{\"} \item Should not have control characters, e.g., \verb{\n} \item Should not have just dots, e.g., \code{.} or \code{..} \item Should not have Windows reserved words, e.g., \code{com1} @@ -98,13 +97,14 @@ using file paths: \code{/}, \verb{?}, \code{<}, \code{>}, \verb{\\}, \code{:}, \ } \code{vcr::check_cassette_names()} is meant to be run during your tests, from -a \code{setup-pkgname.R} file inside the \code{tests/testthat} directory. It only -checks that cassette names are not duplicated. Note that if you do need -to have duplicated cassette names you can do so by using the -\code{allowed_duplicates} parameter in \code{check_cassette_names()}. A helper -function \code{check_cassette_names()} runs inside -\code{\link[=insert_cassette]{insert_cassette()}} that checks that cassettes -do not have: spaces, file extensions, unaccepted characters (slashes) +a \href{https://testthat.r-lib.org/reference/test_dir.html#special-files}{\verb{helper-*.R} file} +inside the \code{tests/testthat} directory. It only checks that cassette +names are not duplicated. Note that if you do need to have duplicated +cassette names you can do so by using the \code{allowed_duplicates} parameter +in \code{check_cassette_names()}. A helper function \code{check_cassette_names()} +runs inside \code{\link[=insert_cassette]{insert_cassette()}} that checks that +cassettes do not have: spaces, file extensions, unaccepted characters +(slashes). } \section{Cassette options}{ @@ -128,7 +128,7 @@ webmockr::webmockr_allow_net_connect() current_cassette() x$new_recorded_interactions x$previously_recorded_interactions() -cli <- crul::HttpClient$new(url = "https://httpbin.org") +cli <- crul::HttpClient$new(url = "https://hb.opencpu.org") cli$get("get") x$new_recorded_interactions # 1 interaction x$previously_recorded_interactions() # empty diff --git a/man/lightswitch.Rd b/man/lightswitch.Rd index c6a3ccc..f54d9fa 100644 --- a/man/lightswitch.Rd +++ b/man/lightswitch.Rd @@ -35,8 +35,8 @@ package. The following attempts to break down all the options. \code{vcr} has the following four exported functions: \itemize{ \item \code{turned_off()} - Turns vcr off for the duration of a code block -\item \code{turn_off()} - Turns vcr off completely, so that it no longer -handles every HTTP request +\item \code{turn_off()} - Turns vcr off completely, so that it no longer handles +every HTTP request \item \code{turn_on()} - turns vcr on; the opposite of \code{turn_off()} \item \code{turned_on()} - Asks if vcr is turned on, returns a boolean } @@ -48,11 +48,11 @@ Docker containers, or running R non-interactively from the command line. The full set of environment variables \code{vcr} uses, all of which accept only \code{TRUE} or \code{FALSE}: \itemize{ -\item \code{VCR_TURN_OFF}: turn off vcr altogether; set to \code{TRUE} to skip any -vcr usage; default: \code{FALSE} -\item \code{VCR_TURNED_OFF}: set the \code{turned_off} internal package setting; -this does not turn off vcr completely as does \code{VCR_TURN_OFF} does, -but rather is looked at together with \code{VCR_IGNORE_CASSETTES} +\item \code{VCR_TURN_OFF}: turn off vcr altogether; set to \code{TRUE} to skip any vcr +usage; default: \code{FALSE} +\item \code{VCR_TURNED_OFF}: set the \code{turned_off} internal package setting; this +does not turn off vcr completely as does \code{VCR_TURN_OFF} does, but +rather is looked at together with \code{VCR_IGNORE_CASSETTES} \item \code{VCR_IGNORE_CASSETTES}: set the \code{ignore_cassettes} internal package setting; this is looked at together with \code{VCR_TURNED_OFF} } @@ -64,13 +64,17 @@ completely turning \code{vcr} off, unloading it, etc. What happens internally is we turn off \code{vcr}, run your code block, then on exit turn \code{vcr} back on - such that \code{vcr} is only turned off for the duration of your code block. Even if your code block errors, \code{vcr} will -be turned back on due to use of \code{on.exit(turn_on())}\if{html}{\out{
}}\preformatted{library(vcr) +be turned back on due to use of \code{on.exit(turn_on())} + +\if{html}{\out{
}}\preformatted{library(vcr) library(crul) turned_off(\{ con <- HttpClient$new(url = "https://httpbin.org/get") con$get() \}) -}\if{html}{\out{
}}\if{html}{\out{
}}\preformatted{#> +}\if{html}{\out{
}} + +\if{html}{\out{
}}\preformatted{#> #> url: https://httpbin.org/get #> request_headers: #> User-Agent: libcurl/7.54.0 r-curl/4.3 crul/0.9.0 @@ -99,7 +103,9 @@ make R ignore \code{vcr::insert_cassette()} and \code{vcr::use_cassette()} block in your test suite - letting the code in the block run as if they were not wrapped in \code{vcr} code - so that all you have to do to run your tests with cached requests/responses AND with real HTTP requests is toggle a -single R function or environment variable.\if{html}{\out{
}}\preformatted{library(vcr) +single R function or environment variable. + +\if{html}{\out{
}}\preformatted{library(vcr) vcr_configure(dir = tempdir()) # real HTTP request works - vcr is not engaged here crul::HttpClient$new(url = "https://eu.httpbin.org/get")$get() @@ -128,15 +134,27 @@ use_cassette("foo_bar3", \{ \subsection{turned_on}{ \code{turned_on()} does what it says on the tin - it tells you if \code{vcr} is -turned on or not.\if{html}{\out{
}}\preformatted{library(vcr) +turned on or not. + +\if{html}{\out{
}}\preformatted{library(vcr) turn_on() turned_on() -}\if{html}{\out{
}}\preformatted{## [1] TRUE -}\if{html}{\out{
}}\preformatted{turn_off() -}\if{html}{\out{
}}\preformatted{## vcr turned off; see ?turn_on to turn vcr back on -}\if{html}{\out{
}}\preformatted{turned_on() -}\if{html}{\out{
}}\preformatted{## [1] FALSE -} +}\if{html}{\out{
}} + +\if{html}{\out{
}}\preformatted{## [1] TRUE +}\if{html}{\out{
}} + +\if{html}{\out{
}}\preformatted{turn_off() +}\if{html}{\out{
}} + +\if{html}{\out{
}}\preformatted{## vcr turned off; see ?turn_on to turn vcr back on +}\if{html}{\out{
}} + +\if{html}{\out{
}}\preformatted{turned_on() +}\if{html}{\out{
}} + +\if{html}{\out{
}}\preformatted{## [1] FALSE +}\if{html}{\out{
}} } \subsection{Environment variables}{ @@ -144,16 +162,22 @@ turned_on() The \code{VCR_TURN_OFF} environment variable can be used within R or on the command line to turn off \code{vcr}. For example, you can run tests for a package that uses \code{vcr}, but ignore any \code{use_cassette}/\code{insert_cassette} -usage, by running this on the command line in the root of your package:\preformatted{VCR_TURN_OFF=true Rscript -e "devtools::test()" -} +usage, by running this on the command line in the root of your package: -Or, similarly within R:\if{html}{\out{
}}\preformatted{Sys.setenv(VCR_TURN_OFF = TRUE) +\if{html}{\out{
}}\preformatted{VCR_TURN_OFF=true Rscript -e "devtools::test()" +}\if{html}{\out{
}} + +Or, similarly within R: + +\if{html}{\out{
}}\preformatted{Sys.setenv(VCR_TURN_OFF = TRUE) devtools::test() }\if{html}{\out{
}} The \code{VCR_TURNED_OFF} and \code{VCR_IGNORE_CASSETTES} environment variables -can be used in combination to achieve the same thing as \code{VCR_TURN_OFF}:\preformatted{VCR_TURNED_OFF=true VCR_IGNORE_CASSETTES=true Rscript -e "devtools::test()" -} +can be used in combination to achieve the same thing as \code{VCR_TURN_OFF}: + +\if{html}{\out{
}}\preformatted{VCR_TURNED_OFF=true VCR_IGNORE_CASSETTES=true Rscript -e "devtools::test()" +}\if{html}{\out{
}} } } \examples{ @@ -167,7 +191,7 @@ turn_off() # turn off for duration of a block library(crul) turned_off({ - res <- HttpClient$new(url = "https://eu.httpbin.org/get")$get() + res <- HttpClient$new(url = "https://hb.opencpu.org/get")$get() }) res @@ -175,7 +199,7 @@ res turn_off() library(webmockr) crul::mock() -# HttpClient$new(url = "https://eu.httpbin.org/get")$get(verbose = TRUE) +# HttpClient$new(url = "https://hb.opencpu.org/get")$get(verbose = TRUE) turn_on() } } diff --git a/man/request-matching.Rd b/man/request-matching.Rd index fe1d3ff..6bbb111 100644 --- a/man/request-matching.Rd +++ b/man/request-matching.Rd @@ -17,11 +17,11 @@ You can customize how we match requests with one or more of the following options, some of which are on by default, some of which can be used together, and some alone. \itemize{ -\item \code{method}: Use the \strong{method} request matcher to match requests on -the HTTP method (i.e. GET, POST, PUT, DELETE, etc). You will -generally want to use this matcher. The \strong{method} matcher is used -(along with the \strong{uri} matcher) by default if you do not specify -how requests should match. +\item \code{method}: Use the \strong{method} request matcher to match requests on the +HTTP method (i.e. GET, POST, PUT, DELETE, etc). You will generally +want to use this matcher. The \strong{method} matcher is used (along with +the \strong{uri} matcher) by default if you do not specify how requests +should match. \item \code{uri}: Use the \strong{uri} request matcher to match requests on the request URI. The \strong{uri} matcher is used (along with the \strong{method} matcher) by default if you do not specify how requests should match. @@ -30,10 +30,10 @@ request host. You can use this (alone, or in combination with \strong{path}) as an alternative to \strong{uri} so that non-deterministic portions of the URI are not considered as part of the request matching. -\item \code{path}: Use the \strong{path} request matcher to match requests on the -path portion of the request URI. You can use this (alone, or in -combination with \strong{host}) as an alternative to \strong{uri} so that -non-deterministic portions of the URI +\item \code{path}: Use the \strong{path} request matcher to match requests on the path +portion of the request URI. You can use this (alone, or in combination +with \strong{host}) as an alternative to \strong{uri} so that non-deterministic +portions of the URI \item \code{query}: Use the \strong{query} request matcher to match requests on the query string portion of the request URI. You can use this (alone, or in combination with others) as an alternative to \strong{uri} so that @@ -46,15 +46,21 @@ the request headers. } You can set your own options by tweaking the \code{match_requests_on} -parameter in \code{use_cassette()}:\if{html}{\out{
}}\preformatted{library(vcr) -}\if{html}{\out{
}}\if{html}{\out{
}}\preformatted{use_cassette(name = "foo_bar", \{ +parameter in \code{use_cassette()}: + +\if{html}{\out{
}}\preformatted{library(vcr) +}\if{html}{\out{
}} + +\if{html}{\out{
}}\preformatted{use_cassette(name = "foo_bar", \{ cli$post("post", body = list(a = 5)) \}, match_requests_on = c('method', 'headers', 'body') ) }\if{html}{\out{
}} \subsection{Matching}{ -\subsection{headers}{\if{html}{\out{
}}\preformatted{library(crul) +\subsection{headers}{ + +\if{html}{\out{
}}\preformatted{library(crul) library(vcr) cli <- crul::HttpClient$new("https://httpbin.org/get", headers = list(foo = "bar")) diff --git a/man/request_response.Rd b/man/request_response.Rd index 8a5e004..b972baa 100644 --- a/man/request_response.Rd +++ b/man/request_response.Rd @@ -40,7 +40,7 @@ your data/etc. as this is only for printing a summary of the response } \examples{ # request -url <- "https://httpbin.org" +url <- "https://hb.opencpu.org" body <- list(foo = "bar") headers <- list( `User-Agent` = "r-curl/3.2", diff --git a/man/rmdhunks/cassette-editing-vignette.Rmd b/man/rmdhunks/cassette-editing-vignette.Rmd index 205cead..9144f43 100644 --- a/man/rmdhunks/cassette-editing-vignette.Rmd +++ b/man/rmdhunks/cassette-editing-vignette.Rmd @@ -24,7 +24,7 @@ First, write your test e.g. ```r vcr::use_cassette("api-error", { - testhat("Errors are handled well", { + test_that("Errors are handled well", { vcr::skip_if_vcr_off() expect_error(call_my_api()), "error message") }) @@ -32,7 +32,7 @@ vcr::use_cassette("api-error", { ``` -Then run your tests a first time. +Then run your tests the first time. 1. It will fail 2. It will have created a cassette under `tests/fixtures/api-error.yml` that looks @@ -97,7 +97,7 @@ behavior of your package in case of errors. Below we assume `api_url()` returns the URL `call_my_api()` calls. ```r -testhat("Errors are handled well", { +test_that("Errors are handled well", { webmockr::enable() stub <- webmockr::stub_request("get", api_url()) webmockr::to_return(stub, status = 503) @@ -119,7 +119,7 @@ First, write your test e.g. ```r vcr::use_cassette("api-error", { - testhat("Errors are handled well", { + test_that("Errors are handled well", { vcr::skip_if_vcr_off() expect_message(thing <- call_my_api()), "retry message") expect_s4_class(thing, "data.frame") @@ -128,7 +128,7 @@ vcr::use_cassette("api-error", { ``` -Then run your tests a first time. +Then run your tests the first time. 1. It will fail 2. It will have created a cassette under `tests/fixtures/api-error.yml` that looks @@ -219,7 +219,7 @@ behavior of your package in case of errors. Below we assume `api_url()` returns the URL `call_my_api()` calls. ```r -testhat("Errors are handled well", { +test_that("Errors are handled well", { webmockr::enable() stub <- webmockr::stub_request("get", api_url()) stub %>% diff --git a/man/rmdhunks/cassette-names.Rmd b/man/rmdhunks/cassette-names.Rmd index 8ee6f77..d7f24eb 100644 --- a/man/rmdhunks/cassette-names.Rmd +++ b/man/rmdhunks/cassette-names.Rmd @@ -17,11 +17,7 @@ file paths: `/`, `?`, `<`, `>`, `\\`, `:`, `*`, `|`, and `\"` - Should not have trailing dots - Should not be longer than 255 characters -`vcr::check_cassette_names()` is meant to be run during your tests, from a -`setup-pkgname.R` file inside the `tests/testthat` directory. It only -checks that cassette names are not duplicated. Note that if you do -need to have duplicated cassette names you can do so by using the -`allowed_duplicates` parameter in `check_cassette_names()`. A helper function -`check_cassette_names()` runs inside [insert_cassette()] that checks -that cassettes do not have: spaces, file extensions, unaccepted -characters (slashes) +`vcr::check_cassette_names()` is meant to be run during your tests, from a [`helper-*.R` file](https://testthat.r-lib.org/reference/test_dir.html#special-files) inside the `tests/testthat` directory. +It only checks that cassette names are not duplicated. +Note that if you do need to have duplicated cassette names you can do so by using the `allowed_duplicates` parameter in `check_cassette_names()`. +A helper function `check_cassette_names()` runs inside [insert_cassette()] that checks that cassettes do not have: spaces, file extensions, unaccepted characters (slashes). diff --git a/man/rmdhunks/configuration-vignette.Rmd b/man/rmdhunks/configuration-vignette.Rmd index 22e7699..1b71073 100644 --- a/man/rmdhunks/configuration-vignette.Rmd +++ b/man/rmdhunks/configuration-vignette.Rmd @@ -58,7 +58,7 @@ One of: 'all', 'none', 'new_episodes', 'once'. See `?recording` for info on the vcr_configure(record = "new_episodes") ``` -### match_requests_on +### match_requests_on Customize how `vcr` matches requests @@ -66,7 +66,7 @@ Customize how `vcr` matches requests vcr_configure(match_requests_on = c('query', 'headers')) ``` -### allow_unused_http_interactions +### allow_unused_http_interactions Allow HTTP connections when no cassette @@ -80,7 +80,10 @@ vcr_configure(allow_unused_http_interactions = FALSE) ### serialize_with -Which serializer to use. Right now only option is "yaml" +Which serializer to use: "yaml" or "json". Note that you can have +multiple cassettes with the same name as long as they use different +serializers; so if you only want one cassette for a given cassette name, +make sure to not switch serializers, or clean up files you no longer need. ```{r} vcr_configure(serialize_with = "yaml") @@ -132,7 +135,7 @@ use_cassette("foo_bar", { The request to httpbin.org will be handled by `vcr`, a cassette created for the request/response to that url, while the google.com request will be ignored and not cached at all. -Note: ignoring requests only works for the `crul` package for now; it should work for `httr` in a later `vcr` version. +Note: ignoring requests only works for the `crul` package for now; it should work for `httr` and `httr2` in a later `vcr` version. ### uri_parse @@ -157,7 +160,7 @@ of the cassette. vcr_configure(preserve_exact_body_bytes = TRUE) ``` -### filter_sensitive_data +### filter_sensitive_data A named list of values to replace. Sometimes your package or script is working with sensitive tokens/keys, which you do not want to accidentally @@ -192,7 +195,7 @@ value with which to replace the real value. A request header you set to remove or replace is only removed/replaced from the cassette, and any requests using a cassette, but will still be in -your crul or httr response objects on a real request that creates the +your `crul`, `httr` or `httr2` response objects on a real request that creates the cassette. Examples: @@ -220,7 +223,7 @@ value with which to replace the real value. A response header you set to remove or replace is only removed/replaced from the cassette, and any requests using a cassette, but will still be in -your crul or httr response objects on a real request that creates the +your `crul`, `httr` or `httr2` response objects on a real request that creates the cassette. Examples: @@ -248,7 +251,7 @@ value is the value with which to replace the real value. A response header you set to remove or replace is only removed/replaced from the cassette, and any requests using a cassette, but will still be in -your crul or httr response objects on a real request that creates the +your `crul`, `httr` or `httr2` response objects on a real request that creates the cassette. Beware of your `match_requests_on` option when using this filter. If you diff --git a/man/rmdhunks/elevator-pitch.Rmd b/man/rmdhunks/elevator-pitch.Rmd index 11264ee..62177a1 100644 --- a/man/rmdhunks/elevator-pitch.Rmd +++ b/man/rmdhunks/elevator-pitch.Rmd @@ -5,4 +5,4 @@ Now your tests can work without any internet connection! -[Demo of adding vcr testing to an R package](https://github.com/maelle/exemplighratia/pull/2/files), [corresponding narrative](https://books.ropensci.org/http-testing/vcr.html). +[Demo of adding vcr testing to an R package](https://github.com/ropensci-books/exemplighratia/pull/2/files), [corresponding narrative](https://books.ropensci.org/http-testing/vcr.html). diff --git a/man/rmdhunks/internals-vignette.Rmd b/man/rmdhunks/internals-vignette.Rmd index 9d2e9dc..9ad8258 100644 --- a/man/rmdhunks/internals-vignette.Rmd +++ b/man/rmdhunks/internals-vignette.Rmd @@ -16,7 +16,7 @@ When you run that request again using `vcr::use_cassette()` or `vcr::insert_cass Of course if you do a different request, even slightly (but depending on which matching format you decided to use), then the request will have no matching stub and no cached response, and then a real HTTP request is done - we then cache it, then subsequent requests will pull from that cached response. -`webmockr` has adapters for each R client (crul and httr) - so that we actually intercept HTTP requests when `webmockr` is loaded and the user turns it on. So, `webmockr` doesn't actually require an internet or localhost connection at all, but can do its thing just fine by matching on whatever the user requests to match on. In fact, `webmockr` doesn't allow real HTTP requests by default, but can be toggled off of course. +`webmockr` has adapters for each R client (`crul`, `httr` and `httr2`) - so that we actually intercept HTTP requests when `webmockr` is loaded and the user turns it on. So, `webmockr` doesn't actually require an internet or localhost connection at all, but can do its thing just fine by matching on whatever the user requests to match on. In fact, `webmockr` doesn't allow real HTTP requests by default, but can be toggled off of course. The main use case we are going for in `vcr` is to deal with real HTTP requests and responses, so we allow real HTTP requests when we need to, and turn it off when we don't. diff --git a/man/rmdhunks/setup.Rmd b/man/rmdhunks/setup.Rmd index 947b3f4..8ab3cf7 100644 --- a/man/rmdhunks/setup.Rmd +++ b/man/rmdhunks/setup.Rmd @@ -17,7 +17,7 @@ This will: * setup a config file for `vcr` * add an example test file for `vcr` * make a `.gitattributes` file with settings for `vcr` -* make a `./tests/testthat/setup-vcr.R` file +* make a `./tests/testthat/helper-vcr.R` file What you will see in the R console: @@ -28,10 +28,10 @@ What you will see in the R console: ✓ Creating directory: ./tests/testthat ◉ Looking for testthat.R file or similar ✓ tests/testthat.R: added -✓ Adding vcr config to tests/testthat/setup-vcr.example.R +✓ Adding vcr config to tests/testthat/helper-vcr.example.R ✓ Adding example test file tests/testthat/test-vcr_example.R ✓ .gitattributes: added -◉ Learn more about `vcr`: https://books.ropensci.org/http-testing +◉ Learn more about `vcr`: https://books.ropensci.org/http-testing/ ``` ### Protecting secrets @@ -40,7 +40,7 @@ Secrets often turn up in API work. A common example is an API key. `vcr` saves responses from APIs as YAML files, and this will include your secrets unless you indicate to `vcr` what they are and how to protect them. The `vcr_configure` function has the `filter_sensitive_data` argument function for just this situation. The `filter_sensitive_data` argument takes a named list where the _name_ of the list is the string that will be used in the recorded cassettes _instead of_ the secret, which is the list _item_. -`vcr` will manage the replacement of that for you, so all you need to do is to edit your `setup-vcr.R` file like this: +`vcr` will manage the replacement of that for you, so all you need to do is to edit your [`helper-vcr.R` file](https://testthat.r-lib.org/reference/test_dir.html#special-files) like this: ```r library("vcr") # *Required* as vcr is set up on loading @@ -88,7 +88,7 @@ Furthermore, as by default requests matching does not include the API key, thing E.g. to have tests pass on continuous integration for external pull requests to your code repository. * vcr does not need an actual API key for requests once the cassettes are created, as no real requests will be made. -* you still need to fool your _package_ into believing there is an API key as it will construct requests with it. So add the following lines to a testthat setup file (e.g. `tests/testthat/setup-vcr.R`) +* you still need to fool your _package_ into believing there is an API key as it will construct requests with it. So add the following lines to a testthat setup file (e.g. `tests/testthat/helper-vcr.R`) ```r if (!nzchar(Sys.getenv("APIKEY"))) { diff --git a/man/rmdhunks/vcr-design.Rmd b/man/rmdhunks/vcr-design.Rmd new file mode 100644 index 0000000..3dea398 --- /dev/null +++ b/man/rmdhunks/vcr-design.Rmd @@ -0,0 +1,139 @@ +This section explains `vcr`'s internal design and architecture. + +### Where vcr comes from and why R6 + +`vcr` was "ported" from the Ruby gem (aka, library) of the same name[^1]. +Because it was ported from Ruby, an object-oriented programming language +I thought it would be easier to use an object system in R that most +closely resemble that used in Ruby (at least in my opinion). This +thinking lead to choosing [R6][]. The exported functions users interact +with are not R6 classes, but are rather normal R functions. However, +most of the internal code in the package uses R6. Thus, familiarity +with R6 is important for people that may want to contribute to `vcr`, +but not required at all for `vcr` users. + +### Principles + +#### An easy to use interface hides complexity + +As described above, `vcr` uses R6 internally, but users interact with +normal R functions. Internal functions that are quite complicated are +largely R6 while exported, simpler functions users interact with are +normal R functions. + +#### Class/function names are inherited from Ruby vcr + +Since R `vcr` was ported from Ruby, we kept most of the names of +functions/classes and variables. So if you're wondering about why +a function, class, or variable has a particular name, its derivation +can not be found out in this package, for the most part that is. + +#### Hooks into HTTP clients + +Perhaps the most fundamental thing about that this package work is +how it knows what HTTP requests are being made. This stumped me for +quite a long time. When looking at Ruby vcr, at first I thought it +must be "listening" for HTTP requests somehow. Then I found out about +[monkey patching][mp]; that's how it's achieved in Ruby. That is, the Ruby +vcr package literally overrides certain methods in Ruby HTTP clients, +hijacking internals of the HTTP clients. + +However, monkey patching is not allowed in R. Thus, in R we have to +somehow have "hooks" into HTTP clients in R. Fortunately, Scott is the +maintainer of one of the HTTP clients, `crul`, so was able to quickly +create a hook. Fortunately, there was already a hook mechanism +in the `httr` and `httr2` packages. + +The actual hooks are not in `vcr`, but in `webmockr`. `vcr` depends on +`webmockr` for hooking into HTTP clients `httr`, `httr2` and `crul`. + +### Internal classes + +An overview of some of the more important aspects of vcr. + +#### Configuration + +An internal object (`vcr_c`) is created when `vcr` is loaded with +the default vcr configuration options inside of an R6 class `VCRConfig` - +see . This +class is keeps track of default and user specified configuration options. +You can access `vcr_c` using triple namespace `:::`, though it is not +intended for general use. Whenever you make calls to `vcr_configure()` +or other configuration functions, `vcr_c` is affected. + +#### Cassette class + +`Cassette` is an R6 class that handles internals/state for each cassette. +Each time you run `use_cassette()` this class is used. The class has quite +a few methods in it, so there's a lot going on in the class. Ideally +the class would be separated into subclasses to handle similar sets +of logic, but there's not an easy way to do that with R6. + +Of note in `Cassette` is that when called, within the `initialize()` +call `webmockr` is used to create webmockr stubs. + +#### How HTTP requests are handled + +Within `webmockr`, there are calls to the vcr class `RequestHandler`, which +has child classes `RequestHandlerCrul`, `RequestHandlerHttr` and `RequestHandlerHttr2` for `crul`, `httr` and `httr2`, respectively. These classes determine what to do with each HTTP request. The options for each HTTP request include: + +- **Ignored** You can ignore HTTP requests under certain rules using the +configuration options `ignore_hosts` and `ignore_localhost` +- **Stubbed by vcr** This is an HTTP request for which a match is found +in the cassette defined in the `use_cassette()`/`insert_cassette()` call. +In this case the matching request/response from the cassette is returned +with no real HTTP request allowed. +- **Recordable** This is an HTTP request for which no match is found +in the cassette defined in the `use_cassette()`/`insert_cassette()` call. +In this case a real HTTP request is allowed, and the request/response is +recorded to the cassette. +- **Unhandled** This is a group of cases, all of which cause an error +to be thrown with a message trying to help the user figure out how to +fix the problem. + +If you use [vcr logging][logging] you'll see these categories in your logs. + +#### Serializers + +Serializers handle in what format cassettes are written to files on disk. +The current options are YAML (default) and JSON. YAML was implemented first +in `vcr` because that's the default option in Ruby vcr. + +An R6 class `Serializer` is the parent class for all serializer types; +`YAML` and `JSON` are both R6 classes that inherit from `Serializer`. Both +`YAML` and `JSON` define just two methods: `serialize()` and `deserialize()` +for converting R structures to yaml or json, and converting yaml or json back +to R structures, respectively. + + +### Environments + +#### Logging + +An internal environment (`vcr_log_env`) is used when you use logging. +At this point it only keeps track of one variable - `file` - to be able +to refer to what file is used for logging across many classes/functions +that need to write to the log file. + +#### A bit of housekeeping + +Another internal environment (`vcr__env`) is used to keep track of a +few items, including the current cassette in use, and the last vcr error. + +#### Lightswitch + +Another internal environment (`light_switch`) is used to keep track of users +turning on and off `vcr`. See `?lightswitch`. + + + +[^1]: The first version of Ruby's vcr was released in February 2010 +https://rubygems.org/gems/vcr/versions/0.1.0. Ruby vcr source code: +https://github.com/vcr/vcr/ + + + + +[R6]: https://adv-r.hadley.nz/r6.html +[mp]: https://en.wikipedia.org/wiki/Monkey_patch +[logging]: https://docs.ropensci.org/vcr/articles/debugging.html?q=logging#logging-1 diff --git a/man/str_splitter.Rd b/man/str_splitter.Rd new file mode 100644 index 0000000..0500b13 --- /dev/null +++ b/man/str_splitter.Rd @@ -0,0 +1,23 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/split_string.R +\name{str_splitter} +\alias{str_splitter} +\title{split string every N characters} +\usage{ +str_splitter(str, length) +} +\arguments{ +\item{str}{(character) a string} + +\item{length}{(integer) number of characters to split by} +} +\description{ +split string every N characters +} +\examples{ +\dontrun{ +str = "XOVEWVJIEWNIGOIWENVOIWEWVWEW" +str_splitter(str, 5) +str_splitter(str, 5L) +} +} diff --git a/man/use_cassette.Rd b/man/use_cassette.Rd index 8b7c37c..91d3e22 100644 --- a/man/use_cassette.Rd +++ b/man/use_cassette.Rd @@ -151,14 +151,14 @@ library(crul) vcr_configure(dir = tempdir()) use_cassette(name = "apple7", { - cli <- HttpClient$new(url = "https://httpbin.org") + cli <- HttpClient$new(url = "https://hb.opencpu.org") resp <- cli$get("get") }) readLines(file.path(tempdir(), "apple7.yml")) # preserve exact body bytes - records in base64 encoding use_cassette("things4", { - cli <- crul::HttpClient$new(url = "https://httpbin.org") + cli <- crul::HttpClient$new(url = "https://hb.opencpu.org") bbb <- cli$get("get") }, preserve_exact_body_bytes = TRUE) ## see the body string value in the output here @@ -174,7 +174,7 @@ library(httr) vcr_configure(dir = tempdir(), log = TRUE, log_opts = list(file = file.path(tempdir(), "vcr.log"))) use_cassette(name = "stuff350", { - res <- GET("https://httpbin.org/get") + res <- GET("https://hb.opencpu.org/get") }) readLines(file.path(tempdir(), "stuff350.yml")) diff --git a/man/vcr-package.Rd b/man/vcr-package.Rd new file mode 100644 index 0000000..283c7d3 --- /dev/null +++ b/man/vcr-package.Rd @@ -0,0 +1,79 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/vcr-package.R +\docType{package} +\name{vcr-package} +\alias{vcr} +\alias{vcr-package} +\title{vcr: Record 'HTTP' Calls to Disk} +\description{ +Record test suite 'HTTP' requests and replays them during future runs. A port of the Ruby gem of the same name (\url{https://github.com/vcr/vcr/}). Works by hooking into the 'webmockr' R package for matching 'HTTP' requests by various rules ('HTTP' method, 'URL', query parameters, headers, body, etc.), and then caching real 'HTTP' responses on disk in 'cassettes'. Subsequent 'HTTP' requests matching any previous requests in the same 'cassette' use a cached 'HTTP' response. +} +\section{Backstory}{ + +A Ruby gem of the same name (\code{VCR}, \url{https://github.com/vcr/vcr}) was +created many years ago and is the original. Ports in many languages +have been done. Check out that GitHub repo for all the details on +how the canonical version works. +} + +\section{Main functions}{ + +The \link{use_cassette} function is most likely what you'll want to use. It +sets the cassette you want to record to, inserts the cassette, and then +ejects the cassette, recording the interactions to the cassette. + +Instead, you can use \link{insert_cassette}, but then you have to make sure +to use \link{eject_cassette}. +} + +\section{vcr configuration}{ + +\link{vcr_configure} is the function to use to set R session wide settings. +See it's manual file for help. +} + +\section{Record modes}{ + +See \link{recording} for help on record modes. +} + +\section{Request matching}{ + +See \link{request-matching} for help on the many request matching options. +} + +\section{Async}{ + +As of \pkg{crul} v1.5, \code{vcr} will work for async http requests with +\pkg{crul}. \pkg{httr} does not do async requests, and \pkg{httr2} +async plumbing does not have any hooks for mocking via \pkg{webmockr} +or recording real requests via this package +} + +\seealso{ +Useful links: +\itemize{ + \item \url{https://github.com/ropensci/vcr/} + \item \url{https://books.ropensci.org/http-testing/} + \item \url{https://docs.ropensci.org/vcr/} + \item Report bugs at \url{https://github.com/ropensci/vcr/issues} +} + +} +\author{ +\strong{Maintainer}: Scott Chamberlain \email{sckott@protonmail.com} (\href{https://orcid.org/0000-0003-1444-9135}{ORCID}) + +Authors: +\itemize{ + \item Aaron Wolen (\href{https://orcid.org/0000-0003-2542-2202}{ORCID}) + \item Maëlle Salmon (\href{https://orcid.org/0000-0002-2815-0399}{ORCID}) + \item Daniel Possenriede (\href{https://orcid.org/0000-0002-6738-9845}{ORCID}) +} + +Other contributors: +\itemize{ + \item rOpenSci (https://ropensci.org) [funder] +} + +} +\keyword{internal} diff --git a/man/vcr.Rd b/man/vcr.Rd deleted file mode 100644 index e9c18d1..0000000 --- a/man/vcr.Rd +++ /dev/null @@ -1,52 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/vcr-package.R -\docType{package} -\name{vcr} -\alias{vcr} -\alias{vcr-package} -\title{vcr: Record HTTP Calls to Disk} -\description{ -\pkg{vcr} records test suite 'HTTP' requests and replay them during -future runs. -} -\details{ -Check out the \href{https://books.ropensci.org/http-testing/}{http testing book} -for a lot more documentation on \code{vcr}, \code{webmockr}, and \code{crul} -} -\section{Backstory}{ - -A Ruby gem of the same name (\code{VCR}, \url{https://github.com/vcr/vcr}) was -created many years ago and is the original. Ports in many languages -have been done. Check out that GitHub repo for all the details on -how the canonical version works. -} - -\section{Main functions}{ - -The \link{use_cassette} function is most likely what you'll want to use. It -sets the cassette you want to record to, inserts the cassette, and then -ejects the cassette, recording the interactions to the cassette. - -Instead, you can use \link{insert_cassette}, but then you have to make sure -to use \link{eject_cassette}. -} - -\section{vcr configuration}{ - -\link{vcr_configure} is the function to use to set R session wide settings. -See it's manual file for help. -} - -\section{Record modes}{ - -See \link{recording} for help on record modes. -} - -\section{Request matching}{ - -See \link{request-matching} for help on the many request matching options. -} - -\author{ -Scott Chamberlain \email{myrmecocystus@gmail.com} -} diff --git a/man/vcr_configure.Rd b/man/vcr_configure.Rd index 5c3efe6..2c90bf1 100644 --- a/man/vcr_configure.Rd +++ b/man/vcr_configure.Rd @@ -62,8 +62,10 @@ google.com. These hosts are ignored and real HTTP requests allowed to go through \item \code{ignore_localhost} (logical) Default: \code{FALSE} \item \code{ignore_request} List of requests to ignore. NOT USED RIGHT NOW, sorry -\item \code{filter_sensitive_data} named list of values to replace. Format is:\preformatted{list(thing_to_replace_it_with = thing_to_replace) -} +\item \code{filter_sensitive_data} named list of values to replace. Format is: + +\if{html}{\out{
}}\preformatted{list(thing_to_replace_it_with = thing_to_replace) +}\if{html}{\out{
}} We replace all instances of \code{thing_to_replace} with \code{thing_to_replace_it_with}. Uses \code{\link[=gsub]{gsub()}} internally, with \code{fixed=TRUE}; @@ -158,7 +160,7 @@ be recorded back to file. Default: \code{FALSE} \item \code{quiet} (logical) Suppress any messages from both vcr and webmockr. Default: \code{TRUE} \item \code{warn_on_empty_cassette} (logical) Should a warning be thrown when an -empty cassette is detected? Empty cassettes are claned up (deleted) either +empty cassette is detected? Empty cassettes are cleaned up (deleted) either way. This option only determines whether a warning is thrown or not. Default: \code{FALSE} \item \code{record_separate_redirects} (logical) If http redirects are diff --git a/man/vcr_test_path.Rd b/man/vcr_test_path.Rd index 8f2a363..4e7dd84 100644 --- a/man/vcr_test_path.Rd +++ b/man/vcr_test_path.Rd @@ -9,7 +9,7 @@ vcr_test_path(...) \arguments{ \item{...}{Character vectors giving path component. each character string gets added on to the path, e.g., \code{vcr_test_path("a", "b")} becomes -\code{tests/a/b} when run from the root of the package.} +\code{tests/a/b} relative to the root of the package.} } \value{ A character vector giving the path @@ -18,6 +18,9 @@ A character vector giving the path This function, similar to \code{testthat::test_path()}, is designed to work both interactively and during tests, locating files in the \verb{tests/} directory. } +\note{ +\code{vcr_test_path()} assumes you are using testthat for your unit tests. +} \examples{ if (interactive()) { vcr_test_path("fixtures") diff --git a/revdep/README.md b/revdep/README.md index 0d8c754..bc4bdae 100644 --- a/revdep/README.md +++ b/revdep/README.md @@ -1,22 +1,33 @@ # Platform -|field |value | -|:--------|:-------------------------------------------| -|version |R version 3.6.3 Patched (2020-02-29 r77909) | -|os |macOS Catalina 10.15.3 | -|system |x86_64, darwin15.6.0 | -|ui |X11 | -|language |(EN) | -|collate |en_US.UTF-8 | -|ctype |en_US.UTF-8 | -|tz |US/Pacific | -|date |2020-03-25 | +|field |value | +|:--------|:-----------------------------------| +|version |R version 4.3.2 (2023-10-31) | +|os |macOS Ventura 13.6.3 | +|system |aarch64, darwin20 | +|ui |X11 | +|language |(EN) | +|collate |en_US.UTF-8 | +|ctype |en_US.UTF-8 | +|tz |America/Los_Angeles | +|date |2024-01-09 | +|pandoc |3.1.11.1 @ /opt/homebrew/bin/pandoc | # Dependencies -|package |old |new |Δ | -|:-------|:-----|:-----|:--| -|vcr |0.5.0 |0.5.4 |* | +|package |old |new |Δ | +|:---------|:-----|:--------|:--| +|vcr |1.2.2 |1.2.2.91 |* | +|askpass |NA |1.2.0 |* | +|curl |NA |5.2.0 |* | +|httr |NA |1.4.7 |* | +|openssl |NA |2.1.1 |* | +|Rcpp |NA |1.0.11 |* | +|rprojroot |NA |2.0.4 |* | +|sys |NA |3.4.2 |* | +|triebeard |NA |0.4.1 |* | +|whisker |NA |0.4.1 |* | +|yaml |NA |2.3.8 |* | # Revdeps diff --git a/revdep/cran.md b/revdep/cran.md new file mode 100644 index 0000000..d457c96 --- /dev/null +++ b/revdep/cran.md @@ -0,0 +1,7 @@ +## revdepcheck results + +We checked 66 reverse dependencies, comparing R CMD check results across CRAN and dev versions of this package. + + * We saw 0 new problems + * We failed to check 0 packages + diff --git a/src/.gitignore b/src/.gitignore deleted file mode 100644 index 22034c4..0000000 --- a/src/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.o -*.so -*.dll diff --git a/src/cpp11.cpp b/src/cpp11.cpp deleted file mode 100644 index 0bac6d4..0000000 --- a/src/cpp11.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// Generated by cpp11: do not edit by hand -// clang-format off - - -#include "cpp11/declarations.hpp" - -// split_str.cpp -std::vector split_str(const std::string& str, int splitLength); -extern "C" SEXP _vcr_split_str(SEXP str, SEXP splitLength) { - BEGIN_CPP11 - return cpp11::as_sexp(split_str(cpp11::as_cpp>(str), cpp11::as_cpp>(splitLength))); - END_CPP11 -} - -extern "C" { -/* .Call calls */ -extern SEXP _vcr_split_str(SEXP, SEXP); - -static const R_CallMethodDef CallEntries[] = { - {"_vcr_split_str", (DL_FUNC) &_vcr_split_str, 2}, - {NULL, NULL, 0} -}; -} - -extern "C" void R_init_vcr(DllInfo* dll){ - R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); - R_useDynamicSymbols(dll, FALSE); -} diff --git a/src/split_str.cpp b/src/split_str.cpp deleted file mode 100644 index 33e8373..0000000 --- a/src/split_str.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include -using namespace cpp11; - -// borrowed from https://stackoverflow.com/a/25022977/1091766 -[[cpp11::register]] -std::vector split_str(const std::string& str, int splitLength) { - int NumSubstrings = str.length() / splitLength; - std::vector ret; - - for (auto i = 0; i < NumSubstrings; i++) { - ret.push_back(str.substr(i * splitLength, splitLength)); - } - - // If there are leftover characters, create a shorter item at the end. - if (str.length() % splitLength != 0) { - ret.push_back(str.substr(splitLength * NumSubstrings)); - } - - return ret; -} diff --git a/tests/testthat/helper-vcr.R b/tests/testthat/helper-vcr.R index a229f1f..a4cb58c 100644 --- a/tests/testthat/helper-vcr.R +++ b/tests/testthat/helper-vcr.R @@ -62,3 +62,38 @@ check_url <- function(x, ...) { } sw <- function(x) suppressWarnings(x) sm <- function(x) suppressMessages(x) + + +# Base url for tests +hb <- function(x = NULL) { + tryCatch( + if (is.null(x)) base_url else paste0(base_url, x), + error = function(e) "https://not.aurl" + ) +} +urls <- c( + "https://hb.cran.dev", + "https://hb.opencpu.org", + "https://nghttp2.org/httpbin" +) +h <- curl::new_handle(timeout = 10, failonerror = FALSE) +base_url <- "" +tryCatch({ + out <- list() + for (i in seq_along(urls)) { + out[[i]] <- curl::curl_fetch_memory(urls[i], handle = h) + } + codes <- vapply(out, "[[", 1, "status_code") + if (all(codes != 200)) stop("all httpbin servers down") + base_url <- urls[codes == 200][1] + cat(paste0("using base url for tests: ", base_url), sep = "\n") +}, error = function(e) message(e$message)) + +# httpbin local +local_httpbin_app <- function() { + check_for_a_pkg("webfakes") + webfakes::local_app_process( + webfakes::httpbin_app(), + .local_envir = testthat::teardown_env() + ) +} diff --git a/tests/testthat/httr2_obj.rda b/tests/testthat/httr2_obj.rda new file mode 100644 index 0000000..bd61dfb Binary files /dev/null and b/tests/testthat/httr2_obj.rda differ diff --git a/tests/testthat/httr_obj.rda b/tests/testthat/httr_obj.rda index af8cf1c..02fac29 100644 Binary files a/tests/testthat/httr_obj.rda and b/tests/testthat/httr_obj.rda differ diff --git a/tests/testthat/httr_resp1.rda b/tests/testthat/httr_resp1.rda index b40ef74..a4ffec4 100644 Binary files a/tests/testthat/httr_resp1.rda and b/tests/testthat/httr_resp1.rda differ diff --git a/tests/testthat/httr_resp2.rda b/tests/testthat/httr_resp2.rda index 8ed22e8..a041681 100644 Binary files a/tests/testthat/httr_resp2.rda and b/tests/testthat/httr_resp2.rda differ diff --git a/tests/testthat/test-Cassette.R b/tests/testthat/test-Cassette.R index 5544b9b..2f392ea 100644 --- a/tests/testthat/test-Cassette.R +++ b/tests/testthat/test-Cassette.R @@ -31,16 +31,16 @@ test_that("Cassette fails well with invalid request matchers", { test_that("make_http_interaction works as expected", { #### Prepare http responses - # crul_resp1 <- crul::HttpClient$new("https://httpbin.org/get?foo=bar")$get() + # crul_resp1 <- crul::HttpClient$new(hb("/get?foo=bar"))$get() # save(crul_resp1, file = "tests/testthat/crul_resp1.rda", version = 2) - # crul_resp2 <- crul::HttpClient$new("https://httpbin.org/image/png")$get() + # crul_resp2 <- crul::HttpClient$new(hb("/image/png"))$get() # save(crul_resp2, file = "tests/testthat/crul_resp2.rda", version = 2) - # httr_resp1 <- httr::GET("https://httpbin.org/get?foo=bar") + # httr_resp1 <- httr::GET(hb("/get?foo=bar")) # save(httr_resp1, file = "tests/testthat/httr_resp1.rda", version = 2) - # httr_resp2 <- httr::GET("https://httpbin.org/image/png") + # httr_resp2 <- httr::GET(hb("/image/png")) # save(httr_resp2, file = "tests/testthat/httr_resp2.rda", version = 2) # make a cassettes diff --git a/tests/testthat/test-HttpInteraction.R b/tests/testthat/test-HttpInteraction.R index 015ca56..aca8516 100644 --- a/tests/testthat/test-HttpInteraction.R +++ b/tests/testthat/test-HttpInteraction.R @@ -3,7 +3,7 @@ context("HttpInteraction") test_that("HttpInteraction", { crul::mock(FALSE) - url <- "https://eu.httpbin.org/post" + url <- hb("/post") body <- list(foo = "bar") cli <- crul::HttpClient$new(url = url) res <- cli$post(body = body) diff --git a/tests/testthat/test-HttpInteractionList.R b/tests/testthat/test-HttpInteractionList.R index 391e347..ce81726 100644 --- a/tests/testthat/test-HttpInteractionList.R +++ b/tests/testthat/test-HttpInteractionList.R @@ -1,8 +1,8 @@ test_that("HTTPInteractionList", { crul::mock(FALSE) - url <- "https://eu.httpbin.org/post" - url2 <- "https://eu.httpbin.org/get" + url <- hb("/post") + url2 <- hb("/get") url3 <- "https://scottchamberlain.info" body <- list(foo = "bar") cli <- crul::HttpClient$new(url = url) diff --git a/tests/testthat/test-Request.R b/tests/testthat/test-Request.R index f4aa7bf..8369c3b 100644 --- a/tests/testthat/test-Request.R +++ b/tests/testthat/test-Request.R @@ -25,7 +25,7 @@ test_that("Request basic stuff", { }) test_that("Request usage", { - url <- "https://eu.httpbin.org/post" + url <- hb("/post") body <- list(foo = "bar") headers <- list( `User-Agent` = "libcurl/7.54.0 r-curl/3.2 crul/0.5.2", @@ -38,9 +38,8 @@ test_that("Request usage", { expect_is(aa$method, "character") expect_equal(aa$method, "post") expect_is(aa$uri, "character") - expect_equal(aa$uri, "https://eu.httpbin.org/post") + expect_equal(aa$uri, hb("/post")) expect_is(aa$host, "character") - expect_equal(aa$host, "eu.httpbin.org") expect_is(aa$path, "character") expect_equal(aa$path, "post") expect_is(aa$headers, "list") diff --git a/tests/testthat/test-RequestHandler.R b/tests/testthat/test-RequestHandler.R index 0732928..3195045 100644 --- a/tests/testthat/test-RequestHandler.R +++ b/tests/testthat/test-RequestHandler.R @@ -1,3 +1,5 @@ +skip_on_cran() + vcr_configure(dir = tempdir()) test_that("RequestHandlerHttr", { diff --git a/tests/testthat/test-RequestIgnorer.R b/tests/testthat/test-RequestIgnorer.R index b04145b..ab909fe 100644 --- a/tests/testthat/test-RequestIgnorer.R +++ b/tests/testthat/test-RequestIgnorer.R @@ -100,7 +100,7 @@ test_that("RequestIgnorer usage: w/ vcr_configure() usage", { vcr_configure(dir = tmpdir) # vcr_configuration() cas_not_ignored <- use_cassette("test_ignore_host", { - HttpClient$new("https://httpbin.org")$get() + HttpClient$new(hb())$get() HttpClient$new("https://scottchamberlain.info")$get() }) diff --git a/tests/testthat/test-ause_cassette.R b/tests/testthat/test-ause_cassette.R index 8e5d07e..599ced3 100644 --- a/tests/testthat/test-ause_cassette.R +++ b/tests/testthat/test-ause_cassette.R @@ -10,7 +10,7 @@ test_that("use_cassette works as expected", { invisible(vcr_configure(dir = mydir)) unlink(file.path(vcr_c$dir, "testing1.yml")) aa <- use_cassette(name = "testing1", { - res <- crul::HttpClient$new("https://eu.httpbin.org/get")$get() + res <- crul::HttpClient$new(hb("/get"))$get() }) # test `print.cassette` method @@ -24,7 +24,7 @@ test_that("use_cassette works as expected", { expect_is(aa$name, "character") expect_equal(aa$name, "testing1") expect_false(aa$allow_playback_repeats) - # expect_true(aa$any_new_recorded_interactions()) # FIXME: uncomment w/ webmockr update + expect_true(aa$any_new_recorded_interactions()) expect_is(aa$args, "list") expect_is(aa$call_block, "function") @@ -33,9 +33,9 @@ test_that("use_cassette works as expected", { cas <- readLines(file.path(vcr_c$dir, "testing1.yml")) expect_is(cas, "character") - # expect_gt(length(cas), 10) # FIXME: uncomment w/ webmockr update - # expect_true(any(grepl('http_interactions', cas))) # FIXME: uncomment w/ webmockr update - # expect_true(any(grepl('recorded_with', cas))) # FIXME: uncomment w/ webmockr update + expect_gt(length(cas), 10) + expect_true(any(grepl('http_interactions', cas))) + expect_true(any(grepl('recorded_with', cas))) }) diff --git a/tests/testthat/test-ause_cassette_match_body_empty_body.R b/tests/testthat/test-ause_cassette_match_body_empty_body.R index 68d8af4..a2e2f2a 100644 --- a/tests/testthat/test-ause_cassette_match_body_empty_body.R +++ b/tests/testthat/test-ause_cassette_match_body_empty_body.R @@ -5,7 +5,7 @@ test_that("use_cassette: match on body w/ empty body", { mydir <- file.path(tempdir(), "asdfasdfsd") invisible(vcr_configure(dir = mydir)) unlink(file.path(vcr_c$dir, "testing1.yml")) - cli <- HttpClient$new(url = "https://httpbin.org") + cli <- HttpClient$new(url = hb()) ### matchers: method, uri, body # run it diff --git a/tests/testthat/test-ause_cassette_match_query.R b/tests/testthat/test-ause_cassette_match_query.R new file mode 100644 index 0000000..dd1c17a --- /dev/null +++ b/tests/testthat/test-ause_cassette_match_query.R @@ -0,0 +1,29 @@ + +url <- hb("/get?update=2022-01-01T00:00:00&p2=ok") +req_crul <- function(url) { + tmp <- crul::HttpClient$new(url)$get() +} +req_httr <- function(url) { + tmp <- httr::GET(url) +} + +test_that('request matching is not sensitive to escaping special characters', { + skip_on_cran() + skip_on_ci() + # run twice the request with curl (curl does not escape) + aa <- vcr::use_cassette('get_crul_match', { + req_crul(url) + }, match_requests_on = c("method", "uri", "query")) + res <- req_crul(url) + expect_true(res$status_code == 200) + # run twice the request with httr (httr does escape on parameters) + bb <- vcr::use_cassette('get_httr_match', { + req_httr(url) + }, match_requests_on = c("method", "uri", "query")) + res <- req_httr(url) + expect_true(res$status_code == 200) +}) + +# cleanup +files <- c("get_crul_match.yml", "get_httr_match.yml") +unlink(file.path(vcr_configuration()$dir, files)) diff --git a/tests/testthat/test-ause_cassette_match_requests_on.R b/tests/testthat/test-ause_cassette_match_requests_on.R index f9b321a..7f8a268 100644 --- a/tests/testthat/test-ause_cassette_match_requests_on.R +++ b/tests/testthat/test-ause_cassette_match_requests_on.R @@ -5,7 +5,7 @@ test_that("use_cassette: match_requests_on - body works w/ crul", { mydir <- file.path(tempdir(), "asdfasdfsd") invisible(vcr_configure(dir = mydir)) unlink(file.path(vcr_c$dir, "testing1.yml")) - cli <- HttpClient$new(url = "https://httpbin.org") + cli <- HttpClient$new(url = hb()) ### matchers: method, uri, body # run it @@ -66,11 +66,11 @@ test_that("use_cassette: match_requests_on - body works w/ crul", { ### matchers: host only (note how query is ignored) # run it aa <- use_cassette(name = "testing_host1", { - res <- HttpClient$new(url = "https://httpbin.org")$get(query = list(b=99999)) + res <- HttpClient$new(url = hb())$get(query = list(b=99999)) }, match_requests_on = "host") # run it again bb <- use_cassette(name = "testing_host1", { - res2 <- HttpClient$new(url = "https://httpbin.org")$get(query = list(a=5)) + res2 <- HttpClient$new(url = hb())$get(query = list(a=5)) }, match_requests_on = "host") # the recorded_at time doesn't change # - that is, the request matched and the recorded response in aa @@ -136,11 +136,11 @@ test_that("use_cassette: match_requests_on - body works w/ httr", { ### matchers: method, uri, body # run it aa <- use_cassette(name = "testing2", { - res <- POST("https://httpbin.org/post", body = list(foo = "bar")) + res <- POST(hb("/post"), body = list(foo = "bar")) }, match_requests_on = c("method", "uri", "body")) # run it again bb <- use_cassette(name = "testing2", { - res <- POST("https://httpbin.org/post", body = list(foo = "bar")) + res <- POST(hb("/post"), body = list(foo = "bar")) }, match_requests_on = c("method", "uri", "body")) # the recorded_at time doesn't change # - that is, the request matched and the recorded response in aa @@ -154,11 +154,11 @@ test_that("use_cassette: match_requests_on - body works w/ httr", { ### matchers: method, body (uri ignored essentially) # run it aa <- use_cassette(name = "testing4", { - res <- POST("https://httpbin.org/post", query = list(a = 5), body = list(foo = "bar")) + res <- POST(hb("/post"), query = list(a = 5), body = list(foo = "bar")) }, match_requests_on = c("method", "body")) # run it again bb <- use_cassette(name = "testing4", { - res <- POST("https://httpbin.org/post", query = list(b = 2), body = list(foo = "bar")) + res <- POST(hb("/post"), query = list(b = 2), body = list(foo = "bar")) }, match_requests_on = c("method", "body")) # the recorded_at time doesn't change # - that is, the request matched and the recorded response in aa @@ -172,15 +172,15 @@ test_that("use_cassette: match_requests_on - body works w/ httr", { ### matchers: body only # run it aa <- use_cassette(name = "testing5", { - res <- POST("https://httpbin.org/post", body = list(foo = "bar")) + res <- POST(hb("/post"), body = list(foo = "bar")) }, match_requests_on = "body") # run it again, method and uri changed bb <- use_cassette(name = "testing5", { - res <- PUT("https://httpbin.org/put", body = list(foo = "bar")) + res <- PUT(hb("/put"), body = list(foo = "bar")) }, match_requests_on = "body") # run it again, method and uri changed again cc <- use_cassette(name = "testing5", { - res <- PATCH("https://httpbin.org/patch", body = list(foo = "bar")) + res <- PATCH(hb("/patch"), body = list(foo = "bar")) }, match_requests_on = "body") # the recorded_at time doesn't change # - that is, the request matched and the recorded response in aa diff --git a/tests/testthat/test-ause_cassette_match_requests_on_json.R b/tests/testthat/test-ause_cassette_match_requests_on_json.R index 223c7bc..81ea8e9 100644 --- a/tests/testthat/test-ause_cassette_match_requests_on_json.R +++ b/tests/testthat/test-ause_cassette_match_requests_on_json.R @@ -13,7 +13,7 @@ test_that("use_cassette: match_requests_on - JSON-encoded body w/ crul", { invisible(vcr_configure(dir = mydir)) library(crul) - cli <- HttpClient$new(url = "https://httpbin.org") + cli <- HttpClient$new(url = hb()) ### matchers: method, uri, body # run it @@ -71,11 +71,11 @@ test_that("use_cassette: match_requests_on - JSON-encoded body w/ httr", { ### matchers: method, uri, body # run it aa <- use_cassette(name = "testing2", { - res <- POST("https://httpbin.org/post", body = list(foo = "bar"), encode = "json") + res <- POST(hb("/post"), body = list(foo = "bar"), encode = "json") }, match_requests_on = c("method", "uri", "body")) # run it again bb <- use_cassette(name = "testing2", { - res <- POST("https://httpbin.org/post", body = list(foo = "bar"), encode = "json") + res <- POST(hb("/post"), body = list(foo = "bar"), encode = "json") }, match_requests_on = c("method", "uri", "body")) # the recorded_at time doesn't change # - that is, the request matched and the recorded response in aa @@ -89,14 +89,14 @@ test_that("use_cassette: match_requests_on - JSON-encoded body w/ httr", { # matching fails when the body changes expect_error( use_cassette(name = "testing2", { - res <- POST("https://httpbin.org/post", body = list(foo = "bar1"), encode = "json") + res <- POST(hb("/post"), body = list(foo = "bar1"), encode = "json") }, match_requests_on = "body"), "An HTTP request has been made that vcr does not know how to handle" ) # matching succeeds when the changed body is ignored cc <- use_cassette(name = "testing2", { - res <- POST("https://httpbin.org/post", body = list(foo = "bar1"), encode = "json") + res <- POST(hb("/post"), body = list(foo = "bar1"), encode = "json") }, match_requests_on = c("uri", "method")) expect_identical(recorded_at(aa), recorded_at(cc)) }) diff --git a/tests/testthat/test-ause_cassette_re_record.R b/tests/testthat/test-ause_cassette_re_record.R index 7fc37d2..365a657 100644 --- a/tests/testthat/test-ause_cassette_re_record.R +++ b/tests/testthat/test-ause_cassette_re_record.R @@ -3,7 +3,7 @@ context("use_cassette options: re_record_interval") # library(crul, quietly = TRUE) mydir <- file.path(tempdir(), "use_cassette_re_record") # invisible(vcr_configure(dir = mydir)) -conn <- crul::HttpClient$new("https://eu.httpbin.org") +conn <- crul::HttpClient$new(hb()) # vcr::vcr_configure( # dir = mydir, # log = TRUE, diff --git a/tests/testthat/test-ause_cassette_record_modes.R b/tests/testthat/test-ause_cassette_record_modes.R index 003ea6c..0ea8d5f 100644 --- a/tests/testthat/test-ause_cassette_record_modes.R +++ b/tests/testthat/test-ause_cassette_record_modes.R @@ -3,7 +3,7 @@ context("use_cassette: record modes work as expected") library(crul, quietly = TRUE) mydir <- file.path(tempdir(), "use_cassette_record_mode") invisible(vcr_configure(dir = mydir)) -conn <- crul::HttpClient$new("https://eu.httpbin.org") +conn <- crul::HttpClient$new(hb()) test_that("use_cassette record mode: once", { # record mode `once`: diff --git a/tests/testthat/test-ause_cassette_write_to_disk.R b/tests/testthat/test-ause_cassette_write_to_disk.R index 89324a3..d14c3f3 100644 --- a/tests/testthat/test-ause_cassette_write_to_disk.R +++ b/tests/testthat/test-ause_cassette_write_to_disk.R @@ -13,7 +13,7 @@ test_that("fails well if write_disk_path not set", { f <- tempfile(fileext = ".json") expect_error( sw(use_cassette("write_disk_path_not_set_crul", { - out <- HttpClient$new("https://httpbin.org/get")$get(disk = f) + out <- HttpClient$new(hb("/get"))$get(disk = f) })), "write_disk_path must be given" ) @@ -22,7 +22,7 @@ test_that("fails well if write_disk_path not set", { g <- tempfile(fileext = ".json") expect_error( sw(use_cassette("write_disk_path_not_set_httr", { - out <- GET("https://httpbin.org/get", write_disk(g, TRUE)) + out <- GET(hb("/get"), write_disk(g, TRUE)) })), "write_disk_path must be given" ) @@ -43,24 +43,22 @@ test_that("use_cassette w/ request that writes to disk: crul", { f <- tempfile(fileext = ".json") ## make a request use_cassette("test_write_to_disk", { - out <- HttpClient$new("https://httpbin.org/get")$get(disk = f) + out <- HttpClient$new(hb("/get"))$get(disk = f) }) expect_is(out, "HttpResponse") expect_is(out$content, "character") expect_match(out$content, "\\.json") expect_is(out$parse(), "character") - expect_match(out$parse(), "httpbin") # works on 2nd request use_cassette("test_write_to_disk", { - out2 <- HttpClient$new("https://httpbin.org/get")$get(disk = f) + out2 <- HttpClient$new(hb("/get"))$get(disk = f) }) expect_is(out2, "HttpResponse") expect_is(out2$content, "character") expect_match(out2$content, "\\.json") expect_is(out2$parse(), "character") - expect_match(out2$parse(), "httpbin") expect_equal(out$parse(), out2$parse()) }) @@ -73,7 +71,7 @@ test_that("use_cassette w/ request that writes to disk: httr", { f <- tempfile(fileext = ".json") ## make a request use_cassette("test_write_to_disk_httr", { - out <- GET("https://httpbin.org/get", write_disk(f, TRUE)) + out <- GET(hb("/get"), write_disk(f, TRUE)) }) expect_is(out, "response") @@ -82,7 +80,7 @@ test_that("use_cassette w/ request that writes to disk: httr", { # works on 2nd request use_cassette("test_write_to_disk_httr", { - out2 <- GET("https://httpbin.org/get", write_disk(f, TRUE)) + out2 <- GET(hb("/get"), write_disk(f, TRUE)) }) expect_is(out2, "response") expect_is(out2$content, "path") diff --git a/tests/testthat/test-binary_images.R b/tests/testthat/test-binary_images.R index 26325ac..e7426e3 100644 --- a/tests/testthat/test-binary_images.R +++ b/tests/testthat/test-binary_images.R @@ -8,7 +8,7 @@ test_that("use_cassette w/ with images: httr", { skip_if_not_installed("jpeg") library(httr) - url <- "https://httpbin.org/image/jpeg" + url <- hb("/image/jpeg") ## preserve_exact_body_bytes = FALSE # works on 1st request - doing a real http request @@ -57,7 +57,7 @@ test_that("use_cassette w/ with images: crul", { skip_on_cran() library(crul) - url <- "https://httpbin.org/image/jpeg" + url <- hb("/image/jpeg") ## preserve_exact_body_bytes = FALSE # works on 1st request - doing a real http request diff --git a/tests/testthat/test-crul.R b/tests/testthat/test-crul.R index 3f762db..9643a50 100644 --- a/tests/testthat/test-crul.R +++ b/tests/testthat/test-crul.R @@ -7,7 +7,7 @@ context("adapter-crul: POST requests works") test_that("crul POST requests works", { # body type: named list out <- use_cassette("crul_post_named_list", { - x <- HttpClient$new("https://httpbin.org/post")$post(body = list(foo = "bar")) + x <- HttpClient$new(hb("/post"))$post(body = list(foo = "bar")) }) expect_false(out$is_empty()) expect_is(x, "HttpResponse") @@ -18,7 +18,7 @@ test_that("crul POST requests works", { # body type: character out2 <- use_cassette("crul_post_string", { - z <- HttpClient$new("https://httpbin.org/post")$post(body = "some string") + z <- HttpClient$new(hb("/post"))$post(body = "some string") }) expect_false(out2$is_empty()) expect_is(z, "HttpResponse") @@ -30,7 +30,7 @@ test_that("crul POST requests works", { # body type: raw out3 <- use_cassette("crul_post_raw", { - z <- HttpClient$new("https://httpbin.org/post")$post(body = charToRaw("some string")) + z <- HttpClient$new(hb("/post"))$post(body = charToRaw("some string")) }) expect_false(out3$is_empty()) expect_is(z, "HttpResponse") @@ -45,7 +45,7 @@ test_that("crul POST requests works", { ff <- tempfile(fileext = ".txt") cat("hello world\n", file = ff) out4 <- use_cassette("crul_post_upload_file", { - b <- HttpClient$new("https://httpbin.org/post")$post( + b <- HttpClient$new(hb("/post"))$post( body = list(y = crul::upload(ff))) }) expect_false(out4$is_empty()) @@ -59,7 +59,7 @@ test_that("crul POST requests works", { ## upload_file not in a list out6 <- use_cassette("crul_post_upload_file_no_list", { - d <- HttpClient$new("https://httpbin.org/post")$post( + d <- HttpClient$new(hb("/post"))$post( body = crul::upload(system.file("CITATION"))) }) expect_false(out6$is_empty()) @@ -72,7 +72,7 @@ test_that("crul POST requests works", { # body type: NULL out5 <- use_cassette("crul_post_null", { - m <- HttpClient$new("https://httpbin.org/post")$post(body = NULL) + m <- HttpClient$new(hb("/post"))$post(body = NULL) }) expect_false(out5$is_empty()) expect_is(z, "HttpResponse") diff --git a/tests/testthat/test-errors.R b/tests/testthat/test-errors.R index 0d0eaf2..1ee7bef 100644 --- a/tests/testthat/test-errors.R +++ b/tests/testthat/test-errors.R @@ -4,7 +4,7 @@ dir <- tempdir() invisible(vcr_configure(dir = dir, warn_on_empty_cassette = FALSE)) request <- Request$new( - "post", "https://eu.httpbin.org/post?a=5", "", list(foo = "bar")) + "post", hb("/post?a=5"), "", list(foo = "bar")) test_that("UnhandledHTTPRequestError fails well", { z <- UnhandledHTTPRequestError$new(request) @@ -59,7 +59,7 @@ invisible( warn_on_empty_cassette = FALSE ) ) -url <- paste0("https://eu.httpbin.org/get?api_key=", +url <- paste0(hb("/get?api_key="), Sys.getenv("FOO_BAR"), "&other_secret=", Sys.getenv("HELLO_WORLD")) request <- Request$new("get", url, "") unlink(file.path(vcr_c$dir, "bunny")) @@ -102,7 +102,7 @@ invisible( warn_on_empty_cassette = FALSE ) ) -url <- "https://eu.httpbin.org/get" +url <- hb("/get") request <- Request$new("get", url, "", list(api_key = Sys.getenv("FOO_BAR"))) unlink(file.path(vcr_c$dir, "frog")) cas <- suppressMessages(insert_cassette("frog", @@ -144,7 +144,7 @@ invisible( warn_on_empty_cassette = FALSE ) ) -url <- paste0("https://eu.httpbin.org/get?api_key=", Sys.getenv("HELLO_MARS")) +url <- paste0(hb("/get?api_key="), Sys.getenv("HELLO_MARS")) request <- Request$new("get", url, "") unlink(file.path(vcr_c$dir, "bunny2")) cas <- suppressMessages(insert_cassette("bunny2")) @@ -188,7 +188,7 @@ vcr_configure_reset() # vcr_configure(dir = dir, filter_sensitive_data = # list("<>" = Sys.getenv("FOO_BAR"))) # ) -# url <- "https://eu.httpbin.org/get" +# url <- hb("/get") # request <- Request$new("get", url, list(api_key = Sys.getenv("FOO_BAR"))) # unlink(file.path(vcr_c$dir, "alligator")) # cas <- suppressMessages(insert_cassette("alligator", diff --git a/tests/testthat/test-filter_headers.R b/tests/testthat/test-filter_headers.R index 5cc451b..e488995 100644 --- a/tests/testthat/test-filter_headers.R +++ b/tests/testthat/test-filter_headers.R @@ -10,7 +10,7 @@ test_that("filter_headers/request/remove", { # request headers: remove only # no header filtering to compare below stuff to vcr_configure(dir = mydir) - con <- crul::HttpClient$new("https://eu.httpbin.org/get", headers=list(Foo="bar")) + con <- crul::HttpClient$new(hb("/get"), headers=list(Foo="bar")) unlink(file.path(vcr_c$dir, "filterheaders_no_filtering.yml")) cas_nofilters <- use_cassette(name = "filterheaders_no_filtering", { res_nofilters <- con$get() @@ -19,7 +19,7 @@ test_that("filter_headers/request/remove", { vcr_configure_reset() vcr_configure(dir = mydir, filter_request_headers = c("Foo", "Accept")) unlink(file.path(vcr_c$dir, "filterheaders_remove.yml")) - con <- crul::HttpClient$new("https://eu.httpbin.org/get", headers=list(Foo="bar")) + con <- crul::HttpClient$new(hb("/get"), headers=list(Foo="bar")) cas1 <- use_cassette(name = "filterheaders_remove", { res1 <- con$get() }) @@ -67,7 +67,7 @@ test_that("filter_headers/request/replace", { # no header filtering to compare below stuff to vcr_configure_reset() vcr_configure(dir = mydir) - con1 <- crul::HttpClient$new("https://eu.httpbin.org/get", + con1 <- crul::HttpClient$new(hb("/get"), headers=list(Authorization="mysecret")) unlink(file.path(vcr_c$dir, "filterheaders_no_filtering.yml")) cas_nofilters <- use_cassette(name = "filterheaders_no_filtering", { @@ -109,7 +109,7 @@ test_that("filter_headers doesn't add a header that doesn't exist", { mydir <- file.path(tempdir(), "filter_headers_doesnt_add_header") vcr_configure_reset() vcr_configure(dir = mydir, filter_request_headers = list("Authorization" = "XXXXXXX")) - con1 <- crul::HttpClient$new("https://eu.httpbin.org/get") + con1 <- crul::HttpClient$new(hb("/get")) unlink(file.path(vcr_c$dir, "filterheaders_no_header.yml")) cas_nh1 <- use_cassette(name = "filterheaders_no_header", { res <- con1$get() @@ -142,7 +142,7 @@ test_that("filter_headers/response/remove", { # response headers: remove only vcr_configure(dir = mydir) - con <- crul::HttpClient$new("https://eu.httpbin.org/get") + con <- crul::HttpClient$new(hb("/get")) unlink(file.path(vcr_c$dir, "filterheaders_no_filtering.yml")) cas_nofilters <- use_cassette(name = "filterheaders_no_filtering", { res_nofilters <- con$get() @@ -189,7 +189,7 @@ test_that("filter_headers/response/replace", { # response headers: replace only vcr_configure(dir = mydir) - con <- crul::HttpClient$new("https://eu.httpbin.org/get") + con <- crul::HttpClient$new(hb("/get")) unlink(file.path(vcr_c$dir, "filterheaders_no_filtering.yml")) cas_nofilters <- use_cassette(name = "filterheaders_no_filtering", { res_nofilters <- con$get() @@ -238,7 +238,7 @@ test_that("filter_headers/request/remove/json", { # request headers: remove only # no header filtering to compare below stuff to vcr_configure(dir = mydir, serialize_with = 'json') - con <- crul::HttpClient$new("https://eu.httpbin.org/get", + con <- crul::HttpClient$new(hb("/get"), headers=list(Foo="bar")) unlink(file.path(vcr_c$dir, "filterheaders_no_filtering.yml")) cas_nofilters <- use_cassette(name = "filterheaders_no_filtering", { @@ -249,7 +249,7 @@ test_that("filter_headers/request/remove/json", { vcr_configure(dir = mydir, filter_request_headers = c("Foo", "Accept"), serialize_with = 'json') unlink(file.path(vcr_c$dir, "filterheaders_remove_json.yml")) - con <- crul::HttpClient$new("https://eu.httpbin.org/get", headers=list(Foo="bar")) + con <- crul::HttpClient$new(hb("/get"), headers=list(Foo="bar")) cas1 <- use_cassette(name = "filterheaders_remove_json", { res1 <- con$get() }) diff --git a/tests/testthat/test-filter_query_parameters.R b/tests/testthat/test-filter_query_parameters.R index 2579b96..264b2ec 100644 --- a/tests/testthat/test-filter_query_parameters.R +++ b/tests/testthat/test-filter_query_parameters.R @@ -15,7 +15,7 @@ test_that("filter_query_parameters: remove", { # remove only # no query param filtering to compare below stuff to vcr_configure(dir = mydir) - con <- crul::HttpClient$new("https://eu.httpbin.org/get") + con <- crul::HttpClient$new(hb("/get")) unlink(file.path(vcr_c$dir, "filterparams_no_filtering.yml")) cas_nofilters <- use_cassette(name = "filterparams_no_filtering", { res_nofilters <- con$get(query = list(Foo="bar")) @@ -24,7 +24,7 @@ test_that("filter_query_parameters: remove", { vcr_configure_reset() vcr_configure(dir = mydir, filter_query_parameters = "Foo") unlink(file.path(vcr_c$dir, "filterparams_remove.yml")) - con <- crul::HttpClient$new("https://eu.httpbin.org/get") + con <- crul::HttpClient$new(hb("/get")) cas1 <- use_cassette(name = "filterparams_remove", { res1 <- con$get(query = list(Foo="bar")) }) @@ -62,7 +62,7 @@ test_that("filter_query_parameters: replace", { # remove only # no query param filtering to compare below stuff to vcr_configure(dir = mydir) - con <- crul::HttpClient$new("https://eu.httpbin.org/get") + con <- crul::HttpClient$new(hb("/get")) unlink(file.path(vcr_c$dir, "filterparams_no_filtering.yml")) cas_nofilters <- use_cassette(name = "filterparams_no_filtering", { res_nofilters <- con$get(query = list(Foo="bar")) @@ -71,7 +71,7 @@ test_that("filter_query_parameters: replace", { vcr_configure_reset() vcr_configure(dir = mydir, filter_query_parameters = list(Foo = "placeholder")) unlink(file.path(vcr_c$dir, "filterparams_replace.yml")) - con <- crul::HttpClient$new("https://eu.httpbin.org/get") + con <- crul::HttpClient$new(hb("/get")) cas1 <- use_cassette(name = "filterparams_replace", { res1 <- con$get(query = list(Foo="bar")) }) @@ -104,7 +104,7 @@ test_that("filter_query_parameters: replace with secret", { skip_on_cran() library(crul) - con <- crul::HttpClient$new("https://eu.httpbin.org/get") + con <- crul::HttpClient$new(hb("/get")) mydir <- file.path(tempdir(), "filter_query_parameters_replace_with") Sys.setenv(MY_KEY = "my-secret-key") # Sys.getenv("MY_KEY") @@ -161,17 +161,17 @@ test_that("filter_query_parameters: remove (httr)", { vcr_configure(dir = mydir) unlink(file.path(vcr_c$dir, "filterparams_no_filtering.yml")) cas_nofilters <- use_cassette(name = "filterparams_no_filtering", { - res_nofilters <- GET("https://eu.httpbin.org/get?Foo=bar") + res_nofilters <- GET(hb("/get?Foo=bar")) }) # Do filtering vcr_configure_reset() vcr_configure(dir = mydir, filter_query_parameters = "Foo") unlink(file.path(vcr_c$dir, "filterparams_remove.yml")) cas1 <- use_cassette(name = "filterparams_remove", { - res1 <- GET("https://eu.httpbin.org/get?Foo=bar") + res1 <- GET(hb("/get?Foo=bar")) }) cas2 <- use_cassette(name = "filterparams_remove", { - res2 <- GET("https://eu.httpbin.org/get?Foo=bar") + res2 <- GET(hb("/get?Foo=bar")) }) # with no filtering, request headers have Foo @@ -206,17 +206,17 @@ test_that("filter_query_parameters: replace (httr)", { vcr_configure(dir = mydir) unlink(file.path(vcr_c$dir, "filterparams_no_filtering.yml")) cas_nofilters <- use_cassette(name = "filterparams_no_filtering", { - res_nofilters <- GET("https://eu.httpbin.org/get?Foo=bar") + res_nofilters <- GET(hb("/get?Foo=bar")) }) # Do filtering vcr_configure_reset() vcr_configure(dir = mydir, filter_query_parameters = list(Foo = "placeholder")) unlink(file.path(vcr_c$dir, "filterparams_replace.yml")) cas1 <- use_cassette(name = "filterparams_replace", { - res1 <- GET("https://eu.httpbin.org/get?Foo=bar") + res1 <- GET(hb("/get?Foo=bar")) }) cas2 <- use_cassette(name = "filterparams_replace", { - res2 <- GET("https://eu.httpbin.org/get?Foo=bar") + res2 <- GET(hb("/get?Foo=bar")) }) # with no filtering, request headers have Foo diff --git a/tests/testthat/test-httr.R b/tests/testthat/test-httr.R index 7aebe4f..8661dff 100644 --- a/tests/testthat/test-httr.R +++ b/tests/testthat/test-httr.R @@ -47,10 +47,10 @@ test_that("httr use_cassette works", { skip_if_not_installed("xml2") out <- use_cassette("httr_test1", { - x <- GET("https://httpbin.org/404") + x <- GET(hb("/404")) }) invisible(use_cassette("httr_test1", { - x2 <- GET("https://httpbin.org/404") + x2 <- GET(hb("/404")) })) # cassette @@ -62,7 +62,7 @@ test_that("httr use_cassette works", { # request - 1st http call expect_is(x$request, "request") expect_equal(x$request$method, "GET") - expect_equal(x$request$url, "https://httpbin.org/404") + expect_equal(x$request$url, hb("/404")) expect_named(x$request$headers, "Accept") expect_null(x$request$fields) expect_true(x$request$options$httpget) @@ -71,7 +71,7 @@ test_that("httr use_cassette works", { # request - 2nd http call expect_is(x2$request, "request") expect_equal(x2$request$method, "GET") - expect_equal(x2$request$url, "https://httpbin.org/404") + expect_equal(x2$request$url, hb("/404")) expect_named(x2$request$headers, "Accept") expect_null(x2$request$fields) expect_true(x2$request$options$httpget) @@ -80,7 +80,7 @@ test_that("httr use_cassette works", { # response expect_is(x, "response") expect_equal(x$status_code, 404) - expect_equal(x$url, "https://httpbin.org/404") + expect_equal(x$url, hb("/404")) expect_output(print(x), "Not Found") expect_output(print(x), "HTML PUBLIC") @@ -100,7 +100,7 @@ test_that("httr use_cassette works", { skip_if_not_installed("xml2") out <- use_cassette("httr_test2", { - x <- GET("https://httpbin.org/404") + x <- GET(hb("/404")) }, preserve_exact_body_bytes = TRUE) # cassette @@ -112,12 +112,12 @@ test_that("httr use_cassette works", { # response expect_is(x, "response") expect_equal(x$status_code, 404) - expect_equal(x$url, "https://httpbin.org/404") + expect_equal(x$url, hb("/404")) # response body str <- yaml::yaml.load_file(out$manfile) str <- rawToChar(base64enc::base64decode( - str$http_interactions[[1]]$response$body$string)) + str$http_interactions[[1]]$response$body$base64_string)) expect_is(str, "character") expect_match(str, "404") expect_match(str, "DOCTYPE HTML") @@ -132,9 +132,9 @@ test_that("httr w/ >1 request per cassette", { skip_if_not_installed("xml2") out <- use_cassette("multiple_queries_httr_record_once", { - x404 <- GET("https://httpbin.org/status/404") - x500 <- GET("https://httpbin.org/status/500") - x418 <- GET("https://httpbin.org/status/418") + x404 <- GET(hb("/status/404")) + x500 <- GET(hb("/status/500")) + x418 <- GET(hb("/status/418")) expect_equal(status_code(x404), 404) expect_equal(status_code(x500), 500) @@ -171,8 +171,7 @@ context("adapter-httr: use_cassette w/ simple auth") test_that("httr works with simple auth and hides auth details", { use_cassette("httr_test_simple_auth", { - x <- GET("https://httpbin.org/basic-auth/foo/bar", - authenticate("foo", "bar")) + x <- GET(hb("/basic-auth/foo/bar"), authenticate("foo", "bar")) }) # successful request @@ -194,7 +193,7 @@ context("adapter-httr: POST requests works") test_that("httr POST requests works", { # body type: named list out <- use_cassette("httr_post_named_list", { - x <- POST("https://httpbin.org/post", body = list(foo = "bar")) + x <- POST(hb("/post"), body = list(foo = "bar")) }) expect_false(out$is_empty()) expect_is(x, "response") @@ -205,7 +204,7 @@ test_that("httr POST requests works", { # body type: character out2 <- use_cassette("httr_post_string", { - z <- POST("https://httpbin.org/post", body = "some string") + z <- POST(hb("/post"), body = "some string") }) expect_false(out2$is_empty()) expect_is(z, "response") @@ -216,7 +215,7 @@ test_that("httr POST requests works", { # body type: raw out3 <- use_cassette("httr_post_raw", { - z <- POST("https://httpbin.org/post", body = charToRaw("some string")) + z <- POST(hb("/post"), body = charToRaw("some string")) }) expect_false(out3$is_empty()) expect_is(z, "response") @@ -229,7 +228,7 @@ test_that("httr POST requests works", { ff <- tempfile(fileext = ".txt") cat("hello world\n", file = ff) out4 <- use_cassette("httr_post_upload_file", { - b <- POST("https://httpbin.org/post", + b <- POST(hb("/post"), body = list(y = httr::upload_file(ff))) }) expect_false(out4$is_empty()) @@ -243,7 +242,7 @@ test_that("httr POST requests works", { ## upload_file not in a list # out6 <- use_cassette("httr_post_upload_file_no_list", { - # d <- POST("https://httpbin.org/post", + # d <- POST(hb("/post"), # body = httr::upload_file(system.file("CITATION"))) # }) # expect_false(out6$is_empty()) @@ -256,7 +255,7 @@ test_that("httr POST requests works", { # body type: NULL out5 <- use_cassette("httr_post_null", { - m <- POST("https://httpbin.org/post", body = NULL) + m <- POST(hb("/post"), body = NULL) }) expect_false(out5$is_empty()) expect_is(m, "response") diff --git a/tests/testthat/test-httr2.R b/tests/testthat/test-httr2.R new file mode 100644 index 0000000..e6778e1 --- /dev/null +++ b/tests/testthat/test-httr2.R @@ -0,0 +1,331 @@ +skip_on_cran() + +library("httr2") +vcr_configure(dir = tempdir()) + +context("adapter-httr2: status code works") +test_that("httr2 status code works", { + # httr2_obj <- request(hb("/getttttt")) + # save(httr2_obj, file="tests/testthat/httr2_obj.rda", version = 2L) + load("httr2_obj.rda") + + expect_is(httr2_obj, "httr2_request") + + x <- RequestHandlerHttr2$new(httr2_obj) + + expect_is(x, "RequestHandlerHttr2") + expect_is(x$handle, "function") + expect_error(x$handle()) + + # do request + insert_cassette("bluecow") + the_response <- x$handle() + # the_response <- httr2::last_response() + + expect_is(the_response, "httr2_response") + # status code is correct + expect_equal(the_response$status_code, 404) + + eject_cassette("bluecow") + + # call again + insert_cassette("bluecow") + x$handle() + response2 <- httr2::last_response() + + expect_is(response2, "httr2_response") + # status code is correct + expect_equal(response2$status_code, 404) + + eject_cassette("bluecow") + + # cleanup + unlink(file.path(vcr_configuration()$dir, "bluecow")) +}) + + +context("adapter-httr2: use_cassette works") +test_that("httr2 use_cassette works", { + out <- use_cassette("httr2_test1", { + x <- request(hb("/get")) %>% req_perform() + }) + invisible(use_cassette("httr2_test1", { + x2 <- request(hb("/get")) %>% req_perform() + })) + + # cassette + expect_is(out, "Cassette") + expect_match(out$manfile, "httr2_test1") + expect_false(out$is_empty()) + expect_is(out$recorded_at, "POSIXct") + + # request - 1st http call + expect_is(x$request, "httr2_request") + expect_equal(x$request$method, "GET") + expect_equal(x$request$url, hb("/get")) + expect_named(x$request$headers, NULL) + expect_is(x$request$fields, "list") + + # request - 2nd http call + expect_is(x2$request, "httr2_request") + expect_equal(x2$request$method, "GET") + expect_equal(x2$request$url, hb("/get")) + expect_named(x2$request$headers, NULL) + expect_null(x2$request$fields) + + # response - stuff + expect_is(x, "httr2_response") + expect_equal(x$status_code, 200) + expect_equal(x$url, hb("/get")) + + # fixture file + str <- yaml::yaml.load_file(out$manfile)$http_interactions + expect_is(str[[1]]$response$body$string, "character") + expect_match(str[[1]]$response$body$string, "headers") + expect_match(str[[1]]$response$body$string, "libcurl") + + # cleanup + unlink(file.path(vcr_configuration()$dir, "httr2_test1.yml")) +}) + + +context("adapter-httr2: use_cassette w/ preserve_exact_body_bytes") +test_that("httr2 use_cassette works", { + out <- use_cassette("httr2_test2", { + x <- request(hb("/get")) %>% req_perform() + }, preserve_exact_body_bytes = TRUE) + + # cassette + expect_is(out, "Cassette") + expect_match(out$manfile, "httr2_test2") + expect_false(out$is_empty()) + expect_is(out$recorded_at, "POSIXct") + + # response + expect_is(x, "httr2_response") + expect_equal(x$status_code, 200) + expect_equal(x$url, hb("/get")) + + # response body + str <- yaml::yaml.load_file(out$manfile) + str <- rawToChar(base64enc::base64decode( + str$http_interactions[[1]]$response$body$base64_string)) + expect_is(str, "character") + expect_match(str, "Connection") + expect_match(str, "httpbin") + + # cleanup + unlink(file.path(vcr_configuration()$dir, "httr2_test2.yml")) +}) + +context("adapter-httr2: use_cassette w/ req_error") +test_that("httr2 w/ req_error", { + out <- use_cassette("httr2_errors_modify_with_req_error", { + x404 <- request(hb("/status/404")) %>% + req_error(is_error = function(resp) FALSE) %>% + req_perform() + }) + # let's do it again to make sure using a cassette w/ errors still works + use_cassette("httr2_errors_modify_with_req_error", { + x404 <- request(hb("/status/404")) %>% + req_error(is_error = function(resp) FALSE) %>% + req_perform() + }) + + expect_equal(x404$status_code, 404) + + # cassette + expect_is(out, "Cassette") + expect_match(out$manfile, "httr2_errors_modify_with_req_error") + expect_false(out$is_empty()) + expect_is(out$recorded_at, "POSIXct") + + # response + expect_is(x404, "httr2_response") + expect_equal(x404$status_code, 404) + + # response body + str <- yaml::yaml.load_file(out$manfile)$http_interactions + expect_is(str, "list") + expect_is(str[[1]], "list") + expect_match(str[[1]]$request$uri , "404") + + # cleanup + unlink(file.path(vcr_configuration()$dir, + "httr2_errors_modify_with_req_error.yml")) +}) + +context("adapter-httr2: use_cassette just catch error") +test_that("httr2 error", { + use_cassette("httr2_errors_catch_error", { + expect_error( + request(hb("/status/404")) %>% req_perform() + ) + }) + # let's do it again to make sure using a cassette w/ errors still works + use_cassette("httr2_errors_catch_error", { + expect_error( + request(hb("/status/404")) %>% req_perform() + ) + }) + + # cleanup + unlink(file.path(vcr_configuration()$dir, + "httr2_errors_catch_error.yml")) +}) + +context("adapter-httr2: use_cassette w/ multiple errors per cassette") +test_that("httr2 w/ multiple errors per cassette", { + use_cassette("multiple_errors_per_cassette", { + expect_error(request(hb("/status/404")) %>% req_perform()) + expect_error(request(hb("/status/500")) %>% req_perform()) + expect_error(request(hb("/status/418")) %>% req_perform()) + }) + # let's do it again to make sure using a cassette w/ errors still works + use_cassette("multiple_errors_per_cassette", { + expect_error(request(hb("/status/404")) %>% req_perform()) + expect_error(request(hb("/status/500")) %>% req_perform()) + expect_error(request(hb("/status/418")) %>% req_perform()) + }) + + # cleanup + unlink(file.path(vcr_configuration()$dir, + "multiple_errors_per_cassette.yml")) +}) + +## httr removes the header, but with httr2 we have to explicity remove it +context("adapter-httr2: use_cassette w/ simple auth") +test_that("httr2 works with simple auth and hides auth details", { + # Authorization header IS in the cassette after filtering + use_cassette("httr2_test_simple_auth_no_filter", { + x <- request(hb("/basic-auth/foo/bar")) %>% + req_auth_basic("foo", "bar") %>% + req_perform() + }) + + path <- file.path(vcr_configuration()$dir, "httr2_test_simple_auth_no_filter.yml") + chars <- paste0(readLines(path), collapse = "") + yml <- yaml::yaml.load_file(path) + + expect_true(grepl("Authorization", chars)) + expect_true("Authorization" %in% names(yml$http_interactions[[1]]$request$headers)) + + # Authorization header IS NOT in the cassette after filtering + vcr_configure(dir = tempdir(), filter_request_headers = "Authorization") + use_cassette("httr2_test_simple_auth_yes_filter", { + x <- request(hb("/basic-auth/foo/bar")) %>% + req_auth_basic("foo", "bar") %>% + req_perform() + }) + + path <- file.path(vcr_configuration()$dir, "httr2_test_simple_auth_yes_filter.yml") + chars <- paste0(readLines(path), collapse = "") + yml <- yaml::yaml.load_file(path) + + expect_false(grepl("Authorization", chars)) + expect_false("Authorization" %in% names(yml$http_interactions[[1]]$request$headers)) + + # back to default vcr config + vcr_configure(dir = tempdir()) + # cleanup + unlink(file.path(vcr_configuration()$dir, "httr2_test_simple_auth_no_filter.yml")) + unlink(file.path(vcr_configuration()$dir, "httr2_test_simple_auth_yes_filter.yml")) +}) + +context("adapter-httr2: POST requests works") +test_that("httr2 POST requests works", { + # body type: named list + out <- use_cassette("httr2_post_named_list", { + x <- request(hb("/post")) %>% + req_body_json(list(foo = "bar")) %>% + req_perform() + }) + expect_false(out$is_empty()) + expect_is(x, "httr2_response") + expect_equal(x$status_code, 200) + str <- yaml::yaml.load_file(out$manfile)$http_interactions + strj <- jsonlite::fromJSON(str[[1]]$response$body$string) + expect_equal(strj$data, "{\"foo\":\"bar\"}") + + # body type: character + out2 <- use_cassette("httr2_post_string", { + z <- request(hb("/post")) %>% + req_body_raw("some string") %>% + req_perform() + }) + expect_false(out2$is_empty()) + expect_is(z, "httr2_response") + expect_equal(z$status_code, 200) + str <- yaml::yaml.load_file(out2$manfile)$http_interactions + strj <- jsonlite::fromJSON(str[[1]]$response$body$string) + expect_equal(strj$data, "some string") + + # body type: raw + out3 <- use_cassette("httr2_post_raw", { + z <- request(hb("/post")) %>% + req_body_raw(charToRaw("some string")) %>% + req_perform() + # z <- POST(hb("/post"), body = charToRaw("some string")) + }) + expect_false(out3$is_empty()) + expect_is(z, "httr2_response") + expect_equal(z$status_code, 200) + str <- yaml::yaml.load_file(out3$manfile)$http_interactions + strj <- jsonlite::fromJSON(str[[1]]$response$body$string) + expect_equal(strj$data, "some string") + + # file with req_body_file + ff <- tempfile(fileext = ".txt") + cat("hello world\n", file = ff) + out4 <- use_cassette("httr2_post_body_file", { + b <- request(hb("/post")) %>% + req_body_file(ff) %>% + req_perform() + }) + expect_false(out4$is_empty()) + expect_is(b, "httr2_response") + expect_equal(b$status_code, 200) + str <- yaml::yaml.load_file(out4$manfile)$http_interactions + strj <- jsonlite::fromJSON(str[[1]]$response$body$string) + expect_equal(length(strj$files$y), 0) # files empty + expect_match(strj$data, "hello world") # data not empty + unlink(ff) + + # using multipart + gg <- tempfile(fileext = ".txt") + cat("hello world\n", file = gg) + out4 <- use_cassette("httr2_post_body_multipart", { + b <- request(hb("/post")) %>% + req_body_multipart(a = curl::form_file(gg), b = "some data") %>% + req_perform() + }) + expect_false(out4$is_empty()) + expect_is(b, "httr2_response") + expect_equal(b$status_code, 200) + str <- yaml::yaml.load_file(out4$manfile)$http_interactions + strj <- jsonlite::fromJSON(str[[1]]$response$body$string) + expect_match(strj$files$a, "hello world") # files not empty + expect_false(nzchar(strj$data)) # data empty + unlink(gg) + + # body type: NULL + out5 <- use_cassette("httr2_post_null", { + m <- request(hb("/post")) %>% + req_body_raw("") %>% + req_perform() + }) + expect_false(out5$is_empty()) + expect_is(m, "httr2_response") + expect_equal(m$status_code, 200) + str <- yaml::yaml.load_file(out5$manfile)$http_interactions + strj <- jsonlite::fromJSON(str[[1]]$response$body$string) + expect_equal(strj$data, "") + expect_equal(strj$headers$`Content-Length`, "0") + + # cleanup + unlink(file.path(vcr_configuration()$dir, "httr2_post_named_list.yml")) + unlink(file.path(vcr_configuration()$dir, "httr2_post_string.yml")) + unlink(file.path(vcr_configuration()$dir, "httr2_post_raw.yml")) + unlink(file.path(vcr_configuration()$dir, "httr2_post_upload_file.yml")) + unlink(file.path(vcr_configuration()$dir, "httr2_post_null.yml")) +}) diff --git a/tests/testthat/test-issues.R b/tests/testthat/test-issues.R new file mode 100644 index 0000000..ecf8daa --- /dev/null +++ b/tests/testthat/test-issues.R @@ -0,0 +1,6 @@ +test_that('issue 249 is correctly handled.', { + vcr::use_cassette('get_401', { + res <- httr::GET(hb('/status/401')) + }) + expect_true(res$status_code == 401) +}) diff --git a/tests/testthat/test-lightswitch.R b/tests/testthat/test-lightswitch.R index 159493e..d871428 100644 --- a/tests/testthat/test-lightswitch.R +++ b/tests/testthat/test-lightswitch.R @@ -137,7 +137,7 @@ test_that("turned_off", { # no cassette in use expect_true(turned_on()) suppressMessages(turned_off({ - beetle <- crul::HttpClient$new(url = "https://eu.httpbin.org/get")$get() + beetle <- crul::HttpClient$new(url = hb("/get"))$get() })) expect_is(beetle, "HttpResponse") expect_true(turned_on()) diff --git a/tests/testthat/test-localhost_port.R b/tests/testthat/test-localhost_port.R new file mode 100644 index 0000000..a657cf7 --- /dev/null +++ b/tests/testthat/test-localhost_port.R @@ -0,0 +1,33 @@ +# orginally via https://github.com/ropensci/vcr/issues/264 + +tmpdir <- tempdir() +vcr_configure(dir = tmpdir) + +test_that("testing against localhost port works", { + # httpbin <- webfakes::local_app_process(webfakes::httpbin_app()) + httpbin <- local_httpbin_app() + url <- httpbin$url("/status/404") + port <- httpbin$get_port() + + # real request w/o vcr + resp <- httr::GET(url) + expect_s3_class(resp, "response") + + # real request w/ vcr + use_cassette("localhost_port", { + resp <- httr::GET(url) + # check that response object is correct + expect_s3_class(resp, "response") + }) + + # check that the port is actually in the cassette file + path <- file.path(tmpdir, "localhost_port.yml") + file <- yaml::yaml.load_file(path) + url <- file$http_interactions[[1]]$request$uri + expect_is(url, "character") + expect_match(url, "http://.+:[0-9]+/") + expect_match(url, as.character(port)) +}) + +# reset configuration +vcr_configure_reset() diff --git a/tests/testthat/test-no-cassette-in-use.R b/tests/testthat/test-no-cassette-in-use.R index 2ff9c51..e882b36 100644 --- a/tests/testthat/test-no-cassette-in-use.R +++ b/tests/testthat/test-no-cassette-in-use.R @@ -5,7 +5,7 @@ context("no_cassette_in_use") # # test_that("no cassette in use behaves as expected", { # crul::mock() -# x <- crul::HttpClient$new(url = "https://httpbin.org") +# x <- crul::HttpClient$new(url = hb()) # # # when no cassette in use, we get expected vcr error # expect_error( diff --git a/tests/testthat/test-quiet.R b/tests/testthat/test-quiet.R index 5ecbc6e..bb70afd 100644 --- a/tests/testthat/test-quiet.R +++ b/tests/testthat/test-quiet.R @@ -5,18 +5,19 @@ vcr_configure(dir = tmpdir) test_that("quiet works", { library(crul) + con <- HttpClient$new(hb()) # default: quiet=TRUE expect_true(vcr_configuration()$quiet) expect_message( - use_cassette("foo3", crul::ok("https://eu.httpbin.org/get")), + use_cassette("foo3", con$get("get")), NA ) expect_message( - use_cassette("foo1", crul::ok("https://eu.httpbin.org/get")), + use_cassette("foo1", con$get("get")), NA ) expect_message( - use_cassette("foo2", crul::ok("https://eu.httpbin.org/get")), + use_cassette("foo2", con$get("get")), NA ) @@ -25,15 +26,15 @@ test_that("quiet works", { expect_false(vcr_configuration()$quiet) webmockr::webmockr_disable_net_connect() expect_message( - use_cassette("foo3", crul::ok("https://eu.httpbin.org/get")), + use_cassette("foo3", con$get("get")), "allowed" ) expect_message( - use_cassette("foo1", crul::ok("https://eu.httpbin.org/get")), + use_cassette("foo1", con$get("get")), "enabled" ) expect_message( - use_cassette("foo2", crul::ok("https://eu.httpbin.org/get")), + use_cassette("foo2", con$get("get")), "disabled" ) }) diff --git a/tests/testthat/test-request_summary.R b/tests/testthat/test-request_summary.R index c0e629e..a162575 100644 --- a/tests/testthat/test-request_summary.R +++ b/tests/testthat/test-request_summary.R @@ -1,7 +1,7 @@ context("request_summary") library("crul") -url <- "https://eu.httpbin.org" +url <- hb() cli <- crul::HttpClient$new(url = url) crul::mock(FALSE) webmockr::webmockr_allow_net_connect() @@ -24,11 +24,11 @@ test_that("request_summary works", { expect_is(cc, "character") expect_is(dd, "character") - expect_match(aa, "post https://eu.httpbin.org/") - expect_match(bb, "post https://eu.httpbin.org/ foo=bar") + expect_match(aa, "post .+/") + expect_match(bb, "post .+/ foo=bar") expect_match(cc, "post") - expect_match(cc, "https://eu.httpbin.org/") + expect_match(cc, ".+") expect_match(cc, "libcurl") expect_match(cc, "r-curl") expect_match(cc, "crul") @@ -37,7 +37,7 @@ test_that("request_summary works", { expect_false(grepl("foo=bar", cc)) expect_match(dd, "post") - expect_match(dd, "https://eu.httpbin.org/") + expect_match(dd, ".+") expect_match(dd, "foo=bar") expect_match(dd, "libcurl") expect_match(dd, "r-curl") diff --git a/tests/testthat/test-response_summary.R b/tests/testthat/test-response_summary.R index 5808552..cda941a 100644 --- a/tests/testthat/test-response_summary.R +++ b/tests/testthat/test-response_summary.R @@ -1,7 +1,7 @@ context("response_summary") library("crul") -url <- "https://eu.httpbin.org" +url <- hb() cli <- crul::HttpClient$new(url = url) crul::mock(FALSE) webmockr::webmockr_allow_net_connect() @@ -70,12 +70,13 @@ test_that("response_summary - handles bad multibyte characters by changing encod if (rv <= 353) { expect_is(substring(gsub("\n", " ", google_response), 1, 80), "character") - } else { - ## doesn't error on Windows - if (Sys.info()[['sysname']] != "Windows") { - expect_error(substring(gsub("\n", " ", google_response), 1, 80)) - } } + # else { + ## doesn't error on Windows + # if (Sys.info()[['sysname']] != "Windows") { + # expect_error(substring(gsub("\n", " ", google_response), 1, 80)) + # } + # } # response_summary doesn't error now with useBytes=TRUE aa <- response_summary(x) diff --git a/tests/testthat/test-serializers.R b/tests/testthat/test-serializers.R index 5227bcd..a404f01 100644 --- a/tests/testthat/test-serializers.R +++ b/tests/testthat/test-serializers.R @@ -19,10 +19,10 @@ test_that("you can record a new cassette of same name with different serializer" invisible(vcr_configure(dir = mydir)) unlink(file.path(vcr_c$dir, "testing1.yml")) cas_yml <- use_cassette(name = "testing1", { - res <- crul::HttpClient$new("https://eu.httpbin.org/get")$get() + res <- crul::HttpClient$new(hb("/get"))$get() }, serialize_with = "yaml") cas_json <- use_cassette(name = "testing1", { - res2 <- crul::HttpClient$new("https://eu.httpbin.org/get")$get() + res2 <- crul::HttpClient$new(hb("/get"))$get() }, serialize_with = "json") expect_is(cas_yml, "Cassette") expect_is(cas_json, "Cassette") diff --git a/tests/testthat/test-serializers_json.R b/tests/testthat/test-serializers_json.R index 193e940..376f8ed 100644 --- a/tests/testthat/test-serializers_json.R +++ b/tests/testthat/test-serializers_json.R @@ -29,7 +29,7 @@ test_that("JSON usage", { # does one request work? aa <- use_cassette("testing2", { - res <- crul::HttpClient$new("https://eu.httpbin.org/get")$get() + res <- crul::HttpClient$new(hb("/get"))$get() }) expect_is(aa, "Cassette") expect_is(res, "HttpResponse") @@ -37,8 +37,8 @@ test_that("JSON usage", { # do two requests work? cc <- use_cassette("testing4", { - ref <- crul::HttpClient$new("https://eu.httpbin.org/get")$get() - the <- crul::HttpClient$new("https://eu.httpbin.org/post")$post(body = "fafaa") + ref <- crul::HttpClient$new(hb("/get"))$get() + the <- crul::HttpClient$new(hb("/post"))$post(body = "fafaa") }) expect_is(ref, "HttpResponse") expect_is(the, "HttpResponse") @@ -46,11 +46,10 @@ test_that("JSON usage", { # preserve exact body bytes dd <- use_cassette("testing5", { - raf <- crul::HttpClient$new("https://eu.httpbin.org/get")$get( + raf <- crul::HttpClient$new(hb("/get"))$get( query=list(cheese="string")) - raz <- crul::HttpClient$new( - "https://eu.httpbin.org/post" - )$post(body = list(foo = "bar", baz = "ball")) + raz <- crul::HttpClient$new(hb("/post"))$post( + body = list(foo = "bar", baz = "ball")) }, preserve_exact_body_bytes = TRUE) expect_is(raf, "HttpResponse") expect_is(raz, "HttpResponse") diff --git a/tests/testthat/test-use_vcr.R b/tests/testthat/test-use_vcr.R index 0671fda..6ef234a 100644 --- a/tests/testthat/test-use_vcr.R +++ b/tests/testthat/test-use_vcr.R @@ -11,8 +11,8 @@ test_that("use_vcr works", { expect_null(res) expect_true(dir.exists(file.path(dir, "tests"))) expect_true(file.exists(file.path(dir, "tests/testthat.R"))) - expect_true(file.exists(file.path(dir, "tests/testthat/setup-foobar.R"))) - help <- paste0(readLines(file.path(dir, "tests/testthat/setup-foobar.R")), + expect_true(file.exists(file.path(dir, "tests/testthat/helper-vcr.R"))) + help <- paste0(readLines(file.path(dir, "tests/testthat/helper-vcr.R")), collapse = " ") expect_match(help, "vcr::vcr_configure") expect_match(help, "vcr::check_cassette_names") diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R index 70e4815..17da91c 100644 --- a/tests/testthat/test-utils.R +++ b/tests/testthat/test-utils.R @@ -24,15 +24,29 @@ test_that("try_encoding", { }) test_that("is_base64", { + not64 <- Cassette$new('notbase64') + is64 <- Cassette$new('isbase64', preserve_exact_body_bytes = TRUE) + expect_error(is_base64(), "\"x\" is missing") - # actual base64 strings are base64 - expect_true(is_base64(base64enc::base64encode(charToRaw("foo")))) - # regular character strings are not base64 - expect_false(is_base64("foo")) - # numbers as strings are not base64 - expect_false(is_base64("12345")) - # numbers as numbers are not base64 - expect_false(is_base64(12345)) + expect_false(is_base64(base64enc::base64encode(charToRaw("foo")), not64)) + + expect_true(is_base64(list(base64_string = "adfadsf"), is64)) + z = expect_message(is_base64(list(string = "adfadsf"), is64)) + expect_true(z) + + expect_false(is_base64(list(string = "adfadsf"), not64)) + expect_true(is_base64(list(base64_string = "adfadsf"), not64)) + # # actual base64 strings are base64 + # expect_true(is_base64(base64enc::base64encode(charToRaw("foo")))) + # # regular character strings are not base64 + # expect_false(is_base64("foo")) + # # numbers as strings are not base64 + # expect_false(is_base64("12345")) + # # numbers as numbers are not base64 + # expect_false(is_base64(12345)) + + suppressWarnings(not64$eject()) + suppressWarnings(is64$eject()) }) test_that("serializable_body", { @@ -44,7 +58,7 @@ test_that("serializable_body", { expect_is(aa, "character") expect_true(attr(aa, "base64")) expect_true(is_base64(aa)) - expect_true(is_base64(aa[[1]])) + expect_false(is_base64(aa[[1]])) bb <- serializable_body("foo", FALSE) expect_is(bb, "character") @@ -65,7 +79,7 @@ test_that("body_from", { cc <- body_from(base64enc::base64encode(charToRaw("foo"))) expect_is(cc, "character") - expect_true(is_base64(base64enc::base64encode(charToRaw("foo")))) + expect_false(is_base64(base64enc::base64encode(charToRaw("foo")))) expect_false(is_base64(cc)) dd <- body_from(charToRaw("foo")) diff --git a/tests/testthat/test-vcr_last_error.R b/tests/testthat/test-vcr_last_error.R index fd873eb..3ec482f 100644 --- a/tests/testthat/test-vcr_last_error.R +++ b/tests/testthat/test-vcr_last_error.R @@ -25,14 +25,14 @@ vcr_configure_reset() dir <- tempdir() invisible(vcr_configure(dir = dir)) request <- Request$new( - "post", "https://eu.httpbin.org/post?a=5", "", list(foo = "bar")) + "post", hb("/post?a=5"), "", list(foo = "bar")) test_that("vcr_last_error works: no casssette in use yet", { err <- UnhandledHTTPRequestError$new(request) expect_error(err$construct_message()) expect_message(vcr_last_error(), "There is currently no cassette in use") expect_message(vcr_last_error(), "If you want vcr to record this request") - expect_message(vcr_last_error(), "http-testing/logging") + expect_message(vcr_last_error(), "http-testing/debugging-") }) test_that("vcr_last_error works: casssette in use", { diff --git a/tests/testthat/test-vcr_test_path.R b/tests/testthat/test-vcr_test_path.R index 8dc5836..448e1a0 100644 --- a/tests/testthat/test-vcr_test_path.R +++ b/tests/testthat/test-vcr_test_path.R @@ -1,7 +1,53 @@ -test_that("vcr_test_path works", { - expect_match(vcr_test_path("fixtures"), "../fixtures") - withr::local_envvar(c("TESTTHAT" = "false")) - # expect_match(vcr_test_path("fixtures"), "tests/fixtures") - expect_message(vcr_test_path("fixtures"), "creating") - expect_error(vcr_test_path("", "a"), "non empty") +test_that("vcr_test_path works with testthat", { + skip_on_cran() + + # setup + dir <- file.path(tempdir(), "bunny") + dir.create(file.path(dir, "tests", "testthat"), recursive = TRUE) + withr::local_dir(dir) + + # test + expect_message(pth <- vcr_test_path("fixtures"), "creating", fixed = TRUE) + expect_match(pth, file.path("tests", "fixtures"), fixed = TRUE) + expect_match( + list.dirs(file.path(dir, "tests"), full.names = FALSE, recursive = FALSE), + "fixtures", + fixed = TRUE, + all = FALSE + ) + + # cleanup + unlink(dir, recursive = TRUE, force = TRUE) +}) + +test_that("vcr_test_path works with testthat in a dir that isn't `tests`", { + skip_on_cran() + + # setup + dir <- file.path(tempdir(), "tests_xyz") + dir.create(file.path(dir, "testthat"), recursive = TRUE) + withr::local_dir(dir) + + # test + expect_message(pth <- vcr_test_path("fixtures"), "creating", fixed = TRUE) + expect_match(pth, file.path("fixtures"), fixed = TRUE) + expect_match( + list.dirs(file.path(dir), full.names = FALSE, recursive = FALSE), + "fixtures", + fixed = TRUE, + all = FALSE + ) + + # cleanup + unlink(dir, recursive = TRUE, force = TRUE) +}) + +test_that("vcr_test_path errors with wrongly specified paths", { + skip_on_cran() + + ## Paths may not be empty strings + expect_error(vcr_test_path("", "a"), "non empty", fixed = TRUE) + ## User must provide a dir name + expect_error(vcr_test_path(), "provide", fixed = TRUE) + }) diff --git a/tests/testthat/test-write_disk_path_package_context.R b/tests/testthat/test-write_disk_path_package_context.R index b5e2f42..f815e34 100644 --- a/tests/testthat/test-write_disk_path_package_context.R +++ b/tests/testthat/test-write_disk_path_package_context.R @@ -10,7 +10,7 @@ test_that("use_cassette w/ request that writes to disk: crul", { dir.create(file.path(dir, "tests/files"), recursive = TRUE) strg <- 'ffff <- function() { f <- tempfile(fileext = ".json") - con <- crul::HttpClient$new("https://httpbin.org") + con <- crul::HttpClient$new("https://hb.opencpu.org") con$get("get", query = list(apples = 56), disk = f) }\n\ntest_that("ffff works", { vcr::use_cassette("ffff_testing", { @@ -26,7 +26,7 @@ invisible(vcr::vcr_configure( write_disk_path = "../files" )) vcr::check_cassette_names()' - cat(z, file = file.path(dir, "tests/testthat/setup-rabbit.R")) + cat(z, file = file.path(dir, "tests/testthat/helper-rabbit.R")) file_string <- '{ "args": { @@ -35,19 +35,19 @@ vcr::check_cassette_names()' "headers": { "Accept": "application/json, text/xml, application/xml, */*", "Accept-Encoding": "gzip, deflate", - "Host": "httpbin.org", + "Host": "hb.opencpu.org", "User-Agent": "libcurl/7.64.1 r-curl/4.3 crul/0.9.0", "X-Amzn-Trace-Id": "Root=1-5e78ddc3-6bdd2bd4ef4d3082831b10ea" }, "origin": "24.21.229.59", - "url": "https://httpbin.org/get?apples=56" + "url": "https://hb.opencpu.org/get?apples=56" }' cat(file_string, file = file.path(dir, "tests/files/file3aa4401aca64.json")) fixtures1 <- "http_interactions: - request: method: get - uri: https://httpbin.org/get?apples=56 + uri: https://hb.opencpu.org/get?apples=56 body: encoding: '' string: '' @@ -84,8 +84,8 @@ vcr::check_cassette_names()' on.exit(setwd(og)) mm <- testthat::test_dir("tests/testthat", reporter = testthat::ListReporter$new()) - expect_equal(capture.output(mm[[1]]$results[[1]]), "As expected ") - expect_equal(capture.output(mm[[1]]$results[[2]]), "As expected ") + expect_equal(capture.output(mm[[1]]$results[[1]])[2], "As expected") + expect_equal(capture.output(mm[[1]]$results[[2]])[2], "As expected") # cleanup unlink(dir, TRUE, TRUE) diff --git a/tests/testthat/test-write_interactions.R b/tests/testthat/test-write_interactions.R index 118669b..67b5798 100644 --- a/tests/testthat/test-write_interactions.R +++ b/tests/testthat/test-write_interactions.R @@ -3,7 +3,7 @@ context("write_interactions") # body <- readRDS(file = "~/d1xmlbody.rds") # body <- substring(body, 1, 3000) # nchar(body) -request <- Request$new("POST", uri = 'https://eu.httpbin.org/post?a=5', +request <- Request$new("POST", uri = hb('/post?a=5'), body = "", headers = list(foo = "bar")) status <- list(status_code = "200", message = "OK", explanation = "Request fulfilled, document follows") diff --git a/vignettes/design.Rmd b/vignettes/design.Rmd new file mode 100644 index 0000000..8cd1191 --- /dev/null +++ b/vignettes/design.Rmd @@ -0,0 +1,18 @@ +--- +title: "Design of vcr" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Design of vcr} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>" +) +``` + +```{r child='../man/rmdhunks/vcr-design.Rmd', eval=TRUE} +``` diff --git a/vignettes/vcr.Rmd b/vignettes/vcr.Rmd index 9a5a735..fe72754 100644 --- a/vignettes/vcr.Rmd +++ b/vignettes/vcr.Rmd @@ -32,7 +32,7 @@ vcr introduction The main use case is for unit tests, but you can use it outside of the unit test use case. -`vcr` works with the `crul` and `httr` HTTP request packages. +`vcr` works with the `crul`, `httr` and `httr2` HTTP request packages. Check out the [HTTP testing book](https://books.ropensci.org/http-testing/) for a lot more documentation on `vcr`, `webmockr`, and `crul`, and other packages.