mirror of
https://github.com/Blah-IM/blahrs.git
synced 2025-05-01 08:41:09 +00:00
refactor(tests): simplify and rename
This commit is contained in:
parent
2759891b7b
commit
35b5aace08
1 changed files with 89 additions and 76 deletions
|
@ -1,5 +1,6 @@
|
||||||
#![expect(clippy::unwrap_used, reason = "FIXME: random false positive")]
|
#![expect(clippy::unwrap_used, reason = "FIXME: random false positive")]
|
||||||
#![expect(clippy::toplevel_ref_arg, reason = "easy to use for fixtures")]
|
#![expect(clippy::toplevel_ref_arg, reason = "easy to use for fixtures")]
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::future::{Future, IntoFuture};
|
use std::future::{Future, IntoFuture};
|
||||||
use std::sync::{Arc, LazyLock};
|
use std::sync::{Arc, LazyLock};
|
||||||
|
@ -11,6 +12,8 @@ use blah_types::{
|
||||||
};
|
};
|
||||||
use blahd::{ApiError, AppState, Database, RoomList, RoomMetadata};
|
use blahd::{ApiError, AppState, Database, RoomList, RoomMetadata};
|
||||||
use ed25519_dalek::SigningKey;
|
use ed25519_dalek::SigningKey;
|
||||||
|
use futures_util::TryFutureExt;
|
||||||
|
use rand::rngs::mock::StepRng;
|
||||||
use rand::RngCore;
|
use rand::RngCore;
|
||||||
use reqwest::{header, Method, StatusCode};
|
use reqwest::{header, Method, StatusCode};
|
||||||
use rstest::{fixture, rstest};
|
use rstest::{fixture, rstest};
|
||||||
|
@ -52,6 +55,7 @@ impl<T: fmt::Debug> ResultExt for Result<T> {
|
||||||
struct Server {
|
struct Server {
|
||||||
port: u16,
|
port: u16,
|
||||||
client: reqwest::Client,
|
client: reqwest::Client,
|
||||||
|
rng: RefCell<StepRng>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Server {
|
impl Server {
|
||||||
|
@ -102,6 +106,68 @@ impl Server {
|
||||||
.await?
|
.await?
|
||||||
.unwrap())
|
.unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_room(
|
||||||
|
&self,
|
||||||
|
key: &SigningKey,
|
||||||
|
attrs: RoomAttrs,
|
||||||
|
title: &str,
|
||||||
|
) -> impl Future<Output = Result<Id>> + use<'_> {
|
||||||
|
let req = sign(
|
||||||
|
key,
|
||||||
|
&mut *self.rng.borrow_mut(),
|
||||||
|
CreateRoomPayload {
|
||||||
|
attrs,
|
||||||
|
members: RoomMemberList(vec![RoomMember {
|
||||||
|
permission: MemberPermission::ALL,
|
||||||
|
user: UserKey(key.verifying_key().to_bytes()),
|
||||||
|
}]),
|
||||||
|
title: title.to_string(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
async move {
|
||||||
|
Ok(self
|
||||||
|
.request(Method::POST, "/room/create", None, Some(&req))
|
||||||
|
.await?
|
||||||
|
.unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn join_room(
|
||||||
|
&self,
|
||||||
|
rid: Id,
|
||||||
|
key: &SigningKey,
|
||||||
|
permission: MemberPermission,
|
||||||
|
) -> impl Future<Output = Result<()>> + use<'_> {
|
||||||
|
let req = sign(
|
||||||
|
key,
|
||||||
|
&mut *self.rng.borrow_mut(),
|
||||||
|
RoomAdminPayload {
|
||||||
|
room: rid,
|
||||||
|
op: RoomAdminOp::AddMember {
|
||||||
|
permission,
|
||||||
|
user: UserKey(key.verifying_key().to_bytes()),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
self.request::<_, NoContent>(Method::POST, format!("/room/{rid}/admin"), None, Some(req))
|
||||||
|
.map_ok(|None| {})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn leave_room(&self, rid: Id, key: &SigningKey) -> impl Future<Output = Result<()>> + use<'_> {
|
||||||
|
let req = sign(
|
||||||
|
key,
|
||||||
|
&mut *self.rng.borrow_mut(),
|
||||||
|
RoomAdminPayload {
|
||||||
|
room: rid,
|
||||||
|
op: RoomAdminOp::RemoveMember {
|
||||||
|
user: UserKey(key.verifying_key().to_bytes()),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
self.request::<_, NoContent>(Method::POST, format!("/room/{rid}/admin"), None, Some(req))
|
||||||
|
.map_ok(|None| {})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixture]
|
#[fixture]
|
||||||
|
@ -130,7 +196,8 @@ fn server() -> Server {
|
||||||
|
|
||||||
tokio::spawn(axum::serve(listener, router).into_future());
|
tokio::spawn(axum::serve(listener, router).into_future());
|
||||||
let client = reqwest::ClientBuilder::new().no_proxy().build().unwrap();
|
let client = reqwest::ClientBuilder::new().no_proxy().build().unwrap();
|
||||||
Server { port, client }
|
let rng = StepRng::new(24, 1).into();
|
||||||
|
Server { port, client, rng }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
|
@ -152,33 +219,6 @@ fn auth(key: &SigningKey, rng: &mut impl RngCore) -> String {
|
||||||
serde_json::to_string(&sign(key, rng, AuthPayload {})).unwrap()
|
serde_json::to_string(&sign(key, rng, AuthPayload {})).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_room<'s>(
|
|
||||||
server: &'s Server,
|
|
||||||
key: &SigningKey,
|
|
||||||
rng: &mut dyn RngCore,
|
|
||||||
attrs: RoomAttrs,
|
|
||||||
title: &str,
|
|
||||||
) -> impl Future<Output = Result<Id>> + use<'s> {
|
|
||||||
let req = sign(
|
|
||||||
key,
|
|
||||||
rng,
|
|
||||||
CreateRoomPayload {
|
|
||||||
attrs,
|
|
||||||
members: RoomMemberList(vec![RoomMember {
|
|
||||||
permission: MemberPermission::ALL,
|
|
||||||
user: UserKey(key.verifying_key().to_bytes()),
|
|
||||||
}]),
|
|
||||||
title: title.to_string(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
async move {
|
|
||||||
Ok(server
|
|
||||||
.request(Method::POST, "/room/create", None, Some(&req))
|
|
||||||
.await?
|
|
||||||
.unwrap())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case::public(true)]
|
#[case::public(true)]
|
||||||
#[case::private(false)]
|
#[case::private(false)]
|
||||||
|
@ -198,13 +238,15 @@ async fn room_create_get(server: Server, ref mut rng: impl RngCore, #[case] publ
|
||||||
};
|
};
|
||||||
|
|
||||||
// Alice has permission.
|
// Alice has permission.
|
||||||
let rid = create_room(&server, &ALICE_PRIV, rng, room_meta.attrs, &room_meta.title)
|
let rid = server
|
||||||
|
.create_room(&ALICE_PRIV, room_meta.attrs, &room_meta.title)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
room_meta.rid = rid;
|
room_meta.rid = rid;
|
||||||
|
|
||||||
// Bob has no permission.
|
// Bob has no permission.
|
||||||
create_room(&server, &BOB_PRIV, rng, room_meta.attrs, &room_meta.title)
|
server
|
||||||
|
.create_room(&BOB_PRIV, room_meta.attrs, &room_meta.title)
|
||||||
.await
|
.await
|
||||||
.expect_api_err(StatusCode::FORBIDDEN, "permission_denied");
|
.expect_api_err(StatusCode::FORBIDDEN, "permission_denied");
|
||||||
|
|
||||||
|
@ -261,39 +303,17 @@ async fn room_create_get(server: Server, ref mut rng: impl RngCore, #[case] publ
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn room_join_leave(server: Server, ref mut rng: impl RngCore) {
|
async fn room_join_leave(server: Server, ref mut rng: impl RngCore) {
|
||||||
let rid_pub = create_room(
|
let rid_pub = server
|
||||||
&server,
|
.create_room(&ALICE_PRIV, RoomAttrs::PUBLIC_JOINABLE, "public room")
|
||||||
&ALICE_PRIV,
|
.await
|
||||||
rng,
|
.unwrap();
|
||||||
RoomAttrs::PUBLIC_JOINABLE,
|
let rid_priv = server
|
||||||
"public room",
|
.create_room(&ALICE_PRIV, RoomAttrs::empty(), "private room")
|
||||||
)
|
.await
|
||||||
.await
|
.unwrap();
|
||||||
.unwrap();
|
|
||||||
let rid_priv = create_room(
|
|
||||||
&server,
|
|
||||||
&ALICE_PRIV,
|
|
||||||
rng,
|
|
||||||
RoomAttrs::empty(),
|
|
||||||
"private room",
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let mut join = |rid: Id, key: &SigningKey| {
|
let join =
|
||||||
let req = sign(
|
|rid: Id, key: &SigningKey| server.join_room(rid, key, MemberPermission::MAX_SELF_ADD);
|
||||||
key,
|
|
||||||
rng,
|
|
||||||
RoomAdminPayload {
|
|
||||||
room: rid,
|
|
||||||
op: RoomAdminOp::AddMember {
|
|
||||||
permission: MemberPermission::MAX_SELF_ADD,
|
|
||||||
user: UserKey(key.verifying_key().to_bytes()),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
server.request::<_, NoContent>(Method::POST, format!("/room/{rid}/admin"), None, Some(req))
|
|
||||||
};
|
|
||||||
|
|
||||||
// Ok.
|
// Ok.
|
||||||
join(rid_pub, &BOB_PRIV).await.unwrap();
|
join(rid_pub, &BOB_PRIV).await.unwrap();
|
||||||
|
@ -309,6 +329,11 @@ async fn room_join_leave(server: Server, ref mut rng: impl RngCore) {
|
||||||
join(Id::INVALID, &BOB_PRIV)
|
join(Id::INVALID, &BOB_PRIV)
|
||||||
.await
|
.await
|
||||||
.expect_api_err(StatusCode::NOT_FOUND, "not_found");
|
.expect_api_err(StatusCode::NOT_FOUND, "not_found");
|
||||||
|
// Overly high permission.
|
||||||
|
server
|
||||||
|
.join_room(rid_priv, &BOB_PRIV, MemberPermission::ALL)
|
||||||
|
.await
|
||||||
|
.expect_api_err(StatusCode::BAD_REQUEST, "deserialization");
|
||||||
|
|
||||||
// Bob is joined now.
|
// Bob is joined now.
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -321,19 +346,7 @@ async fn room_join_leave(server: Server, ref mut rng: impl RngCore) {
|
||||||
1,
|
1,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut leave = |rid: Id, key: &SigningKey| {
|
let leave = |rid: Id, key: &SigningKey| server.leave_room(rid, key);
|
||||||
let req = sign(
|
|
||||||
key,
|
|
||||||
rng,
|
|
||||||
RoomAdminPayload {
|
|
||||||
room: rid,
|
|
||||||
op: RoomAdminOp::RemoveMember {
|
|
||||||
user: UserKey(key.verifying_key().to_bytes()),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
server.request::<_, NoContent>(Method::POST, format!("/room/{rid}/admin"), None, Some(req))
|
|
||||||
};
|
|
||||||
|
|
||||||
// Ok.
|
// Ok.
|
||||||
leave(rid_pub, &BOB_PRIV).await.unwrap();
|
leave(rid_pub, &BOB_PRIV).await.unwrap();
|
||||||
|
@ -345,7 +358,7 @@ async fn room_join_leave(server: Server, ref mut rng: impl RngCore) {
|
||||||
leave(rid_priv, &BOB_PRIV)
|
leave(rid_priv, &BOB_PRIV)
|
||||||
.await
|
.await
|
||||||
.expect_api_err(StatusCode::NOT_FOUND, "not_found");
|
.expect_api_err(StatusCode::NOT_FOUND, "not_found");
|
||||||
// Unpermitted and not inside.
|
// Invalid room.
|
||||||
leave(Id::INVALID, &BOB_PRIV)
|
leave(Id::INVALID, &BOB_PRIV)
|
||||||
.await
|
.await
|
||||||
.expect_api_err(StatusCode::NOT_FOUND, "not_found");
|
.expect_api_err(StatusCode::NOT_FOUND, "not_found");
|
Loading…
Add table
Reference in a new issue