diff --git a/.Rbuildignore b/.Rbuildignore index bf1de74f..95e6b03b 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -2,4 +2,5 @@ ^renv$ ^renv\.lock$ ^.venv -^schematic$ \ No newline at end of file +^schematic$ +^\.github$ diff --git a/.github/.gitignore b/.github/.gitignore new file mode 100644 index 00000000..2d19fc76 --- /dev/null +++ b/.github/.gitignore @@ -0,0 +1 @@ +*.html diff --git a/.github/workflows/test-coverage.yaml b/.github/workflows/test-coverage.yaml new file mode 100644 index 00000000..07ebf33d --- /dev/null +++ b/.github/workflows/test-coverage.yaml @@ -0,0 +1,62 @@ +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples +# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help +on: + push: + branches: [main, develop] + pull_request: + branches: [main, develop] + +name: test-coverage + +permissions: read-all + +jobs: + test-coverage: + runs-on: ubuntu-latest + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + SYNAPSE_PAT: ${{ secrets.SYNAPSE_PAT }} + + steps: + - uses: actions/checkout@v4 + + - uses: r-lib/actions/setup-r@v2 + with: + use-public-rspm: true + + - uses: r-lib/actions/setup-r-dependencies@v2 + with: + extra-packages: any::covr, any::xml2, any::testthat + needs: coverage + + - name: Test coverage + run: | + cov <- covr::package_coverage( + quiet = FALSE, + clean = FALSE, + install_path = file.path(normalizePath(Sys.getenv("RUNNER_TEMP"), winslash = "/"), "package") + ) + covr::to_cobertura(cov) + shell: Rscript {0} + + - uses: codecov/codecov-action@v4 + with: + fail_ci_if_error: ${{ github.event_name != 'pull_request' && true || false }} + file: ./cobertura.xml + plugin: noop + disable_search: true + token: ${{ secrets.CODECOV_TOKEN }} + + - name: Show testthat output + if: always() + run: | + ## -------------------------------------------------------------------- + find '${{ runner.temp }}/package' -name 'testthat.Rout*' -exec cat '{}' \; || true + shell: bash + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v4 + with: + name: coverage-test-failures + path: ${{ runner.temp }}/package diff --git a/.github/workflows/test_schematic_api.yml b/.github/workflows/test_schematic_api.yml deleted file mode 100644 index 3407dbfc..00000000 --- a/.github/workflows/test_schematic_api.yml +++ /dev/null @@ -1,89 +0,0 @@ -# Workflow derived from https://github.com/r-lib/actions/tree/master/examples -# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help - -# This workflow creates an instance of data curator app with schematic, then -# creates a flask server running schematic to test data curator's use of -# schematic's REST API endpoints. -name: test-schematic-api - -on: - pull_request: - branches: - - main - -jobs: - test-schematic-rest-api: - runs-on: ubuntu-latest - # This image seems to be based on rocker/r-ver which in turn is based on debian - container: rocker/rstudio - env: - # This should not be necessary for installing from public repo's however remotes::install_github() fails without it. - GITHUB_PAT: ${{ secrets.REPO_PAT }} - - steps: - - name: Install System Dependencies - run: | - sudo apt-get update - sudo apt-get install -y pip python3.8-venv libcurl4-openssl-dev - - - uses: actions/checkout@v2 - - - uses: r-lib/actions/setup-pandoc@v1 - - - name: Create and Activate Python Virtual Environment - shell: bash - run: | - python3 -m venv .venv - chmod 755 .venv/bin/activate - source .venv/bin/activate - - - name: Install R Packages Dependencies - run: | - R -f install-pkgs.R - - - name: Install Schematic - shell: bash - run: | - source .venv/bin/activate - # use 'poetry' to install schematic from the develop branch - pip3 install poetry - git clone --single-branch --branch develop https://github.com/Sage-Bionetworks/schematic.git - cd schematic - poetry build - pip3 install dist/schematicpy-1.0.0-py3-none-any.whl - - - name: Set Configurations for Schematic - shell: bash - run: | - source .venv/bin/activate - # download data model to the correct location - R -e ' - config <- yaml::yaml.load_file(".github/schematic_config.yml"); - url <- config$model$input$download_url; - path <- config$model$input$location; - system(sprintf("mkdir -p %s", dirname(path))); - system(sprintf("wget %s -O %s", url, path)); - ' - # overwrite the config.yml in schematic - mv -f .github/schematic_config.yml schematic/config.yml - # write out configuration files using github secrets - echo "${{ secrets.SCHEMATIC_SYNAPSE_CONFIG }}" > schematic/.synapseConfig - echo "${{ secrets.SCHEMATIC_SERVICE_ACCT_CREDS }}" > schematic/schematic_service_account_creds.json - echo "${{ secrets.SCHEMATIC_CREDS_PATH }}" > schematic/credentials.json - echo "${{ secrets.SCHEMATIC_TOKEN_PICKLE }}" | base64 -d > schematic/token.pickle - - - name: Run schematic API service - shell: bash - run: | - echo "SYNAPSE_PAT='${{ secrets.SYNAPSE_PAT }}'" > .Renviron - source .venv/bin/activate - cd schematic - pip3 uninstall -y markupsafe - pip3 install markupsafe==2.0.1 - python3 run_api.py & - - - name: Run tests - shell: Rscript {0} - run: | - devtools::test() - diff --git a/DESCRIPTION b/DESCRIPTION index c6a1bea2..0dd6e3c6 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -7,6 +7,6 @@ License: file LICENSE Encoding: UTF-8 Roxygen: list(markdown = TRUE) RoxygenNote: 7.3.1 -Imports: httr, dplyr, jsonlite, shinyjs, yaml, promises, readr +Imports: httr, dplyr, jsonlite, shinyjs, yaml, promises, readr, httr2 Suggests: covr diff --git a/NAMESPACE b/NAMESPACE index f36e80b2..2b209cac 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -12,6 +12,7 @@ export(manifest_populate) export(manifest_validate) export(model_component_requirements) export(model_submit) +export(parse_env_var) export(storage_dataset_files) export(storage_project_datasets) export(storage_projects) diff --git a/R/datacurator_package.R b/R/datacurator_package.R new file mode 100644 index 00000000..59fae0f7 --- /dev/null +++ b/R/datacurator_package.R @@ -0,0 +1 @@ +#' @importFrom httr GET POST content diff --git a/R/read_dca_config.R b/R/read_dca_config.R new file mode 100644 index 00000000..747959ef --- /dev/null +++ b/R/read_dca_config.R @@ -0,0 +1,148 @@ +#' @title Read the DCA config file and report issues +#' @param config URL or filepath to a DCA JSON config file +read_dca_config <- function(config) { + conf <- jsonlite::fromJSON(config) + + name_check <- function(req, prov) { + if (!all(req %in% prov)) { + which_miss <- req[which(!req %in% prov)] + stop(sprintf("DCA config missing %s", which_miss)) + } + } + + lvl_1_props_req <- list( + "dcc" = list(), + "dca" = list(), + "schematic" = list() + ) + lvl_1_props_ops <- list() # Placeholder for optional properties + lvl_1_props_conf <- names(conf) + name_check(names(lvl_1_props_req), lvl_1_props_conf) + + dca_props_req <- list() # Placeholder for required DCA properties + dca_props_ops <- list( + "use_compliance_dashboard" = FALSE, + "primary_col" = "#2a668d", + "secondary_col" = "#184e71", + "sidebar_col" = "#191919" + ) + dca_props_conf <- names(conf$dca) + name_check(names(dca_props_req), dca_props_conf) + + if (!"use_compliance_dashboard" %in% dca_props_conf) { + conf$dca$use_compliance_dashboard <- FALSE + } + if (!"primary_col" %in% dca_props_conf) { + conf$dca$primary_col <- "#2a668d" + } + if (!"secondary_col" %in% dca_props_conf) { + conf$dca$secondary_col <- "#184e71" + } + if (!"primary_col" %in% dca_props_conf) { + conf$dca$sidebar_col <- "#191919" + } + + dcc_props_req <- list( + "name" = list(), + "synapse_asset_view" = list(), + "data_model_url" = list(), + "template_menu_config_file" = list() + ) + dcc_props_ops <- list( + "data_model_info" = NA_character_, + "logo_location" = "https://raw.githubusercontent.com/Sage-Bionetworks/data_curator_config/prod/demo/sage_logo_mark_only.png", + "logo_link" = "https://synapse.org", + "dcc_help_link" = NA_character_, + "portal_help_link" = NA_character_ + ) + dcc_props_conf <- names(conf$dcc) + name_check(names(dcc_props_req), dcc_props_conf) + + if (!"logo_location" %in% dcc_props_conf) { + conf$dcc$logo_location <- dcc_props_ops$logo_location + } + if (!"logo_link" %in% dcc_props_conf) { + conf$dcc$logo_link <- dcc_props_ops$logo_link + } + + # required elements should not have a default. Should error if not provided. + # WIP, confirm required and move others to ops with defaults + schematic_props_req <- list( + "manifest_generate" = list(), + "model_validate" = list(), + "model_submit" = list() + ) + schematic_props_ops <- list( + "global" = list() + ) + schematic_props_conf <- names(conf$schematic) + name_check(names(schematic_props_req), schematic_props_conf) + + if (!"global" %in% schematic_props_conf) { + conf$schematic$global <- list() + } + + global_ops <- list( + "data_model_labels" = "class_label" + ) + global_conf <- names(conf$schematic$global) + if (!"data_model_labels" %in% global_conf) { + conf$schematic$global$data_model_labels <- "class_label" + } + + # required elements should not have a default. Should error if not provided. + # WIP, confirm required and move others to ops with defaults + mg_props_req <- list( + "output_format" = "excel", + "use_annotations" = TRUE + ) + mg_props_ops <- list() + mg_props_conf <- names(conf$schematic$manifest_generate) + name_check(names(mg_props_req), mg_props_conf) + + # required elements should not have a default. Should error if not provided. + # WIP, confirm required and move others to ops with defaults + mv_props_req <- list( + "restrict_rules" = FALSE + ) + mv_props_ops <- list( + "cross_manifest_validation" = FALSE + ) + mv_props_conf <- names(conf$schematic$model_validate) + name_check(names(mv_props_req), mv_props_conf) + + if (!"cross_manifest_validation" %in% mv_props_conf) { + conf$schematic$model_validate$cross_manifest_validation <- FALSE + } + + # required elements should not have a default. Should error if not provided. + # WIP, confirm required and move others to ops with defaults + ms_props_req <- list( + "table_manipulation" = "replace", + "manifest_record_type" = "file_only" + ) + ms_props_ops <- list( + "table_column_names" = "class_label", + "annotation_keys" = "class_label", + "file_annotations_upload" = TRUE, + "hide_blanks" = FALSE + ) + ms_props_conf <- names(conf$schematic$model_submit) + name_check(names(ms_props_req), ms_props_conf) + + if (!"table_column_names" %in% ms_props_conf) { + conf$schematic$model_submit$table_column_names <- "class_label" + } + if (!"annotation_keys" %in% ms_props_conf) { + conf$schematic$model_submit$annotation_keys <- "class_label" + } + if (!"file_annotations_upload" %in% ms_props_conf) { + conf$schematic$model_submit$file_annotations_upload <- TRUE + } + if (!"hide_blanks" %in% ms_props_conf) { + conf$schematic$model_submit$hide_blanks <- FALSE + } + + conf + +} diff --git a/R/schematic_rest_api.R b/R/schematic_rest_api.R index caf8c051..d2a574fb 100644 --- a/R/schematic_rest_api.R +++ b/R/schematic_rest_api.R @@ -6,6 +6,11 @@ check_success <- function(x){ if (tolower(status$category) == "success") { return() } else { + # Return content text for Data Type errors + if (grepl("LookupError: The DataType", httr::content(x, "text"))) { + stop(httr::content(x, "text")) + } + stop(sprintf("Response from server: %s", status$reason)) } } @@ -409,7 +414,7 @@ get_asset_view_table <- function(url="http://localhost:3001/v1/storage/assets/ta check_success(req) if (return_type=="json") { - return(list2DF(fromJSON(httr::content(req)))) + return(list2DF(jsonlite::fromJSON(httr::content(req)))) } else { csv <- readr::read_csv(httr::content(req), show_col_types = FALSE) return(csv) diff --git a/R/synapse_rest_api.R b/R/synapse_rest_api.R index ea390b94..94cac87f 100644 --- a/R/synapse_rest_api.R +++ b/R/synapse_rest_api.R @@ -38,7 +38,10 @@ synapse_is_certified <- function(url="https://repo-prod.prod.sagebase.org/repo/v ownerid <- user_profile[["ownerId"]] url_req <- file.path(url, ownerid, endpoint) req <- httr::GET(url_req) - httr::content(req)[["passed"]] + resp <- httr::content(req) + if ("certified" %in% names(resp)) { + return(resp[["certified"]]) + } else return(FALSE) } diff --git a/R/utils.R b/R/utils.R new file mode 100644 index 00000000..4ea8a93e --- /dev/null +++ b/R/utils.R @@ -0,0 +1,14 @@ +#' @title parse environment variables for configuration +#' @param x string +#' @param el_delim delimeter of list elements +#' @param kv_delim delimeter of key-value pairs +#' @export +parse_env_var <- function(x, el_delim=",", kv_delim=":"){ + if (!grepl(kv_delim, x)) stop(sprintf("%s delimiter not in %s", kv_delim, x)) + # assume string of key-value pairs + elements <- stringr::str_split(x, el_delim, simplify = TRUE) + unlist(lapply(elements, function(y){ + kv <- stringr::str_split(y, kv_delim, n=2) + setNames(kv[[1]][[2]], kv[[1]][[1]]) + })) +} \ No newline at end of file diff --git a/functions/read_dca_config.R b/functions/read_dca_config.R new file mode 100644 index 00000000..747959ef --- /dev/null +++ b/functions/read_dca_config.R @@ -0,0 +1,148 @@ +#' @title Read the DCA config file and report issues +#' @param config URL or filepath to a DCA JSON config file +read_dca_config <- function(config) { + conf <- jsonlite::fromJSON(config) + + name_check <- function(req, prov) { + if (!all(req %in% prov)) { + which_miss <- req[which(!req %in% prov)] + stop(sprintf("DCA config missing %s", which_miss)) + } + } + + lvl_1_props_req <- list( + "dcc" = list(), + "dca" = list(), + "schematic" = list() + ) + lvl_1_props_ops <- list() # Placeholder for optional properties + lvl_1_props_conf <- names(conf) + name_check(names(lvl_1_props_req), lvl_1_props_conf) + + dca_props_req <- list() # Placeholder for required DCA properties + dca_props_ops <- list( + "use_compliance_dashboard" = FALSE, + "primary_col" = "#2a668d", + "secondary_col" = "#184e71", + "sidebar_col" = "#191919" + ) + dca_props_conf <- names(conf$dca) + name_check(names(dca_props_req), dca_props_conf) + + if (!"use_compliance_dashboard" %in% dca_props_conf) { + conf$dca$use_compliance_dashboard <- FALSE + } + if (!"primary_col" %in% dca_props_conf) { + conf$dca$primary_col <- "#2a668d" + } + if (!"secondary_col" %in% dca_props_conf) { + conf$dca$secondary_col <- "#184e71" + } + if (!"primary_col" %in% dca_props_conf) { + conf$dca$sidebar_col <- "#191919" + } + + dcc_props_req <- list( + "name" = list(), + "synapse_asset_view" = list(), + "data_model_url" = list(), + "template_menu_config_file" = list() + ) + dcc_props_ops <- list( + "data_model_info" = NA_character_, + "logo_location" = "https://raw.githubusercontent.com/Sage-Bionetworks/data_curator_config/prod/demo/sage_logo_mark_only.png", + "logo_link" = "https://synapse.org", + "dcc_help_link" = NA_character_, + "portal_help_link" = NA_character_ + ) + dcc_props_conf <- names(conf$dcc) + name_check(names(dcc_props_req), dcc_props_conf) + + if (!"logo_location" %in% dcc_props_conf) { + conf$dcc$logo_location <- dcc_props_ops$logo_location + } + if (!"logo_link" %in% dcc_props_conf) { + conf$dcc$logo_link <- dcc_props_ops$logo_link + } + + # required elements should not have a default. Should error if not provided. + # WIP, confirm required and move others to ops with defaults + schematic_props_req <- list( + "manifest_generate" = list(), + "model_validate" = list(), + "model_submit" = list() + ) + schematic_props_ops <- list( + "global" = list() + ) + schematic_props_conf <- names(conf$schematic) + name_check(names(schematic_props_req), schematic_props_conf) + + if (!"global" %in% schematic_props_conf) { + conf$schematic$global <- list() + } + + global_ops <- list( + "data_model_labels" = "class_label" + ) + global_conf <- names(conf$schematic$global) + if (!"data_model_labels" %in% global_conf) { + conf$schematic$global$data_model_labels <- "class_label" + } + + # required elements should not have a default. Should error if not provided. + # WIP, confirm required and move others to ops with defaults + mg_props_req <- list( + "output_format" = "excel", + "use_annotations" = TRUE + ) + mg_props_ops <- list() + mg_props_conf <- names(conf$schematic$manifest_generate) + name_check(names(mg_props_req), mg_props_conf) + + # required elements should not have a default. Should error if not provided. + # WIP, confirm required and move others to ops with defaults + mv_props_req <- list( + "restrict_rules" = FALSE + ) + mv_props_ops <- list( + "cross_manifest_validation" = FALSE + ) + mv_props_conf <- names(conf$schematic$model_validate) + name_check(names(mv_props_req), mv_props_conf) + + if (!"cross_manifest_validation" %in% mv_props_conf) { + conf$schematic$model_validate$cross_manifest_validation <- FALSE + } + + # required elements should not have a default. Should error if not provided. + # WIP, confirm required and move others to ops with defaults + ms_props_req <- list( + "table_manipulation" = "replace", + "manifest_record_type" = "file_only" + ) + ms_props_ops <- list( + "table_column_names" = "class_label", + "annotation_keys" = "class_label", + "file_annotations_upload" = TRUE, + "hide_blanks" = FALSE + ) + ms_props_conf <- names(conf$schematic$model_submit) + name_check(names(ms_props_req), ms_props_conf) + + if (!"table_column_names" %in% ms_props_conf) { + conf$schematic$model_submit$table_column_names <- "class_label" + } + if (!"annotation_keys" %in% ms_props_conf) { + conf$schematic$model_submit$annotation_keys <- "class_label" + } + if (!"file_annotations_upload" %in% ms_props_conf) { + conf$schematic$model_submit$file_annotations_upload <- TRUE + } + if (!"hide_blanks" %in% ms_props_conf) { + conf$schematic$model_submit$hide_blanks <- FALSE + } + + conf + +} diff --git a/functions/synapse_rest_api.R b/functions/synapse_rest_api.R index ea390b94..94cac87f 100644 --- a/functions/synapse_rest_api.R +++ b/functions/synapse_rest_api.R @@ -38,7 +38,10 @@ synapse_is_certified <- function(url="https://repo-prod.prod.sagebase.org/repo/v ownerid <- user_profile[["ownerId"]] url_req <- file.path(url, ownerid, endpoint) req <- httr::GET(url_req) - httr::content(req)[["passed"]] + resp <- httr::content(req) + if ("certified" %in% names(resp)) { + return(resp[["certified"]]) + } else return(FALSE) } diff --git a/modules/dashboard/dashboard.R b/modules/dashboard/dashboard.R index 387715ee..4cd880c9 100644 --- a/modules/dashboard/dashboard.R +++ b/modules/dashboard/dashboard.R @@ -84,7 +84,7 @@ dashboard <- function(id, syn.store, project.scope, schema, schema.display.name, # initiate partial loading screen for generating plot dcWaiter( "show", - id = ns("tab-container"), url = "www/img/logo.svg", custom_spinner = TRUE, + id = ns("tab-container"), url = "www/img/sage-loader.svg", custom_spinner = TRUE, msg = "Loading, please wait..." ) diff --git a/server.R b/server.R index d28a88f3..f9e418ab 100644 --- a/server.R +++ b/server.R @@ -127,18 +127,7 @@ shinyServer(function(input, output, session) { if (dca_schematic_api != "offline") { access_token <- session$userData$access_token - has_access <- vapply(all_asset_views, function(x) { - synapse_access(id = x, access = "DOWNLOAD", auth = access_token) - }, 1L) - asset_views(all_asset_views[has_access == 1]) - - if (length(asset_views) == 0) stop("You do not have DOWNLOAD access to any supported Asset Views.") - updateSelectInput(session, "dropdown_asset_view", - choices = asset_views() - ) - user_name <- synapse_user_profile(auth = access_token)$firstName - is_certified <- synapse_is_certified(auth = access_token) if (!is_certified) { dcWaiter("update", landing = TRUE, isCertified = FALSE) @@ -146,6 +135,22 @@ shinyServer(function(input, output, session) { # update waiter loading screen once login successful dcWaiter("update", landing = TRUE, userName = user_name) } + + has_access <- vapply(all_asset_views, function(x) { + synapse_access(id = x, access = "DOWNLOAD", auth = access_token) + }, 1L) + asset_views(all_asset_views[has_access == 1]) + + if (length(asset_views) == 0) { + nx_report_error( + title = "You do not have DOWNLOAD access to any supported Asset Views", + message = "Contact your DCC admin for access" + ) + hide(selector = "#NXReportButton") # hide OK button so users can't continue + } + updateSelectInput(session, "dropdown_asset_view", + choices = asset_views() + ) } else { updateSelectInput(session, "dropdown_asset_view", choices = c("Offline mock data (synXXXXXX)" = "synXXXXXX") @@ -179,7 +184,7 @@ shinyServer(function(input, output, session) { tenant_config_react(tenants_config[tenants_config$synapse_asset_view == selected$master_asset_view(), ]) if (dca_schematic_api == "offline") tenant_config_react(tenants_config[tenants_config$name == "DCA Demo", ]) - dcc_config_react(read_json( + dcc_config_react(read_dca_config( file.path(config_dir, tenant_config_react()$config_location) )) @@ -481,7 +486,7 @@ shinyServer(function(input, output, session) { if (dca_synapse_api == TRUE & dca_schematic_api != "offline") { .folder <- selected$folder() promises::future_promise({ - files <- synapse_entity_children(auth = access_token, parentId = .folder, includeTypes = list("file")) + files <- synapse_entity_children(auth = access_token, parentId = .folder, includeTypes = list("file", "folder")) if (nrow(files) > 0) { files_vec <- setNames(files$id, files$name) } else { @@ -543,7 +548,6 @@ shinyServer(function(input, output, session) { # update selected schema template name observeEvent(input$dropdown_template, { - req(input$tabs %in% "tab_template_select") warn_text <- reactiveVal(NULL) shinyjs::enable("btn_template_select") # update reactive selected values for schema @@ -800,13 +804,17 @@ shinyServer(function(input, output, session) { .infile_data <- inFile$data() .dd_template <- input$dropdown_template .restrict_rules <- dcc_config_react()$schematic$model_validate$restrict_rules - .project_scope <- selected$project_scope() + .project_scope <- NULL .access_token <- access_token .data_model_labels <- dcc_config_react()$schematic$global$data_model_labels # asset view must be NULL to avoid cross-manifest validation. # doing this in a verbose way to avoid warning with ifelse .asset_view <- NULL - if (!is.null(.project_scope)) .asset_view <- selected$master_asset_view() + if (!is.null(dcc_config_react()$schematic$model_validate$enable_cross_manifest_validation) & + isTRUE(dcc_config_react()$schematic$model_validate$enable_cross_manifest_validation)) { + .asset_view <- selected$master_asset_view() + .project_scope <- selected$project() + } promises::future_promise({ annotation_status <- switch(dca_schematic_api, diff --git a/tests/testthat/test_schematic_rest_api.R b/tests/testthat/test_schematic_rest_api.R index 0155b740..804c203a 100644 --- a/tests/testthat/test_schematic_rest_api.R +++ b/tests/testthat/test_schematic_rest_api.R @@ -20,7 +20,7 @@ test_that("manifest_generate returns a URL if sucessful", { skip_it() url <- manifest_generate(url=file.path(schematic_url, "v1/manifest/generate"), - schema_url = schema_url, access_token = Sys.getenv("SNYAPSE_PAT"), + schema_url = schema_url, access_token = Sys.getenv("SYNAPSE_PAT"), title="Test biospecimen", data_type="Biospecimen", use_annotations = FALSE, dataset_id="syn33715357", asset_view="syn33715412", @@ -28,27 +28,34 @@ test_that("manifest_generate returns a URL if sucessful", { expect_true(grepl("^https://docs.google", url)) }) -test_that("manifest_generate returns an xlsx", { - skip_it() - - xlsx <- manifest_generate(title="Test biospecimen", data_type="Biospecimen", - asset_view="syn33715412", output_format="excel") - -}) +# test_that("manifest_generate returns an xlsx", { +# skip_it() +# +# xlsx <- manifest_generate(url=file.path(schematic_url, "v1/manifest/generate"), +# title="Test biospecimen", data_type="Biospecimen", +# asset_view="syn33715412", output_format="excel") +# +# }) -test_that("manifest_populate returns a google sheet link with records filled", { - skip_it() - req <- manifest_populate(data_type="Biospecimen", title="Example", - csv_file = pass_csv) -}) +# test_that("manifest_populate returns a google sheet link with records filled", { +# skip_it() +# req <- manifest_populate(data_type="Biospecimen", title="Example", +# csv_file = pass_csv) +# }) test_that("manifest_validate passes and fails correctly", { skip_it() - pass <- manifest_validate(data_type="Biospecimen", csv_file=pass_csv) - expect_identical(pass, list()) + pass <- manifest_validate(url=file.path(schematic_url, "v1/model/validate"), + data_type="Biospecimen", file_name=fail_csv, + access_token = Sys.getenv("SYNAPSE_PAT"), + schema_url = schema_url) + expect_identical(pass, list(errors = list(), warnings = list())) - fail <- manifest_validate(data_type="Biospecimen", csv_file=fail_csv) + fail <- manifest_validate(url=file.path(schematic_url, "v1/model/validate"), + data_type="Biospecimen", file_name=pass_csv, + access_token = Sys.getenv("SYNAPSE_PAT"), + schema_url = schema_url) expect_true(length(unlist(fail)) > 0L) }) @@ -57,64 +64,67 @@ test_that("model_submit successfully uploads to synapse", { submit <- model_submit(url=file.path(schematic_url,"v1/model/submit"), schema_url = schema_url, - data_type="Biospecimen", dataset_id="syn20977135", - restrict_rules = FALSE, input_token=Sys.getenv("SYNAPSE_PAT"), + data_type=NULL, dataset_id="syn20977135", + restrict_rules = FALSE, access_token=Sys.getenv("SYNAPSE_PAT"), asset_view="syn33715412", file_name=pass_csv, - use_schema_label = TRUE, manifest_record_type="table", + manifest_record_type="file_only", table_manipulation="replace" ) - expect_true(submit) + expect_true(grepl("^syn", submit)) }) test_that("storage_project_datasets returns available datasets", { skip_it() - storage_project_datasets(asset_view="syn23643253", + storage_project_datasets(url=file.path(schematic_url, "v1/storage/project/datasets"), + asset_view="syn23643253", project_id="syn26251192", - input_token=Sys.getenv("SYNAPSE_PAT")) + access_token=Sys.getenv("SYNAPSE_PAT")) }) test_that("storage_projects returns available projects", { skip_it() - storage_projects(url=file.path(schematic_url, "v1/storage/project/datasets"), + storage_projects(url=file.path(schematic_url, "v1/storage/projects"), asset_view="syn23643253", - input_token=Sys.getenv("SYNAPSE_PAT")) + access_token=Sys.getenv("SYNAPSE_PAT")) }) test_that("storage_dataset_files returns files", { skip_it() - storage_dataset_files(asset_view = "syn23643253", + storage_dataset_files(url=file.path(schematic_url, "v1/storage/dataset/files"), + asset_view = "syn23643253", dataset_id = "syn23643250", - input_token=Sys.getenv("SYNAPSE_PAT")) + access_token=Sys.getenv("SYNAPSE_PAT")) }) test_that("model_component_requirements returns list of required components", { skip_it() - good <- model_component_requirements(url="http://localhost:3001/v1/model/component-requirements", + good <- model_component_requirements(url=file.path(schematic_url, "v1/model/component-requirements"), schema_url="https://raw.githubusercontent.com/ncihtan/data-models/main/HTAN.model.jsonld", source_component="Patient", as_graph = FALSE) expect_equal(length(good), 8L) - expect_error(model_component_requirements(url="http://localhost:3001/v1/model/component-requirements", + expect_error(model_component_requirements(url=file.path(schematic_url, "v1/model/component-requirements"), schema_url="https://aaaabad.url.jsonld", source_component="Patient", as_graph = FALSE)) }) -test_that("manifest_download returns a csv.", { - skip_it() - csv <- manifest_download(input_token=Sys.getenv("SYNAPSE_PAT"), - asset_view="syn28559058", - dataset_id="syn28268700") - exp <- setNames(c("BulkRNA-seqAssay", "CSV/TSV", "Sample_A", "GRCm38", NA, 2022L, "syn28278954"), - c("Component", "File Format", "Filename", "Genome Build", "Genome FASTA", "Sample ID", "entityId")) - expect_equal(unlist(csv), exp) -}) +# test_that("manifest_download returns a csv.", { +# skip_it() +# csv <- manifest_download(url=file.path(schematic_url, "v1/manifest/download"), +# manifest_id="syn51078535", +# access_token=Sys.getenv("SYNAPSE_PAT")) +# exp <- setNames(c("BulkRNA-seqAssay", "CSV/TSV", "Sample_A", "GRCm38", NA, 2022L, "syn28278954"), +# c("Component", "File Format", "Filename", "Genome Build", "Genome FASTA", "Sample ID", "entityId")) +# expect_equal(unlist(csv), exp) +# }) test_that("get_asset_view_table returns asset view table", { skip_it() - av <- get_asset_view_table(input_token = Sys.getenv("SYNAPSE_PAT"), + av <- get_asset_view_table(url=file.path(schematic_url, "v1/storage/assets/tables"), + access_token = Sys.getenv("SYNAPSE_PAT"), asset_view="syn23643253") storage_tbl <- subset(av, av$name == "synapse_storage_manifest.csv") expect_true(inherits(av, "data.frame"), "name" %in% names(av)) @@ -124,13 +134,13 @@ test_that("asset_tables returns a data.frame", { skip_it() tst <- get_asset_view_table(url=file.path(schematic_url, "v1/storage/assets/tables"), asset_view = "syn28559058", - input_token = Sys.getenv("SYNAPSE_TOKEN"), - as_json=TRUE) - expect_identical(nrow(tst), 3L) + access_token = Sys.getenv("SYNAPSE_PAT"), + return_type="json") + expect_identical(nrow(tst), 4L) - tst2 <- get_asset_view_table(url=file.path(schematic_url, "v1/storage/assets/tables"), + expect_error(get_asset_view_table(url=file.path(schematic_url, "v1/storage/assets/tables"), asset_view = "syn28559058", - input_token = Sys.getenv("SYNAPSE_TOKEN"), - as_json=FALSE) - expect_identical(nrow(tst2), 3L) + access_token = Sys.getenv("SYNAPSE_PAT"), + return_type = "csv") + ) }) diff --git a/tests/testthat/test_synapse_rest_api.R b/tests/testthat/test_synapse_rest_api.R index e7a91124..7165fd20 100644 --- a/tests/testthat/test_synapse_rest_api.R +++ b/tests/testthat/test_synapse_rest_api.R @@ -7,7 +7,7 @@ test_that("synapse_user_profile returns list with successful auth", { test_that("synapse_user_profile bad auth token returns message", { req <- synapse_user_profile(auth="bad token") - expect_identical(req, list(reason="Invalid access token")) + expect_identical(req$reason, "Invalid access token") }) test_that("synapse_user_profile returns list with NULL auth", { @@ -19,7 +19,7 @@ test_that("synapse_user_profile returns list with NULL auth", { test_that("is_certified returns TRUE or FALSE", { expect_true(synapse_is_certified(auth=Sys.getenv("SYNAPSE_PAT"))) - expect_true(synapse_is_certified(auth=NULL)) + expect_false(synapse_is_certified(auth=NULL)) expect_false(synapse_is_certified(auth="bad auth")) }) @@ -27,7 +27,7 @@ test_that("is_certified returns TRUE or FALSE", { test_that("get returns a tibble or error", { good_req <- synapse_get(id="syn23643255", auth=Sys.getenv("SYNAPSE_PAT")) - expect_true(nrow(good_req) == 1) + expect_true(length(good_req) > 1) expect_error(synapse_get(id="bad", auth=Sys.getenv("SYNAPSE_PAT"))) expect_error(synapse_get(id=NULL, auth=Sys.getenv("SYNAPSE_PAT"))) diff --git a/tests/testthat/test_utils.R b/tests/testthat/test_utils.R index 2c2f430b..8a9b95b0 100644 --- a/tests/testthat/test_utils.R +++ b/tests/testthat/test_utils.R @@ -1,6 +1,6 @@ context("Test utils") -testthat("parse_env_var handles empty string", { +test_that("parse_env_var handles empty string", { expect_error(parse_env_var(""), "delimiter not in") expect_error(parse_env_var(Sys.getenv(".fake_env")), "delimiter not in") })