Translate HTTP and network tests
This commit is contained in:
@@ -4,7 +4,10 @@
|
||||
//! surfaces. Their behavior is implemented only when the owning API slice is
|
||||
//! ported.
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::future::Future;
|
||||
use std::marker::PhantomData;
|
||||
use std::pin::Pin;
|
||||
use std::sync::{
|
||||
Arc,
|
||||
atomic::{AtomicBool, Ordering},
|
||||
@@ -91,7 +94,7 @@ impl CancellationToken {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
|
||||
#[derive(Debug, Default, Eq, Hash, PartialEq)]
|
||||
pub struct Subscription;
|
||||
|
||||
pub type EventHandler<T> = Arc<dyn Fn(T) + Send + Sync>;
|
||||
@@ -143,17 +146,65 @@ pub struct TimeProvider;
|
||||
|
||||
pub struct MediaTypeHeaderValue(pub String);
|
||||
|
||||
pub struct HttpMessageHandler;
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct HttpRequest {
|
||||
pub method: String,
|
||||
pub uri: Uri,
|
||||
pub headers: BTreeMap<String, String>,
|
||||
pub content_type: Option<String>,
|
||||
pub body: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct HttpResponse {
|
||||
pub status_code: u16,
|
||||
pub headers: BTreeMap<String, String>,
|
||||
pub content_type: Option<String>,
|
||||
pub body: Vec<u8>,
|
||||
}
|
||||
|
||||
impl HttpResponse {
|
||||
#[must_use]
|
||||
pub const fn is_success_status_code(&self) -> bool {
|
||||
self.status_code >= 200 && self.status_code < 300
|
||||
}
|
||||
}
|
||||
|
||||
pub type HttpResponseFuture = Pin<Box<dyn Future<Output = HttpResponse> + Send>>;
|
||||
|
||||
type HttpHandler = dyn Fn(HttpRequest, CancellationToken) -> HttpResponseFuture + Send + Sync;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct HttpMessageHandler(Arc<HttpHandler>);
|
||||
|
||||
impl HttpMessageHandler {
|
||||
pub fn new<F, Fut>(handler: F) -> Self
|
||||
where
|
||||
F: Fn(HttpRequest, CancellationToken) -> Fut + Send + Sync + 'static,
|
||||
Fut: Future<Output = HttpResponse> + Send + 'static,
|
||||
{
|
||||
Self(Arc::new(move |request, cancellation_token| {
|
||||
Box::pin(handler(request, cancellation_token))
|
||||
}))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn send(
|
||||
&self,
|
||||
request: HttpRequest,
|
||||
cancellation_token: CancellationToken,
|
||||
) -> HttpResponseFuture {
|
||||
(self.0)(request, cancellation_token)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct HttpClient;
|
||||
|
||||
pub struct HttpResponse;
|
||||
|
||||
pub struct HttpMethod(pub String);
|
||||
|
||||
pub struct AuthenticationHeaderValue(pub String);
|
||||
|
||||
pub trait IProgress<T> {}
|
||||
pub trait IProgress<T>: Send + Sync {}
|
||||
|
||||
pub struct IEnumerator;
|
||||
|
||||
@@ -200,3 +251,55 @@ pub struct UnicodeCategory(pub i32);
|
||||
pub struct TextEncoding;
|
||||
|
||||
pub struct SocketException;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{CancellationToken, HttpMessageHandler, HttpRequest, HttpResponse, Uri};
|
||||
use std::collections::BTreeMap;
|
||||
use std::future::Future;
|
||||
use std::task::{Context, Poll, Waker};
|
||||
|
||||
#[test]
|
||||
fn http_handler_preserves_request_and_response_data() {
|
||||
let handler = HttpMessageHandler::new(|request, _cancellation_token| async move {
|
||||
HttpResponse {
|
||||
status_code: 201,
|
||||
headers: request.headers,
|
||||
content_type: request.content_type,
|
||||
body: request.body,
|
||||
}
|
||||
});
|
||||
let mut response = handler.send(
|
||||
HttpRequest {
|
||||
method: "PUT".into(),
|
||||
uri: Uri("http://example.test/".into()),
|
||||
headers: BTreeMap::from([("Location".into(), "slcaps://fixture".into())]),
|
||||
content_type: Some("application/llsd+xml".into()),
|
||||
body: b"test".to_vec(),
|
||||
},
|
||||
CancellationToken::default(),
|
||||
);
|
||||
let mut context = Context::from_waker(Waker::noop());
|
||||
let response = match Future::poll(response.as_mut(), &mut context) {
|
||||
Poll::Ready(response) => response,
|
||||
Poll::Pending => panic!("immediate handler unexpectedly remained pending"),
|
||||
};
|
||||
|
||||
assert!(response.is_success_status_code());
|
||||
assert_eq!(response.headers["Location"], "slcaps://fixture");
|
||||
assert_eq!(
|
||||
response.content_type.as_deref(),
|
||||
Some("application/llsd+xml")
|
||||
);
|
||||
assert_eq!(response.body, b"test");
|
||||
assert!(
|
||||
!HttpResponse {
|
||||
status_code: 399,
|
||||
headers: BTreeMap::new(),
|
||||
content_type: None,
|
||||
body: Vec::new(),
|
||||
}
|
||||
.is_success_status_code()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,8 @@ pub enum Error {
|
||||
Argument,
|
||||
/// An index or destination buffer boundary was exceeded.
|
||||
IndexOutOfRange,
|
||||
/// An operation observed a requested cancellation.
|
||||
Cancelled,
|
||||
}
|
||||
|
||||
impl Error {
|
||||
@@ -61,7 +63,7 @@ impl Error {
|
||||
pub const fn csharp_member(self) -> Option<&'static str> {
|
||||
match self {
|
||||
Self::NotImplemented(error) => Some(error.csharp_member()),
|
||||
Self::ArgumentNull | Self::Argument | Self::IndexOutOfRange => None,
|
||||
Self::ArgumentNull | Self::Argument | Self::IndexOutOfRange | Self::Cancelled => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,6 +81,7 @@ impl fmt::Display for Error {
|
||||
Self::ArgumentNull => formatter.write_str("required argument was null"),
|
||||
Self::Argument => formatter.write_str("argument was invalid"),
|
||||
Self::IndexOutOfRange => formatter.write_str("index was out of range"),
|
||||
Self::Cancelled => formatter.write_str("operation was cancelled"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11377,19 +11377,11 @@ impl GridClient {
|
||||
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.GridClient.Parcels")
|
||||
}
|
||||
/// C# member: `P:LibreMetaverse.GridClient.Self`.
|
||||
pub fn self_(&self) -> libremetaverse::AgentManager {
|
||||
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.GridClient.Self")
|
||||
}
|
||||
/// Setter for C# member: `P:LibreMetaverse.GridClient.Self`.
|
||||
pub fn set_self_(&mut self, value: libremetaverse::AgentManager) {
|
||||
pub fn self_(&mut self) -> &mut libremetaverse::AgentManager {
|
||||
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.GridClient.Self")
|
||||
}
|
||||
/// C# member: `P:LibreMetaverse.GridClient.Settings`.
|
||||
pub fn settings(&self) -> libremetaverse::Settings {
|
||||
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.GridClient.Settings")
|
||||
}
|
||||
/// Setter for C# member: `P:LibreMetaverse.GridClient.Settings`.
|
||||
pub fn set_settings(&mut self, value: libremetaverse::Settings) {
|
||||
pub fn settings(&mut self) -> &mut libremetaverse::Settings {
|
||||
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.GridClient.Settings")
|
||||
}
|
||||
/// C# member: `P:LibreMetaverse.GridClient.Sound`.
|
||||
@@ -25747,7 +25739,7 @@ impl Settings {
|
||||
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Settings.TexturePipeline")
|
||||
}
|
||||
/// C# member: `P:LibreMetaverse.Settings.Timing`.
|
||||
pub fn timing(&self) -> libremetaverse::TimingSettings {
|
||||
pub fn timing(&mut self) -> &mut libremetaverse::TimingSettings {
|
||||
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Settings.Timing")
|
||||
}
|
||||
/// C# member: `P:LibreMetaverse.Settings.UploadCost`.
|
||||
|
||||
Reference in New Issue
Block a user