From 479b8588d7dc8d0e0731b047ec58f7ec7d037831 Mon Sep 17 00:00:00 2001 From: Johannes Rainer Date: Fri, 20 Sep 2024 16:31:43 +0200 Subject: [PATCH] tests: expand unit tests --- R/MsBackendSql-functions.R | 63 +++++---- tests/testthat/test_MsBackendOfflineSql.R | 50 ++++++++ tests/testthat/test_MsBackendSql-functions.R | 128 +++++++++++++++++++ 3 files changed, 215 insertions(+), 26 deletions(-) diff --git a/R/MsBackendSql-functions.R b/R/MsBackendSql-functions.R index 77fed40..a8e0af4 100644 --- a/R/MsBackendSql-functions.R +++ b/R/MsBackendSql-functions.R @@ -157,19 +157,22 @@ MsBackendSql <- function() { } else character() } +.is_maria_db <- function(x) { + inherits(x, "MariaDBConnection") +} + ## ## Insertion of data below. ## - -.initialize_tables <- function(con, cols, partitionBy = "none", - partitionNumber = 10) { +.initialize_tables_sql <- function(con, cols, partitionBy = "none", + partitionNumber = 10) { sql_a <- paste0("CREATE TABLE msms_spectrum (", paste(names(cols), cols, collapse = ", "), ", spectrum_id_ INTEGER, PRIMARY KEY (spectrum_id_))") sql_b <- paste0("CREATE TABLE msms_spectrum_peak (mz DOUBLE, intensity ", "REAL, spectrum_id_ INTEGER") ## MySQL/MariaDB supports partitioning - if (inherits(con, "MariaDBConnection")) { + if (.is_maria_db(con)) { sql_a <- paste0(sql_a, " ENGINE=ARIA;") if (partitionBy == "none") sql_b <- paste0(sql_b, ", INDEX (spectrum_id_)) ENGINE=ARIA;") @@ -184,19 +187,25 @@ MsBackendSql <- function() { partitionNumber, ";") } else sql_b <- paste0(sql_b, ");") - res <- dbExecute(con, sql_a) - res <- dbExecute(con, sql_b) + list(sql_a, sql_b) } -.initialize_tables_blob <- function(con, cols, partitionBy = "none", - partitionNumber = 10) { +.initialize_tables <- function(con, cols, partitionBy = "none", + partitionNumber = 10) { + sql <- .initialize_tables_sql(con, cols, partitionBy, partitionNumber) + res <- dbExecute(con, sql[[1L]]) + res <- dbExecute(con, sql[[2L]]) +} + +.initialize_tables_blob_sql <- function(con, cols, partitionBy = "none", + partitionNumber = 10) { sql_a <- paste0("CREATE TABLE msms_spectrum (", paste(names(cols), cols, collapse = ", "), ", spectrum_id_ INTEGER, PRIMARY KEY (spectrum_id_))") sql_b <- paste0("CREATE TABLE msms_spectrum_peak_blob (mz MEDIUMBLOB, ", "intensity MEDIUMBLOB, spectrum_id_ INTEGER") ## MySQL/MariaDB supports partitioning - if (inherits(con, "MariaDBConnection")) { + if (.is_maria_db(con)) { sql_a <- paste0(sql_a, " ENGINE=ARIA;") if (partitionBy == "none") sql_b <- paste0(sql_b, ", PRIMARY KEY (spectrum_id_)) ENGINE=ARIA;") @@ -211,8 +220,14 @@ MsBackendSql <- function() { partitionNumber, ";") } else sql_b <- paste0(sql_b, ");") - res <- dbExecute(con, sql_a) - res <- dbExecute(con, sql_b) + list(sql_a, sql_b) +} + +.initialize_tables_blob <- function(con, cols, partitionBy = "none", + partitionNumber = 10) { + sql <- .initialize_tables_blob_sql(con, cols, partitionBy, partitionNumber) + res <- dbExecute(con, sql[[1L]]) + res <- dbExecute(con, sql[[2L]]) } #' @importFrom DBI dbWriteTable @@ -223,18 +238,20 @@ MsBackendSql <- function() { if (length(info$dbname)) data$dataStorage <- info$dbname else data$dataStorage <- "" - if (inherits(con, "MariaDBConnection") || inherits(con, "MySQLConnection")) + if (.is_maria_db(con) || inherits(con, "MySQLConnection")) .load_data_file(con, data, "msms_spectrum") else dbWriteTable(con, name = "msms_spectrum", value = data, append = TRUE) + invisible(TRUE) } .insert_peaks <- function(con, data) { - if (inherits(con, "MariaDBConnection") || inherits(con, "MySQLConnection")) + if (.is_maria_db(con) || inherits(con, "MySQLConnection")) .load_data_file(con, data, "msms_spectrum_peak") else dbWriteTable(con, name = "msms_spectrum_peak", value = data, append = TRUE) + invisible(TRUE) } #' For MySQL databases: export data and use LOAD DATA FILE to import. @@ -246,22 +263,16 @@ MsBackendSql <- function() { #' @noRd .load_data_file <- function(con, data, name) { f <- tempfile() - logicals <- which(vapply(data, is.logical, logical(1))) + logicals <- which(vapply(data, is.logical, TRUE)) if (length(logicals)) for (i in logicals) data[, i] <- as.integer(data[, i]) - ## message("writing file") fwrite(data, file = f, row.names = FALSE, col.names = FALSE, sep = "\t", na = "\\N", eol = "\n", quote = FALSE, showProgress = FALSE) - ## message("connection valid ", dbIsValid(conm)) - ## message("executing insert") res <- dbExecute( con, paste0("LOAD DATA LOCAL INFILE '", f, "' INTO TABLE ", name, " FIELDS TERMINATED BY 0x09;")) - ## message("removing file") - res <- file.remove(f) - if (!res) - stop("failed to remove temporary file") + file.remove(f) } #' Inserts the data of a single backend to a database. @@ -294,7 +305,7 @@ MsBackendSql <- function() { lns <- lengths(pks) / 2 pks <- as.data.frame(do.call(rbind, pks)) pks$spectrum_id_ <- rep(spectrum_id, lns) - if (partitionBy == "chunk" && inherits(con, "MariaDBConnection")) { + if (partitionBy == "chunk" && .is_maria_db(con)) { ## Append an integer for the current processed chunk to be used for ## the partitioning pks$partition_ <- chunk @@ -404,7 +415,7 @@ MsBackendSql <- function() { ":elapsed"), total = length(chunks), clear = FALSE, force = TRUE) pb$tick(0) - if (inherits(con, "MariaDBConnection")) { + if (.is_maria_db(con)) { res <- dbExecute(con, "SET FOREIGN_KEY_CHECKS = 0;") res <- dbExecute(con, "SET UNIQUE_CHECKS = 0;") res <- dbExecute(con, "ALTER TABLE msms_spectrum DISABLE KEYS;") @@ -450,7 +461,7 @@ MsBackendSql <- function() { .initialize_tables(con, cols, partitionBy = "none", 10) peak_table <- "msms_spectrum_peak" } - if (inherits(con, "MariaDBConnection")) { + if (.is_maria_db(con)) { res <- dbExecute(con, "SET FOREIGN_KEY_CHECKS = 0;") res <- dbExecute(con, "SET UNIQUE_CHECKS = 0;") res <- dbExecute(con, "ALTER TABLE msms_spectrum DISABLE KEYS;") @@ -477,7 +488,7 @@ MsBackendSql <- function() { .create_indices <- function(con, peak_table) { message("Creating indices ", appendLF = FALSE) - if (inherits(con, "MariaDBConnection")) { + if (.is_maria_db(con)) { res <- dbExecute(con, "SET FOREIGN_KEY_CHECKS = 1;") message(".", appendLF = FALSE) res <- dbExecute(con, "SET UNIQUE_CHECKS = 1;") @@ -662,7 +673,7 @@ createMsBackendSqlDatabase <- function(dbcon, x = character(), .initialize_tables(dbcon, cols) } if (nrow(data)) { - if (inherits(dbcon, "MariaDBConnection")) { + if (.is_maria_db(dbcon)) { res <- dbExecute(dbcon, "SET FOREIGN_KEY_CHECKS = 0;") res <- dbExecute(dbcon, "SET UNIQUE_CHECKS = 0;") res <- dbExecute(dbcon, "ALTER TABLE msms_spectrum DISABLE KEYS;") diff --git a/tests/testthat/test_MsBackendOfflineSql.R b/tests/testthat/test_MsBackendOfflineSql.R index fc8c75a..1ce6cb4 100644 --- a/tests/testthat/test_MsBackendOfflineSql.R +++ b/tests/testthat/test_MsBackendOfflineSql.R @@ -1,14 +1,27 @@ mm_be_off <- backendInitialize(MsBackendOfflineSql(), SQLite(), dbname = dbGetInfo(mm_db)$dbname) +tmt_be_off <- backendInitialize(MsBackendOfflineSql(), SQLite(), + dbname = dbGetInfo(tmt_db)$dbname) + test_that("MsBackendOfflineSql works", { res <- MsBackendOfflineSql() expect_s4_class(res, "MsBackendOfflineSql") expect_true(validObject(res)) }) +test_that(".db_connect works", { + res <- .db_connect(MsBackendOfflineSql()) + expect_equal(res, NULL) + res <- .db_connect(mm_be_off) + expect_s4_class(res, "SQLiteConnection") + dbDisconnect(res) +}) + test_that("backendInitialize,MsBackendOfflineSql works", { expect_error(backendInitialize(MsBackendOfflineSql()), "must be specified") + expect_error(backendInitialize(MsBackendOfflineSql(), SQLite()), + "At least the database name") dbn <- dbGetInfo(mm8_db)$dbname @@ -21,6 +34,15 @@ test_that("backendInitialize,MsBackendOfflineSql works", { expect_true(validObject(res)) expect_output(show(res), "MsBackendOfflineSql") + + ## with data. + data <- spectraData(mm8_be) + tf <- tempfile() + res <- backendInitialize(MsBackendOfflineSql(), SQLite(), dbname = tf, + data = data) + expect_s4_class(res, "MsBackendOfflineSql") + expect_equal(rtime(res), data$rtime) + unlink(tf) }) test_that("dataStorage,MsBackendOfflineSql works", { @@ -201,6 +223,26 @@ test_that("filterDataOrigin,MsBackendOfflineSql works", { expect_equal(unique(dataOrigin(res)), normalizePath(c(mm14_file, mm8_file))) }) +test_that("filterPrecursorMzRange,MsBackendOfflineSql works", { + res <- filterPrecursorMzRange(mm_be_off, c(100, 200)) + expect_s4_class(res, "MsBackendOfflineSql") + expect_true(length(res) == 0) + + res <- filterPrecursorMzRange(tmt_be_off, c(500, 600)) + expect_s4_class(res, "MsBackendOfflineSql") + expect_true(length(res) > 0) + expect_true(all(msLevel(res) == 2L)) + expect_true(all(precursorMz(res) > 500 & precursorMz(res) < 600)) +}) + +test_that("filterPrecursorMzValues,MsBackendOfflineSql works", { + res <- filterPrecursorMzValues(tmt_be_off, 517, tolerance = 1) + expect_s4_class(res, "MsBackendOfflineSql") + expect_true(length(res) > 0) + expect_true(all(msLevel(res) == 2L)) + expect_true(all(precursorMz(res) > 515 & precursorMz(res) < 519)) +}) + test_that("uniqueMsLevels,MsBackendOfflineSql works", { expect_equal(uniqueMsLevels(mm_be_off), 1L) expect_false(dbIsValid(mm_be_off@dbcon)) @@ -280,4 +322,12 @@ test_that("setBackend,Spectra,MsBackendOfflineSql works", { spectraData(res, c("rtime", "dataOrigin"))) expect_equal(peaksData(ref), peaksData(res)) expect_true(length(processingLog(res)) > length(processingLog(ref))) + + ref <- Spectra() + dbf <- tempfile() + res <- setBackend(ref, MsBackendOfflineSql(), drv = SQLite(), dbname = dbf) + expect_s4_class(res, "Spectra") + expect_true(length(res) == 0) + expect_equal(msLevel(ref), msLevel(res)) + unlink(dbf) }) diff --git a/tests/testthat/test_MsBackendSql-functions.R b/tests/testthat/test_MsBackendSql-functions.R index 1ac630e..ebf8fed 100644 --- a/tests/testthat/test_MsBackendSql-functions.R +++ b/tests/testthat/test_MsBackendSql-functions.R @@ -1,3 +1,13 @@ +test_that(".valid_dbcon works", { + expect_equal(.valid_dbcon(NULL), NULL) + expect_match(.valid_dbcon(3), "expected to be") + tf <- tempfile() + cn <- dbConnect(SQLite(), tf) + expect_match(.valid_dbcon(cn), "Database lacks") + dbDisconnect(cn) + unlink(tf) +}) + test_that(".insert_data et al work", { db_file <- tempfile() db <- dbConnect(SQLite(), db_file) @@ -133,6 +143,10 @@ test_that(".spectra_data_sql works", { expect_identical(length(mm8_be), nrow(res)) expect_s4_class(res$mz, "NumericList") + expect_error( + .spectra_data_sql(mm8_be, columns = c("rtime", "other_column")), + " not available.") + tmp <- mm8_be[c(3, 2, 2, 3, 1, 10, 1)] res <- .spectra_data_sql(tmp, c("rtime", "msLevel", "mz")) expect_identical(colnames(res), c("rtime", "msLevel", "mz")) @@ -151,6 +165,10 @@ test_that(".spectra_data_sql works", { expect_identical(length(tmp), nrow(res)) expect_s4_class(res$mz, "NumericList") + expect_error( + .spectra_data_sql(mm8_be_blob, columns = c("rtime", "other_column")), + " not available.") + expect_equal(tmp_sps$mz, res$mz) expect_equal(tmp_sps$rtime, res$rtime) expect_equal(tmp_sps$intensity, tmp$intensity) @@ -159,6 +177,12 @@ test_that(".spectra_data_sql works", { test_that(".available_peaks_variables works", { res <- .available_peaks_variables(mm8_be) expect_equal(res, c("mz", "intensity")) + + res <- .available_peaks_variables(mm8_be_blob) + expect_equal(res, c("mz", "intensity")) + + res <- .available_peaks_variables(MsBackendSql()) + expect_equal(res, character()) }) test_that(".has_local_variable works", { @@ -170,6 +194,10 @@ test_that(".has_local_variable works", { expect_true(res) }) +test_that(".is_maria_db works", { + expect_false(.is_maria_db(10)) +}) + test_that(".precursor_mz_query works", { res <- .precursor_mz_query(10, ppm = 0, tolerance = 0.1) expect_equal(res, "precursorMz >= 9.9 and precursorMz <= 10.1") @@ -202,6 +230,106 @@ test_that(".combine works", { expect_equal(mm8_be[1:10], res) }) +test_that(".initialize_tables_sql works", { + res <- .initialize_tables_sql(3, c("a", "b")) + expect_true(length(res) == 2L) + expect_equal(res[[2L]], paste0("CREATE TABLE msms_spectrum_peak (mz ", + "DOUBLE, intensity REAL, spectrum_id_ ", + "INTEGER);")) + with_mock( + "MsBackendSql:::.is_maria_db" = function(x) TRUE, + res <- .initialize_tables_sql(3, c("a", "b")) + ) + expect_match(res[[1L]], "ENGINE=ARIA;") + expect_match(res[[2L]], "ENGINE=ARIA;") + with_mock( + "MsBackendSql:::.is_maria_db" = function(x) TRUE, + res <- .initialize_tables_sql(3, c("a", "b"), partitionBy = "spectrum") + ) + expect_match(res[[2L]], "ENGINE=ARIA PARTITION BY HASH (spectrum_id_", + fixed = TRUE) + with_mock( + "MsBackendSql:::.is_maria_db" = function(x) TRUE, + res <- .initialize_tables_sql(3, c("a", "b"), partitionBy = "chunk") + ) + expect_match(res[[2L]], "ENGINE=ARIA PARTITION BY HASH (partition_", + fixed = TRUE) +}) + +test_that(".load_data_file works", { + d <- data.frame(a = 1:4, b = TRUE, c = FALSE, d = 5) + with_mock( + "dbExecute" = function(...) TRUE, + expect_true(.load_data_file(3, d)) + ) +}) + +test_that(".insert_peaks works", { + d <- data.frame(a = 1:4, b = TRUE, c = FALSE, d = 5) + with_mocked_bindings( + "dbExecute" = function(...) TRUE, + ".is_maria_db" = function(x) TRUE, + code = expect_true(.insert_peaks(3, d)) + ) +}) + +test_that(".insert_spectra_variables works", { + d <- data.frame(a = 1:4, b = TRUE, c = FALSE, d = 5) + with_mocked_bindings( + "dbExecute" = function(...) TRUE, + ".is_maria_db" = function(x) TRUE, + ".load_data_file" = function(con, data, name) {}, + code = expect_true(.insert_spectra_variables(mm_db, d)) + ) + s <- new("SQLiteConnection") + with_mocked_bindings( + "dbExecute" = function(...) TRUE, + ".is_maria_db" = function(x) TRUE, + ".load_data_file" = function(con, data, name) {}, + code = expect_true(.insert_spectra_variables(s, d)) + ) +}) + +test_that(".insert_backend works", { + with_mocked_bindings( + ".insert_spectra_variables" = function(...) {}, + ".insert_peaks" = function(...) {}, + ".is_maria_db" = function(x) TRUE, + code = expect_true( + length(.insert_backend(3, mm8_sps, partitionBy = "chunk", 1L)) == 1L + ) + ) +}) + + +test_that(".initialize_tables_blob_sql works", { + res <- .initialize_tables_blob_sql(3, c("a", "b")) + expect_true(length(res) == 2L) + expect_equal(res[[2L]], paste0("CREATE TABLE msms_spectrum_peak_blob (mz ", + "MEDIUMBLOB, intensity MEDIUMBLOB, ", + "spectrum_id_ INTEGER);")) + with_mock( + "MsBackendSql:::.is_maria_db" = function(x) TRUE, + res <- .initialize_tables_blob_sql(3, c("a", "b")) + ) + expect_match(res[[1L]], "ENGINE=ARIA;") + expect_match(res[[2L]], "ENGINE=ARIA;") + with_mock( + "MsBackendSql:::.is_maria_db" = function(x) TRUE, + res <- .initialize_tables_blob_sql(3, c("a", "b"), + partitionBy = "spectrum") + ) + expect_match(res[[2L]], "ENGINE=ARIA PARTITION BY HASH (spectrum_id_", + fixed = TRUE) + with_mock( + "MsBackendSql:::.is_maria_db" = function(x) TRUE, + res <- .initialize_tables_blob_sql(3, c("a", "b"), + partitionBy = "chunk") + ) + expect_match(res[[2L]], "ENGINE=ARIA PARTITION BY HASH (partition_", + fixed = TRUE) +}) + test_that(".create_from_spectra_data works", { ## wrong format or missing data. tmpf <- tempfile()