#![allow(clippy::result_large_err)]
use futures::{SinkExt, StreamExt};
use ocpp_client::{NegotiatedClient, OcppVersion, connect};
use ocpp_types::v16::HeartbeatRequest as V16HeartbeatRequest;
use ocpp_types::v201::HeartbeatRequest;
use serde_json::{Value, json};
use tokio::net::TcpListener;
use tokio_tungstenite::tungstenite::Message;
#[tokio::test]
async fn connect_negotiates_whichever_version_the_server_picks() {
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
let addr = listener.local_addr().unwrap();
let server = tokio::spawn(async move {
let (tcp, _) = listener.accept().await.unwrap();
let mut offered_protocols = None;
let mut ws = tokio_tungstenite::accept_hdr_async(
tcp,
|req: &tokio_tungstenite::tungstenite::handshake::server::Request,
mut response: tokio_tungstenite::tungstenite::handshake::server::Response| {
offered_protocols = req
.headers()
.get("Sec-WebSocket-Protocol")
.map(|v| v.to_str().unwrap().to_string());
response
.headers_mut()
.insert("Sec-WebSocket-Protocol", "ocpp2.0.1".parse().unwrap());
Ok(response)
},
)
.await
.unwrap();
let offered_protocols = offered_protocols.unwrap();
assert!(offered_protocols.contains("ocpp2.1"));
assert!(offered_protocols.contains("ocpp2.0.1"));
assert!(offered_protocols.contains("ocpp1.6"));
let frame = match ws.next().await.unwrap().unwrap() {
Message::Text(text) => text.to_string(),
other => panic!("expected a text frame, got {other:?}"),
};
let call: Value = serde_json::from_str(&frame).unwrap();
assert_eq!(call[2], "Heartbeat");
let message_id = call[1].as_str().unwrap().to_string();
let response = json!([3, message_id, { "currentTime": "2024-01-01T00:00:00Z" }]);
ws.send(Message::text(serde_json::to_string(&response).unwrap()))
.await
.unwrap();
});
let client = connect(&format!("ws://{addr}"), None, None).await.unwrap();
let client = match client {
NegotiatedClient::V2_0_1(client) => client,
_ => panic!("expected the server's ocpp2.0.1 pick, got a different version"),
};
let response = client
.send_heartbeat(HeartbeatRequest { custom_data: None })
.await
.unwrap();
assert_eq!(response.current_time, "2024-01-01T00:00:00Z");
server.await.unwrap();
}
#[tokio::test]
async fn connect_only_offers_the_caller_supplied_versions() {
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
let addr = listener.local_addr().unwrap();
let server = tokio::spawn(async move {
let (tcp, _) = listener.accept().await.unwrap();
let mut offered_protocols = None;
let mut ws = tokio_tungstenite::accept_hdr_async(
tcp,
|req: &tokio_tungstenite::tungstenite::handshake::server::Request,
mut response: tokio_tungstenite::tungstenite::handshake::server::Response| {
offered_protocols = req
.headers()
.get("Sec-WebSocket-Protocol")
.map(|v| v.to_str().unwrap().to_string());
response
.headers_mut()
.insert("Sec-WebSocket-Protocol", "ocpp1.6".parse().unwrap());
Ok(response)
},
)
.await
.unwrap();
assert_eq!(offered_protocols.unwrap(), "ocpp1.6");
let frame = match ws.next().await.unwrap().unwrap() {
Message::Text(text) => text.to_string(),
other => panic!("expected a text frame, got {other:?}"),
};
let call: Value = serde_json::from_str(&frame).unwrap();
assert_eq!(call[2], "Heartbeat");
let message_id = call[1].as_str().unwrap().to_string();
let response = json!([3, message_id, { "currentTime": "2024-01-01T00:00:00Z" }]);
ws.send(Message::text(serde_json::to_string(&response).unwrap()))
.await
.unwrap();
});
let client = connect(&format!("ws://{addr}"), Some(&[OcppVersion::V1_6]), None)
.await
.unwrap();
let client = match client {
NegotiatedClient::V1_6(client) => client,
_ => panic!("expected the server's ocpp1.6 pick, got a different version"),
};
let response = client.send_heartbeat(V16HeartbeatRequest {}).await.unwrap();
assert_eq!(response.current_time, "2024-01-01T00:00:00Z");
server.await.unwrap();
}