From 35035c715cddec6e21ed0bf19b63649cf5c68f63 Mon Sep 17 00:00:00 2001 From: Ning Sun Date: Sun, 7 Mar 2021 12:10:20 +0800 Subject: [PATCH 01/24] (refactor) use http header auth --- influxdb/src/client/mod.rs | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/influxdb/src/client/mod.rs b/influxdb/src/client/mod.rs index a8dcac3..2d79700 100644 --- a/influxdb/src/client/mod.rs +++ b/influxdb/src/client/mod.rs @@ -18,12 +18,12 @@ use futures_util::TryFutureExt; use http::StatusCode; #[cfg(feature = "reqwest")] -use reqwest::{Client as HttpClient, Response as HttpResponse}; +use reqwest::{Client as HttpClient, RequestBuilder, Response as HttpResponse}; use std::collections::{BTreeMap, HashMap}; use std::fmt::{self, Debug, Formatter}; use std::sync::Arc; #[cfg(feature = "surf")] -use surf::{Client as HttpClient, Response as HttpResponse}; +use surf::{Client as HttpClient, RequestBuilder, Response as HttpResponse}; use crate::query::QueryType; use crate::Error; @@ -34,6 +34,8 @@ use crate::Query; pub struct Client { pub(crate) url: Arc, pub(crate) parameters: Arc>, + pub(crate) username: Option, + pub(crate) password: Option, pub(crate) client: HttpClient, } @@ -89,6 +91,8 @@ impl Client { url: Arc::new(url.into()), parameters: Arc::new(parameters), client: HttpClient::new(), + username: None, + password: None, } } @@ -112,10 +116,8 @@ impl Client { S1: Into, S2: Into, { - let mut with_auth = self.parameters.as_ref().clone(); - with_auth.insert("u", username.into()); - with_auth.insert("p", password.into()); - self.parameters = Arc::new(with_auth); + self.username = Some(username.into()); + self.password = Some(password.into()); self } @@ -226,9 +228,9 @@ impl Client { parameters.insert("q", read_query.clone()); if read_query.contains("SELECT") || read_query.contains("SHOW") { - self.client.get(url).query(¶meters) + self.try_authed(self.client.get(url)).query(¶meters) } else { - self.client.post(url).query(¶meters) + self.try_authed(self.client.post(url)).query(¶meters) } } QueryType::WriteQuery(precision) => { @@ -236,7 +238,9 @@ impl Client { let mut parameters = self.parameters.as_ref().clone(); parameters.insert("precision", precision); - self.client.post(url).body(query.get()).query(¶meters) + self.try_authed(self.client.post(url)) + .body(query.get()) + .query(¶meters) } }; @@ -273,6 +277,14 @@ impl Client { Ok(s) } + + fn try_authed(&self, rb: RequestBuilder) -> RequestBuilder { + if let (Some(ref username), Some(ref password)) = (&self.username, &self.password) { + rb.header("Authorization", format!("Basic {}:{}", username, password)) + } else { + rb + } + } } pub(crate) fn check_status(res: &HttpResponse) -> Result<(), Error> { From e4b6bed02f14a62c5de65ec999d7aa85ddf7e84d Mon Sep 17 00:00:00 2001 From: Ning Sun Date: Sat, 13 Mar 2021 22:37:52 +0800 Subject: [PATCH 02/24] (feat) add support for token based auth --- influxdb/src/client/mod.rs | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/influxdb/src/client/mod.rs b/influxdb/src/client/mod.rs index 2d79700..ce681b6 100644 --- a/influxdb/src/client/mod.rs +++ b/influxdb/src/client/mod.rs @@ -36,6 +36,7 @@ pub struct Client { pub(crate) parameters: Arc>, pub(crate) username: Option, pub(crate) password: Option, + pub(crate) token: Option, pub(crate) client: HttpClient, } @@ -93,6 +94,7 @@ impl Client { client: HttpClient::new(), username: None, password: None, + token: None, } } @@ -128,6 +130,19 @@ impl Client { self } + /// Add authorization token to [`Client`](crate::Client) + /// + /// This is designed for influxdb 2.0's backward-compatible API which + /// requires authrozation by default. You can create such token from + /// console of influxdb 2.0 . + pub fn with_token(mut self, token: S) -> Self + where + S: Into, + { + self.token = Some(token.into()); + self + } + /// Returns the name of the database the client is using pub fn database_name(&self) -> &str { // safe to unwrap: we always set the database name in `Self::new` @@ -228,9 +243,9 @@ impl Client { parameters.insert("q", read_query.clone()); if read_query.contains("SELECT") || read_query.contains("SHOW") { - self.try_authed(self.client.get(url)).query(¶meters) + self.client.get(url).query(¶meters) } else { - self.try_authed(self.client.post(url)).query(¶meters) + self.client.post(url).query(¶meters) } } QueryType::WriteQuery(precision) => { @@ -238,9 +253,7 @@ impl Client { let mut parameters = self.parameters.as_ref().clone(); parameters.insert("precision", precision); - self.try_authed(self.client.post(url)) - .body(query.get()) - .query(¶meters) + self.client.post(url).body(query.get()).query(¶meters) } }; @@ -249,7 +262,7 @@ impl Client { error: err.to_string(), })?; - let res = request_builder + let res = self.try_authed(request_builder) .send() .map_err(|err| Error::ConnectionError { error: err.to_string(), @@ -281,6 +294,8 @@ impl Client { fn try_authed(&self, rb: RequestBuilder) -> RequestBuilder { if let (Some(ref username), Some(ref password)) = (&self.username, &self.password) { rb.header("Authorization", format!("Basic {}:{}", username, password)) + } else if let Some(ref token) = self.token { + rb.header("Authorization", format!("Token {}", token)) } else { rb } From d7f2505fdc02a355aeef6aff8f5aabff33cbb97e Mon Sep 17 00:00:00 2001 From: Ning Sun Date: Sat, 13 Mar 2021 23:11:47 +0800 Subject: [PATCH 03/24] (test) fix test case that checking parameter length for auth --- influxdb/src/client/mod.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/influxdb/src/client/mod.rs b/influxdb/src/client/mod.rs index ce681b6..da98a2e 100644 --- a/influxdb/src/client/mod.rs +++ b/influxdb/src/client/mod.rs @@ -350,9 +350,15 @@ mod tests { assert_eq!(client.parameters.get("db").unwrap(), "database"); let with_auth = client.with_auth("username", "password"); - assert_eq!(with_auth.parameters.len(), 3); + assert_eq!(with_auth.parameters.len(), 1); assert_eq!(with_auth.parameters.get("db").unwrap(), "database"); - assert_eq!(with_auth.parameters.get("u").unwrap(), "username"); - assert_eq!(with_auth.parameters.get("p").unwrap(), "password"); + assert_eq!(with_auth.username.unwrap(), "username"); + assert_eq!(with_auth.password.unwrap(), "password"); + + let client = Client::new("http://localhost:8068", "database"); + let with_auth = client.with_token("token"); + assert_eq!(with_auth.parameters.len(), 1); + assert_eq!(with_auth.parameters.get("db").unwrap(), "database"); + assert_eq!(with_auth.token.unwrap(), "token"); } } From cd70338fbf6685fc9c5aec2e134a99a3c0f6223e Mon Sep 17 00:00:00 2001 From: Ning Sun Date: Sun, 14 Mar 2021 00:01:16 +0800 Subject: [PATCH 04/24] (fix) revert changes for v1 username and password --- influxdb/src/client/mod.rs | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/influxdb/src/client/mod.rs b/influxdb/src/client/mod.rs index da98a2e..f96f364 100644 --- a/influxdb/src/client/mod.rs +++ b/influxdb/src/client/mod.rs @@ -34,8 +34,6 @@ use crate::Query; pub struct Client { pub(crate) url: Arc, pub(crate) parameters: Arc>, - pub(crate) username: Option, - pub(crate) password: Option, pub(crate) token: Option, pub(crate) client: HttpClient, } @@ -90,10 +88,8 @@ impl Client { parameters.insert("db", database.into()); Client { url: Arc::new(url.into()), - parameters: Arc::new(parameters), + parameters: Arc::new(parameters), client: HttpClient::new(), - username: None, - password: None, token: None, } } @@ -118,8 +114,10 @@ impl Client { S1: Into, S2: Into, { - self.username = Some(username.into()); - self.password = Some(password.into()); + let mut with_auth = self.parameters.as_ref().clone(); + with_auth.insert("u", username.into()); + with_auth.insert("p", password.into()); + self.parameters = Arc::new(with_auth); self } @@ -235,11 +233,11 @@ impl Client { error: err.to_string(), })?; + let mut parameters = self.parameters.as_ref().clone(); let request_builder = match q.get_type() { QueryType::ReadQuery => { let read_query = query.get(); let url = &format!("{}/query", &self.url); - let mut parameters = self.parameters.as_ref().clone(); parameters.insert("q", read_query.clone()); if read_query.contains("SELECT") || read_query.contains("SHOW") { @@ -262,7 +260,7 @@ impl Client { error: err.to_string(), })?; - let res = self.try_authed(request_builder) + let res = self.auth_if_needed(request_builder) .send() .map_err(|err| Error::ConnectionError { error: err.to_string(), @@ -291,10 +289,8 @@ impl Client { Ok(s) } - fn try_authed(&self, rb: RequestBuilder) -> RequestBuilder { - if let (Some(ref username), Some(ref password)) = (&self.username, &self.password) { - rb.header("Authorization", format!("Basic {}:{}", username, password)) - } else if let Some(ref token) = self.token { + fn auth_if_needed(&self, rb: RequestBuilder) -> RequestBuilder { + if let Some(ref token) = self.token { rb.header("Authorization", format!("Token {}", token)) } else { rb @@ -350,10 +346,10 @@ mod tests { assert_eq!(client.parameters.get("db").unwrap(), "database"); let with_auth = client.with_auth("username", "password"); - assert_eq!(with_auth.parameters.len(), 1); + assert_eq!(with_auth.parameters.len(), 3); assert_eq!(with_auth.parameters.get("db").unwrap(), "database"); - assert_eq!(with_auth.username.unwrap(), "username"); - assert_eq!(with_auth.password.unwrap(), "password"); + assert_eq!(with_auth.parameters.get("u").unwrap(), "username"); + assert_eq!(with_auth.parameters.get("p").unwrap(), "password"); let client = Client::new("http://localhost:8068", "database"); let with_auth = client.with_token("token"); From a89218d5dbf6eb1da87813b175b24562af104337 Mon Sep 17 00:00:00 2001 From: Ning Sun Date: Fri, 19 Mar 2021 23:22:29 +0800 Subject: [PATCH 05/24] (test) use separated integration tests for v1 and v2 --- .github/workflows/rust.yml | 41 +- influxdb/tests/integration_tests_v2.rs | 586 +++++++++++++++++++++++++ 2 files changed, 625 insertions(+), 2 deletions(-) create mode 100644 influxdb/tests/integration_tests_v2.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 4011d52..f5d37d3 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -50,6 +50,22 @@ jobs: - name: Build run: cargo build --verbose + unit_test: + name: Unit test (${{ matrix.rust_release }}/${{ matrix.os }}) + runs-on: ${{ matrix.os }} + strategy: + matrix: + rust_release: [1.45, stable, nightly] + os: [ubuntu-latest, windows-latest, macOS-latest] + + steps: + - uses: actions/checkout@v1 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ matrix.rust_release }} + - name: test + run: cargo test --lib + integration_test: name: Integration Tests (stable/ubuntu-latest) runs-on: ubuntu-latest @@ -71,11 +87,32 @@ jobs: INFLUXDB_ADMIN_PASSWORD: password INFLUXDB_USER: nopriv_user INFLUXDB_USER_PASSWORD: password - steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@stable - - run: cargo test --manifest-path=./influxdb/Cargo.toml --no-default-features --features 'use-serde derive ${{ matrix.http-backend }}' --no-fail-fast + - run: cargo test --manifest-path=./influxdb/Cargo.toml --no-default-features --features 'use-serde derive ${{ matrix.http-backend }}' --no-fail-fast --test integration_tests + + integration_test_v2: + name: Integration Tests (stable/ubuntu-latest) + runs-on: ubuntu-latest + strategy: + matrix: + http-backend: [curl-client, h1-client, h1-client-rustls, hyper-client] + services: + influxdbv2: + image: influxdb:2.0 + ports: + - 8086:8086 + env: + DOCKER_INFLUXDB_INIT_USERNAME: admin + DOCKER_INFLUXDB_INIT_PASSWORD: password + DOCKER_INFLUXDB_INIT_ORG: testing + DOCKER_INFLUXDB_INIT_BUCKET: mydb + DOCKER_INFLUXDB_INIT_ADMIN_TOKEN: admintoken + steps: + - uses: actions/checkout@v1 + - uses: dtolnay/rust-toolchain@stable + - run: cargo test --manifest-path=./influxdb/Cargo.toml --no-default-features --features 'use-serde derive ${{ matrix.http-backend }}' --no-fail-fast --test integration_tests_v2 coverage: name: Code Coverage (stable/ubuntu-latest) diff --git a/influxdb/tests/integration_tests_v2.rs b/influxdb/tests/integration_tests_v2.rs new file mode 100644 index 0000000..9f03fbe --- /dev/null +++ b/influxdb/tests/integration_tests_v2.rs @@ -0,0 +1,586 @@ +extern crate influxdb; + +#[path = "./utilities.rs"] +mod utilities; +use utilities::{ + assert_result_err, assert_result_ok, create_client, create_db, delete_db, run_test, +}; + +use influxdb::InfluxDbWriteable; +use influxdb::{Client, Error, Query, Timestamp}; + +/// INTEGRATION TEST +/// +/// This test case tests whether the InfluxDB server can be connected to and gathers info about it - tested with async_std +#[async_std::test] +#[cfg(not(tarpaulin_include))] +async fn test_ping_influx_db_async_std() { + let client = create_client("notusedhere"); + let result = client.ping().await; + assert_result_ok(&result); + + let (build, version) = result.unwrap(); + assert!(!build.is_empty(), "Build should not be empty"); + assert!(!version.is_empty(), "Build should not be empty"); + + println!("build: {} version: {}", build, version); +} + +/// INTEGRATION TEST +/// +/// This test case tests whether the InfluxDB server can be connected to and gathers info about it * tested with tokio +#[tokio::test] +#[cfg(not(tarpaulin_include))] +async fn test_ping_influx_db_tokio() { + let client = create_client("notusedhere"); + let result = client.ping().await; + assert_result_ok(&result); + + let (build, version) = result.unwrap(); + assert!(!build.is_empty(), "Build should not be empty"); + assert!(!version.is_empty(), "Build should not be empty"); + + println!("build: {} version: {}", build, version); +} + +/// INTEGRATION TEST +/// +/// This test case tests connection error +#[async_std::test] +#[cfg(not(tarpaulin_include))] +async fn test_connection_error() { + let test_name = "test_connection_error"; + let client = Client::new("http://127.0.0.1:10086", test_name).with_token("admintoken"); + let read_query = Query::raw_read_query("SELECT * FROM weather"); + let read_result = client.query(&read_query).await; + assert_result_err(&read_result); + match read_result { + Err(Error::ConnectionError { .. }) => {} + _ => panic!( + "Should cause a ConnectionError: {}", + read_result.unwrap_err() + ), + } +} + +/// INTEGRATION TEST +/// +/// This test case tests the Authentication +#[async_std::test] +#[cfg(not(tarpaulin_include))] +async fn test_authed_write_and_read() { + const TEST_NAME: &str = "test_authed_write_and_read"; + + run_test( + || async move { + let client = Client::new("http://127.0.0.1:9086", TEST_NAME).with_token("admintoken"); + let query = format!("CREATE DATABASE {}", TEST_NAME); + client + .query(&Query::raw_read_query(query)) + .await + .expect("could not setup db"); + + let client = Client::new("http://127.0.0.1:9086", TEST_NAME).with_token("admintoken"); + let write_query = Timestamp::Hours(11) + .into_query("weather") + .add_field("temperature", 82); + let write_result = client.query(&write_query).await; + assert_result_ok(&write_result); + + let read_query = Query::raw_read_query("SELECT * FROM weather"); + let read_result = client.query(&read_query).await; + assert_result_ok(&read_result); + assert!( + !read_result.unwrap().contains("error"), + "Data contained a database error" + ); + }, + || async move { + let client = Client::new("http://127.0.0.1:9086", TEST_NAME).with_token("admintoken"); + let query = format!("DROP DATABASE {}", TEST_NAME); + + client + .query(&Query::raw_read_query(query)) + .await + .expect("could not clean up db"); + }, + ) + .await; +} + +/// INTEGRATION TEST +/// +/// This test case tests the Authentication +#[async_std::test] +#[cfg(not(tarpaulin_include))] +async fn test_wrong_authed_write_and_read() { + const TEST_NAME: &str = "test_wrong_authed_write_and_read"; + + run_test( + || async move { + let client = Client::new("http://127.0.0.1:9086", TEST_NAME).with_token("admintoken"); + let query = format!("CREATE DATABASE {}", TEST_NAME); + client + .query(&Query::raw_read_query(query)) + .await + .expect("could not setup db"); + + let client = Client::new("http://127.0.0.1:9086", TEST_NAME).with_token("falsetoken"); + let write_query = Timestamp::Hours(11) + .into_query("weather") + .add_field("temperature", 82); + let write_result = client.query(&write_query).await; + assert_result_err(&write_result); + match write_result { + Err(Error::AuthorizationError) => {} + _ => panic!( + "Should be an AuthorizationError: {}", + write_result.unwrap_err() + ), + } + + let read_query = Query::raw_read_query("SELECT * FROM weather"); + let read_result = client.query(&read_query).await; + assert_result_err(&read_result); + match read_result { + Err(Error::AuthorizationError) => {} + _ => panic!( + "Should be an AuthorizationError: {}", + read_result.unwrap_err() + ), + } + + let client = Client::new("http://127.0.0.1:9086", TEST_NAME) + .with_auth("nopriv_user", "password"); + let read_query = Query::raw_read_query("SELECT * FROM weather"); + let read_result = client.query(&read_query).await; + assert_result_err(&read_result); + match read_result { + Err(Error::AuthenticationError) => {} + _ => panic!( + "Should be an AuthenticationError: {}", + read_result.unwrap_err() + ), + } + }, + || async move { + let client = Client::new("http://127.0.0.1:9086", TEST_NAME).with_token("admintoken"); + let query = format!("DROP DATABASE {}", TEST_NAME); + client + .query(&Query::raw_read_query(query)) + .await + .expect("could not clean up db"); + }, + ) + .await; +} + +/// INTEGRATION TEST +/// +/// This test case tests the Authentication +#[async_std::test] +#[cfg(not(tarpaulin_include))] +async fn test_non_authed_write_and_read() { + const TEST_NAME: &str = "test_non_authed_write_and_read"; + + run_test( + || async move { + let client = Client::new("http://127.0.0.1:9086", TEST_NAME).with_token("admintoken"); + let query = format!("CREATE DATABASE {}", TEST_NAME); + client + .query(&Query::raw_read_query(query)) + .await + .expect("could not setup db"); + let non_authed_client = Client::new("http://127.0.0.1:9086", TEST_NAME); + let write_query = Timestamp::Hours(11) + .into_query("weather") + .add_field("temperature", 82); + let write_result = non_authed_client.query(&write_query).await; + assert_result_err(&write_result); + match write_result { + Err(Error::AuthorizationError) => {} + _ => panic!( + "Should be an AuthorizationError: {}", + write_result.unwrap_err() + ), + } + + let read_query = Query::raw_read_query("SELECT * FROM weather"); + let read_result = non_authed_client.query(&read_query).await; + assert_result_err(&read_result); + match read_result { + Err(Error::AuthorizationError) => {} + _ => panic!( + "Should be an AuthorizationError: {}", + read_result.unwrap_err() + ), + } + }, + || async move { + let client = Client::new("http://127.0.0.1:9086", TEST_NAME).with_token("admintoken"); + let query = format!("DROP DATABASE {}", TEST_NAME); + client + .query(&Query::raw_read_query(query)) + .await + .expect("could not clean up db"); + }, + ) + .await; +} + +/// INTEGRATION TEST +/// +/// This integration tests that writing data and retrieving the data again is working +#[async_std::test] +#[cfg(not(tarpaulin_include))] +async fn test_write_and_read_field() { + const TEST_NAME: &str = "test_write_field"; + + run_test( + || async move { + create_db(TEST_NAME).await.expect("could not setup db"); + let client = create_client(TEST_NAME); + let write_query = Timestamp::Hours(11) + .into_query("weather") + .add_field("temperature", 82); + let write_result = client.query(&write_query).await; + assert_result_ok(&write_result); + + let read_query = Query::raw_read_query("SELECT * FROM weather"); + let read_result = client.query(&read_query).await; + assert_result_ok(&read_result); + assert!( + !read_result.unwrap().contains("error"), + "Data contained a database error" + ); + }, + || async move { + delete_db(TEST_NAME).await.expect("could not clean up db"); + }, + ) + .await; +} + +/// INTEGRATION TEST +/// +/// This integration tests that writing data and retrieving the data again is working +#[async_std::test] +#[cfg(feature = "use-serde")] +#[cfg(not(tarpaulin_include))] +async fn test_write_and_read_option() { + use serde::Deserialize; + + const TEST_NAME: &str = "test_write_and_read_option"; + + run_test( + || { + async move { + create_db(TEST_NAME).await.expect("could not setup db"); + + let client = create_client(TEST_NAME); + // Todo: Convert this to derive based insert for easier comparison of structs + let write_query = Timestamp::Hours(11) + .into_query("weather") + .add_field("temperature", 82) + .add_field("wind_strength", >::None); + let write_result = client.query(&write_query).await; + assert_result_ok(&write_result); + + #[derive(Deserialize, Debug, PartialEq)] + struct Weather { + time: String, + // different order to verify field names + // are being used instead of just order + wind_strength: Option, + temperature: i32, + } + + let query = + Query::raw_read_query("SELECT time, temperature, wind_strength FROM weather"); + let result = client + .json_query(query) + .await + .and_then(|mut db_result| db_result.deserialize_next::()); + assert_result_ok(&result); + + assert_eq!( + result.unwrap().series[0].values[0], + Weather { + time: "1970-01-01T11:00:00Z".to_string(), + temperature: 82, + wind_strength: None, + } + ); + } + }, + || async move { + delete_db("test_write_and_read_option") + .await + .expect("could not clean up db"); + }, + ) + .await; +} + +/// INTEGRATION TEST +/// +/// This test case tests whether JSON can be decoded from a InfluxDB response and whether that JSON +/// is equal to the data which was written to the database +#[async_std::test] +#[cfg(feature = "use-serde")] +#[cfg(not(tarpaulin_include))] +async fn test_json_query() { + use serde::Deserialize; + + const TEST_NAME: &str = "test_json_query"; + + run_test( + || async move { + create_db(TEST_NAME).await.expect("could not setup db"); + + let client = create_client(TEST_NAME); + + let write_query = Timestamp::Hours(11) + .into_query("weather") + .add_field("temperature", 82); + let write_result = client.query(&write_query).await; + assert_result_ok(&write_result); + + #[derive(Deserialize, Debug, PartialEq)] + struct Weather { + time: String, + temperature: i32, + } + + let query = Query::raw_read_query("SELECT * FROM weather"); + let result = client + .json_query(query) + .await + .and_then(|mut db_result| db_result.deserialize_next::()); + assert_result_ok(&result); + + assert_eq!( + result.unwrap().series[0].values[0], + Weather { + time: "1970-01-01T11:00:00Z".to_string(), + temperature: 82 + } + ); + }, + || async move { + delete_db(TEST_NAME).await.expect("could not clean up db"); + }, + ) + .await; +} + +/// INTEGRATION TEST +/// +/// This test case tests whether the response to a GROUP BY can be parsed by +// deserialize_next_tagged into a tags struct +#[async_std::test] +#[cfg(feature = "use-serde")] +#[cfg(not(tarpaulin_include))] +async fn test_json_query_tagged() { + use serde::Deserialize; + + const TEST_NAME: &str = "test_json_query_tagged"; + + run_test( + || async move { + create_db(TEST_NAME).await.expect("could not setup db"); + + let client = create_client(TEST_NAME); + + let write_query = Timestamp::Hours(11) + .into_query("weather") + .add_tag("location", "London") + .add_field("temperature", 82); + let write_result = client.query(&write_query).await; + assert_result_ok(&write_result); + + #[derive(Deserialize, Debug, PartialEq)] + struct WeatherMeta { + location: String, + } + + #[derive(Deserialize, Debug, PartialEq)] + struct Weather { + time: String, + temperature: i32, + } + + let query = Query::raw_read_query("SELECT * FROM weather GROUP BY location"); + let result = client.json_query(query).await.and_then(|mut db_result| { + db_result.deserialize_next_tagged::() + }); + assert_result_ok(&result); + let result = result.unwrap(); + + assert_eq!( + result.series[0].tags, + WeatherMeta { + location: "London".to_string(), + } + ); + assert_eq!( + result.series[0].values[0], + Weather { + time: "1970-01-01T11:00:00Z".to_string(), + temperature: 82 + } + ); + }, + || async move { + delete_db(TEST_NAME).await.expect("could not clean up db"); + }, + ) + .await; +} + +/// INTEGRATION TEST +/// +/// This test case tests whether JSON can be decoded from a InfluxDB response and wether that JSON +/// is equal to the data which was written to the database +/// (tested with tokio) +#[tokio::test] +#[cfg(feature = "use-serde")] +#[cfg(not(tarpaulin_include))] +async fn test_json_query_vec() { + use serde::Deserialize; + + const TEST_NAME: &str = "test_json_query_vec"; + + run_test( + || async move { + create_db(TEST_NAME).await.expect("could not setup db"); + + let client = create_client(TEST_NAME); + let write_query1 = Timestamp::Hours(11) + .into_query("temperature_vec") + .add_field("temperature", 16); + let write_query2 = Timestamp::Hours(12) + .into_query("temperature_vec") + .add_field("temperature", 17); + let write_query3 = Timestamp::Hours(13) + .into_query("temperature_vec") + .add_field("temperature", 18); + + let _write_result = client.query(&write_query1).await; + let _write_result2 = client.query(&write_query2).await; + let _write_result2 = client.query(&write_query3).await; + + #[derive(Deserialize, Debug, PartialEq)] + struct Weather { + time: String, + temperature: i32, + } + + let query = Query::raw_read_query("SELECT * FROM temperature_vec"); + let result = client + .json_query(query) + .await + .and_then(|mut db_result| db_result.deserialize_next::()); + assert_result_ok(&result); + assert_eq!(result.unwrap().series[0].values.len(), 3); + }, + || async move { + delete_db(TEST_NAME).await.expect("could not clean up db"); + }, + ) + .await; +} + +/// INTEGRATION TEST +/// +/// This integration test tests whether using the wrong query method fails building the query +#[async_std::test] +#[cfg(feature = "use-serde")] +#[cfg(not(tarpaulin_include))] +async fn test_serde_multi_query() { + use serde::Deserialize; + + const TEST_NAME: &str = "test_serde_multi_query"; + + run_test( + || async move { + create_db(TEST_NAME).await.expect("could not setup db"); + + #[derive(Deserialize, Debug, PartialEq)] + struct Temperature { + time: String, + temperature: i32, + } + + #[derive(Deserialize, Debug, PartialEq)] + struct Humidity { + time: String, + humidity: i32, + } + + let client = create_client(TEST_NAME); + let write_query = Timestamp::Hours(11) + .into_query("temperature") + .add_field("temperature", 16); + let write_query2 = Timestamp::Hours(11) + .into_query("humidity") + .add_field("humidity", 69); + + let write_result = client.query(&write_query).await; + let write_result2 = client.query(&write_query2).await; + assert_result_ok(&write_result); + assert_result_ok(&write_result2); + + let result = client + .json_query( + Query::raw_read_query("SELECT * FROM temperature") + .add_query("SELECT * FROM humidity"), + ) + .await + .and_then(|mut db_result| { + let temp = db_result.deserialize_next::()?; + let humidity = db_result.deserialize_next::()?; + + Ok((temp, humidity)) + }); + assert_result_ok(&result); + + let (temp, humidity) = result.unwrap(); + assert_eq!( + temp.series[0].values[0], + Temperature { + time: "1970-01-01T11:00:00Z".to_string(), + temperature: 16 + }, + ); + assert_eq!( + humidity.series[0].values[0], + Humidity { + time: "1970-01-01T11:00:00Z".to_string(), + humidity: 69 + } + ); + }, + || async move { + delete_db(TEST_NAME).await.expect("could not clean up db"); + }, + ) + .await; +} + +/// INTEGRATION TEST +/// +/// This integration test tests whether using the wrong query method fails building the query +#[async_std::test] +#[cfg(feature = "use-serde")] +#[cfg(not(tarpaulin_include))] +async fn test_wrong_query_errors() { + let client = create_client("test_name"); + let result = client + .json_query(Query::raw_read_query("CREATE DATABASE this_should_fail")) + .await; + assert!( + result.is_err(), + "Should only build SELECT and SHOW queries." + ); +} From bd68980625d7e9bd6e0117f4f2e600ea4825cca3 Mon Sep 17 00:00:00 2001 From: Ning Sun Date: Fri, 19 Mar 2021 23:41:46 +0800 Subject: [PATCH 06/24] (fix) fix lint issues --- .github/workflows/rust.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index f5d37d3..23353a0 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -67,7 +67,7 @@ jobs: run: cargo test --lib integration_test: - name: Integration Tests (stable/ubuntu-latest) + name: Integration Tests for Influxdb 1.x (stable/ubuntu-latest) runs-on: ubuntu-latest strategy: matrix: @@ -93,7 +93,7 @@ jobs: - run: cargo test --manifest-path=./influxdb/Cargo.toml --no-default-features --features 'use-serde derive ${{ matrix.http-backend }}' --no-fail-fast --test integration_tests integration_test_v2: - name: Integration Tests (stable/ubuntu-latest) + name: Integration Tests for Influxdb 2.0 (stable/ubuntu-latest) runs-on: ubuntu-latest strategy: matrix: From d0a8c38c86ae2382db585f18ac16ecff83937a3e Mon Sep 17 00:00:00 2001 From: Ning Sun Date: Sat, 27 Mar 2021 21:05:22 +0800 Subject: [PATCH 07/24] (test) fix port error in integration test v2 --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 23353a0..4162183 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -102,7 +102,7 @@ jobs: influxdbv2: image: influxdb:2.0 ports: - - 8086:8086 + - 9086:8086 env: DOCKER_INFLUXDB_INIT_USERNAME: admin DOCKER_INFLUXDB_INIT_PASSWORD: password From 41fe7f8e40935df8056c8aca531e6609e58f5ba6 Mon Sep 17 00:00:00 2001 From: Ning Sun Date: Sat, 27 Mar 2021 21:12:22 +0800 Subject: [PATCH 08/24] (fix) clippy error --- influxdb/tests/integration_tests.rs | 1 + influxdb/tests/integration_tests_v2.rs | 45 ++++++++++++++------------ 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/influxdb/tests/integration_tests.rs b/influxdb/tests/integration_tests.rs index ca6979f..be75b06 100644 --- a/influxdb/tests/integration_tests.rs +++ b/influxdb/tests/integration_tests.rs @@ -215,6 +215,7 @@ async fn test_non_authed_write_and_read() { let read_query = ReadQuery::new("SELECT * FROM weather"); let read_result = non_authed_client.query(read_query).await; + assert_result_err(&read_result); match read_result { Err(Error::AuthorizationError) => {} diff --git a/influxdb/tests/integration_tests_v2.rs b/influxdb/tests/integration_tests_v2.rs index 9f03fbe..7aca3c3 100644 --- a/influxdb/tests/integration_tests_v2.rs +++ b/influxdb/tests/integration_tests_v2.rs @@ -7,7 +7,7 @@ use utilities::{ }; use influxdb::InfluxDbWriteable; -use influxdb::{Client, Error, Query, Timestamp}; +use influxdb::{Client, Error, ReadQuery, Timestamp}; /// INTEGRATION TEST /// @@ -51,7 +51,7 @@ async fn test_ping_influx_db_tokio() { async fn test_connection_error() { let test_name = "test_connection_error"; let client = Client::new("http://127.0.0.1:10086", test_name).with_token("admintoken"); - let read_query = Query::raw_read_query("SELECT * FROM weather"); + let read_query = ReadQuery::new("SELECT * FROM weather"); let read_result = client.query(&read_query).await; assert_result_err(&read_result); match read_result { @@ -76,7 +76,7 @@ async fn test_authed_write_and_read() { let client = Client::new("http://127.0.0.1:9086", TEST_NAME).with_token("admintoken"); let query = format!("CREATE DATABASE {}", TEST_NAME); client - .query(&Query::raw_read_query(query)) + .query(ReadQuery::new(query)) .await .expect("could not setup db"); @@ -87,8 +87,8 @@ async fn test_authed_write_and_read() { let write_result = client.query(&write_query).await; assert_result_ok(&write_result); - let read_query = Query::raw_read_query("SELECT * FROM weather"); - let read_result = client.query(&read_query).await; + let read_query = ReadQuery::new("SELECT * FROM weather"); + let read_result = client.query(read_query).await; assert_result_ok(&read_result); assert!( !read_result.unwrap().contains("error"), @@ -100,7 +100,7 @@ async fn test_authed_write_and_read() { let query = format!("DROP DATABASE {}", TEST_NAME); client - .query(&Query::raw_read_query(query)) + .query(ReadQuery::new(query)) .await .expect("could not clean up db"); }, @@ -121,7 +121,7 @@ async fn test_wrong_authed_write_and_read() { let client = Client::new("http://127.0.0.1:9086", TEST_NAME).with_token("admintoken"); let query = format!("CREATE DATABASE {}", TEST_NAME); client - .query(&Query::raw_read_query(query)) + .query(ReadQuery::new(query)) .await .expect("could not setup db"); @@ -139,7 +139,7 @@ async fn test_wrong_authed_write_and_read() { ), } - let read_query = Query::raw_read_query("SELECT * FROM weather"); + let read_query = ReadQuery::new("SELECT * FROM weather"); let read_result = client.query(&read_query).await; assert_result_err(&read_result); match read_result { @@ -152,7 +152,7 @@ async fn test_wrong_authed_write_and_read() { let client = Client::new("http://127.0.0.1:9086", TEST_NAME) .with_auth("nopriv_user", "password"); - let read_query = Query::raw_read_query("SELECT * FROM weather"); + let read_query = ReadQuery::new("SELECT * FROM weather"); let read_result = client.query(&read_query).await; assert_result_err(&read_result); match read_result { @@ -167,7 +167,7 @@ async fn test_wrong_authed_write_and_read() { let client = Client::new("http://127.0.0.1:9086", TEST_NAME).with_token("admintoken"); let query = format!("DROP DATABASE {}", TEST_NAME); client - .query(&Query::raw_read_query(query)) + .query(ReadQuery::new(query)) .await .expect("could not clean up db"); }, @@ -188,7 +188,7 @@ async fn test_non_authed_write_and_read() { let client = Client::new("http://127.0.0.1:9086", TEST_NAME).with_token("admintoken"); let query = format!("CREATE DATABASE {}", TEST_NAME); client - .query(&Query::raw_read_query(query)) + .query(ReadQuery::new(query)) .await .expect("could not setup db"); let non_authed_client = Client::new("http://127.0.0.1:9086", TEST_NAME); @@ -205,7 +205,7 @@ async fn test_non_authed_write_and_read() { ), } - let read_query = Query::raw_read_query("SELECT * FROM weather"); + let read_query = ReadQuery::new("SELECT * FROM weather"); let read_result = non_authed_client.query(&read_query).await; assert_result_err(&read_result); match read_result { @@ -220,7 +220,7 @@ async fn test_non_authed_write_and_read() { let client = Client::new("http://127.0.0.1:9086", TEST_NAME).with_token("admintoken"); let query = format!("DROP DATABASE {}", TEST_NAME); client - .query(&Query::raw_read_query(query)) + .query(ReadQuery::new(query)) .await .expect("could not clean up db"); }, @@ -246,7 +246,7 @@ async fn test_write_and_read_field() { let write_result = client.query(&write_query).await; assert_result_ok(&write_result); - let read_query = Query::raw_read_query("SELECT * FROM weather"); + let read_query = ReadQuery::new("SELECT * FROM weather"); let read_result = client.query(&read_query).await; assert_result_ok(&read_result); assert!( @@ -295,8 +295,9 @@ async fn test_write_and_read_option() { temperature: i32, } - let query = - Query::raw_read_query("SELECT time, temperature, wind_strength FROM weather"); + let query = ReadQuery::new( + "SELECT time, temperature, wind_strength FROM weather", + ); let result = client .json_query(query) .await @@ -352,7 +353,7 @@ async fn test_json_query() { temperature: i32, } - let query = Query::raw_read_query("SELECT * FROM weather"); + let query = ReadQuery::new("SELECT * FROM weather"); let result = client .json_query(query) .await @@ -410,7 +411,7 @@ async fn test_json_query_tagged() { temperature: i32, } - let query = Query::raw_read_query("SELECT * FROM weather GROUP BY location"); + let query = ReadQuery::new("SELECT * FROM weather GROUP BY location"); let result = client.json_query(query).await.and_then(|mut db_result| { db_result.deserialize_next_tagged::() }); @@ -476,7 +477,7 @@ async fn test_json_query_vec() { temperature: i32, } - let query = Query::raw_read_query("SELECT * FROM temperature_vec"); + let query = ReadQuery::new("SELECT * FROM temperature_vec"); let result = client .json_query(query) .await @@ -533,7 +534,7 @@ async fn test_serde_multi_query() { let result = client .json_query( - Query::raw_read_query("SELECT * FROM temperature") + ReadQuery::new("SELECT * FROM temperature") .add_query("SELECT * FROM humidity"), ) .await @@ -577,7 +578,9 @@ async fn test_serde_multi_query() { async fn test_wrong_query_errors() { let client = create_client("test_name"); let result = client - .json_query(Query::raw_read_query("CREATE DATABASE this_should_fail")) + .json_query(ReadQuery::new( + "CREATE DATABASE this_should_fail", + )) .await; assert!( result.is_err(), From fbeda3159e753cc4f24fb258e595e8b7e9e0fc7d Mon Sep 17 00:00:00 2001 From: Ning Sun Date: Sat, 27 Mar 2021 21:35:40 +0800 Subject: [PATCH 09/24] (fix) update minimal rust version to 1.46 as socket2 requires --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 4162183..5eca8a8 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -55,7 +55,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - rust_release: [1.45, stable, nightly] + rust_release: [1.46, stable, nightly] os: [ubuntu-latest, windows-latest, macOS-latest] steps: From ea2bf8938d95aaa521a9533ca9f34e19c4646f3d Mon Sep 17 00:00:00 2001 From: Ning Sun Date: Sat, 27 Mar 2021 21:42:22 +0800 Subject: [PATCH 10/24] (fix) clippy error --- influxdb/tests/derive_integration_tests.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/influxdb/tests/derive_integration_tests.rs b/influxdb/tests/derive_integration_tests.rs index 258aef4..7167aa6 100644 --- a/influxdb/tests/derive_integration_tests.rs +++ b/influxdb/tests/derive_integration_tests.rs @@ -101,6 +101,7 @@ async fn test_write_and_read_option() { .query(&weather_reading.into_query("weather_reading".to_string())) .await; assert_result_ok(&write_result); + let query = ReadQuery::new("SELECT time, pressure, wind_strength FROM weather_reading"); let result = client.json_query(query).await.and_then(|mut db_result| { println!("{:?}", db_result); From 1f901ed022ae3e2e2ed146cfff57780336ee2b94 Mon Sep 17 00:00:00 2001 From: Ning Sun Date: Sat, 27 Mar 2021 21:46:13 +0800 Subject: [PATCH 11/24] (test) remove test that was duplicated in v2 --- influxdb/tests/integration_tests_v2.rs | 364 +------------------------ 1 file changed, 1 insertion(+), 363 deletions(-) diff --git a/influxdb/tests/integration_tests_v2.rs b/influxdb/tests/integration_tests_v2.rs index 7aca3c3..faea7f7 100644 --- a/influxdb/tests/integration_tests_v2.rs +++ b/influxdb/tests/integration_tests_v2.rs @@ -2,9 +2,7 @@ extern crate influxdb; #[path = "./utilities.rs"] mod utilities; -use utilities::{ - assert_result_err, assert_result_ok, create_client, create_db, delete_db, run_test, -}; +use utilities::{assert_result_err, assert_result_ok, create_client, run_test}; use influxdb::InfluxDbWriteable; use influxdb::{Client, Error, ReadQuery, Timestamp}; @@ -227,363 +225,3 @@ async fn test_non_authed_write_and_read() { ) .await; } - -/// INTEGRATION TEST -/// -/// This integration tests that writing data and retrieving the data again is working -#[async_std::test] -#[cfg(not(tarpaulin_include))] -async fn test_write_and_read_field() { - const TEST_NAME: &str = "test_write_field"; - - run_test( - || async move { - create_db(TEST_NAME).await.expect("could not setup db"); - let client = create_client(TEST_NAME); - let write_query = Timestamp::Hours(11) - .into_query("weather") - .add_field("temperature", 82); - let write_result = client.query(&write_query).await; - assert_result_ok(&write_result); - - let read_query = ReadQuery::new("SELECT * FROM weather"); - let read_result = client.query(&read_query).await; - assert_result_ok(&read_result); - assert!( - !read_result.unwrap().contains("error"), - "Data contained a database error" - ); - }, - || async move { - delete_db(TEST_NAME).await.expect("could not clean up db"); - }, - ) - .await; -} - -/// INTEGRATION TEST -/// -/// This integration tests that writing data and retrieving the data again is working -#[async_std::test] -#[cfg(feature = "use-serde")] -#[cfg(not(tarpaulin_include))] -async fn test_write_and_read_option() { - use serde::Deserialize; - - const TEST_NAME: &str = "test_write_and_read_option"; - - run_test( - || { - async move { - create_db(TEST_NAME).await.expect("could not setup db"); - - let client = create_client(TEST_NAME); - // Todo: Convert this to derive based insert for easier comparison of structs - let write_query = Timestamp::Hours(11) - .into_query("weather") - .add_field("temperature", 82) - .add_field("wind_strength", >::None); - let write_result = client.query(&write_query).await; - assert_result_ok(&write_result); - - #[derive(Deserialize, Debug, PartialEq)] - struct Weather { - time: String, - // different order to verify field names - // are being used instead of just order - wind_strength: Option, - temperature: i32, - } - - let query = ReadQuery::new( - "SELECT time, temperature, wind_strength FROM weather", - ); - let result = client - .json_query(query) - .await - .and_then(|mut db_result| db_result.deserialize_next::()); - assert_result_ok(&result); - - assert_eq!( - result.unwrap().series[0].values[0], - Weather { - time: "1970-01-01T11:00:00Z".to_string(), - temperature: 82, - wind_strength: None, - } - ); - } - }, - || async move { - delete_db("test_write_and_read_option") - .await - .expect("could not clean up db"); - }, - ) - .await; -} - -/// INTEGRATION TEST -/// -/// This test case tests whether JSON can be decoded from a InfluxDB response and whether that JSON -/// is equal to the data which was written to the database -#[async_std::test] -#[cfg(feature = "use-serde")] -#[cfg(not(tarpaulin_include))] -async fn test_json_query() { - use serde::Deserialize; - - const TEST_NAME: &str = "test_json_query"; - - run_test( - || async move { - create_db(TEST_NAME).await.expect("could not setup db"); - - let client = create_client(TEST_NAME); - - let write_query = Timestamp::Hours(11) - .into_query("weather") - .add_field("temperature", 82); - let write_result = client.query(&write_query).await; - assert_result_ok(&write_result); - - #[derive(Deserialize, Debug, PartialEq)] - struct Weather { - time: String, - temperature: i32, - } - - let query = ReadQuery::new("SELECT * FROM weather"); - let result = client - .json_query(query) - .await - .and_then(|mut db_result| db_result.deserialize_next::()); - assert_result_ok(&result); - - assert_eq!( - result.unwrap().series[0].values[0], - Weather { - time: "1970-01-01T11:00:00Z".to_string(), - temperature: 82 - } - ); - }, - || async move { - delete_db(TEST_NAME).await.expect("could not clean up db"); - }, - ) - .await; -} - -/// INTEGRATION TEST -/// -/// This test case tests whether the response to a GROUP BY can be parsed by -// deserialize_next_tagged into a tags struct -#[async_std::test] -#[cfg(feature = "use-serde")] -#[cfg(not(tarpaulin_include))] -async fn test_json_query_tagged() { - use serde::Deserialize; - - const TEST_NAME: &str = "test_json_query_tagged"; - - run_test( - || async move { - create_db(TEST_NAME).await.expect("could not setup db"); - - let client = create_client(TEST_NAME); - - let write_query = Timestamp::Hours(11) - .into_query("weather") - .add_tag("location", "London") - .add_field("temperature", 82); - let write_result = client.query(&write_query).await; - assert_result_ok(&write_result); - - #[derive(Deserialize, Debug, PartialEq)] - struct WeatherMeta { - location: String, - } - - #[derive(Deserialize, Debug, PartialEq)] - struct Weather { - time: String, - temperature: i32, - } - - let query = ReadQuery::new("SELECT * FROM weather GROUP BY location"); - let result = client.json_query(query).await.and_then(|mut db_result| { - db_result.deserialize_next_tagged::() - }); - assert_result_ok(&result); - let result = result.unwrap(); - - assert_eq!( - result.series[0].tags, - WeatherMeta { - location: "London".to_string(), - } - ); - assert_eq!( - result.series[0].values[0], - Weather { - time: "1970-01-01T11:00:00Z".to_string(), - temperature: 82 - } - ); - }, - || async move { - delete_db(TEST_NAME).await.expect("could not clean up db"); - }, - ) - .await; -} - -/// INTEGRATION TEST -/// -/// This test case tests whether JSON can be decoded from a InfluxDB response and wether that JSON -/// is equal to the data which was written to the database -/// (tested with tokio) -#[tokio::test] -#[cfg(feature = "use-serde")] -#[cfg(not(tarpaulin_include))] -async fn test_json_query_vec() { - use serde::Deserialize; - - const TEST_NAME: &str = "test_json_query_vec"; - - run_test( - || async move { - create_db(TEST_NAME).await.expect("could not setup db"); - - let client = create_client(TEST_NAME); - let write_query1 = Timestamp::Hours(11) - .into_query("temperature_vec") - .add_field("temperature", 16); - let write_query2 = Timestamp::Hours(12) - .into_query("temperature_vec") - .add_field("temperature", 17); - let write_query3 = Timestamp::Hours(13) - .into_query("temperature_vec") - .add_field("temperature", 18); - - let _write_result = client.query(&write_query1).await; - let _write_result2 = client.query(&write_query2).await; - let _write_result2 = client.query(&write_query3).await; - - #[derive(Deserialize, Debug, PartialEq)] - struct Weather { - time: String, - temperature: i32, - } - - let query = ReadQuery::new("SELECT * FROM temperature_vec"); - let result = client - .json_query(query) - .await - .and_then(|mut db_result| db_result.deserialize_next::()); - assert_result_ok(&result); - assert_eq!(result.unwrap().series[0].values.len(), 3); - }, - || async move { - delete_db(TEST_NAME).await.expect("could not clean up db"); - }, - ) - .await; -} - -/// INTEGRATION TEST -/// -/// This integration test tests whether using the wrong query method fails building the query -#[async_std::test] -#[cfg(feature = "use-serde")] -#[cfg(not(tarpaulin_include))] -async fn test_serde_multi_query() { - use serde::Deserialize; - - const TEST_NAME: &str = "test_serde_multi_query"; - - run_test( - || async move { - create_db(TEST_NAME).await.expect("could not setup db"); - - #[derive(Deserialize, Debug, PartialEq)] - struct Temperature { - time: String, - temperature: i32, - } - - #[derive(Deserialize, Debug, PartialEq)] - struct Humidity { - time: String, - humidity: i32, - } - - let client = create_client(TEST_NAME); - let write_query = Timestamp::Hours(11) - .into_query("temperature") - .add_field("temperature", 16); - let write_query2 = Timestamp::Hours(11) - .into_query("humidity") - .add_field("humidity", 69); - - let write_result = client.query(&write_query).await; - let write_result2 = client.query(&write_query2).await; - assert_result_ok(&write_result); - assert_result_ok(&write_result2); - - let result = client - .json_query( - ReadQuery::new("SELECT * FROM temperature") - .add_query("SELECT * FROM humidity"), - ) - .await - .and_then(|mut db_result| { - let temp = db_result.deserialize_next::()?; - let humidity = db_result.deserialize_next::()?; - - Ok((temp, humidity)) - }); - assert_result_ok(&result); - - let (temp, humidity) = result.unwrap(); - assert_eq!( - temp.series[0].values[0], - Temperature { - time: "1970-01-01T11:00:00Z".to_string(), - temperature: 16 - }, - ); - assert_eq!( - humidity.series[0].values[0], - Humidity { - time: "1970-01-01T11:00:00Z".to_string(), - humidity: 69 - } - ); - }, - || async move { - delete_db(TEST_NAME).await.expect("could not clean up db"); - }, - ) - .await; -} - -/// INTEGRATION TEST -/// -/// This integration test tests whether using the wrong query method fails building the query -#[async_std::test] -#[cfg(feature = "use-serde")] -#[cfg(not(tarpaulin_include))] -async fn test_wrong_query_errors() { - let client = create_client("test_name"); - let result = client - .json_query(ReadQuery::new( - "CREATE DATABASE this_should_fail", - )) - .await; - assert!( - result.is_err(), - "Should only build SELECT and SHOW queries." - ); -} From f27edb43b2b910d79fff3eab71aebf9bfa663f09 Mon Sep 17 00:00:00 2001 From: Ning Sun Date: Sat, 27 Mar 2021 21:51:36 +0800 Subject: [PATCH 12/24] (fix) clippy warnings --- influxdb/tests/utilities.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/influxdb/tests/utilities.rs b/influxdb/tests/utilities.rs index ced7f89..0ec0524 100644 --- a/influxdb/tests/utilities.rs +++ b/influxdb/tests/utilities.rs @@ -22,6 +22,7 @@ where Client::new("http://127.0.0.1:8086", db_name) } +#[allow(dead_code)] #[cfg(not(tarpaulin_include))] pub async fn create_db(name: T) -> Result where @@ -32,6 +33,7 @@ where create_client(test_name).query(ReadQuery::new(query)).await } +#[allow(dead_code)] #[cfg(not(tarpaulin_include))] pub async fn delete_db(name: T) -> Result where From 9e176c11011f592ba1c0e4989a0b67d368d705f1 Mon Sep 17 00:00:00 2001 From: Ning Sun Date: Sat, 27 Mar 2021 21:53:33 +0800 Subject: [PATCH 13/24] (test) remove unneeded v2 tests --- influxdb/tests/integration_tests_v2.rs | 55 +------------------------- influxdb/tests/utilities.rs | 1 + 2 files changed, 2 insertions(+), 54 deletions(-) diff --git a/influxdb/tests/integration_tests_v2.rs b/influxdb/tests/integration_tests_v2.rs index faea7f7..944e581 100644 --- a/influxdb/tests/integration_tests_v2.rs +++ b/influxdb/tests/integration_tests_v2.rs @@ -2,67 +2,14 @@ extern crate influxdb; #[path = "./utilities.rs"] mod utilities; -use utilities::{assert_result_err, assert_result_ok, create_client, run_test}; +use utilities::{assert_result_err, assert_result_ok, run_test}; use influxdb::InfluxDbWriteable; use influxdb::{Client, Error, ReadQuery, Timestamp}; /// INTEGRATION TEST /// -/// This test case tests whether the InfluxDB server can be connected to and gathers info about it - tested with async_std -#[async_std::test] -#[cfg(not(tarpaulin_include))] -async fn test_ping_influx_db_async_std() { - let client = create_client("notusedhere"); - let result = client.ping().await; - assert_result_ok(&result); - - let (build, version) = result.unwrap(); - assert!(!build.is_empty(), "Build should not be empty"); - assert!(!version.is_empty(), "Build should not be empty"); - - println!("build: {} version: {}", build, version); -} - -/// INTEGRATION TEST -/// -/// This test case tests whether the InfluxDB server can be connected to and gathers info about it * tested with tokio -#[tokio::test] -#[cfg(not(tarpaulin_include))] -async fn test_ping_influx_db_tokio() { - let client = create_client("notusedhere"); - let result = client.ping().await; - assert_result_ok(&result); - - let (build, version) = result.unwrap(); - assert!(!build.is_empty(), "Build should not be empty"); - assert!(!version.is_empty(), "Build should not be empty"); - println!("build: {} version: {}", build, version); -} - -/// INTEGRATION TEST -/// -/// This test case tests connection error -#[async_std::test] -#[cfg(not(tarpaulin_include))] -async fn test_connection_error() { - let test_name = "test_connection_error"; - let client = Client::new("http://127.0.0.1:10086", test_name).with_token("admintoken"); - let read_query = ReadQuery::new("SELECT * FROM weather"); - let read_result = client.query(&read_query).await; - assert_result_err(&read_result); - match read_result { - Err(Error::ConnectionError { .. }) => {} - _ => panic!( - "Should cause a ConnectionError: {}", - read_result.unwrap_err() - ), - } -} - -/// INTEGRATION TEST -/// /// This test case tests the Authentication #[async_std::test] #[cfg(not(tarpaulin_include))] diff --git a/influxdb/tests/utilities.rs b/influxdb/tests/utilities.rs index 0ec0524..8b3d5a7 100644 --- a/influxdb/tests/utilities.rs +++ b/influxdb/tests/utilities.rs @@ -14,6 +14,7 @@ pub fn assert_result_ok(result: &Result< result.as_ref().expect("assert_result_ok failed"); } +#[allow(dead_code)] #[cfg(not(tarpaulin_include))] pub fn create_client(db_name: T) -> Client where From f2048aca306a00749bfb3b10cf10b64e6ee4f3c2 Mon Sep 17 00:00:00 2001 From: Vladimir Shakhov Date: Tue, 21 Feb 2023 20:50:09 +0100 Subject: [PATCH 14/24] package `rustls v0.20.8` requires rustc 1.57 or newer --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 5eca8a8..3ec3b71 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -39,7 +39,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - rust_release: ["1.56", stable, nightly] + rust_release: ["1.57", stable, nightly] os: [ubuntu-latest, windows-latest, macOS-latest] steps: From 89d37260e3b68559db21a50c5e1face3993e9317 Mon Sep 17 00:00:00 2001 From: Vladimir Shakhov Date: Tue, 21 Feb 2023 20:56:04 +0100 Subject: [PATCH 15/24] cargo fmt --- influxdb/src/client/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/influxdb/src/client/mod.rs b/influxdb/src/client/mod.rs index f96f364..e391708 100644 --- a/influxdb/src/client/mod.rs +++ b/influxdb/src/client/mod.rs @@ -88,7 +88,7 @@ impl Client { parameters.insert("db", database.into()); Client { url: Arc::new(url.into()), - parameters: Arc::new(parameters), + parameters: Arc::new(parameters), client: HttpClient::new(), token: None, } @@ -260,7 +260,8 @@ impl Client { error: err.to_string(), })?; - let res = self.auth_if_needed(request_builder) + let res = self + .auth_if_needed(request_builder) .send() .map_err(|err| Error::ConnectionError { error: err.to_string(), From 41358e9452ed535c544ddb974caa45c974b6dd41 Mon Sep 17 00:00:00 2001 From: Vladimir Shakhov Date: Tue, 21 Feb 2023 20:57:54 +0100 Subject: [PATCH 16/24] fix rust version --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 3ec3b71..d8e0ddd 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -55,7 +55,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - rust_release: [1.46, stable, nightly] + rust_release: ["1.57", stable, nightly] os: [ubuntu-latest, windows-latest, macOS-latest] steps: From f236fc81d40e72cc6c9c5894d602b35a989fe3ff Mon Sep 17 00:00:00 2001 From: Vladimir Shakhov Date: Tue, 21 Feb 2023 21:09:21 +0100 Subject: [PATCH 17/24] package `async-global-executor v2.3.1` requires rustc 1.59 or newer --- .github/workflows/rust.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index d8e0ddd..4dcedde 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -39,7 +39,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - rust_release: ["1.57", stable, nightly] + rust_release: ["1.59", stable, nightly] os: [ubuntu-latest, windows-latest, macOS-latest] steps: @@ -55,7 +55,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - rust_release: ["1.57", stable, nightly] + rust_release: ["1.59", stable, nightly] os: [ubuntu-latest, windows-latest, macOS-latest] steps: From 61d49c396340d83f6594f259694660dfe15637c9 Mon Sep 17 00:00:00 2001 From: Vladimir Shakhov Date: Tue, 21 Feb 2023 21:11:56 +0100 Subject: [PATCH 18/24] DOCKER_INFLUXDB_INIT_MODE: setup --- .github/workflows/rust.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 4dcedde..daa63e2 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -104,6 +104,7 @@ jobs: ports: - 9086:8086 env: + DOCKER_INFLUXDB_INIT_MODE: setup DOCKER_INFLUXDB_INIT_USERNAME: admin DOCKER_INFLUXDB_INIT_PASSWORD: password DOCKER_INFLUXDB_INIT_ORG: testing From 4fea768058cb6f7371552e7db733bd14aa2ead7c Mon Sep 17 00:00:00 2001 From: Vladimir Date: Sat, 25 Feb 2023 22:21:26 +0100 Subject: [PATCH 19/24] using one hardcoded bucket in integration tests v2 --- influxdb/tests/integration_tests_v2.rs | 72 ++++---------------------- 1 file changed, 10 insertions(+), 62 deletions(-) diff --git a/influxdb/tests/integration_tests_v2.rs b/influxdb/tests/integration_tests_v2.rs index 944e581..5bc00f0 100644 --- a/influxdb/tests/integration_tests_v2.rs +++ b/influxdb/tests/integration_tests_v2.rs @@ -14,18 +14,10 @@ use influxdb::{Client, Error, ReadQuery, Timestamp}; #[async_std::test] #[cfg(not(tarpaulin_include))] async fn test_authed_write_and_read() { - const TEST_NAME: &str = "test_authed_write_and_read"; run_test( || async move { - let client = Client::new("http://127.0.0.1:9086", TEST_NAME).with_token("admintoken"); - let query = format!("CREATE DATABASE {}", TEST_NAME); - client - .query(ReadQuery::new(query)) - .await - .expect("could not setup db"); - - let client = Client::new("http://127.0.0.1:9086", TEST_NAME).with_token("admintoken"); + let client = Client::new("http://127.0.0.1:9086", "mydb").with_token("admintoken"); let write_query = Timestamp::Hours(11) .into_query("weather") .add_field("temperature", 82); @@ -41,13 +33,11 @@ async fn test_authed_write_and_read() { ); }, || async move { - let client = Client::new("http://127.0.0.1:9086", TEST_NAME).with_token("admintoken"); - let query = format!("DROP DATABASE {}", TEST_NAME); - - client - .query(ReadQuery::new(query)) - .await - .expect("could not clean up db"); + let client = Client::new("http://127.0.0.1:9086", "mydb").with_token("admintoken"); + let read_query = ReadQuery::new("DELETE MEASUREMENT weather"); + let read_result = client.query(read_query).await; + assert_result_ok(&read_result); + assert!(!read_result.unwrap().contains("error"), "Teardown failed"); }, ) .await; @@ -59,18 +49,10 @@ async fn test_authed_write_and_read() { #[async_std::test] #[cfg(not(tarpaulin_include))] async fn test_wrong_authed_write_and_read() { - const TEST_NAME: &str = "test_wrong_authed_write_and_read"; run_test( || async move { - let client = Client::new("http://127.0.0.1:9086", TEST_NAME).with_token("admintoken"); - let query = format!("CREATE DATABASE {}", TEST_NAME); - client - .query(ReadQuery::new(query)) - .await - .expect("could not setup db"); - - let client = Client::new("http://127.0.0.1:9086", TEST_NAME).with_token("falsetoken"); + let client = Client::new("http://127.0.0.1:9086", "mydb").with_token("falsetoken"); let write_query = Timestamp::Hours(11) .into_query("weather") .add_field("temperature", 82); @@ -94,28 +76,8 @@ async fn test_wrong_authed_write_and_read() { read_result.unwrap_err() ), } - - let client = Client::new("http://127.0.0.1:9086", TEST_NAME) - .with_auth("nopriv_user", "password"); - let read_query = ReadQuery::new("SELECT * FROM weather"); - let read_result = client.query(&read_query).await; - assert_result_err(&read_result); - match read_result { - Err(Error::AuthenticationError) => {} - _ => panic!( - "Should be an AuthenticationError: {}", - read_result.unwrap_err() - ), - } - }, - || async move { - let client = Client::new("http://127.0.0.1:9086", TEST_NAME).with_token("admintoken"); - let query = format!("DROP DATABASE {}", TEST_NAME); - client - .query(ReadQuery::new(query)) - .await - .expect("could not clean up db"); }, + || async move {}, ) .await; } @@ -126,17 +88,10 @@ async fn test_wrong_authed_write_and_read() { #[async_std::test] #[cfg(not(tarpaulin_include))] async fn test_non_authed_write_and_read() { - const TEST_NAME: &str = "test_non_authed_write_and_read"; run_test( || async move { - let client = Client::new("http://127.0.0.1:9086", TEST_NAME).with_token("admintoken"); - let query = format!("CREATE DATABASE {}", TEST_NAME); - client - .query(ReadQuery::new(query)) - .await - .expect("could not setup db"); - let non_authed_client = Client::new("http://127.0.0.1:9086", TEST_NAME); + let non_authed_client = Client::new("http://127.0.0.1:9086", "mydb"); let write_query = Timestamp::Hours(11) .into_query("weather") .add_field("temperature", 82); @@ -161,14 +116,7 @@ async fn test_non_authed_write_and_read() { ), } }, - || async move { - let client = Client::new("http://127.0.0.1:9086", TEST_NAME).with_token("admintoken"); - let query = format!("DROP DATABASE {}", TEST_NAME); - client - .query(ReadQuery::new(query)) - .await - .expect("could not clean up db"); - }, + || async move {}, ) .await; } From 9eb83c718340efeda2e5c842cbed36e157d31aeb Mon Sep 17 00:00:00 2001 From: Vladimir Date: Sun, 26 Feb 2023 16:58:00 +0100 Subject: [PATCH 20/24] fixed no db "mydb" in integration tests seems to not happen anymore on influxdb 2.6 --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index daa63e2..09d3c8a 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -100,7 +100,7 @@ jobs: http-backend: [curl-client, h1-client, h1-client-rustls, hyper-client] services: influxdbv2: - image: influxdb:2.0 + image: influxdb:2.6 ports: - 9086:8086 env: From 8c414697a162e03bbda837135c9909ef673f4425 Mon Sep 17 00:00:00 2001 From: Vladimir Shakhov Date: Fri, 3 Mar 2023 19:18:27 +0100 Subject: [PATCH 21/24] readme and fixed readme check --- auxiliary/update_cargo-readme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auxiliary/update_cargo-readme.sh b/auxiliary/update_cargo-readme.sh index c678006..d2180d1 100755 --- a/auxiliary/update_cargo-readme.sh +++ b/auxiliary/update_cargo-readme.sh @@ -1,7 +1,7 @@ #!/usr/bin/bash our_version=$(cargo readme -V | perl -ne 'print $1 while /v([\d.]+)/g') -last_version=$(cargo search cargo-readme | perl -ne 'print $1 while /^cargo-readme = "([\d.]+)"/g') +last_version=$(cargo search --color=never cargo-readme | perl -ne 'print $1 while /^cargo-readme = "([\d.]+)"/g') if [ "$our_version" == "$last_version" ]; then echo Version $our_version is of cargo-readme is installed and up to date. From 8fc0df130ec184a71aeb883bc77299de7c33a7f3 Mon Sep 17 00:00:00 2001 From: Vladimir Shakhov Date: Fri, 3 Mar 2023 20:07:08 +0100 Subject: [PATCH 22/24] style check --- influxdb/src/query/mod.rs | 6 +++++- influxdb/tests/integration_tests_v2.rs | 3 --- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/influxdb/src/query/mod.rs b/influxdb/src/query/mod.rs index d1025ed..d12275a 100644 --- a/influxdb/src/query/mod.rs +++ b/influxdb/src/query/mod.rs @@ -281,7 +281,11 @@ mod tests { } #[test] fn test_timestamp_from_chrono_date() { - let timestamp_from_datetime: Timestamp = Utc.ymd(1970, 1, 1).and_hms(0, 0, 1).into(); + let timestamp_from_datetime: Timestamp = Utc + .with_ymd_and_hms(1970, 1, 1, 0, 0, 1) + .single() + .unwrap() + .into(); assert_eq!( Timestamp::Nanoseconds(MILLIS_PER_SECOND * NANOS_PER_MILLI), timestamp_from_datetime diff --git a/influxdb/tests/integration_tests_v2.rs b/influxdb/tests/integration_tests_v2.rs index 5bc00f0..259ea2d 100644 --- a/influxdb/tests/integration_tests_v2.rs +++ b/influxdb/tests/integration_tests_v2.rs @@ -14,7 +14,6 @@ use influxdb::{Client, Error, ReadQuery, Timestamp}; #[async_std::test] #[cfg(not(tarpaulin_include))] async fn test_authed_write_and_read() { - run_test( || async move { let client = Client::new("http://127.0.0.1:9086", "mydb").with_token("admintoken"); @@ -49,7 +48,6 @@ async fn test_authed_write_and_read() { #[async_std::test] #[cfg(not(tarpaulin_include))] async fn test_wrong_authed_write_and_read() { - run_test( || async move { let client = Client::new("http://127.0.0.1:9086", "mydb").with_token("falsetoken"); @@ -88,7 +86,6 @@ async fn test_wrong_authed_write_and_read() { #[async_std::test] #[cfg(not(tarpaulin_include))] async fn test_non_authed_write_and_read() { - run_test( || async move { let non_authed_client = Client::new("http://127.0.0.1:9086", "mydb"); From 1eaffaa7186e1bad78f32d797f8273611b5c7d22 Mon Sep 17 00:00:00 2001 From: Vladimir Shakhov Date: Fri, 3 Mar 2023 21:11:22 +0100 Subject: [PATCH 23/24] integration_tests_v2 are excluded from tarpaulin run because influxdb1.8 does not support auth tokens --- influxdb/tests/integration_tests_v2.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/influxdb/tests/integration_tests_v2.rs b/influxdb/tests/integration_tests_v2.rs index 259ea2d..2cedfec 100644 --- a/influxdb/tests/integration_tests_v2.rs +++ b/influxdb/tests/integration_tests_v2.rs @@ -12,7 +12,7 @@ use influxdb::{Client, Error, ReadQuery, Timestamp}; /// This test case tests the Authentication #[async_std::test] -#[cfg(not(tarpaulin_include))] +#[cfg(not(tarpaulin))] async fn test_authed_write_and_read() { run_test( || async move { @@ -46,7 +46,7 @@ async fn test_authed_write_and_read() { /// /// This test case tests the Authentication #[async_std::test] -#[cfg(not(tarpaulin_include))] +#[cfg(not(tarpaulin))] async fn test_wrong_authed_write_and_read() { run_test( || async move { @@ -84,7 +84,7 @@ async fn test_wrong_authed_write_and_read() { /// /// This test case tests the Authentication #[async_std::test] -#[cfg(not(tarpaulin_include))] +#[cfg(not(tarpaulin))] async fn test_non_authed_write_and_read() { run_test( || async move { From 8a11f6dcefe47b9dbe5ef5a22ee10f200a216c5d Mon Sep 17 00:00:00 2001 From: Vladimir Shakhov Date: Fri, 3 Mar 2023 21:25:59 +0100 Subject: [PATCH 24/24] clippy --- influxdb/src/query/line_proto_term.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/influxdb/src/query/line_proto_term.rs b/influxdb/src/query/line_proto_term.rs index 3d1845a..dca0b2a 100644 --- a/influxdb/src/query/line_proto_term.rs +++ b/influxdb/src/query/line_proto_term.rs @@ -23,8 +23,8 @@ impl LineProtoTerm<'_> { pub fn escape(self) -> String { use LineProtoTerm::*; match self { - Measurement(x) => Self::escape_any(x, &*COMMAS_SPACES), - TagKey(x) | FieldKey(x) => Self::escape_any(x, &*COMMAS_SPACES_EQUALS), + Measurement(x) => Self::escape_any(x, &COMMAS_SPACES), + TagKey(x) | FieldKey(x) => Self::escape_any(x, &COMMAS_SPACES_EQUALS), FieldValue(x) => Self::escape_field_value(x), TagValue(x) => Self::escape_tag_value(x), } @@ -44,7 +44,7 @@ impl LineProtoTerm<'_> { Float(v) => v.to_string(), SignedInteger(v) => format!("{}i", v), UnsignedInteger(v) => format!("{}u", v), - Text(v) => format!(r#""{}""#, Self::escape_any(v, &*QUOTES_SLASHES)), + Text(v) => format!(r#""{}""#, Self::escape_any(v, "ES_SLASHES)), } } @@ -62,7 +62,7 @@ impl LineProtoTerm<'_> { Float(v) => format!(r#"{}"#, v), SignedInteger(v) => format!(r#"{}"#, v), UnsignedInteger(v) => format!(r#"{}"#, v), - Text(v) => Self::escape_any(v, &*SLASHES), + Text(v) => Self::escape_any(v, &SLASHES), } }