From 5a04aeee7e542c44258b852d45109525e1059ba5 Mon Sep 17 00:00:00 2001 From: Simon Couch Date: Mon, 10 Aug 2026 12:09:39 -0500 Subject: [PATCH 1/3] add live warehouse test helpers --- DESCRIPTION | 1 + tests/testthat/README.md | 31 ++++++++++++++ tests/testthat/helper-live-warehouses.R | 55 +++++++++++++++++++++++++ tests/testthat/test-live-warehouses.R | 44 ++++++++++++++++++++ 4 files changed, 131 insertions(+) create mode 100644 tests/testthat/README.md create mode 100644 tests/testthat/helper-live-warehouses.R create mode 100644 tests/testthat/test-live-warehouses.R diff --git a/DESCRIPTION b/DESCRIPTION index 4691d14..ba580cb 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -43,6 +43,7 @@ Suggests: dbplyr, dplyr, htmltools, + odbc, otel (>= 0.2.0), otelsdk (>= 0.2.0), pins, diff --git a/tests/testthat/README.md b/tests/testthat/README.md new file mode 100644 index 0000000..c510119 --- /dev/null +++ b/tests/testthat/README.md @@ -0,0 +1,31 @@ +# Live warehouse tests + +The Snowflake and Databricks smoke tests are opt in. The ordinary test suite +skips them before connecting, so contributors do not need warehouse credentials +or ODBC drivers. + +To run the Snowflake test, configure `odbc::snowflake()` as usual and set: + +```sh +export COMMONS_LIVE_SNOWFLAKE=true +export COMMONS_SNOWFLAKE_DATABASE=... +export COMMONS_SNOWFLAKE_SCHEMA=... +export COMMONS_SNOWFLAKE_TABLE=... +``` + +To run the Databricks test, configure an ODBC DSN named `Databricks` and set: + +```sh +export COMMONS_LIVE_DATABRICKS=true +export COMMONS_DATABRICKS_CATALOG=... +export COMMONS_DATABRICKS_SCHEMA=... +export COMMONS_DATABRICKS_TABLE=... +``` + +Set `COMMONS_DATABRICKS_DSN` to use a differently named DSN. Identifiers are +passed as separate `catalog`, `schema`, and `table` components of `DBI::Id()`; +do not combine them into a dotted string. + +Each test queries the current identity and namespace, then reads at most one row +from the configured table. If a live-test switch or identifier is absent, that +backend's test skips. Once enabled, connection and query failures fail the test. diff --git a/tests/testthat/helper-live-warehouses.R b/tests/testthat/helper-live-warehouses.R new file mode 100644 index 0000000..47b0ab5 --- /dev/null +++ b/tests/testthat/helper-live-warehouses.R @@ -0,0 +1,55 @@ +local_warehouse_connection <- function(backend, env = parent.frame()) { + backend <- match.arg(backend, c("snowflake", "databricks")) + skip_unless_live_warehouse(backend) + skip_if_not_installed("odbc") + + con <- switch( + backend, + snowflake = DBI::dbConnect(odbc::snowflake()), + databricks = DBI::dbConnect( + odbc::odbc(), + Sys.getenv("COMMONS_DATABRICKS_DSN", unset = "Databricks") + ) + ) + withr::defer(DBI::dbDisconnect(con), envir = env) + con +} + +warehouse_test_objects <- function(backend) { + backend <- match.arg(backend, c("snowflake", "databricks")) + skip_unless_live_warehouse(backend) + + prefix <- toupper(backend) + top_level <- if (identical(backend, "snowflake")) "DATABASE" else "CATALOG" + names <- paste0( + "COMMONS_", prefix, "_", c(top_level, "SCHEMA", "TABLE") + ) + values <- Sys.getenv(names, unset = NA_character_) + missing <- names[is.na(values) | !nzchar(values)] + if (length(missing)) { + skip(paste("Missing live warehouse configuration:", paste(missing, collapse = ", "))) + } + + list(table = DBI::Id( + catalog = unname(values[[1]]), + schema = unname(values[[2]]), + table = unname(values[[3]]) + )) +} + +skip_unless_live_warehouse <- function(backend) { + variable <- paste0("COMMONS_LIVE_", toupper(backend)) + skip_if_not( + identical(tolower(Sys.getenv(variable)), "true"), + paste0("Set ", variable, "=true to run live warehouse tests") + ) +} + +warehouse_read_one <- function(con, id) { + sql <- paste( + "SELECT * FROM", + DBI::dbQuoteIdentifier(con, id), + "LIMIT 1" + ) + DBI::dbGetQuery(con, sql) +} diff --git a/tests/testthat/test-live-warehouses.R b/tests/testthat/test-live-warehouses.R new file mode 100644 index 0000000..dae3ecc --- /dev/null +++ b/tests/testthat/test-live-warehouses.R @@ -0,0 +1,44 @@ +test_that("live Snowflake connection reads a configured table", { + objects <- warehouse_test_objects("snowflake") + con <- local_warehouse_connection("snowflake") + + session <- DBI::dbGetQuery( + con, + paste( + "SELECT CURRENT_USER() AS principal,", + "CURRENT_ROLE() AS role,", + "CURRENT_DATABASE() AS catalog,", + "CURRENT_SCHEMA() AS schema" + ) + ) + rows <- warehouse_read_one(con, objects$table) + names(session) <- tolower(names(session)) + + expect_equal(nrow(session), 1) + expect_named(session, c("principal", "role", "catalog", "schema")) + expect_true(nzchar(session$principal[[1]])) + expect_s3_class(rows, "data.frame") + expect_true(nrow(rows) <= 1) +}) + +test_that("live Databricks connection reads a configured table", { + objects <- warehouse_test_objects("databricks") + con <- local_warehouse_connection("databricks") + + session <- DBI::dbGetQuery( + con, + paste( + "SELECT CURRENT_USER() AS principal,", + "CURRENT_CATALOG() AS catalog,", + "CURRENT_SCHEMA() AS schema" + ) + ) + rows <- warehouse_read_one(con, objects$table) + names(session) <- tolower(names(session)) + + expect_equal(nrow(session), 1) + expect_named(session, c("principal", "catalog", "schema")) + expect_true(nzchar(session$principal[[1]])) + expect_s3_class(rows, "data.frame") + expect_true(nrow(rows) <= 1) +}) From 3619dbf25f594ca3de32958c74c9bc66e639a884 Mon Sep 17 00:00:00 2001 From: Simon Couch Date: Mon, 10 Aug 2026 12:46:40 -0500 Subject: [PATCH 2/3] select snowflake test warehouse --- tests/testthat/README.md | 1 + tests/testthat/helper-live-warehouses.R | 13 ++++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/testthat/README.md b/tests/testthat/README.md index c510119..22c061c 100644 --- a/tests/testthat/README.md +++ b/tests/testthat/README.md @@ -8,6 +8,7 @@ To run the Snowflake test, configure `odbc::snowflake()` as usual and set: ```sh export COMMONS_LIVE_SNOWFLAKE=true +export COMMONS_SNOWFLAKE_WAREHOUSE=... export COMMONS_SNOWFLAKE_DATABASE=... export COMMONS_SNOWFLAKE_SCHEMA=... export COMMONS_SNOWFLAKE_TABLE=... diff --git a/tests/testthat/helper-live-warehouses.R b/tests/testthat/helper-live-warehouses.R index 47b0ab5..dbbc60c 100644 --- a/tests/testthat/helper-live-warehouses.R +++ b/tests/testthat/helper-live-warehouses.R @@ -5,7 +5,10 @@ local_warehouse_connection <- function(backend, env = parent.frame()) { con <- switch( backend, - snowflake = DBI::dbConnect(odbc::snowflake()), + snowflake = DBI::dbConnect( + odbc::snowflake(), + warehouse = live_warehouse_setting("COMMONS_SNOWFLAKE_WAREHOUSE") + ), databricks = DBI::dbConnect( odbc::odbc(), Sys.getenv("COMMONS_DATABRICKS_DSN", unset = "Databricks") @@ -15,6 +18,14 @@ local_warehouse_connection <- function(backend, env = parent.frame()) { con } +live_warehouse_setting <- function(name) { + value <- Sys.getenv(name, unset = NA_character_) + if (is.na(value) || !nzchar(value)) { + skip(paste("Missing live warehouse configuration:", name)) + } + value +} + warehouse_test_objects <- function(backend) { backend <- match.arg(backend, c("snowflake", "databricks")) skip_unless_live_warehouse(backend) From 402399eba690fc551b4450ae9c87a5e735714fce Mon Sep 17 00:00:00 2001 From: Simon Couch Date: Mon, 10 Aug 2026 12:56:23 -0500 Subject: [PATCH 3/3] simplify live warehouse configuration --- tests/testthat/README.md | 34 +++++++-------- tests/testthat/helper-live-warehouses.R | 56 ++++++++----------------- tests/testthat/test-live-warehouses.R | 8 ++-- 3 files changed, 37 insertions(+), 61 deletions(-) diff --git a/tests/testthat/README.md b/tests/testthat/README.md index 22c061c..2a49820 100644 --- a/tests/testthat/README.md +++ b/tests/testthat/README.md @@ -4,29 +4,27 @@ The Snowflake and Databricks smoke tests are opt in. The ordinary test suite skips them before connecting, so contributors do not need warehouse credentials or ODBC drivers. -To run the Snowflake test, configure `odbc::snowflake()` as usual and set: +To run the Snowflake test, configure `odbc::snowflake()` with a default +warehouse and set: -```sh -export COMMONS_LIVE_SNOWFLAKE=true -export COMMONS_SNOWFLAKE_WAREHOUSE=... -export COMMONS_SNOWFLAKE_DATABASE=... -export COMMONS_SNOWFLAKE_SCHEMA=... -export COMMONS_SNOWFLAKE_TABLE=... +```r +options(commons.test.snowflake = DBI::Id( + catalog = "...", + schema = "...", + table = "..." +)) ``` To run the Databricks test, configure an ODBC DSN named `Databricks` and set: -```sh -export COMMONS_LIVE_DATABRICKS=true -export COMMONS_DATABRICKS_CATALOG=... -export COMMONS_DATABRICKS_SCHEMA=... -export COMMONS_DATABRICKS_TABLE=... +```r +options(commons.test.databricks = DBI::Id( + catalog = "...", + schema = "...", + table = "..." +)) ``` -Set `COMMONS_DATABRICKS_DSN` to use a differently named DSN. Identifiers are -passed as separate `catalog`, `schema`, and `table` components of `DBI::Id()`; -do not combine them into a dotted string. - Each test queries the current identity and namespace, then reads at most one row -from the configured table. If a live-test switch or identifier is absent, that -backend's test skips. Once enabled, connection and query failures fail the test. +from the configured table. If a backend's option is absent, its test skips. Once +enabled, connection and query failures fail the test. diff --git a/tests/testthat/helper-live-warehouses.R b/tests/testthat/helper-live-warehouses.R index dbbc60c..564952e 100644 --- a/tests/testthat/helper-live-warehouses.R +++ b/tests/testthat/helper-live-warehouses.R @@ -1,59 +1,37 @@ local_warehouse_connection <- function(backend, env = parent.frame()) { backend <- match.arg(backend, c("snowflake", "databricks")) - skip_unless_live_warehouse(backend) + warehouse_test_table(backend) skip_if_not_installed("odbc") con <- switch( backend, - snowflake = DBI::dbConnect( - odbc::snowflake(), - warehouse = live_warehouse_setting("COMMONS_SNOWFLAKE_WAREHOUSE") - ), + snowflake = DBI::dbConnect(odbc::snowflake()), databricks = DBI::dbConnect( odbc::odbc(), - Sys.getenv("COMMONS_DATABRICKS_DSN", unset = "Databricks") + "Databricks" ) ) withr::defer(DBI::dbDisconnect(con), envir = env) con } -live_warehouse_setting <- function(name) { - value <- Sys.getenv(name, unset = NA_character_) - if (is.na(value) || !nzchar(value)) { - skip(paste("Missing live warehouse configuration:", name)) - } - value -} - -warehouse_test_objects <- function(backend) { +warehouse_test_table <- function(backend, call = rlang::caller_env()) { backend <- match.arg(backend, c("snowflake", "databricks")) - skip_unless_live_warehouse(backend) - - prefix <- toupper(backend) - top_level <- if (identical(backend, "snowflake")) "DATABASE" else "CATALOG" - names <- paste0( - "COMMONS_", prefix, "_", c(top_level, "SCHEMA", "TABLE") + option <- paste0("commons.test.", backend) + table <- getOption(option) + skip_if( + is.null(table), + paste0( + "Set options(", option, " = DBI::Id(...)) to run live warehouse tests" + ) ) - values <- Sys.getenv(names, unset = NA_character_) - missing <- names[is.na(values) | !nzchar(values)] - if (length(missing)) { - skip(paste("Missing live warehouse configuration:", paste(missing, collapse = ", "))) + if (!inherits(table, "Id")) { + cli::cli_abort( + "The {.option {option}} option must be a {.cls DBI::Id} object.", + call = call + ) } - - list(table = DBI::Id( - catalog = unname(values[[1]]), - schema = unname(values[[2]]), - table = unname(values[[3]]) - )) -} - -skip_unless_live_warehouse <- function(backend) { - variable <- paste0("COMMONS_LIVE_", toupper(backend)) - skip_if_not( - identical(tolower(Sys.getenv(variable)), "true"), - paste0("Set ", variable, "=true to run live warehouse tests") - ) + table } warehouse_read_one <- function(con, id) { diff --git a/tests/testthat/test-live-warehouses.R b/tests/testthat/test-live-warehouses.R index dae3ecc..6fa1f5a 100644 --- a/tests/testthat/test-live-warehouses.R +++ b/tests/testthat/test-live-warehouses.R @@ -1,5 +1,5 @@ test_that("live Snowflake connection reads a configured table", { - objects <- warehouse_test_objects("snowflake") + table <- warehouse_test_table("snowflake") con <- local_warehouse_connection("snowflake") session <- DBI::dbGetQuery( @@ -11,7 +11,7 @@ test_that("live Snowflake connection reads a configured table", { "CURRENT_SCHEMA() AS schema" ) ) - rows <- warehouse_read_one(con, objects$table) + rows <- warehouse_read_one(con, table) names(session) <- tolower(names(session)) expect_equal(nrow(session), 1) @@ -22,7 +22,7 @@ test_that("live Snowflake connection reads a configured table", { }) test_that("live Databricks connection reads a configured table", { - objects <- warehouse_test_objects("databricks") + table <- warehouse_test_table("databricks") con <- local_warehouse_connection("databricks") session <- DBI::dbGetQuery( @@ -33,7 +33,7 @@ test_that("live Databricks connection reads a configured table", { "CURRENT_SCHEMA() AS schema" ) ) - rows <- warehouse_read_one(con, objects$table) + rows <- warehouse_read_one(con, table) names(session) <- tolower(names(session)) expect_equal(nrow(session), 1)