Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Unexpected '<' in POST response #9

Closed
MarkEdmondson1234 opened this issue Oct 19, 2017 · 4 comments
Closed

Unexpected '<' in POST response #9

MarkEdmondson1234 opened this issue Oct 19, 2017 · 4 comments

Comments

@MarkEdmondson1234
Copy link

@MarkEdmondson1234 MarkEdmondson1234 commented Oct 19, 2017

Hi Neal, I have a failing test occur when the response includes an auth_token = <environment> field. The generated file is shown below - it is a POST batch from googleanalyticsR which is generated with this code ( link to file on GitHub)

The POST response returns other responses within it that may be GET, DELETE etc - its a way to send many API calls at once. Perhaps it is unexpected for your mock functions though.

library(httptest)
.mockPaths("..")

library(googleAnalyticsR)

accountId <- 54019251
webPropId <- "UA-54019251-4"
ga_id <- 106249469

context("Batch API Mocking")

test_that("Record requests if online", {
  skip_if_disconnected()
  skip_if_no_env_auth(local_auth)
  
  ## test reqs
  capture_requests(
    {
      google_analytics(c(ga_id2, ga_id),
                       start = "2015-07-30", end = "2015-10-01",
                       dimensions=c('medium'),
                       metrics = c('sessions'),
                       sort = "ga:sessions",
                       multi_account_batching = TRUE)
  })
})

with_mock_API({
  
  test_that("v3 multi account batching without flag", {

    skip_on_cran()
    multi <- google_analytics(c(ga_id, ga_id2),
                              start = "2015-07-31", end = "2015-10-01",
                              dimensions=c('medium'),
                              metrics = c('sessions'),
                              sort = "ga:sessions")

    expect_length(multi, 2)

    expect_s3_class(multi[[1]], "data.frame")
    expect_s3_class(multi[[2]], "data.frame")

  })

})

The offending response is below:

