R/smartspeed_tests.R

Defines functions get_smartspeed_tests

Documented in get_smartspeed_tests

#' Get SmartSpeed tests
#'
#' Retrieves SmartSpeed test summary data modified since a given start date.
#'
#' @param start_date Optional ISO 8601 UTC date string (e.g. "2025-06-25T00:00:00Z").
#'
#' @return A data frame containing SmartSpeed test summaries. If no tests are
#' found, returns an empty data frame. Returned invisibly.
#' Internal function (not designed to be used directly by end users)
#' @keywords internal
get_smartspeed_tests <- function(start_date = NULL) {
    config <- get_config(quiet = TRUE)
    access_token <- authenticate()

    # Resolve start_date from argument or stored config
    if (is.null(start_date)) {
        start_date <- get_start_date()
        if (is.null(start_date)) {
            stop("Start date not set. Please call `set_start_date(\"<ISO 8601 UTC>\")` first.")
        }
    } else {
        if (!grepl("^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z$", start_date)) {
            stop("`start_date` must be in ISO 8601 format: e.g. '2025-06-25T00:00:00Z'")
        }
    }

    modified_from_utc <- start_date
    all_tests <- list()

    repeat {
        url <- paste0(config$endpoints$smartspeed, "/v1/test/tests-by-modified-date")

        query_params <- list(
            TenantId = config$tenant_id,
            ModifiedFromUtc = modified_from_utc
        )

        response <- tryCatch(
            httr::GET(
                url = url,
                query = query_params,
                .add_vald_headers(access_token)
            ),
            error = function(e) {
                stop("Failed to connect to the SmartSpeed API: ", e$message, call. = FALSE)
            }
        )

        .handle_api_response(response)

        if (response$status_code == 204) {
            message("No more tests to retrieve. Stopping pagination.")
            break
        }

        body_txt <- httr::content(response, as = "text", encoding = "UTF-8")
        test_data <- tryCatch(
            jsonlite::fromJSON(body_txt, simplifyVector = FALSE),
            error = function(e) {
                stop("Failed to parse JSON from API: ", e$message, call. = FALSE)
            }
        )

        if (!is.null(test_data$summaries) && length(test_data$summaries) > 0L) {
            all_tests <- append(all_tests, test_data$summaries)
            modified_from_utc <- test_data$summaries[[length(test_data$summaries)]]$modifiedDateUtc
            message("Continuing pagination from ", modified_from_utc)
        } else {
            message("No tests returned, stopping pagination.")
            break
        }

        Sys.sleep(0.2) # Pause to respect rate limits
    }

    if (length(all_tests) == 0L) {
        return(invisible(data.frame()))
    }

    tests_df <- .build_smartspeed_df(all_tests)

    # SmartSpeed modifiedDateUtc may include fractional seconds, with or
    # without a trailing Z, so clean it before storing as the next start_date.
    latest_mod_time <- max(tests_df$modifiedDateUtc, na.rm = TRUE)
    latest_mod_time_clean <- sub("\\.\\d+(Z)?$", "", latest_mod_time)

    if (!grepl("Z$", latest_mod_time_clean)) {
        latest_mod_time_clean <- paste0(latest_mod_time_clean, "Z")
    }

    set_start_date(latest_mod_time_clean)

    invisible(tests_df)
}

Try the valdr package in your browser

Any scripts or data that you put into this service are public.

valdr documentation built on April 22, 2026, 9:08 a.m.