surrealpatch/tests/common/rest_client.rs

100 lines
2.9 KiB
Rust

use crate::common::docker::DOCKER_EXPOSED_PORT;
use crate::common::expected::Expected;
use http::{header, HeaderMap, StatusCode};
use reqwest::Client;
use serde_json::Value as JsonValue;
use std::time::{Duration, SystemTime};
use tokio::time::sleep;
use tracing::{debug, error, warn};
// A very basic Rest client.
// The goal is to have a client that can connect to any version of SurrealDB.
// Using the REST API / sql endpoint
pub struct RestClient {
client: Client,
url: String,
user: String,
pass: String,
}
impl RestClient {
pub fn new(ns: &str, db: &str, user: &str, pass: &str) -> Self {
let mut headers = HeaderMap::new();
headers.insert("NS", ns.parse().unwrap());
headers.insert("DB", db.parse().unwrap());
headers.insert(header::ACCEPT, "application/json".parse().unwrap());
let client = Client::builder()
.connect_timeout(Duration::from_millis(10))
.default_headers(headers)
.build()
.expect("Client::builder()...build()");
Self {
client,
url: format!("http://127.0.0.1:{DOCKER_EXPOSED_PORT}/sql"),
user: user.to_string(),
pass: pass.to_string(),
}
}
pub async fn wait_for_connection(self, time_out: &Duration) -> Option<Self> {
sleep(Duration::from_secs(2)).await;
let start = SystemTime::now();
while start.elapsed().unwrap().le(time_out) {
sleep(Duration::from_secs(2)).await;
if let Some(r) = self.query("INFO FOR ROOT").await {
if r.status() == StatusCode::OK {
return Some(self);
}
}
warn!("DB not yet responding");
sleep(Duration::from_secs(2)).await;
}
None
}
pub async fn query(&self, q: &str) -> Option<reqwest::Response> {
match self
.client
.post(&self.url)
.basic_auth(&self.user, Some(&self.pass))
.body(q.to_string())
.send()
.await
{
Ok(r) => Some(r),
Err(e) => {
error!("{e}");
None
}
}
}
pub async fn checked_query(&self, q: &str, expected: &Expected) {
let r = self.query(q).await.unwrap_or_else(|| panic!("No response for {q}"));
assert_eq!(
r.status(),
StatusCode::OK,
"Wrong response for {q} -> {}",
r.text().await.expect(q)
);
// Convert the result to JSON
let j: JsonValue = r.json().await.expect(q);
debug!("{q} => {j:#}");
// The result should be an array
let results_with_status = j.as_array().expect(q);
assert_eq!(results_with_status.len(), 1, "Wrong number of results on query {q}");
let result_with_status = &results_with_status[0];
// Check the status
let status =
result_with_status.get("status").unwrap_or_else(|| panic!("No status on query: {q}"));
assert_eq!(status.as_str(), Some("OK"), "Wrong status for {q} => {status:#}");
// Extract the results
let results =
result_with_status.get("result").unwrap_or_else(|| panic!("No result for query: {q}"));
if !matches!(expected, Expected::Any) {
// Check the results
let results = results.as_array().expect(q);
expected.check_results(q, results);
}
}
}