From 018170dd5bc99fba124bb790bbb2744292c1addf Mon Sep 17 00:00:00 2001 From: Bogdan Mircea Date: Thu, 21 Apr 2022 23:37:11 +0300 Subject: [PATCH] Fixed tests and docs --- .gitignore | 3 +- Cargo.toml | 10 ++--- src/con_opts/mod.rs | 5 +-- src/connection/http_transport/reader.rs | 2 +- src/connection/http_transport/writer.rs | 2 +- src/connection/mod.rs | 36 +++++++-------- src/connection/row.rs | 6 +-- src/lib.rs | 20 ++++----- tests/basic.rs | 60 +++++++++++++++++++++++++ tests/encrypted_compression.rs | 32 ++++++++++++- tests/rustls_test_panic.rs | 4 +- tests/simple_compression.rs | 19 +++++++- 12 files changed, 148 insertions(+), 51 deletions(-) create mode 100644 tests/basic.rs diff --git a/.gitignore b/.gitignore index ed59cb6..3f4980a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /target Cargo.lock .idea -env_setup.ps1 \ No newline at end of file +env_setup.ps1 +test_data.csv \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 37f7fb9..a251bf2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,13 +31,9 @@ __rustls = {version = "0.20.4", optional = true , package = "rustls"} flate2 = { version = "1.0.22", optional = true } [features] -native-tls-basic = ["rcgen", "__native_tls", "tungstenite/native-tls"] -rustls_dangerous = ["__rustls/dangerous_configuration"] -rustls = ["rcgen", "__rustls", "tungstenite/__rustls-tls"] +native-tls-basic = ["rcgen", "__native_tls", "tungstenite/native-tls"] # meant for internal use +rustls = ["rcgen", "__rustls", "tungstenite/__rustls-tls"] # meant for internal use native-tls = ["tungstenite/native-tls", "native-tls-basic"] native-tls-vendored = ["tungstenite/native-tls-vendored", "native-tls-basic"] rustls-tls-webpki-roots = ["tungstenite/rustls-tls-webpki-roots", "rustls"] -rustls-tls-native-roots = ["tungstenite/rustls-tls-native-roots", "rustls"] - -[dev-dependencies] -exasol = { path = ".", features = ["native-tls", "rustls-tls-webpki-roots", "rustls_dangerous", "flate2"] } \ No newline at end of file +rustls-tls-native-roots = ["tungstenite/rustls-tls-native-roots", "rustls"] \ No newline at end of file diff --git a/src/con_opts/mod.rs b/src/con_opts/mod.rs index 181acd8..992bfad 100644 --- a/src/con_opts/mod.rs +++ b/src/con_opts/mod.rs @@ -40,12 +40,11 @@ type ConResult = std::result::Result; /// autocommit: true /// /// ``` -/// use exasol::ConOpts; +/// use exasol::{ConOpts, LoginKind, Credentials}; /// /// let mut opts = ConOpts::new(); // calls default() under the hood /// opts.set_dsn("test_dsn"); -/// opts.set_user("test_user"); -/// opts.set_password("test_password"); +/// opts.set_login_kind(LoginKind::Credentials(Credentials::new("test_user", "test_password"))); /// opts.set_schema(Some("test_schema")); /// opts.set_autocommit(false); /// ``` diff --git a/src/connection/http_transport/reader.rs b/src/connection/http_transport/reader.rs index 2c15638..78d7bf4 100644 --- a/src/connection/http_transport/reader.rs +++ b/src/connection/http_transport/reader.rs @@ -2,7 +2,7 @@ use crossbeam::channel::{IntoIter, Receiver}; use std::io::Read; /// HTTP Transport reader that can be used -/// in custom closures in [Connection::export_to_closure]. +/// in custom closures in [Connection::export_to_closure](crate::Connection). pub struct ExaReader { receiver: IntoIter>, buf: Vec, diff --git a/src/connection/http_transport/writer.rs b/src/connection/http_transport/writer.rs index 5a0e138..33c7369 100644 --- a/src/connection/http_transport/writer.rs +++ b/src/connection/http_transport/writer.rs @@ -3,7 +3,7 @@ use crossbeam::channel::Sender; use std::io::{Error, ErrorKind, Write}; /// HTTP Transport writer that can be used -/// in custom closures in [Connection::import_from_closure]. +/// in custom closures in [Connection::import_from_closure](crate::Connection). pub struct ExaWriter { sender: Sender>, buf: Vec, diff --git a/src/connection/mod.rs b/src/connection/mod.rs index a9971cd..d53156f 100644 --- a/src/connection/mod.rs +++ b/src/connection/mod.rs @@ -84,7 +84,6 @@ where /// /// As a best practice, though, put some effort into manually closing the results and /// prepared statements created so as not to bloat the connection. -#[doc(hidden)] pub struct Connection { driver_attr: DriverAttributes, ws: ExaWebSocket, @@ -146,7 +145,7 @@ impl Connection { /// an error is returned. /// ``` /// use std::env; - /// use exasol::{ConOpts, Connection}; + /// use exasol::*; /// /// let dsn = env::var("EXA_DSN").unwrap(); /// let schema = env::var("EXA_SCHEMA").unwrap(); @@ -155,8 +154,7 @@ impl Connection { /// /// let mut opts = ConOpts::new(); /// opts.set_dsn(dsn); - /// opts.set_user(user); - /// opts.set_password(password); + /// opts.set_login_kind(LoginKind::Credentials(Credentials::new(user, password))); /// opts.set_schema(None::); /// /// let mut exa_con = Connection::new(opts).unwrap(); @@ -223,7 +221,7 @@ impl Connection { self.driver_attr.fetch_size } - /// Sets the fetch size in bytes when retrieving [ResultSet](crate::query::ResultSet) chunks + /// Sets the fetch size in bytes when retrieving [ResultSet] chunks. /// /// ``` /// # use exasol::connect; @@ -261,8 +259,7 @@ impl Connection { self.driver_attr.lowercase_columns } - /// Sets whether the [ResultSet](crate::query::ResultSet) [Column](crate::response::Column) - /// names will be implicitly cast to lowercase + /// Sets whether the [ResultSet] [Column] names will be implicitly cast to lowercase. /// /// ``` /// # use exasol::connect; @@ -513,10 +510,7 @@ impl Connection { /// # /// let mut exa_con = connect(&dsn, &schema, &user, &password).unwrap(); /// let mut result = exa_con.execute("SELECT '1', '2', '3' UNION ALL SELECT '4', '5', '6'").unwrap(); - /// let data: Vec> = exa_con.iter_result(&mut result).unwrap(); - /// - /// let mut result2 = exa_con.execute("SELECT '1', '2', '3' UNION ALL SELECT '4', '5', '6'").unwrap(); - /// let data2 = exa_con.iter_result(&mut result2).collect::>>>().unwrap(); + /// let data = exa_con.iter_result(&mut result).collect::>>>().unwrap(); /// assert_eq!(data.len(), 2); /// ``` pub fn iter_result<'a, T: DeserializeOwned>( @@ -531,7 +525,7 @@ impl Connection { /// HTTP Transport export with a closure that deserializes rows into a `Vec`. /// ``` - /// # use exasol::{connect, QueryResult}; + /// # use exasol::{connect, ExportOpts, QueryResult}; /// # use exasol::error::Result; /// # use serde_json::Value; /// # use std::env; @@ -541,7 +535,9 @@ impl Connection { /// # let user = env::var("EXA_USER").unwrap(); /// # let password = env::var("EXA_PASSWORD").unwrap(); /// let mut exa_con = connect(&dsn, &schema, &user, &password).unwrap(); - /// let result = exa_con.export_to_vec("SELECT * FROM EXA_RUST_TEST LIMIT 1000", None).unwrap(); + /// let mut opts = ExportOpts::new(); + /// opts.set_query("SELECT 'a', 'b', 1 UNION ALL SELECT 'c', 'd', 2;"); + /// let result = exa_con.export_to_vec(opts).unwrap(); /// /// result.into_iter().take(5).for_each(|v: (String, String, u32)| println!("{:?}", v)) /// ``` @@ -609,7 +605,7 @@ impl Connection { } /// HTTP Transport export implementation that can take any closure and an instance - /// of [ExportOpts]. The closure must make use of a reader implementing [Read]. + /// of [ExportOpts]. The closure must make use of a reader implementing [Read](std::io::Read). /// For examples check [Connection::export_to_file] and [Connection::export_to_vec]. pub fn export_to_closure(&mut self, callback: F, opts: ExportOpts) -> Result where @@ -626,7 +622,7 @@ impl Connection { /// HTTP Transport import with a closure that serializes rows from a type implementing /// [IntoIterator]. /// ``` - /// # use exasol::{connect, QueryResult}; + /// # use exasol::*; /// # use exasol::error::Result; /// # use serde_json::Value; /// # use std::env; @@ -636,8 +632,12 @@ impl Connection { /// # let user = env::var("EXA_USER").unwrap(); /// # let password = env::var("EXA_PASSWORD").unwrap(); /// let mut exa_con = connect(&dsn, &schema, &user, &password).unwrap(); - /// let result: Vec<(String, String, u32)> = exa_con.export_to_vec("SELECT * FROM EXA_RUST_TEST LIMIT 1000", None).unwrap(); - /// exa_con.import_from_iter("EXA_RUST_TEST", result, None).unwrap(); + /// let mut export_opts = ExportOpts::new(); + /// export_opts.set_query("SELECT 'a', 'b', 1 UNION ALL SELECT 'c', 'd', 2;"); + /// let result: Vec<(String, String, u32)> = exa_con.export_to_vec(export_opts).unwrap(); + /// let mut import_opts = ImportOpts::new(); + /// import_opts.set_table_name("EXA_RUST_TEST"); + /// exa_con.import_from_iter(result, import_opts).unwrap(); /// ``` pub fn import_from_iter(&mut self, iter: I, mut opts: ImportOpts) -> Result<()> where @@ -708,7 +708,7 @@ impl Connection { } /// HTTP Transport import implementation that can take any closure and an instance - /// of [ImportOpts]. The closure must make use of a writer implementing [Write]. + /// of [ImportOpts]. The closure must make use of a writer implementing [Write](std::io::Write). /// For examples check [Connection::import_from_file] and [Connection::import_from_iter]. pub fn import_from_closure(&mut self, callback: F, opts: ImportOpts) -> Result where diff --git a/src/connection/row.rs b/src/connection/row.rs index ab714c3..f7d54b7 100644 --- a/src/connection/row.rs +++ b/src/connection/row.rs @@ -441,16 +441,16 @@ impl serde::Serialize for ColumnIteratorAdapter { /// SomeVar4(SomeRow2) /// } /// -/// let data: Vec = exa_con.fetch(&mut result1, 1).unwrap(); +/// let data: Vec = exa_con.iter_result(&mut result1).take(1).collect::>().unwrap(); /// // Due to the unsupported external tagging /// // deserialization this will error out: /// // let data: Vec = exa_con.fetch(&mut result1, 1).unwrap(); /// /// // But internal tagging works -/// let data: Vec = exa_con.fetch(&mut result2, 1).unwrap(); +/// let data: Vec = exa_con.iter_result(&mut result2).take(1).collect::>().unwrap(); /// /// // And so does untagged deserialization -/// let data: Vec = exa_con.fetch(&mut result3, 1).unwrap(); +/// let data: Vec = exa_con.iter_result(&mut result3).take(1).collect::>().unwrap(); /// ``` pub fn deserialize_as_seq<'de, D, F>(deserializer: D) -> std::result::Result where diff --git a/src/lib.rs b/src/lib.rs index 8b16008..b166edd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,7 +31,7 @@ //! //! // Retrieving data associated with the result set. //! // A Vec of rows is returned, and the row type in this case will be Vec. -//! let data: Vec> = exa_con.iter_result(&mut result).unwrap(); +//! let data = exa_con.iter_result(&mut result).collect::>>>().unwrap(); //! ``` //! //! The [Connection::iter_result] method returns a lazy iterator over a result's rows. Only a given @@ -66,7 +66,7 @@ //! // Only enough calls necessary to retrieve 100 rows will be made to the database. //! // Any leftover data in the chunk will still be present in the ResultSet buffer. //! // and can be used in later retrievals. -//! let data: Vec<(String, String, u16)> = exa_con.fetch(&mut result, 100).unwrap(); +//! let data: Vec<(String, String, u16)> = exa_con.iter_result(&mut result).take(100).collect::>().unwrap(); //! // do stuff with data //! //! counter += 1; @@ -111,13 +111,13 @@ //! let mut result = exa_con.execute("SELECT 1, 2 UNION ALL SELECT 1, 2;").unwrap(); //! //! // Change the expected row type with the turbofish notation -//! let mut data = exa_con.fetch::<[u8; 2]>(&mut result, 1).unwrap(); +//! let mut data: Vec<[u8; 2]> = exa_con.iter_result(&mut result).collect::>().unwrap(); //! let row1 = data[0]; //! //! // You can also rely on type inference. //! // Nothing stops you from changing row types //! // on the same result set. -//! let mut data: Vec> = exa_con.fetch(&mut result, 1).unwrap();; +//! let mut data: Vec> = exa_con.iter_result(&mut result).collect::>().unwrap();; //! let row2 = data.pop(); //! //! let mut result = exa_con.execute("SELECT 1 as col1, 2 as col2, 3 as col3 \ @@ -131,7 +131,7 @@ //! col3: u8, //! } //! -//! let data = exa_con.iter_result::(&mut result).unwrap(); +//! let data = exa_con.iter_result::(&mut result).collect::>>().unwrap(); //! for row in data { //! // do stuff with row //! } @@ -184,7 +184,7 @@ //! The [Connection] struct can be directly instantiated with the use of [ConOpts]. //! //! ``` -//! use exasol::{ConOpts, Connection}; +//! use exasol::*; //! use std::env; //! //! let dsn = env::var("EXA_DSN").unwrap(); @@ -195,8 +195,7 @@ //! // Only providing fields for which we want custom values //! let mut opts = ConOpts::new(); //! opts.set_dsn(dsn); -//! opts.set_user(user); -//! opts.set_password(password); +//! opts.set_login_kind(LoginKind::Credentials(Credentials::new(user, password))); //! opts.set_schema(Some(schema)); //! //! let exa_con = Connection::new(opts).unwrap(); @@ -216,7 +215,7 @@ //! Attempting to use these methods without their respective features enabled results in panics. //! //! ``` should_panic -//! # use exasol::{ConOpts, Connection}; +//! # use exasol::*; //! # use std::env; //! # //! # let dsn = env::var("EXA_DSN").unwrap(); @@ -227,8 +226,7 @@ //! let mut opts = ConOpts::new(); //! //! opts.set_dsn(dsn); -//! opts.set_user(user); -//! opts.set_password(password); +//! opts.set_login_kind(LoginKind::Credentials(Credentials::new(user, password))); //! opts.set_schema(Some(schema)); //! //! opts.set_encryption(true); diff --git a/tests/basic.rs b/tests/basic.rs new file mode 100644 index 0000000..15b9e91 --- /dev/null +++ b/tests/basic.rs @@ -0,0 +1,60 @@ +//! Basic IMPORT/EXPORT tests. + +#[cfg(test)] +#[allow(unused)] +mod tests { + use exasol::error::Result; + use exasol::*; + use std::env; + + #[test] + #[allow(unused)] + fn http_transport_tests() { + let dsn = env::var("EXA_DSN").unwrap(); + let schema = env::var("EXA_SCHEMA").unwrap(); + let user = env::var("EXA_USER").unwrap(); + let password = env::var("EXA_PASSWORD").unwrap(); + + let mut opts = ConOpts::new(); + opts.set_login_kind(LoginKind::Credentials(Credentials::new(user, password))); + opts.set_dsn(dsn); + + let mut exa_con = Connection::new(opts).unwrap(); + let mut result = exa_con + .execute("SELECT * FROM RUST.EXA_RUST_TEST LIMIT 2001;") + .unwrap(); + + let rows: Vec<(String, String, u16)> = exa_con + .iter_result(&mut result) + .collect::>() + .unwrap(); + + let mut http_opts = ExportOpts::new(); + http_opts.set_encryption(false); + http_opts.set_compression(false); + http_opts.set_query("SELECT * FROM RUST.EXA_RUST_TEST LIMIT 2001"); + let data: Vec<(String, String, u16)> = exa_con.export_to_vec(http_opts).unwrap(); + + let mut http_opts = ImportOpts::new(); + http_opts.set_encryption(false); + http_opts.set_compression(false); + http_opts.set_table_name("RUST.EXA_RUST_TEST"); + exa_con.import_from_iter(data, http_opts).unwrap(); + + let mut http_opts = ExportOpts::new(); + http_opts.set_encryption(false); + http_opts.set_compression(false); + http_opts.set_column_separator(b'|'); + http_opts.set_query("SELECT * FROM RUST.EXA_RUST_TEST LIMIT 2001"); + exa_con.export_to_file("test_data.csv", http_opts).unwrap(); + + let mut http_opts = ImportOpts::new(); + http_opts.set_encryption(false); + http_opts.set_compression(false); + http_opts.set_column_separator(b'|'); + http_opts.set_table_name("RUST.EXA_RUST_TEST"); + exa_con + .import_from_file("test_data.csv", http_opts) + .unwrap(); + } +} diff --git a/tests/encrypted_compression.rs b/tests/encrypted_compression.rs index bce9356..aeeb316 100644 --- a/tests/encrypted_compression.rs +++ b/tests/encrypted_compression.rs @@ -2,6 +2,7 @@ //! We'll also include a fingerprint in the DSN #[cfg(test)] +#[cfg(all(feature = "native-tls-basic", feature = "flate2"))] #[allow(unused)] mod tests { use __native_tls::TlsConnector; @@ -19,10 +20,11 @@ mod tests { let password = env::var("EXA_PASSWORD").unwrap(); let mut opts = ConOpts::new(); - opts.set_user(user); - opts.set_password(password); + opts.set_login_kind(LoginKind::Credentials(Credentials::new(user, password))); opts.set_dsn(dsn); opts.set_schema(Some(schema)); + opts.set_compression(true); + println!("Default encryption with flags: {}", opts.encryption()); let mut config = TlsConnector::builder() .danger_accept_invalid_certs(true) @@ -46,5 +48,31 @@ mod tests { http_opts.set_compression(true); http_opts.set_table_name("RUST.EXA_RUST_TEST"); exa_con.import_from_iter(data, http_opts).unwrap(); + + let mut http_opts = ExportOpts::new(); + http_opts.set_encryption(false); + http_opts.set_compression(true); + http_opts.set_query("SELECT * FROM RUST.EXA_RUST_TEST LIMIT 2001"); + let data: Vec<(String, String, u16)> = exa_con.export_to_vec(http_opts).unwrap(); + + let mut http_opts = ImportOpts::new(); + http_opts.set_encryption(false); + http_opts.set_compression(true); + http_opts.set_table_name("RUST.EXA_RUST_TEST"); + exa_con.import_from_iter(data, http_opts).unwrap(); + + let mut http_opts = ExportOpts::new(); + http_opts.set_encryption(true); + http_opts.set_compression(true); + http_opts.set_query("SELECT * FROM RUST.EXA_RUST_TEST LIMIT 2001"); + exa_con.export_to_file("test_data.csv", http_opts).unwrap(); + + let mut http_opts = ImportOpts::new(); + http_opts.set_encryption(true); + http_opts.set_compression(true); + http_opts.set_table_name("RUST.EXA_RUST_TEST"); + exa_con + .import_from_file("test_data.csv", http_opts) + .unwrap(); } } diff --git a/tests/rustls_test_panic.rs b/tests/rustls_test_panic.rs index 1b013f9..2cb7a4f 100644 --- a/tests/rustls_test_panic.rs +++ b/tests/rustls_test_panic.rs @@ -4,6 +4,7 @@ /// But this is mainly to test that the code compiles with the given rustls features. #[cfg(test)] +#[cfg(all(feature = "rustls", feature = "flate2"))] #[allow(unused)] mod tests { use __rustls::client::{ServerCertVerified, ServerCertVerifier}; @@ -40,8 +41,7 @@ mod tests { let password = env::var("EXA_PASSWORD").unwrap(); let mut opts = ConOpts::new(); - opts.set_user(user); - opts.set_password(password); + opts.set_login_kind(LoginKind::Credentials(Credentials::new(user, password))); opts.set_dsn(dsn); opts.set_schema(Some(schema)); diff --git a/tests/simple_compression.rs b/tests/simple_compression.rs index 0fc11ad..4ce184f 100644 --- a/tests/simple_compression.rs +++ b/tests/simple_compression.rs @@ -3,6 +3,7 @@ //! be discarded. #[cfg(test)] +#[cfg(feature = "flate2")] #[allow(unused)] mod tests { use exasol::error::Result; @@ -18,10 +19,10 @@ mod tests { let password = env::var("EXA_PASSWORD").unwrap(); let mut opts = ConOpts::new(); - opts.set_user(user); - opts.set_password(password); + opts.set_login_kind(LoginKind::Credentials(Credentials::new(user, password))); opts.set_dsn(dsn); opts.set_compression(true); + println!("Default encryption without flags: {}", opts.encryption()); let mut exa_con = Connection::new(opts).unwrap(); let mut result = exa_con @@ -44,5 +45,19 @@ mod tests { http_opts.set_compression(true); http_opts.set_table_name("RUST.EXA_RUST_TEST"); exa_con.import_from_iter(data, http_opts).unwrap(); + + let mut http_opts = ExportOpts::new(); + http_opts.set_encryption(false); + http_opts.set_compression(true); + http_opts.set_query("SELECT * FROM RUST.EXA_RUST_TEST LIMIT 2001"); + exa_con.export_to_file("test_data.csv", http_opts).unwrap(); + + let mut http_opts = ImportOpts::new(); + http_opts.set_encryption(false); + http_opts.set_compression(true); + http_opts.set_table_name("RUST.EXA_RUST_TEST"); + exa_con + .import_from_file("test_data.csv", http_opts) + .unwrap(); } }