File: request_handler.R

package info (click to toggle)
r-cran-vcr 0.6.0%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 1,360 kB
  • sloc: cpp: 15; sh: 13; makefile: 2
file content (196 lines) | stat: -rw-r--r-- 6,728 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
#' @title RequestHandler
#' @description Base handler for http requests, deciding whether a
#' request is stubbed, to be ignored, recordable, or unhandled
#' @export
#' @details
#' \strong{Private Methods}
#'   \describe{
#'     \item{\code{request_type(request)}}{
#'       Get the request type
#'     }
#'     \item{\code{externally_stubbed()}}{
#'       just returns FALSE
#'     }
#'     \item{\code{should_ignore()}}{
#'       should we ignore the request, depends on request ignorer
#'       infrastructure that's not working yet
#'     }
#'     \item{\code{has_response_stub()}}{
#'       Check if there is a matching response stub in the
#'       http interaction list
#'     }
#'     \item{\code{get_stubbed_response()}}{
#'       Check for a response and get it
#'     }
#'     \item{\code{request_summary(request)}}{
#'       get a request summary
#'     }
#'     \item{\code{on_externally_stubbed_request(request)}}{
#'       on externally stubbed request do nothing
#'     }
#'     \item{\code{on_ignored_request(request)}}{
#'       on ignored request, do something
#'     }
#'     \item{\code{on_recordable_request(request)}}{
#'       on recordable request, record the request
#'     }
#'     \item{\code{on_unhandled_request(request)}}{
#'       on unhandled request, run UnhandledHTTPRequestError
#'     }
#'   }
#' @examples \dontrun{
#' # record mode: once
#' vcr_configure(
#'  dir = tempdir(),
#'  record = "once"
#' )
#'
#' data(crul_request)
#' crul_request$url$handle <- curl::new_handle()
#' crul_request
#' x <- RequestHandler$new(crul_request)
#' # x$handle()
#'
#' # record mode: none
#' vcr_configure(
#'  dir = tempdir(),
#'  record = "none"
#' )
#' data(crul_request)
#' crul_request$url$handle <- curl::new_handle()
#' crul_request
#' insert_cassette("testing_record_mode_none", record = "none")
#' #file.path(vcr_c$dir, "testing_record_mode_none.yml")
#' x <- RequestHandlerCrul$new(crul_request)
#' # x$handle()
#' crul_request$url$url <- "https://api.crossref.org/works/10.1039/c8sm90002g/"
#' crul_request$url$handle <- curl::new_handle()
#' z <- RequestHandlerCrul$new(crul_request)
#' # z$handle()
#' eject_cassette("testing_record_mode_none")
#' }
RequestHandler <- R6::R6Class(
  'RequestHandler',
  public = list(
    #' @field request_original original, before any modification
    request_original = NULL,
    #' @field request the request, after any modification
    request = NULL,
    #' @field vcr_response holds [VcrResponse] object
    vcr_response = NULL,
    #' @field stubbed_response the stubbed response
    stubbed_response = NULL,
    #' @field cassette the cassette holder
    cassette = NULL,

    #' @description Create a new `RequestHandler` object
    #' @param request The request from an object of class `HttpInteraction`
    #' @return A new `RequestHandler` object
    initialize = function(request) {
      self$request_original <- request
      self$request <- {
        Request$new(request$method, request$url$url %||% request$url,
          webmockr::pluck_body(request) %||% "", request$headers,
          disk = !is.null(request$output$path))
      }
      self$cassette <- tryCatch(current_cassette(), error = function(e) e)
    },

    #' @description Handle the request (`request` given in `$initialize()`)
    #' @return handles a request, outcomes vary
    handle = function() {
      vcr_log_info(sprintf("Handling request: %s (disabled: %s)",
        private$request_summary(self$request),
        private$is_disabled()), vcr_c$log_opts$date)

      req_type <- private$request_type()
      req_type_fun <- sprintf("private$on_%s_request", req_type)

      vcr_log_info(sprintf("Identified request type: (%s) for %s",
        req_type,
        private$request_summary(self$request)), vcr_c$log_opts$date)

      eval(parse(text = req_type_fun))(self$request)
    }
  ),

  private = list(
    request_summary = function(request) {
      request_matchers <- if (
        !inherits(self$cassette, c("error", "list")) &&
        !is.null(self$cassette)
      ) {
        self$cassette$match_requests_on
      } else {
        vcr_c$match_requests_on
      }
      request_summary(Request$new()$from_hash(request), request_matchers)
    },

    request_type = function() {
      if (private$externally_stubbed()) {
        # FIXME: not quite sure what externally_stubbed is meant for
        #   perhaps we can get rid of it here if only applicable in Ruby
        # cat("request_type: is externally stubbed", "\n")
        "externally_stubbed"
      } else if (private$should_ignore(self$request)) {
        # cat("request_type: is ignored", "\n")
        "ignored"
      } else if (private$has_response_stub(self$request)) {
        # cat("request_type: is stubbed_by_vcr", "\n")
        "stubbed_by_vcr"
      } else if (real_http_connections_allowed()) {
        # cat("request_type: is recordable", "\n")
        "recordable"
      } else {
        # cat("request_type: is unhandled", "\n")
        "unhandled"
      }
    },

    # request type helpers
    externally_stubbed = function() FALSE,
    should_ignore = function(request) {
      request_ignorer$should_be_ignored(request)
    },
    has_response_stub = function(request) {
      hi <- http_interactions()
      if (length(hi$interactions) == 0) return(FALSE)
      hi$has_interaction_matching(request)
    },
    is_disabled = function(adapter = "crul") !webmockr::enabled(adapter),


    # get stubbed response
    get_stubbed_response = function(request) {
      self$stubbed_response <- http_interactions()$response_for(request)
      self$stubbed_response
    },

    #####################################################################
    ### various on* methods, some global for any adapter,
    ###   and some may be specific to an adapter
    ###   - all fxns take `request` param for consistentcy, even if they dont use it
    ##### so we can "monkey patch" these in each HTTP client adapter by
    #####   reassigning some of these functions with ones specific to the HTTP client

    on_externally_stubbed_request = function(request) NULL,
    on_ignored_request = function(request) {
      # perform and return REAL http response
      # reassign per adapter
    },
    on_stubbed_by_vcr_request = function(request) {
      # return stubbed vcr response - no real response to do
      # reassign per adapter
    },
    on_recordable_request = function(request) {
      # do real request - then stub response - then return stubbed vcr response
      # - this may need to be called from webmockr cruladapter?
      # reassign per adapter
    },
    on_unhandled_request = function(request) {
      err <- UnhandledHTTPRequestError$new(request)
      err$run()
    }
  )
)