diff --git a/R/commands.R b/R/commands.R index 3eb3252..ecc0d6a 100644 --- a/R/commands.R +++ b/R/commands.R @@ -264,6 +264,16 @@ if (!is.null(result_metadata$dataset_uuid)) { metadata$dataset_uuid <- result_metadata$dataset_uuid } + # Service-provided blinding status; passed through unchanged, omitted for older responses. + if (!is.null(result_metadata$blinding_status)) { + metadata$blinding_status <- result_metadata$blinding_status + } + + # Service-provided warnings; passed through without interpretation. + result_warnings <- result$warnings + if (is.null(result_warnings)) { + result_warnings <- list() + } dry_publish_or_publish_result <- list( success = isTRUE(result$success), @@ -280,6 +290,7 @@ dataset_is_valid = result_checks$dataset_is_valid ), errors = result_errors, + warnings = result_warnings, invalid_records = list() ) diff --git a/tests/testthat/test-publish.R b/tests/testthat/test-publish.R index 9789e52..5123023 100644 --- a/tests/testthat/test-publish.R +++ b/tests/testthat/test-publish.R @@ -475,4 +475,76 @@ test_that(".do_put_command correctly aggregates multiple chunked batches of inva expect_true(is.data.frame(result$invalid_records)) expect_equal(nrow(result$invalid_records), 2) expect_equal(result$invalid_records$id, c(1, 2)) -}) \ No newline at end of file +}) +# ============================================================================== +# Blinding status (metadata) and warnings (root) pass-through +# ============================================================================== +.run_put_with_json <- function(json, is_dry_publish) { + read_call_count <- 0 + mock_reader <- list( + read = function() { + read_call_count <<- read_call_count + 1 + if (read_call_count > 1) return(NULL) + charToRaw(json) + } + ) + mock_writer <- list(write_table = function(x) NULL, done_writing = function() NULL, close = function() NULL) + mock_client <- list(do_put = function(descriptor, schema, options) list(mock_writer, mock_reader)) + + mockery::stub(.do_put_command, "reticulate::import", function(...) list(FlightDescriptor = list(for_path = function(x) list(path = x)))) + mockery::stub(.do_put_command, "reticulate::r_to_py", .mock_r_to_py) + mockery::stub(.do_put_command, ".get_flight_options", list()) + + .do_put_command(mock_client, list(is_dry_publish = is_dry_publish), data.frame(subjid = c("001", "002"))) +} + +.envelope_json <- function(blinding = NULL, warnings = NULL) { + paste0( + '{"success": true, "metadata": {"dataset_name": "test", "dataset_version": 1, "column_count": 2', + if (!is.null(blinding)) paste0(', "blinding_status": ', blinding) else "", + '}, "metrics": {"total_valid_rows": 2, "total_invalid_rows": 0, "total_duplicate_rows": 0}, ', + '"checks": {"schema_is_valid": true, "config_is_valid": true, "date_formats_are_valid": true, "dataset_is_valid": true}, ', + '"errors": []', + if (!is.null(warnings)) paste0(', "warnings": ', warnings) else "", + '}' + ) +} + +for (dry in c(TRUE, FALSE)) { + label <- if (dry) "dry_publish" else "publish" + + test_that(paste0(label, ": blinding_status and warnings are returned as provided"), { + result <- .run_put_with_json(.envelope_json('"BLINDED"', '["Blinded columns present"]'), dry) + expect_true(result$success) + expect_equal(result$metadata$blinding_status, "BLINDED") + expect_equal(result$warnings, "Blinded columns present") + expect_equal(result$metadata$dataset_name, "test") + expect_equal(result$metrics$total_valid_rows, 2) + }) + + test_that(paste0(label, ": multiple warnings are returned without becoming errors"), { + result <- .run_put_with_json(.envelope_json('"PARTIALLY_BLINDED"', '["warn one", "warn two", "warn three"]'), dry) + expect_true(result$success) + expect_equal(result$warnings, c("warn one", "warn two", "warn three")) + expect_equal(result$errors, list()) + }) + + test_that(paste0(label, ": older responses omitting both fields remain compatible"), { + result <- .run_put_with_json(.envelope_json(), dry) + expect_true(result$success) + expect_null(result$metadata$blinding_status) + expect_equal(result$warnings, list()) + expect_equal(result$metadata$column_count, 2) + expect_equal(result$errors, list()) + }) + + test_that(paste0(label, ": omitting only one of the new fields is handled"), { + only_status <- .run_put_with_json(.envelope_json('"UNBLINDED"'), dry) + expect_equal(only_status$metadata$blinding_status, "UNBLINDED") + expect_equal(only_status$warnings, list()) + + only_warnings <- .run_put_with_json(.envelope_json(warnings = '["w"]'), dry) + expect_null(only_warnings$metadata$blinding_status) + expect_equal(only_warnings$warnings, "w") + }) +}