use std::collections::HashMap;
use std::net::SocketAddr;
use gwp::client::GqlConnection;
use gwp::proto;
use gwp::server::mock_backend::MockBackend;
use gwp::server::{
CatalogServiceImpl, CreateGraphConfig, GqlServiceImpl, SessionManager, SessionServiceImpl,
TransactionManager,
};
use gwp::types::Value;
async fn start_server() -> SocketAddr {
let addr: SocketAddr = "127.0.0.1:0".parse().unwrap();
let listener = tokio::net::TcpListener::bind(addr).await.unwrap();
let addr = listener.local_addr().unwrap();
tokio::spawn(async move {
let backend = std::sync::Arc::new(MockBackend::new());
let sessions = SessionManager::new();
let transactions = TransactionManager::new();
let session_svc = SessionServiceImpl::new(
std::sync::Arc::clone(&backend),
sessions.clone(),
transactions.clone(),
None,
);
let gql_svc = GqlServiceImpl::new(std::sync::Arc::clone(&backend), sessions, transactions);
let catalog_svc = CatalogServiceImpl::new(std::sync::Arc::clone(&backend));
let incoming = tokio_stream::wrappers::TcpListenerStream::new(listener);
tonic::transport::Server::builder()
.add_service(proto::session_service_server::SessionServiceServer::new(
session_svc,
))
.add_service(proto::gql_service_server::GqlServiceServer::new(gql_svc))
.add_service(proto::catalog_service_server::CatalogServiceServer::new(
catalog_svc,
))
.serve_with_incoming(incoming)
.await
.unwrap();
});
tokio::time::sleep(std::time::Duration::from_millis(50)).await;
addr
}
#[tokio::test]
async fn client_session_lifecycle() {
let addr = start_server().await;
let conn = GqlConnection::connect(&format!("http://{addr}"))
.await
.unwrap();
let mut session = conn.create_session().await.unwrap();
assert!(!session.session_id().is_empty());
let ts = session.ping().await.unwrap();
assert!(ts > 0);
session.set_graph("test_graph").await.unwrap();
session.set_schema("test_schema").await.unwrap();
session.set_time_zone(60).await.unwrap();
session.reset().await.unwrap();
session.close().await.unwrap();
}
#[tokio::test]
async fn client_execute_query() {
let addr = start_server().await;
let conn = GqlConnection::connect(&format!("http://{addr}"))
.await
.unwrap();
let mut session = conn.create_session().await.unwrap();
let mut cursor = session
.execute("MATCH (p:Person) RETURN p.name, p.age", HashMap::new())
.await
.unwrap();
let cols = cursor.column_names().await.unwrap();
assert_eq!(cols, vec!["name", "age"]);
let rows = cursor.collect_rows().await.unwrap();
assert_eq!(rows.len(), 2);
assert_eq!(rows[0][0], Value::String("Alice".to_owned()));
assert_eq!(rows[0][1], Value::Integer(30));
assert_eq!(rows[1][0], Value::String("Bob".to_owned()));
assert_eq!(rows[1][1], Value::Integer(25));
assert!(cursor.is_success().await.unwrap());
}
#[tokio::test]
async fn client_transaction() {
let addr = start_server().await;
let conn = GqlConnection::connect(&format!("http://{addr}"))
.await
.unwrap();
let mut session = conn.create_session().await.unwrap();
let mut tx = session.begin_transaction().await.unwrap();
assert!(!tx.transaction_id().is_empty());
let mut cursor = tx
.execute("INSERT (:Person {name: 'Carol'})", HashMap::new())
.await
.unwrap();
let _ = cursor.collect_rows().await.unwrap();
assert!(cursor.is_success().await.unwrap());
tx.commit().await.unwrap();
}
#[tokio::test]
async fn client_transaction_rollback() {
let addr = start_server().await;
let conn = GqlConnection::connect(&format!("http://{addr}"))
.await
.unwrap();
let mut session = conn.create_session().await.unwrap();
let tx = session.begin_transaction().await.unwrap();
tx.rollback().await.unwrap();
}
#[tokio::test]
async fn catalog_client_list_graphs() {
let addr = start_server().await;
let conn = GqlConnection::connect(&format!("http://{addr}"))
.await
.unwrap();
let mut catalog = conn.create_catalog_client();
let graphs = catalog.list_graphs("default").await.unwrap();
assert_eq!(graphs.len(), 2);
assert_eq!(graphs[0].name, "default");
assert_eq!(graphs[0].node_count, 100);
assert_eq!(graphs[0].edge_count, 50);
assert_eq!(graphs[1].name, "test");
}
#[tokio::test]
async fn catalog_client_create_graph() {
let addr = start_server().await;
let conn = GqlConnection::connect(&format!("http://{addr}"))
.await
.unwrap();
let mut catalog = conn.create_catalog_client();
let info = catalog
.create_graph(CreateGraphConfig {
schema: "default".to_owned(),
name: "bench".to_owned(),
if_not_exists: false,
or_replace: false,
type_spec: None,
copy_of: None,
storage_mode: "InMemory".to_owned(),
memory_limit_bytes: None,
backward_edges: None,
threads: None,
wal_enabled: None,
wal_durability: None,
})
.await
.unwrap();
assert_eq!(info.name, "bench");
assert_eq!(info.node_count, 0);
assert_eq!(info.edge_count, 0);
}
#[tokio::test]
async fn catalog_client_drop_graph() {
let addr = start_server().await;
let conn = GqlConnection::connect(&format!("http://{addr}"))
.await
.unwrap();
let mut catalog = conn.create_catalog_client();
let existed = catalog.drop_graph("default", "test", false).await.unwrap();
assert!(existed);
}
#[tokio::test]
async fn catalog_client_get_graph_info() {
let addr = start_server().await;
let conn = GqlConnection::connect(&format!("http://{addr}"))
.await
.unwrap();
let mut catalog = conn.create_catalog_client();
let info = catalog.get_graph_info("default", "default").await.unwrap();
assert_eq!(info.name, "default");
assert_eq!(info.node_count, 100);
assert_eq!(info.edge_count, 50);
assert_eq!(info.storage_mode, "InMemory");
}
#[tokio::test]
async fn catalog_client_get_graph_info_not_found() {
let addr = start_server().await;
let conn = GqlConnection::connect(&format!("http://{addr}"))
.await
.unwrap();
let mut catalog = conn.create_catalog_client();
let result = catalog.get_graph_info("default", "nonexistent").await;
assert!(result.is_err());
}