From 69eb3bf2da02a84015f06f062b314af3bf3650db Mon Sep 17 00:00:00 2001 From: muzarski Date: Fri, 5 Jul 2024 17:56:35 +0200 Subject: [PATCH] result: implement tests for cass_result basic api. Implemented tests for two cases: - Rows result - i.e. result of SELECT query. - non-Rows result - e.g. result of INSERT query --- scylla-rust-wrapper/src/cass_types.rs | 6 +- scylla-rust-wrapper/src/query_result.rs | 191 ++++++++++++++++++++++++ scylla-rust-wrapper/src/session.rs | 2 +- 3 files changed, 195 insertions(+), 4 deletions(-) diff --git a/scylla-rust-wrapper/src/cass_types.rs b/scylla-rust-wrapper/src/cass_types.rs index f75540ae..66294e74 100644 --- a/scylla-rust-wrapper/src/cass_types.rs +++ b/scylla-rust-wrapper/src/cass_types.rs @@ -15,7 +15,7 @@ include!(concat!(env!("OUT_DIR"), "/cppdriver_data_types.rs")); include!(concat!(env!("OUT_DIR"), "/cppdriver_data_query_error.rs")); include!(concat!(env!("OUT_DIR"), "/cppdriver_batch_types.rs")); -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct UDTDataType { // Vec to preserve the order of types pub field_types: Vec<(String, Arc)>, @@ -131,14 +131,14 @@ impl Default for UDTDataType { } } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub enum MapDataType { Untyped, Key(Arc), KeyAndValue(Arc, Arc), } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub enum CassDataType { Value(CassValueType), UDT(UDTDataType), diff --git a/scylla-rust-wrapper/src/query_result.rs b/scylla-rust-wrapper/src/query_result.rs index 75eaa482..1a46f6a1 100644 --- a/scylla-rust-wrapper/src/query_result.rs +++ b/scylla-rust-wrapper/src/query_result.rs @@ -1377,6 +1377,197 @@ pub unsafe extern "C" fn cass_result_paging_state_token( CassError::CASS_OK } +#[cfg(test)] +mod tests { + use std::{ffi::c_char, ptr::addr_of_mut, sync::Arc}; + + use scylla::{ + frame::response::result::{ColumnSpec, ColumnType, CqlValue, Row, TableSpec}, + transport::PagingStateResponse, + }; + + use crate::{ + cass_error::CassError, + cass_types::{CassDataType, CassValueType}, + query_result::{ + cass_result_column_data_type, cass_result_column_name, cass_result_first_row, + ptr_to_cstr_n, ptr_to_ref, size_t, + }, + session::create_cass_rows_from_rows, + }; + + use super::{cass_result_column_count, cass_result_column_type, CassResult, CassResultData}; + + fn col_spec(name: &str, typ: ColumnType) -> ColumnSpec { + ColumnSpec { + table_spec: TableSpec::borrowed("ks", "tbl"), + name: name.to_string(), + typ, + } + } + + const FIRST_COLUMN_NAME: &str = "bigint_col"; + const SECOND_COLUMN_NAME: &str = "varint_col"; + const THIRD_COLUMN_NAME: &str = "list_double_col"; + fn create_cass_rows_result() -> CassResult { + let metadata = Arc::new(CassResultData::from_result_payload( + PagingStateResponse::NoMorePages, + vec![ + col_spec(FIRST_COLUMN_NAME, ColumnType::BigInt), + col_spec(SECOND_COLUMN_NAME, ColumnType::Varint), + col_spec( + THIRD_COLUMN_NAME, + ColumnType::List(Box::new(ColumnType::Double)), + ), + ], + None, + None, + )); + + let rows = create_cass_rows_from_rows( + Some(vec![Row { + columns: vec![ + Some(CqlValue::BigInt(42)), + None, + Some(CqlValue::List(vec![ + CqlValue::Float(0.5), + CqlValue::Float(42.42), + CqlValue::Float(9999.9999), + ])), + ], + }]), + &metadata, + ); + + CassResult { rows, metadata } + } + + unsafe fn cass_result_column_name_rust_str( + result_ptr: *const CassResult, + column_index: u64, + ) -> Option<&'static str> { + let mut name_ptr: *const c_char = std::ptr::null(); + let mut name_length: size_t = 0; + let cass_err = cass_result_column_name( + result_ptr, + column_index, + addr_of_mut!(name_ptr), + addr_of_mut!(name_length), + ); + assert_eq!(CassError::CASS_OK, cass_err); + ptr_to_cstr_n(name_ptr, name_length) + } + + #[test] + fn rows_cass_result_api_test() { + let result = create_cass_rows_result(); + + unsafe { + let result_ptr = std::ptr::addr_of!(result); + + // cass_result_column_count test + { + let column_count = cass_result_column_count(result_ptr); + assert_eq!(3, column_count); + } + + // cass_result_column_name test + { + let first_column_name = cass_result_column_name_rust_str(result_ptr, 0).unwrap(); + assert_eq!(FIRST_COLUMN_NAME, first_column_name); + let second_column_name = cass_result_column_name_rust_str(result_ptr, 1).unwrap(); + assert_eq!(SECOND_COLUMN_NAME, second_column_name); + let third_column_name = cass_result_column_name_rust_str(result_ptr, 2).unwrap(); + assert_eq!(THIRD_COLUMN_NAME, third_column_name); + } + + // cass_result_column_type test + { + let first_col_type = cass_result_column_type(result_ptr, 0); + assert_eq!(CassValueType::CASS_VALUE_TYPE_BIGINT, first_col_type); + let second_col_type = cass_result_column_type(result_ptr, 1); + assert_eq!(CassValueType::CASS_VALUE_TYPE_VARINT, second_col_type); + let third_col_type = cass_result_column_type(result_ptr, 2); + assert_eq!(CassValueType::CASS_VALUE_TYPE_LIST, third_col_type); + let out_of_bound_col_type = cass_result_column_type(result_ptr, 555); + assert_eq!( + CassValueType::CASS_VALUE_TYPE_UNKNOWN, + out_of_bound_col_type + ); + } + + // cass_result_column_data_type test + { + let first_col_data_type = ptr_to_ref(cass_result_column_data_type(result_ptr, 0)); + assert_eq!( + &CassDataType::Value(CassValueType::CASS_VALUE_TYPE_BIGINT), + first_col_data_type + ); + let second_col_data_type = ptr_to_ref(cass_result_column_data_type(result_ptr, 1)); + assert_eq!( + &CassDataType::Value(CassValueType::CASS_VALUE_TYPE_VARINT), + second_col_data_type + ); + let third_col_data_type = ptr_to_ref(cass_result_column_data_type(result_ptr, 2)); + assert_eq!( + &CassDataType::List { + typ: Some(Arc::new(CassDataType::Value( + CassValueType::CASS_VALUE_TYPE_DOUBLE + ))), + frozen: false + }, + third_col_data_type + ); + let out_of_bound_col_data_type = cass_result_column_data_type(result_ptr, 555); + assert!(out_of_bound_col_data_type.is_null()); + } + } + } + + fn create_non_rows_cass_result() -> CassResult { + let metadata = Arc::new(CassResultData::from_result_payload( + PagingStateResponse::NoMorePages, + vec![], + None, + None, + )); + CassResult { + rows: None, + metadata, + } + } + + #[test] + fn non_rows_cass_result_api_test() { + let result = create_non_rows_cass_result(); + + // Check that API functions do not panic when rows are empty - e.g. for INSERT queries. + unsafe { + let result_ptr = std::ptr::addr_of!(result); + + assert_eq!(0, cass_result_column_count(result_ptr)); + assert_eq!( + CassValueType::CASS_VALUE_TYPE_UNKNOWN, + cass_result_column_type(result_ptr, 0) + ); + assert!(cass_result_column_data_type(result_ptr, 0).is_null()); + assert!(cass_result_first_row(result_ptr).is_null()); + + { + let mut name_ptr: *const c_char = std::ptr::null(); + let mut name_length: size_t = 0; + let cass_err = cass_result_column_name( + result_ptr, + 0, + addr_of_mut!(name_ptr), + addr_of_mut!(name_length), + ); + assert_eq!(CassError::CASS_ERROR_LIB_INDEX_OUT_OF_BOUNDS, cass_err); + } + } + } +} + // CassResult functions: /* extern "C" { diff --git a/scylla-rust-wrapper/src/session.rs b/scylla-rust-wrapper/src/session.rs index bb2be5a2..92a7e618 100644 --- a/scylla-rust-wrapper/src/session.rs +++ b/scylla-rust-wrapper/src/session.rs @@ -377,7 +377,7 @@ pub unsafe extern "C" fn cass_session_execute( } } -fn create_cass_rows_from_rows( +pub(crate) fn create_cass_rows_from_rows( rows: Option>, metadata: &Arc, ) -> Option> {