structure(list(url = "https://www.googleapis.com/batch/analytics/v3", 
    status_code = 200L, headers = structure(list(vary = "Origin", 
        vary = "X-Origin", `content-type` = "multipart/mixed; boundary=batch_83THWe0jLVQ_AAufwBbHho4", 
        `content-encoding` = "gzip", date = "Thu, 19 Oct 2017 08:43:52 GMT", 
        expires = "Thu, 19 Oct 2017 08:43:52 GMT", `cache-control` = "private, max-age=0", 
        `x-content-type-options` = "nosniff", `x-frame-options` = "SAMEORIGIN", 
        `x-xss-protection` = "1; mode=block", server = "GSE", 
        `alt-svc` = "quic=\":443\"; ma=2592000; v=\"39,38,37,35\"", 
        `transfer-encoding` = "chunked"), .Names = c("vary", 
    "vary", "content-type", "content-encoding", "date", "expires", 
    "cache-control", "x-content-type-options", "x-frame-options", 
    "x-xss-protection", "server", "alt-svc", "transfer-encoding"
    ), class = c("insensitive", "list")), all_headers = list(
        structure(list(status = 200L, version = "HTTP/1.1", headers = structure(list(
            vary = "Origin", vary = "X-Origin", `content-type` = "multipart/mixed; boundary=batch_83THWe0jLVQ_AAufwBbHho4", 
            `content-encoding` = "gzip", date = "Thu, 19 Oct 2017 08:43:52 GMT", 
            expires = "Thu, 19 Oct 2017 08:43:52 GMT", `cache-control` = "private, max-age=0", 
            `x-content-type-options` = "nosniff", `x-frame-options` = "SAMEORIGIN", 
            `x-xss-protection` = "1; mode=block", server = "GSE", 
            `alt-svc` = "quic=\":443\"; ma=2592000; v=\"39,38,37,35\"", 
            `transfer-encoding` = "chunked"), .Names = c("vary", 
        "vary", "content-type", "content-encoding", "date", "expires", 
        "cache-control", "x-content-type-options", "x-frame-options", 
        "x-xss-protection", "server", "alt-svc", "transfer-encoding"
        ), class = c("insensitive", "list"))), .Names = c("status", 
        "version", "headers"))), cookies = structure(list(domain = logical(0), 
        flag = logical(0), path = logical(0), secure = logical(0), 
        expiration = structure(numeric(0), class = c("POSIXct", 
        "POSIXt")), name = logical(0), value = logical(0)), .Names = c("domain", 
    "flag", "path", "secure", "expiration", "name", "value"), row.names = integer(0), class = "data.frame"), 
    content = as.raw(c(0x2d, 0x2d, 0x62, 0x61, 0x74, 0x63, 0x68, 
    0x5f, 0x38, 0x33, 0x54, 0x48, 0x57, 0x65, 0x30, 0x6a, 0x4c, 
....
    0x51, 0x5f, 0x41, 0x41, 0x75, 0x66, 0x77, 0x42, 0x62, 0x48, 
    0x68, 0x6f, 0x34, 0x2d, 0x2d, 0x0d, 0x0a)), date = structure(1508402632, class = c("POSIXct", 
    "POSIXt"), tzone = "GMT"), times = structure(c(0, 4e-05, 
    4.2e-05, 0.000102, 0.333098, 0.333141), .Names = c("redirect", 
    "namelookup", "connect", "pretransfer", "starttransfer", 
    "total")), request = structure(list(method = "POST", url = "https://www.googleapis.com/batch/analytics/v3", 
        headers = structure(c("application/json, text/xml, application/xml, */*", 
        "gzip", "multipart/mixed; boundary=gar_batch", "REDACTED"
        ), .Names = c("Accept", "Accept-Encoding", "Content-Type", 
        "Authorization")), fields = NULL, options = structure(list(
            http_version = 0, post = TRUE, postfieldsize = 620L, 
            postfields = as.raw(c(0x2d, 0x2d, 0x67, 0x61, 0x72, 
            0x5f, 0x62, 0x61, 0x74, 0x63, 0x68, 0x0d, 0x0a, 0x43, 
......
            0x68, 0x2d, 0x2d)), useragent = "googleAuthR/0.5.1.9005 (gzip)"), .Names = c("http_version", 
        "post", "postfieldsize", "postfields", "useragent")), 
        auth_token = <environment>, output = structure(list(), class = c("write_memory", 
        "write_function"))), .Names = c("method", "url", "headers", 
    "fields", "options", "auth_token", "output"), class = "request")), .Names = c("url", 
"status_code", "headers", "all_headers", "cookies", "content", 
"date", "times", "request"), class = "response")

When trying to debug I tried to load the file contents via copy-pasting the created file's content and got the same error.

mocked <- COPY-PASTE
#...
#"post", "postfieldsize", "postfields", "useragent")), 
#+                                                                                                                                                                                                                                                                      #auth_token = <environment>, output = structure(list(), class = c("write_memory", 
#Error: unexpected '<' in "                                                                                                                                                                                                #"
#>                                                                                                                                                                                                                                                                                                                                       #"write_function"))), .Names = c("method", "url", "headers", 
#Error: unexpected ')' in "                                                                                                                                                                                                #"
#>       

Also just for future reference, is the expected behaviour to be able to recreate the response from the copy-pasted file contents?

@nealrichardson
Copy link
Owner

@nealrichardson nealrichardson commented Oct 19, 2017

Thanks for reporting. This should be fixed in 570ffff. Please let me know if that addresses the issue for you. Working to get a CRAN release up for this.

@nealrichardson
Copy link
Owner

@nealrichardson nealrichardson commented Oct 19, 2017

And yes, to your last question, you can load the full R response from the recorded file. You don't have to copy and paste--just response <- source(filename)$value. That's what with_mock_API does, in fact: https://github.com/nealrichardson/httptest/blob/master/R/mock-api.R#L38

@nealrichardson
Copy link
Owner

@nealrichardson nealrichardson commented Oct 19, 2017

Also, for an immediate workaround, you can just delete the auth_token = <environment> from the bad .R file that was written out, and then the rest of your code should work. The fix I pushed is only on the recording side (it will purge the auth_token from the request written out), so next time you record, you'll get clean files.

@MarkEdmondson1234
Copy link
Author

@MarkEdmondson1234 MarkEdmondson1234 commented Oct 20, 2017

That works now, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants
You can’t perform that action at this time.