use ostium_rust_sdk::{Network, OstiumClient, Result};
use rust_decimal::Decimal;
use std::env;
async fn create_test_client() -> Result<OstiumClient> {
OstiumClient::builder(Network::Testnet)
.with_network_retry()
.build()
.await
}
async fn create_test_client_with_signer() -> Option<OstiumClient> {
if let Ok(private_key) = env::var("OSTIUM_PRIVATE_KEY") {
OstiumClient::builder(Network::Testnet)
.with_private_key(&private_key)
.ok()?
.with_network_retry()
.build()
.await
.ok()
} else {
println!("Skipping tests requiring signer - set OSTIUM_PRIVATE_KEY environment variable");
None
}
}
#[tokio::test]
async fn test_client_creation() {
let client = create_test_client().await.unwrap();
assert_eq!(client.config().network, Network::Testnet);
assert!(!client.has_signer());
}
#[tokio::test]
async fn test_client_creation_with_signer() {
if let Some(client) = create_test_client_with_signer().await {
assert_eq!(client.config().network, Network::Testnet);
assert!(client.has_signer());
assert!(client.signer_address().is_some());
}
}
#[tokio::test]
async fn test_get_trading_pairs() {
let client = create_test_client().await.unwrap();
let pairs = client.get_pairs().await.unwrap();
assert!(!pairs.is_empty(), "Should have at least one trading pair");
let symbols: Vec<&str> = pairs.iter().map(|p| p.symbol.as_str()).collect();
println!("Available pairs: {:?}", symbols);
let first_pair = &pairs[0];
assert!(!first_pair.symbol.is_empty());
assert!(!first_pair.base_asset.is_empty());
assert!(!first_pair.quote_asset.is_empty());
assert!(first_pair.symbol.contains('/'));
}
#[tokio::test]
async fn test_get_price_btc() {
let client = create_test_client().await.unwrap();
let price = client.get_price("BTC/USD").await.unwrap();
assert_eq!(price.symbol, "BTC/USD");
assert!(price.mark_price > Decimal::from(0));
assert!(price.index_price > Decimal::from(0));
assert!(price.high_24h > price.low_24h);
println!("BTC/USD Price: ${}", price.mark_price);
}
#[tokio::test]
async fn test_get_price_eth() {
let client = create_test_client().await.unwrap();
let price = client.get_price("ETH/USD").await.unwrap();
assert_eq!(price.symbol, "ETH/USD");
assert!(price.mark_price > Decimal::from(0));
println!("ETH/USD Price: ${}", price.mark_price);
}
#[tokio::test]
async fn test_get_trading_hours() {
let client = create_test_client().await.unwrap();
let hours = client.get_trading_hours("BTC/USD").await.unwrap();
assert_eq!(hours.symbol, "BTC/USD");
assert!(hours.is_open);
println!("BTC/USD Market Open: {}", hours.is_open);
}
#[tokio::test]
async fn test_get_balance_no_signer() {
let client = create_test_client().await.unwrap();
let result = client.get_balance(None).await;
assert!(result.is_err());
println!("Expected error without signer: {:?}", result.unwrap_err());
}
#[tokio::test]
async fn test_get_balance_with_signer() {
if let Some(client) = create_test_client_with_signer().await {
let balance = client.get_balance(None).await.unwrap();
assert_eq!(balance.asset, "USDC");
assert!(balance.total >= Decimal::from(0));
assert!(balance.available >= Decimal::from(0));
println!("Account Balance: {} USDC", balance.total);
}
}
#[tokio::test]
async fn test_get_positions_with_signer() {
if let Some(client) = create_test_client_with_signer().await {
let positions = client.get_positions(None).await.unwrap();
println!("Found {} open positions", positions.len());
for position in positions {
assert!(!position.id.is_empty());
assert!(!position.symbol.is_empty());
assert!(position.size > Decimal::from(0));
println!(
"Position: {} {:?} {}",
position.symbol, position.side, position.size
);
}
}
}
#[tokio::test]
async fn test_get_orders_with_signer() {
if let Some(client) = create_test_client_with_signer().await {
let orders = client.get_orders(None).await.unwrap();
println!("Found {} open orders", orders.len());
for order in orders {
assert!(!order.id.is_empty());
assert!(!order.symbol.is_empty());
assert!(order.size > Decimal::from(0));
println!(
"Order: {} {:?} {} @ {:?}",
order.symbol, order.side, order.size, order.price
);
}
}
}
#[tokio::test]
async fn test_multiple_price_requests_concurrent() {
let client = create_test_client().await.unwrap();
let (btc_result, eth_result, sol_result) = tokio::join!(
client.get_price("BTC/USD"),
client.get_price("ETH/USD"),
client.get_price("SOL/USD")
);
let mut successful_requests = 0;
if let Ok(price) = btc_result {
successful_requests += 1;
println!("Got price for {}: ${}", price.symbol, price.mark_price);
}
if let Ok(price) = eth_result {
successful_requests += 1;
println!("Got price for {}: ${}", price.symbol, price.mark_price);
}
if let Ok(price) = sol_result {
successful_requests += 1;
println!("Got price for {}: ${}", price.symbol, price.mark_price);
}
assert!(
successful_requests >= 2,
"At least 2 price requests should succeed"
);
}
#[tokio::test]
async fn test_error_handling_invalid_symbol() {
let client = create_test_client().await.unwrap();
let result = client.get_price("INVALID/SYMBOL").await;
assert!(result.is_err());
println!(
"Expected error for invalid symbol: {:?}",
result.unwrap_err()
);
}
#[tokio::test]
async fn test_retry_mechanism() {
let client = OstiumClient::builder(Network::Testnet)
.with_network_retry() .build()
.await
.unwrap();
let pairs = client.get_pairs().await.unwrap();
assert!(!pairs.is_empty());
}
#[tokio::test]
async fn test_client_configuration() {
let standard_client = OstiumClient::builder(Network::Testnet)
.build()
.await
.unwrap();
let network_optimized_client = OstiumClient::builder(Network::Testnet)
.with_network_retry()
.build()
.await
.unwrap();
let contract_optimized_client = OstiumClient::builder(Network::Testnet)
.with_contract_retry()
.build()
.await
.unwrap();
let graphql_optimized_client = OstiumClient::builder(Network::Testnet)
.with_graphql_retry()
.build()
.await
.unwrap();
assert!(standard_client.get_pairs().await.is_ok());
assert!(network_optimized_client.get_pairs().await.is_ok());
assert!(contract_optimized_client.get_pairs().await.is_ok());
assert!(graphql_optimized_client.get_pairs().await.is_ok());
}
#[tokio::test]
async fn test_performance_multiple_requests() {
let client = create_test_client().await.unwrap();
let start_time = std::time::Instant::now();
let mut successful_requests = 0;
for _ in 0..5 {
if client.get_price("BTC/USD").await.is_ok() {
successful_requests += 1;
}
}
let elapsed = start_time.elapsed();
println!(
"Completed {} requests in {:?}",
successful_requests, elapsed
);
assert!(
successful_requests >= 4,
"At least 4 out of 5 requests should succeed"
);
assert!(
elapsed.as_secs() < 30,
"All requests should complete within 30 seconds"
);
}