Nothing
test_that("awaitCompletion", {
skip_if_not_installed("webfakes")
revision_app <- webfakes::new_app()
revision_app$use(webfakes::mw_json())
revision_app$get("/revisions/:id", function(req, res) {
res$set_status(200L)$send_json(
list(
id = I(req$params$id),
content_id = "content789",
publish_result = "success",
status = "published",
url = "https://example.posit.cloud/content/123",
publish_error_details = NULL
),
auto_unbox = TRUE
)
})
app <- webfakes::new_app_process(revision_app)
service <- parseHttpUrl(app$url())
authInfo <- list(
server = "connect.posit.cloud",
name = "some-user",
username = "some-user",
accountId = "123",
accessToken = "current-token",
refreshToken = "refresh-token"
)
client <- connectCloudClient(service, authInfo)
# test successful completion
result <- client$awaitCompletion("rev123")
expect_true(result$success)
expect_equal(
result$url,
"https://connect.posit.cloud/some-user/content/content789"
)
expect_null(result$error)
})
test_that("awaitCompletion handles failure", {
skip_if_not_installed("webfakes")
revision_app <- webfakes::new_app()
revision_app$use(webfakes::mw_json())
revision_app$get("/revisions/:id", function(req, res) {
res$set_status(200L)$send_json(
list(
id = I(req$params$id),
content_id = "content789",
publish_result = "failure",
status = "published",
url = NULL,
publish_error_details = "Deployment failed due to missing dependencies"
),
auto_unbox = TRUE
)
})
app <- webfakes::new_app_process(revision_app)
service <- parseHttpUrl(app$url())
authInfo <- list(
server = "connect.posit.cloud",
name = "some-user",
username = "some-user",
accountId = "123",
accessToken = "current-token",
refreshToken = "refresh-token"
)
client <- connectCloudClient(service, authInfo)
# test failure case
result <- client$awaitCompletion("rev456")
expect_false(result$success)
expect_equal(
result$url,
"https://connect.posit.cloud/some-user/content/content789"
)
expect_equal(result$error, "Deployment failed due to missing dependencies")
})
test_that("awaitCompletion handles failure with logs", {
skip_if_not_installed("webfakes")
# Mock revision API that returns failure with log channel
cloudApiApp <- webfakes::new_app()
cloudApiApp$use(webfakes::mw_json())
cloudApiApp$get("/revisions/:id", function(req, res) {
res$set_status(200L)$send_json(
list(
id = I(req$params$id),
content_id = "content789",
publish_result = "failure",
status = "published",
url = NULL,
publish_error_details = "Deployment failed due to missing dependencies",
publish_log_channel = "log-channel-123"
),
auto_unbox = TRUE
)
})
# Mock authorization API
cloudApiApp$post("/authorization", function(req, res) {
res$set_status(200L)$send_json(
list(
authorized = TRUE,
token = "auth-token-xyz"
),
auto_unbox = TRUE
)
})
# Mock logs API
logs_app <- webfakes::new_app()
logs_app$use(webfakes::mw_json())
logs_app$get("/v1/logs/:channel", function(req, res) {
res$set_status(200L)$send_json(
list(
data = list(
list(
timestamp = 1234567890 * 1000000,
message = "Starting deployment...",
level = "info"
),
list(
timestamp = 1234567891 * 1000000,
message = "Your app is busted!!",
level = "error"
)
)
),
auto_unbox = TRUE
)
})
# Start the main app and logs app
app <- webfakes::new_app_process(cloudApiApp)
logs_app_process <- webfakes::new_app_process(logs_app)
service <- parseHttpUrl(app$url())
authInfo <- list(
server = "connect.posit.cloud",
name = "some-user",
username = "some-user",
accountId = "123",
accessToken = "current-token",
refreshToken = "refresh-token"
)
# Mock connectCloudUrls and connectCloudLogsClient
local_mocked_bindings(
connectCloudUrls = function() {
list(logs = logs_app_process$url(), ui = "https://connect.posit.cloud")
},
connectCloudLogsClient = function() {
list(
getLogs = function(logChannel, authToken) {
logsUrl <- logs_app_process$url()
service <- parseHttpUrl(paste0(logsUrl, "/v1"))
authInfo <- list(
accessToken = authToken
)
path <- paste0(
"/logs/",
logChannel,
"?traversal_direction=backward&limit=1500"
)
response <- GET(service, authInfo, path)
response
}
)
}
)
client <- connectCloudClient(service, authInfo)
# Test failure case with logs - capture stderr output
stderr_output <- capture.output(
{
result <- client$awaitCompletion("rev456")
},
type = "message"
)
# Check the result object
expect_false(result$success)
expect_equal(
result$url,
"https://connect.posit.cloud/some-user/content/content789"
)
expect_equal(result$error, "Deployment failed due to missing dependencies")
# Check that logs were printed to stderr
stderr_text <- paste(stderr_output, collapse = "\n")
info <- paste0("stderr_text was:\n", stderr_text)
expect_match(stderr_text, "Begin Publishing Log")
expect_match(stderr_text, "End Publishing Log")
expect_match(stderr_text, "Starting deployment...")
expect_match(stderr_text, "Your app is busted!!")
expect_match(stderr_text, "INFO:")
expect_match(stderr_text, "ERROR:")
})
test_that("withTokenRefreshRetry passes through successful requests", {
skip_if_not_installed("webfakes")
# Mock a successful API call
mock_request_fn <- function(service, authInfo, path) {
list(success = TRUE, data = "test response")
}
service <- list(host = "example.com", port = 443, protocol = "https")
authInfo <- list(
server = "connect.posit.cloud",
name = "some-user",
username = "some-user",
accountId = "123",
accessToken = "current-token",
refreshToken = "refresh-token"
)
client <- connectCloudClient(service, authInfo)
result <- client$withTokenRefreshRetry(
mock_request_fn,
"/test"
)
expect_equal(result$success, TRUE)
expect_equal(result$data, "test response")
})
test_that("withTokenRefreshRetry handles 401 with successful token refresh", {
skip_if_not_installed("webfakes")
call_count <- 0
mock_request_fn <- function(service, authInfo, path) {
call_count <<- call_count + 1
if (call_count == 1) {
# First call fails with 401
err <- structure(
list(message = "HTTP 401"),
class = c("rsconnect_http_401", "rsconnect_http", "error", "condition")
)
stop(err)
} else {
# Second call succeeds
list(success = TRUE, data = "success after refresh")
}
}
# Mock cloudAuthClient and registerAccount
register_called <- FALSE
local_mocked_bindings(
cloudAuthClient = function() {
list(
exchangeToken = function(request) {
expect_equal(request$grant_type, "refresh_token")
expect_equal(request$refresh_token, "refresh-token")
list(
access_token = "new-access-token",
refresh_token = "new-refresh-token"
)
}
)
},
registerAccount = function(
server,
name,
accountId,
accessToken,
refreshToken
) {
register_called <<- TRUE
expect_equal(server, "connect.posit.cloud")
expect_equal(name, "test-user")
expect_equal(accountId, "123")
expect_equal(accessToken, "new-access-token")
expect_equal(refreshToken, "new-refresh-token")
}
)
service <- list(host = "example.com", port = 443, protocol = "https")
authInfo <- list(
server = "connect.posit.cloud",
name = "test-user",
accountId = "123",
accessToken = "current-token",
refreshToken = "refresh-token"
)
client <- connectCloudClient(service, authInfo)
result <- client$withTokenRefreshRetry(mock_request_fn, "/test")
expect_equal(result$success, TRUE)
expect_equal(result$data, "success after refresh")
expect_equal(call_count, 2)
expect_true(register_called)
})
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.