add tests for the api

This commit is contained in:
2026-01-01 12:13:05 -05:00
parent 4aa86da14a
commit d3b882f56d
12 changed files with 739 additions and 42 deletions

View File

@@ -75,6 +75,7 @@ impl TelemetryRegistry {
cancellation_token,
uuid: response_uuid,
client: stored_client,
data_type,
}
}
inner(self.client.clone(), name.into(), data_type).await
@@ -96,6 +97,7 @@ pub struct GenericTelemetryHandle {
cancellation_token: CancellationToken,
uuid: Arc<RwLock<Uuid>>,
client: Arc<Client>,
data_type: DataType,
}
impl GenericTelemetryHandle {
@@ -104,6 +106,12 @@ impl GenericTelemetryHandle {
value: DataValue,
timestamp: DateTime<Utc>,
) -> Result<(), MessageError> {
if value.to_data_type() != self.data_type {
return Err(MessageError::IncorrectDataType {
expected: self.data_type,
actual: value.to_data_type(),
});
}
let Ok(lock) = self.uuid.try_read() else {
return Ok(());
};
@@ -165,4 +173,292 @@ impl<T: Into<DataValue>> TelemetryHandle<T> {
}
#[cfg(test)]
mod tests {}
mod tests {
use crate::client::error::MessageError;
use crate::client::telemetry::TelemetryRegistry;
use crate::client::tests::create_test_client;
use crate::client::Callback;
use crate::messages::payload::RequestMessagePayload;
use crate::messages::telemetry_definition::{
TelemetryDefinitionRequest, TelemetryDefinitionResponse,
};
use crate::messages::telemetry_entry::TelemetryEntry;
use crate::messages::ResponseMessage;
use api_core::data_type::DataType;
use api_core::data_value::DataValue;
use futures_util::FutureExt;
use std::sync::Arc;
use std::time::Duration;
use tokio::task::yield_now;
use tokio::time::timeout;
use tokio::try_join;
use uuid::Uuid;
#[tokio::test]
async fn generic() {
// if _c drops then we are disconnected
let (mut rx, _c, client) = create_test_client();
let tlm = TelemetryRegistry::new(Arc::new(client));
let tlm_handle = tlm.register_generic("generic", DataType::Float32);
let tlm_uuid = Uuid::new_v4();
let expected_rx = async {
let msg = rx.recv().await.unwrap();
let Callback::Once(responder) = msg.callback else {
panic!("Expected Once Callback");
};
assert!(msg.msg.response.is_none());
let RequestMessagePayload::TelemetryDefinitionRequest(TelemetryDefinitionRequest {
name,
data_type,
}) = msg.msg.payload
else {
panic!("Expected Telemetry Definition Request")
};
assert_eq!(name, "generic".to_string());
assert_eq!(data_type, DataType::Float32);
responder
.send(ResponseMessage {
uuid: Uuid::new_v4(),
response: Some(msg.msg.uuid),
payload: TelemetryDefinitionResponse { uuid: tlm_uuid }.into(),
})
.unwrap();
};
let (tlm_handle, _) = try_join!(
timeout(Duration::from_secs(1), tlm_handle),
timeout(Duration::from_secs(1), expected_rx),
)
.unwrap();
assert_eq!(*tlm_handle.uuid.try_read().unwrap(), tlm_uuid);
// This should NOT block if there is space in the queue
tlm_handle
.publish_now(0.0f32.into())
.now_or_never()
.unwrap()
.unwrap();
let tlm_msg = timeout(Duration::from_secs(1), rx.recv())
.await
.unwrap()
.unwrap();
assert!(matches!(tlm_msg.callback, Callback::None));
match tlm_msg.msg.payload {
RequestMessagePayload::TelemetryEntry(TelemetryEntry { uuid, value, .. }) => {
assert_eq!(uuid, tlm_uuid);
assert_eq!(value, DataValue::Float32(0.0f32));
}
_ => panic!("Expected Telemetry Entry"),
}
}
#[tokio::test]
async fn mismatched_type() {
let (mut rx, _, client) = create_test_client();
let tlm = TelemetryRegistry::new(Arc::new(client));
let tlm_handle = tlm.register_generic("generic", DataType::Float32);
let tlm_uuid = Uuid::new_v4();
let expected_rx = async {
let msg = rx.recv().await.unwrap();
let Callback::Once(responder) = msg.callback else {
panic!("Expected Once Callback");
};
assert!(msg.msg.response.is_none());
let RequestMessagePayload::TelemetryDefinitionRequest(TelemetryDefinitionRequest {
name,
data_type,
}) = msg.msg.payload
else {
panic!("Expected Telemetry Definition Request")
};
assert_eq!(name, "generic".to_string());
assert_eq!(data_type, DataType::Float32);
responder
.send(ResponseMessage {
uuid: Uuid::new_v4(),
response: Some(msg.msg.uuid),
payload: TelemetryDefinitionResponse { uuid: tlm_uuid }.into(),
})
.unwrap();
};
let (tlm_handle, _) = try_join!(
timeout(Duration::from_secs(1), tlm_handle),
timeout(Duration::from_secs(1), expected_rx),
)
.unwrap();
assert_eq!(*tlm_handle.uuid.try_read().unwrap(), tlm_uuid);
match timeout(
Duration::from_secs(1),
tlm_handle.publish_now(0.0f64.into()),
)
.await
.unwrap()
{
Err(MessageError::IncorrectDataType { expected, actual }) => {
assert_eq!(expected, DataType::Float32);
assert_eq!(actual, DataType::Float64);
}
_ => panic!("Error Expected"),
}
}
#[tokio::test]
async fn typed() {
// if _c drops then we are disconnected
let (mut rx, _c, client) = create_test_client();
let tlm = TelemetryRegistry::new(Arc::new(client));
let tlm_handle = tlm.register::<f32>("typed");
let tlm_uuid = Uuid::new_v4();
let expected_rx = async {
let msg = rx.recv().await.unwrap();
let Callback::Once(responder) = msg.callback else {
panic!("Expected Once Callback");
};
assert!(msg.msg.response.is_none());
let RequestMessagePayload::TelemetryDefinitionRequest(TelemetryDefinitionRequest {
name,
data_type,
}) = msg.msg.payload
else {
panic!("Expected Telemetry Definition Request")
};
assert_eq!(name, "typed".to_string());
assert_eq!(data_type, DataType::Float32);
responder
.send(ResponseMessage {
uuid: Uuid::new_v4(),
response: Some(msg.msg.uuid),
payload: TelemetryDefinitionResponse { uuid: tlm_uuid }.into(),
})
.unwrap();
};
let (tlm_handle, _) = try_join!(
timeout(Duration::from_secs(1), tlm_handle),
timeout(Duration::from_secs(1), expected_rx),
)
.unwrap();
assert_eq!(*tlm_handle.as_generic().uuid.try_read().unwrap(), tlm_uuid);
// This should NOT block if there is space in the queue
tlm_handle
.publish_now(1.0f32.into())
.now_or_never()
.unwrap()
.unwrap();
// This should block as there should not be space in the queue
assert!(tlm_handle
.publish_now(2.0f32.into())
.now_or_never()
.is_none());
let tlm_msg = timeout(Duration::from_secs(1), rx.recv())
.await
.unwrap()
.unwrap();
assert!(matches!(tlm_msg.callback, Callback::None));
match tlm_msg.msg.payload {
RequestMessagePayload::TelemetryEntry(TelemetryEntry { uuid, value, .. }) => {
assert_eq!(uuid, tlm_uuid);
assert_eq!(value, DataValue::Float32(1.0f32));
}
_ => panic!("Expected Telemetry Entry"),
}
let _make_generic_again = tlm_handle.to_generic();
}
#[tokio::test]
async fn reconnect() {
// if _c drops then we are disconnected
let (mut rx, connected, client) = create_test_client();
let tlm = TelemetryRegistry::new(Arc::new(client));
let tlm_handle = tlm.register_generic("generic", DataType::Float32);
let tlm_uuid = Uuid::new_v4();
let expected_rx = async {
let msg = rx.recv().await.unwrap();
let Callback::Once(responder) = msg.callback else {
panic!("Expected Once Callback");
};
assert!(msg.msg.response.is_none());
let RequestMessagePayload::TelemetryDefinitionRequest(TelemetryDefinitionRequest {
name,
data_type,
}) = msg.msg.payload
else {
panic!("Expected Telemetry Definition Request")
};
assert_eq!(name, "generic".to_string());
assert_eq!(data_type, DataType::Float32);
responder
.send(ResponseMessage {
uuid: Uuid::new_v4(),
response: Some(msg.msg.uuid),
payload: TelemetryDefinitionResponse { uuid: tlm_uuid }.into(),
})
.unwrap();
};
let (tlm_handle, _) = try_join!(
timeout(Duration::from_secs(1), tlm_handle),
timeout(Duration::from_secs(1), expected_rx),
)
.unwrap();
assert_eq!(*tlm_handle.uuid.try_read().unwrap(), tlm_uuid);
// Notify Disconnect
connected.send_replace(false);
// Notify Reconnect
connected.send_replace(true);
{
let new_tlm_uuid = Uuid::new_v4();
let msg = rx.recv().await.unwrap();
let Callback::Once(responder) = msg.callback else {
panic!("Expected Once Callback");
};
assert!(msg.msg.response.is_none());
let RequestMessagePayload::TelemetryDefinitionRequest(TelemetryDefinitionRequest {
name,
data_type,
}) = msg.msg.payload
else {
panic!("Expected Telemetry Definition Request")
};
assert_eq!(name, "generic".to_string());
assert_eq!(data_type, DataType::Float32);
responder
.send(ResponseMessage {
uuid: Uuid::new_v4(),
response: Some(msg.msg.uuid),
payload: TelemetryDefinitionResponse { uuid: new_tlm_uuid }.into(),
})
.unwrap();
// Yield to the executor so that the UUIDs can be updated
yield_now().await;
assert_eq!(*tlm_handle.uuid.try_read().unwrap(), new_tlm_uuid);
}
}
}