2023-03-23 02:22:08 +00:00
|
|
|
use crate::{Client, Connection, Credentials, EstablishConnectionError, UserStore};
|
2022-02-16 21:54:00 +00:00
|
|
|
use anyhow::{anyhow, Result};
|
2023-03-23 02:22:08 +00:00
|
|
|
use futures::{stream::BoxStream, StreamExt};
|
2022-02-16 21:54:00 +00:00
|
|
|
use gpui::{executor, ModelHandle, TestAppContext};
|
2021-10-04 19:07:35 +00:00
|
|
|
use parking_lot::Mutex;
|
2022-09-29 20:51:17 +00:00
|
|
|
use rpc::{
|
|
|
|
proto::{self, GetPrivateUserInfo, GetPrivateUserInfoResponse},
|
|
|
|
ConnectionId, Peer, Receipt, TypedEnvelope,
|
|
|
|
};
|
2023-03-23 02:22:08 +00:00
|
|
|
use std::{rc::Rc, sync::Arc};
|
|
|
|
use util::http::FakeHttpClient;
|
2021-10-04 19:07:35 +00:00
|
|
|
|
|
|
|
pub struct FakeServer {
|
|
|
|
peer: Arc<Peer>,
|
2022-02-16 21:54:00 +00:00
|
|
|
state: Arc<Mutex<FakeServerState>>,
|
2021-10-04 19:07:35 +00:00
|
|
|
user_id: u64,
|
2022-02-16 21:54:00 +00:00
|
|
|
executor: Rc<executor::Foreground>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Default)]
|
|
|
|
struct FakeServerState {
|
|
|
|
incoming: Option<BoxStream<'static, Box<dyn proto::AnyTypedEnvelope>>>,
|
|
|
|
connection_id: Option<ConnectionId>,
|
|
|
|
forbid_connections: bool,
|
|
|
|
auth_count: usize,
|
|
|
|
access_token: usize,
|
2021-10-04 19:07:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl FakeServer {
|
|
|
|
pub async fn for_client(
|
|
|
|
client_user_id: u64,
|
2022-05-30 23:16:40 +00:00
|
|
|
client: &Arc<Client>,
|
2021-10-04 19:07:35 +00:00
|
|
|
cx: &TestAppContext,
|
2022-02-16 21:54:00 +00:00
|
|
|
) -> Self {
|
|
|
|
let server = Self {
|
2022-12-14 14:55:56 +00:00
|
|
|
peer: Peer::new(0),
|
2022-02-16 21:54:00 +00:00
|
|
|
state: Default::default(),
|
2021-10-04 19:07:35 +00:00
|
|
|
user_id: client_user_id,
|
2022-02-16 21:54:00 +00:00
|
|
|
executor: cx.foreground(),
|
|
|
|
};
|
2021-10-04 19:07:35 +00:00
|
|
|
|
2022-05-30 23:16:40 +00:00
|
|
|
client
|
2021-10-04 19:07:35 +00:00
|
|
|
.override_authenticate({
|
2022-05-11 04:45:12 +00:00
|
|
|
let state = Arc::downgrade(&server.state);
|
2021-10-04 19:07:35 +00:00
|
|
|
move |cx| {
|
2022-05-11 04:45:12 +00:00
|
|
|
let state = state.clone();
|
2021-10-04 19:07:35 +00:00
|
|
|
cx.spawn(move |_| async move {
|
2022-05-11 04:45:12 +00:00
|
|
|
let state = state.upgrade().ok_or_else(|| anyhow!("server dropped"))?;
|
|
|
|
let mut state = state.lock();
|
|
|
|
state.auth_count += 1;
|
|
|
|
let access_token = state.access_token.to_string();
|
2021-10-04 19:07:35 +00:00
|
|
|
Ok(Credentials {
|
|
|
|
user_id: client_user_id,
|
|
|
|
access_token,
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.override_establish_connection({
|
2022-08-10 21:39:24 +00:00
|
|
|
let peer = Arc::downgrade(&server.peer);
|
2022-05-11 04:45:12 +00:00
|
|
|
let state = Arc::downgrade(&server.state);
|
2021-10-04 19:07:35 +00:00
|
|
|
move |credentials, cx| {
|
2022-02-16 21:54:00 +00:00
|
|
|
let peer = peer.clone();
|
|
|
|
let state = state.clone();
|
2021-10-04 19:07:35 +00:00
|
|
|
let credentials = credentials.clone();
|
2022-02-16 21:54:00 +00:00
|
|
|
cx.spawn(move |cx| async move {
|
2022-05-11 04:45:12 +00:00
|
|
|
let state = state.upgrade().ok_or_else(|| anyhow!("server dropped"))?;
|
|
|
|
let peer = peer.upgrade().ok_or_else(|| anyhow!("server dropped"))?;
|
2022-02-16 21:54:00 +00:00
|
|
|
if state.lock().forbid_connections {
|
|
|
|
Err(EstablishConnectionError::Other(anyhow!(
|
|
|
|
"server is forbidding connections"
|
|
|
|
)))?
|
|
|
|
}
|
|
|
|
|
2022-05-11 04:45:12 +00:00
|
|
|
assert_eq!(credentials.user_id, client_user_id);
|
|
|
|
|
2022-02-16 21:54:00 +00:00
|
|
|
if credentials.access_token != state.lock().access_token.to_string() {
|
|
|
|
Err(EstablishConnectionError::Unauthorized)?
|
|
|
|
}
|
|
|
|
|
2022-04-08 14:04:03 +00:00
|
|
|
let (client_conn, server_conn, _) = Connection::in_memory(cx.background());
|
2022-03-04 21:53:40 +00:00
|
|
|
let (connection_id, io, incoming) =
|
2022-10-12 13:13:41 +00:00
|
|
|
peer.add_test_connection(server_conn, cx.background());
|
2022-02-16 21:54:00 +00:00
|
|
|
cx.background().spawn(io).detach();
|
2022-10-18 17:33:38 +00:00
|
|
|
{
|
|
|
|
let mut state = state.lock();
|
|
|
|
state.connection_id = Some(connection_id);
|
|
|
|
state.incoming = Some(incoming);
|
|
|
|
}
|
|
|
|
peer.send(
|
|
|
|
connection_id,
|
|
|
|
proto::Hello {
|
2022-12-14 14:55:56 +00:00
|
|
|
peer_id: Some(connection_id.into()),
|
2022-10-18 17:33:38 +00:00
|
|
|
},
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
2022-02-16 21:54:00 +00:00
|
|
|
Ok(client_conn)
|
2021-10-04 19:07:35 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
client
|
2022-03-23 18:15:36 +00:00
|
|
|
.authenticate_and_connect(false, &cx.to_async())
|
2021-10-04 19:07:35 +00:00
|
|
|
.await
|
|
|
|
.unwrap();
|
2022-09-29 20:51:17 +00:00
|
|
|
|
2021-10-04 19:07:35 +00:00
|
|
|
server
|
|
|
|
}
|
|
|
|
|
2022-01-12 17:02:41 +00:00
|
|
|
pub fn disconnect(&self) {
|
2022-10-12 13:11:07 +00:00
|
|
|
if self.state.lock().connection_id.is_some() {
|
|
|
|
self.peer.disconnect(self.connection_id());
|
|
|
|
let mut state = self.state.lock();
|
|
|
|
state.connection_id.take();
|
|
|
|
state.incoming.take();
|
|
|
|
}
|
2021-10-04 19:07:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn auth_count(&self) -> usize {
|
2022-02-16 21:54:00 +00:00
|
|
|
self.state.lock().auth_count
|
2021-10-04 19:07:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn roll_access_token(&self) {
|
2022-02-16 21:54:00 +00:00
|
|
|
self.state.lock().access_token += 1;
|
2021-10-04 19:07:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn forbid_connections(&self) {
|
2022-02-16 21:54:00 +00:00
|
|
|
self.state.lock().forbid_connections = true;
|
2021-10-04 19:07:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn allow_connections(&self) {
|
2022-02-16 21:54:00 +00:00
|
|
|
self.state.lock().forbid_connections = false;
|
2021-10-04 19:07:35 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 20:27:13 +00:00
|
|
|
pub fn send<T: proto::EnvelopedMessage>(&self, message: T) {
|
|
|
|
self.peer.send(self.connection_id(), message).unwrap();
|
2021-10-04 19:07:35 +00:00
|
|
|
}
|
|
|
|
|
2022-08-10 21:39:24 +00:00
|
|
|
#[allow(clippy::await_holding_lock)]
|
2021-10-04 19:07:35 +00:00
|
|
|
pub async fn receive<M: proto::EnvelopedMessage>(&self) -> Result<TypedEnvelope<M>> {
|
2022-02-16 21:54:00 +00:00
|
|
|
self.executor.start_waiting();
|
2022-09-29 20:51:17 +00:00
|
|
|
|
|
|
|
loop {
|
|
|
|
let message = self
|
|
|
|
.state
|
|
|
|
.lock()
|
|
|
|
.incoming
|
|
|
|
.as_mut()
|
|
|
|
.expect("not connected")
|
|
|
|
.next()
|
|
|
|
.await
|
|
|
|
.ok_or_else(|| anyhow!("other half hung up"))?;
|
|
|
|
self.executor.finish_waiting();
|
|
|
|
let type_name = message.payload_type_name();
|
|
|
|
let message = message.into_any();
|
|
|
|
|
|
|
|
if message.is::<TypedEnvelope<M>>() {
|
|
|
|
return Ok(*message.downcast().unwrap());
|
|
|
|
}
|
|
|
|
|
|
|
|
if message.is::<TypedEnvelope<GetPrivateUserInfo>>() {
|
|
|
|
self.respond(
|
|
|
|
message
|
|
|
|
.downcast::<TypedEnvelope<GetPrivateUserInfo>>()
|
|
|
|
.unwrap()
|
|
|
|
.receipt(),
|
|
|
|
GetPrivateUserInfoResponse {
|
|
|
|
metrics_id: "the-metrics-id".into(),
|
2022-10-03 17:52:57 +00:00
|
|
|
staff: false,
|
2023-08-25 21:34:19 +00:00
|
|
|
flags: Default::default(),
|
2022-09-29 20:51:17 +00:00
|
|
|
},
|
2023-09-08 01:06:05 +00:00
|
|
|
);
|
2022-09-29 20:51:17 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
panic!(
|
|
|
|
"fake server received unexpected message type: {:?}",
|
|
|
|
type_name
|
|
|
|
);
|
|
|
|
}
|
2021-10-04 19:07:35 +00:00
|
|
|
}
|
|
|
|
|
2023-09-08 01:06:05 +00:00
|
|
|
pub fn respond<T: proto::RequestMessage>(&self, receipt: Receipt<T>, response: T::Response) {
|
2022-02-07 20:27:13 +00:00
|
|
|
self.peer.respond(receipt, response).unwrap()
|
2021-10-04 19:07:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn connection_id(&self) -> ConnectionId {
|
2022-02-16 21:54:00 +00:00
|
|
|
self.state.lock().connection_id.expect("not connected")
|
2021-10-04 19:07:35 +00:00
|
|
|
}
|
2021-11-27 03:35:50 +00:00
|
|
|
|
|
|
|
pub async fn build_user_store(
|
|
|
|
&self,
|
|
|
|
client: Arc<Client>,
|
|
|
|
cx: &mut TestAppContext,
|
|
|
|
) -> ModelHandle<UserStore> {
|
|
|
|
let http_client = FakeHttpClient::with_404_response();
|
|
|
|
let user_store = cx.add_model(|cx| UserStore::new(client, http_client, cx));
|
|
|
|
assert_eq!(
|
|
|
|
self.receive::<proto::GetUsers>()
|
|
|
|
.await
|
|
|
|
.unwrap()
|
|
|
|
.payload
|
|
|
|
.user_ids,
|
|
|
|
&[self.user_id]
|
|
|
|
);
|
|
|
|
user_store
|
|
|
|
}
|
2021-10-04 19:07:35 +00:00
|
|
|
}
|
2021-10-05 00:30:11 +00:00
|
|
|
|
2022-06-01 01:09:33 +00:00
|
|
|
impl Drop for FakeServer {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
self.disconnect();
|
|
|
|
}
|
|
|
|
}
|