Skip to content

Commit afb7211

Browse files
committed
update e2e test to use opensvm api
1 parent 11998d2 commit afb7211

File tree

2 files changed

+69
-305
lines changed

2 files changed

+69
-305
lines changed

tests/e2e.rs

Lines changed: 61 additions & 305 deletions
Original file line numberDiff line numberDiff line change
@@ -1,312 +1,68 @@
1-
use std::sync::{Arc, Mutex};
2-
use std::thread;
3-
use std::time::Duration;
4-
use serde_json::json;
5-
use mcp_sdk::transport::{Transport, JsonRpcMessage, JsonRpcRequest, JsonRpcResponse, JsonRpcVersion, JsonRpcError};
6-
use std::sync::mpsc::{self, Sender, Receiver};
7-
use anyhow::Result;
1+
use solana_client::nonblocking::rpc_client::RpcClient;
2+
use solana_sdk::{
3+
commitment_config::CommitmentConfig,
4+
pubkey::Pubkey,
5+
};
86

9-
struct TestTransport {
10-
tx: Sender<serde_json::Value>,
11-
rx: Arc<Mutex<Receiver<serde_json::Value>>>,
12-
}
13-
14-
impl TestTransport {
15-
fn new() -> (Self, Self) {
16-
let (client_tx, server_rx) = mpsc::channel();
17-
let (server_tx, client_rx) = mpsc::channel();
18-
19-
let client = Self {
20-
tx: client_tx,
21-
rx: Arc::new(Mutex::new(client_rx)),
22-
};
23-
24-
let server = Self {
25-
tx: server_tx,
26-
rx: Arc::new(Mutex::new(server_rx)),
27-
};
28-
29-
(client, server)
30-
}
31-
}
32-
33-
impl Transport for TestTransport {
34-
fn send(&self, message: &JsonRpcMessage) -> Result<()> {
35-
let json = match message {
36-
JsonRpcMessage::Request(req) => {
37-
json!({
38-
"jsonrpc": JsonRpcVersion::V2,
39-
"id": req.id,
40-
"method": req.method,
41-
"params": req.params
42-
})
43-
},
44-
JsonRpcMessage::Response(resp) => {
45-
json!({
46-
"jsonrpc": JsonRpcVersion::V2,
47-
"id": resp.id,
48-
"result": resp.result,
49-
"error": resp.error
50-
})
51-
},
52-
JsonRpcMessage::Notification(_) => {
53-
json!({})
54-
}
55-
};
56-
57-
self.tx.send(json).unwrap();
58-
Ok(())
59-
}
60-
61-
fn receive(&self) -> Result<JsonRpcMessage> {
62-
let value = match self.rx.lock().unwrap().recv_timeout(Duration::from_secs(5)) {
63-
Ok(value) => value,
64-
Err(_) => panic!("Failed to receive message within timeout"),
65-
};
66-
67-
if value.get("error").is_some() {
68-
Ok(JsonRpcMessage::Response(JsonRpcResponse {
69-
jsonrpc: JsonRpcVersion::default(),
70-
id: value["id"].as_u64().unwrap(),
71-
result: None,
72-
error: Some(JsonRpcError {
73-
code: value["error"]["code"].as_i64().unwrap() as i32,
74-
message: value["error"]["message"].as_str().unwrap().to_string(),
75-
data: value["error"].get("data").cloned(),
76-
}),
77-
}))
78-
} else if value.get("result").is_some() {
79-
Ok(JsonRpcMessage::Response(JsonRpcResponse {
80-
jsonrpc: JsonRpcVersion::default(),
81-
id: value["id"].as_u64().unwrap(),
82-
result: Some(value["result"].clone()),
83-
error: None,
84-
}))
85-
} else {
86-
Ok(JsonRpcMessage::Request(JsonRpcRequest {
87-
jsonrpc: JsonRpcVersion::default(),
88-
id: value["id"].as_u64().unwrap(),
89-
method: value["method"].as_str().unwrap().to_string(),
90-
params: value.get("params").cloned(),
91-
}))
92-
}
93-
}
94-
95-
fn open(&self) -> Result<()> {
96-
Ok(())
97-
}
98-
99-
fn close(&self) -> Result<()> {
100-
Ok(())
101-
}
102-
}
103-
104-
fn setup_mock_server() -> TestTransport {
105-
let (client_transport, server_transport) = TestTransport::new();
7+
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
8+
async fn test_blockchain_operations() {
9+
// Connect to Solana devnet
10+
let rpc_url = "https://api.opensvm.com".to_string();
11+
let client = RpcClient::new_with_commitment(rpc_url.clone(), CommitmentConfig::confirmed());
10612

107-
thread::spawn(move || {
108-
loop {
109-
if let Ok(msg) = server_transport.rx.lock().unwrap().recv() {
110-
let id = msg["id"].as_u64().unwrap();
111-
let method = msg["method"].as_str().unwrap();
112-
let auth = msg["params"]["auth"].as_str().unwrap();
113-
114-
match (method, auth) {
115-
("initialize", "test_key_123") => {
116-
server_transport.tx.send(json!({
117-
"jsonrpc": JsonRpcVersion::V2,
118-
"id": id,
119-
"result": {
120-
"server": {
121-
"name": "solana-mcp",
122-
"version": "0.1.2"
123-
},
124-
"protocol": {
125-
"name": "mcp",
126-
"version": "0.1.0"
127-
}
128-
}
129-
})).unwrap();
130-
},
131-
(_, "invalid_key") => {
132-
server_transport.tx.send(json!({
133-
"jsonrpc": JsonRpcVersion::V2,
134-
"id": id,
135-
"error": {
136-
"code": -32601,
137-
"message": "Invalid API key"
138-
}
139-
})).unwrap();
140-
},
141-
("tools/call", "test_key_123") => {
142-
let tool_name = msg["params"]["name"].as_str().unwrap();
143-
match tool_name {
144-
"get_slot" => {
145-
server_transport.tx.send(json!({
146-
"jsonrpc": JsonRpcVersion::V2,
147-
"id": id,
148-
"result": 12345
149-
})).unwrap();
150-
},
151-
_ => {
152-
server_transport.tx.send(json!({
153-
"jsonrpc": JsonRpcVersion::V2,
154-
"id": id,
155-
"error": {
156-
"code": -32601,
157-
"message": "Tool not found"
158-
}
159-
})).unwrap();
160-
}
161-
}
162-
},
163-
_ => {}
164-
}
165-
}
13+
// Configure RPC client to support latest transaction versions
14+
let config = solana_client::rpc_config::RpcBlockConfig {
15+
encoding: None,
16+
transaction_details: None,
17+
rewards: None,
18+
commitment: None,
19+
max_supported_transaction_version: Some(0),
20+
};
21+
22+
println!("\nTesting health check:");
23+
let health = client.get_health().await.unwrap();
24+
println!("Health status: {:?}", health);
25+
26+
println!("\nTesting version info:");
27+
let version = client.get_version().await.unwrap();
28+
println!("Version info: {:?}", version);
29+
30+
println!("\nTesting latest blockhash:");
31+
let blockhash = client.get_latest_blockhash().await.unwrap();
32+
println!("Latest blockhash: {:?}", blockhash);
33+
34+
println!("\nTesting transaction count:");
35+
let count = client.get_transaction_count().await.unwrap();
36+
println!("Transaction count: {}", count);
37+
38+
// Get info about the System Program
39+
println!("\nTesting account info for System Program:");
40+
let system_program_id = "11111111111111111111111111111111".parse::<Pubkey>().unwrap();
41+
let account = client.get_account(&system_program_id).await.unwrap();
42+
println!("System Program Account:");
43+
println!(" Owner: {}", account.owner);
44+
println!(" Lamports: {}", account.lamports);
45+
println!(" Executable: {}", account.executable);
46+
47+
// Get recent confirmed signatures first
48+
println!("\nTesting recent transactions:");
49+
let signatures = client.get_signatures_for_address(&system_program_id).await.unwrap();
50+
println!("Recent transactions for System Program:");
51+
for sig in signatures.iter().take(3) {
52+
println!(" Signature: {}", sig.signature);
53+
println!(" Slot: {}", sig.slot);
54+
if let Some(err) = &sig.err {
55+
println!(" Error: {:?}", err);
16656
}
167-
});
168-
169-
client_transport
170-
}
171-
172-
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
173-
async fn test_server_initialization() {
174-
let transport = setup_mock_server();
175-
176-
let request = JsonRpcMessage::Request(JsonRpcRequest {
177-
jsonrpc: JsonRpcVersion::default(),
178-
id: 1,
179-
method: "initialize".to_string(),
180-
params: Some(json!({
181-
"auth": "test_key_123"
182-
})),
183-
});
184-
185-
transport.send(&request).unwrap();
186-
let response = transport.receive().unwrap();
187-
188-
match response {
189-
JsonRpcMessage::Response(resp) => {
190-
assert_eq!(resp.jsonrpc, JsonRpcVersion::V2);
191-
assert_eq!(resp.id, 1);
192-
let result = resp.result.unwrap();
193-
assert!(result["server"]["name"].as_str().unwrap().contains("solana-mcp"));
194-
assert_eq!(result["protocol"]["name"].as_str().unwrap(), "mcp");
195-
},
196-
_ => panic!("Expected response message"),
19757
}
198-
}
199-
200-
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
201-
async fn test_invalid_api_key() {
202-
let transport = setup_mock_server();
203-
204-
let request = JsonRpcMessage::Request(JsonRpcRequest {
205-
jsonrpc: JsonRpcVersion::default(),
206-
id: 1,
207-
method: "tools/list".to_string(),
208-
params: Some(json!({
209-
"auth": "invalid_key"
210-
})),
211-
});
212-
213-
transport.send(&request).unwrap();
214-
let response = transport.receive().unwrap();
215-
216-
match response {
217-
JsonRpcMessage::Response(resp) => {
218-
assert_eq!(resp.jsonrpc, JsonRpcVersion::V2);
219-
assert_eq!(resp.id, 1);
220-
let error = resp.error.unwrap();
221-
assert_eq!(error.code, -32601);
222-
assert!(error.message.contains("Invalid API key"));
223-
},
224-
_ => panic!("Expected error message"),
225-
}
226-
}
227-
228-
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
229-
async fn test_tool_execution() {
230-
let transport = setup_mock_server();
231-
232-
// First initialize
233-
let init_request = JsonRpcMessage::Request(JsonRpcRequest {
234-
jsonrpc: JsonRpcVersion::default(),
235-
id: 1,
236-
method: "initialize".to_string(),
237-
params: Some(json!({
238-
"auth": "test_key_123"
239-
})),
240-
});
241-
242-
transport.send(&init_request).unwrap();
243-
transport.receive().unwrap();
24458

245-
// Then call tool
246-
let request = JsonRpcMessage::Request(JsonRpcRequest {
247-
jsonrpc: JsonRpcVersion::default(),
248-
id: 2,
249-
method: "tools/call".to_string(),
250-
params: Some(json!({
251-
"auth": "test_key_123",
252-
"name": "get_slot",
253-
"arguments": {}
254-
})),
255-
});
256-
257-
transport.send(&request).unwrap();
258-
let response = transport.receive().unwrap();
259-
260-
match response {
261-
JsonRpcMessage::Response(resp) => {
262-
assert_eq!(resp.jsonrpc, JsonRpcVersion::V2);
263-
assert_eq!(resp.id, 2);
264-
assert!(resp.result.is_some());
265-
},
266-
_ => panic!("Expected response message"),
267-
}
268-
}
269-
270-
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
271-
async fn test_invalid_tool() {
272-
let transport = setup_mock_server();
273-
274-
// First initialize
275-
let init_request = JsonRpcMessage::Request(JsonRpcRequest {
276-
jsonrpc: JsonRpcVersion::default(),
277-
id: 1,
278-
method: "initialize".to_string(),
279-
params: Some(json!({
280-
"auth": "test_key_123"
281-
})),
282-
});
283-
284-
transport.send(&init_request).unwrap();
285-
transport.receive().unwrap();
286-
287-
// Then call invalid tool
288-
let request = JsonRpcMessage::Request(JsonRpcRequest {
289-
jsonrpc: JsonRpcVersion::default(),
290-
id: 2,
291-
method: "tools/call".to_string(),
292-
params: Some(json!({
293-
"auth": "test_key_123",
294-
"name": "nonexistent_tool",
295-
"arguments": {}
296-
})),
297-
});
298-
299-
transport.send(&request).unwrap();
300-
let response = transport.receive().unwrap();
301-
302-
match response {
303-
JsonRpcMessage::Response(resp) => {
304-
assert_eq!(resp.jsonrpc, JsonRpcVersion::V2);
305-
assert_eq!(resp.id, 2);
306-
let error = resp.error.unwrap();
307-
assert_eq!(error.code, -32601);
308-
assert!(error.message.contains("Tool not found"));
309-
},
310-
_ => panic!("Expected error message"),
59+
// Get block data using a slot we know exists from recent transactions
60+
if let Some(first_sig) = signatures.first() {
61+
println!("\nTesting block data for slot {}:", first_sig.slot);
62+
let block = client.get_block_with_config(first_sig.slot, config).await;
63+
match block {
64+
Ok(block) => println!("Block data: {:#?}", block),
65+
Err(e) => println!("Could not fetch block: {}", e),
66+
}
31167
}
31268
}

tests/transport.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
pub use solana_mcp_server::transport::{
2+
Transport,
3+
JsonRpcMessage,
4+
JsonRpcRequest,
5+
JsonRpcResponse,
6+
JsonRpcVersion,
7+
JsonRpcError,
8+
};

0 commit comments

Comments
 (0)