blatherskite

a toy discord-like chat app backend written for a swe class
Log | Files | Refs | README

tests.rs (18324B)


      1 use super::*;
      2 
      3 use hmac::Mac;
      4 use more_asserts::*;
      5 use poem::{
      6     http::StatusCode,
      7     middleware::AddDataEndpoint,
      8     test::TestClient,
      9     Route,
     10 };
     11 use pretty_assertions::assert_eq;
     12 use sha2::Digest;
     13 
     14 type FakeClient = TestClient<AddDataEndpoint<Route, ServerKey>>;
     15 
     16 fn contents_eq<T: PartialEq>(a: Vec<T>, b: Vec<T>) -> bool {
     17     b.iter().all(|item| a.contains(item))
     18 }
     19 
     20 fn setup() -> FakeClient {
     21     let key: String = rand::thread_rng()
     22         .sample_iter(&Alphanumeric)
     23         .take(7)
     24         .map(char::from)
     25         .collect();
     26     let db = Box::new(Cassandra::new("test"));
     27     let api_service = OpenApiService::new(Api::new(db), "Scuttlebutt", "1.0").server("http://localhost:3000/api");
     28     let app = Route::new()
     29         .nest("/api", api_service)
     30         .data(ServerKey::new_from_slice(&key.as_bytes()).unwrap());
     31     TestClient::new(app)
     32 }
     33 
     34 fn hash_pass(pass: &str) -> String {
     35     let mut hasher = Sha256::new();
     36     hasher.update(pass);
     37     hex::encode(hasher.finalize())
     38 }
     39 
     40 async fn make_user(cli: &FakeClient, name: &str, email: &str, pass: &str) -> User {
     41     let hash = hash_pass(pass);
     42     let resp = cli.post(format!("/api/user?name={}&email={}", name, email))
     43         .content_type("text/plain").body(hash).send().await;
     44     resp.assert_status_is_ok();
     45     resp.json().await.value().deserialize::<User>()
     46 }
     47 
     48 async fn login(cli: &FakeClient, id: i64, pass: &str) -> String {
     49     let hash = hash_pass(pass);
     50     let mut resp = cli.post(format!("/api/login?id={}", id)).content_type("text/plain").body(hash).send().await;
     51     resp.assert_status_is_ok();
     52     resp.0.take_body().into_string().await.unwrap()
     53 }
     54 
     55 async fn user_auth(cli: &FakeClient, name: &str, email: &str, pass: &str) -> (User, String) {
     56     let user = make_user(&cli, name, email, pass).await;    
     57     let auth = login(&cli, user.id, pass).await;
     58     (user, auth)
     59 }
     60 
     61 async fn setup_user_auth() -> (FakeClient, User) {
     62     let cli = setup();
     63     let (user, auth) = user_auth(&cli, "test", "test@example.com", "12345").await;
     64     let cli = cli.default_header("Authorization", &auth);
     65     (cli, user)
     66 }
     67 
     68 async fn make_group(cli: &FakeClient, name: &str) -> Group {
     69     let resp = cli.post(format!("/api/group?name={}", name)).send().await;
     70     resp.assert_status_is_ok();
     71     resp.json().await.value().deserialize::<Group>()
     72 }
     73 
     74 async fn add_group_member(cli: &FakeClient, gid: i64, uid: i64) {
     75     let resp = cli.put(format!("/api/group/members?gid={}&uid={}", gid, uid)).send().await;
     76     resp.assert_status_is_ok();
     77 }
     78 
     79 async fn make_dm(cli: &FakeClient, uid: i64) -> Group {
     80     let resp = cli.post(format!("/api/dm?uid={}", uid)).send().await;
     81     resp.assert_status_is_ok();
     82     resp.json().await.value().deserialize::<Group>()
     83 }
     84 
     85 async fn find_groups(cli: &FakeClient) -> Vec<Group> {
     86     let resp = cli.post("/api/user/groups").send().await;
     87     resp.assert_status_is_ok();
     88     resp.json().await.value().deserialize::<Vec<Group>>()
     89 }
     90 
     91 async fn make_channel(cli: &FakeClient, gid: i64, name: &str) -> Channel {
     92     let resp = cli.post(format!("/api/group/channels?gid={}&name={}", gid, name)).send().await;
     93     resp.assert_status_is_ok();
     94     resp.json().await.value().deserialize::<Channel>()
     95 }
     96 
     97 async fn find_channel(cli: &FakeClient, id: i64) -> Channel {
     98     let resp = cli.get(format!("/api/channel?id={}", id)).send().await;
     99     resp.assert_status_is_ok();
    100     resp.json().await.value().deserialize::<Channel>()
    101 }
    102 
    103 async fn find_group(cli: &FakeClient, id: i64) -> Group {
    104     let resp = cli.get(format!("/api/group?id={}", id)).send().await;
    105     resp.assert_status_is_ok();
    106     resp.json().await.value().deserialize::<Group>()
    107 }
    108 
    109 #[tokio::test]
    110 async fn post_login() {
    111     let cli = setup();
    112     let user = make_user(&cli, "test", "test@example.com", "12345").await;
    113     let hash = hash_pass("12345");
    114 
    115     let resp = cli.post(format!("/api/login?id={}", user.id))
    116         .content_type("text/plain").body("abc").send().await;
    117     resp.assert_status(StatusCode::BAD_REQUEST);
    118     let resp = cli.post(format!("/api/login?id={}", user.id))
    119         .content_type("text/plain").send().await;
    120     resp.assert_status(StatusCode::BAD_REQUEST);
    121 
    122     let resp = cli.post("/api/login?id=12")
    123         .content_type("text/plain").body(hash.clone()).send().await;
    124     resp.assert_status(StatusCode::NOT_FOUND);
    125 
    126     let resp = cli.post(format!("/api/login?id={}", user.id))
    127         .header::<&str, &str>("Authorization", "")
    128         .content_type("text/plain").body(hash_pass("123")).send().await;
    129     resp.assert_status(StatusCode::UNAUTHORIZED);
    130 
    131     let mut resp = cli.post(format!("/api/login?id={}", user.id))
    132         .content_type("text/plain").body(hash.clone()).send().await;
    133     resp.assert_status_is_ok();
    134     let raw_str = resp.0.take_body().into_string().await.unwrap();
    135     let claims: Claims = serde_json::from_str(&String::from_utf8(base64::decode(
    136         raw_str.split(".").nth(1).unwrap()
    137     ).unwrap()).unwrap()).unwrap();
    138     assert_eq!(claims.id, user.id);
    139     assert_ge!(claims.exp, Local::now())
    140 }
    141 
    142 #[tokio::test]
    143 async fn get_user() {
    144     let cli = setup();
    145     let user = make_user(&cli, "test", "test@example.com", "12345").await;
    146     let resp = cli.get("/api/user?id=12").send().await;
    147     resp.assert_status(StatusCode::NOT_FOUND);
    148     let resp = cli.get(format!("/api/user?id={}", user.id)).send().await;
    149     resp.assert_status_is_ok();
    150     let ret_user = resp.json().await.value().deserialize::<User>();
    151     assert_eq!(user, ret_user);
    152 }
    153 
    154 #[tokio::test]
    155 async fn post_user() {
    156     let cli = setup();
    157     let user = make_user(&cli, "test", "test@example.com", "12345").await;
    158 
    159     assert_eq!(user.email, "test@example.com");
    160     assert_eq!(user.username, "test");
    161 
    162     let resp = cli.get(format!("/api/user?id={}", user.id)).send().await;
    163     resp.assert_status_is_ok();
    164 
    165     let same_user = resp.json().await.value().deserialize::<User>();
    166     assert_eq!(user, same_user);
    167 }
    168 
    169 #[tokio::test]
    170 async fn post_user_whitebox() {
    171     let cli = setup();
    172     let user = make_user(&cli, "test", "test@example.com", "12345").await;
    173     let db = Cassandra::new("test");
    174     assert_eq!(db.get_user(user.id).unwrap(), user);
    175     assert_eq!(db.get_user_groups(user.id).unwrap(), Vec::<i64>::new());
    176 }
    177 
    178 #[tokio::test]
    179 async fn put_user() {
    180     let (cli, user) = setup_user_auth().await;
    181 
    182     let resp = cli.put("/api/user?name=fred&email=whoo@whee.com")
    183         .header::<&str, &str>("Authorization", "").send().await;
    184     resp.assert_status(StatusCode::UNAUTHORIZED);
    185 
    186     let resp = cli.put("/api/user?name=fred&email=whoo@whee.com").send().await;
    187     resp.assert_status_is_ok();
    188 
    189     let resp = cli.get(format!("/api/user?id={}", user.id)).send().await;
    190     resp.assert_status_is_ok();
    191     let ret_user = resp.json().await.value().deserialize::<User>();
    192     assert_eq!(ret_user.email, "whoo@whee.com");
    193     assert_eq!(ret_user.username, "fred");
    194     // User should retain their underlying ID
    195     assert_eq!(user.id, ret_user.id);
    196 }
    197 
    198 #[tokio::test]
    199 /// FIXME non exhaustive
    200 async fn del_user() {
    201     let (cli, user) = setup_user_auth().await;
    202 
    203     let resp = cli.delete(format!("/api/user?id={}", user.id))
    204         .header::<&str, &str>("Authorization", "").send().await;
    205     resp.assert_status(StatusCode::UNAUTHORIZED);
    206 
    207     let resp = cli.delete(format!("/api/user?id={}", user.id)).send().await;
    208 
    209     resp.assert_status_is_ok();
    210     let resp = cli.get(format!("/api/user?id={}", user.id)).send().await;
    211     resp.assert_status(StatusCode::NOT_FOUND);
    212 }
    213 
    214 #[tokio::test]
    215 async fn post_group() {
    216     let (cli, user) = setup_user_auth().await;
    217     let resp = cli.post("/api/group?name=test")
    218         .header::<&str, &str>("Authorization", "").send().await;
    219     resp.assert_status(StatusCode::UNAUTHORIZED);
    220 
    221     let resp = cli.post("/api/group?name=").send().await;
    222     resp.assert_status(StatusCode::BAD_REQUEST);
    223     let resp = cli.post("/api/group?name=test").send().await;
    224     resp.assert_status_is_ok();
    225 
    226     let group = resp.json().await.value().deserialize::<Group>();
    227     assert_eq!(group.name, "test");
    228     assert_eq!(group.members, vec![user.id]);
    229     assert_eq!(group.admin, vec![user.id]);
    230     assert_eq!(group.owner, user.id);
    231     assert_eq!(group.channels.len(), 1);
    232 
    233     let channel = find_channel(&cli, group.channels[0]).await;
    234     assert_eq!(channel.members, vec![user.id]);
    235     assert_eq!(channel.private, false);
    236     assert_eq!(
    237         find_channel(&cli, group.channels[0]).await.name,
    238         String::from("main")
    239     );
    240 }
    241 
    242 #[tokio::test]
    243 async fn post_dm() {
    244     let (cli, user) = setup_user_auth().await;
    245     let (user2, auth2) = user_auth(&cli, "user2", "who@cares.com", "12").await;
    246     let resp = cli.post("/api/dm?uid=12")
    247         .header::<&str, &str>("Authorization", "").send().await;
    248     resp.assert_status(StatusCode::UNAUTHORIZED);
    249     
    250     let resp = cli.post(format!("/api/dm?uid={}", user2.id)).send().await;
    251     resp.assert_status_is_ok();
    252 
    253     let group = resp.json().await.value().deserialize::<Group>();
    254     assert_eq!(group.name, "");
    255     assert_eq!(group.members, vec![user.id, user2.id]);
    256     assert_eq!(group.admin, Vec::<i64>::new());
    257     assert_eq!(group.owner, user.id);
    258     assert_eq!(group.channels.len(), 1);   
    259 }
    260 
    261 #[tokio::test]
    262 async fn post_dm_whitebox() {
    263     let (cli, user) = setup_user_auth().await;
    264     let (user2, auth2) = user_auth(&cli, "user2", "who@cares.com", "12").await;
    265     let resp = cli.post(format!("/api/dm?uid={}", user2.id)).send().await;
    266     resp.assert_status_is_ok();
    267     let dm = resp.json().await.value().deserialize::<Group>();
    268 
    269     let db = Cassandra::new("test");
    270     assert_eq!(db.get_group(dm.id).unwrap(), dm);
    271     assert_eq!(db.get_user_dms(user.id).unwrap(), vec![dm.id]);
    272 }
    273 
    274 #[tokio::test]
    275 async fn put_group() {
    276     let (cli, _user) = setup_user_auth().await;
    277     let (user2, auth2) = user_auth(&cli, "user2", "who@cares.com", "12").await;
    278     let group = make_group(&cli, "test").await;
    279     add_group_member(&cli, group.id, user2.id).await;
    280 
    281     let resp = cli.put(format!("/api/group?id={}&name=test2", group.id))
    282         .header::<&str, &str>("Authorization", "").send().await;
    283     resp.assert_status(StatusCode::UNAUTHORIZED);
    284     let resp = cli.put(format!("/api/group?id={}&name=test2", group.id))
    285         .header::<&str, &str>("Authorization", &auth2).send().await;
    286     resp.assert_status(StatusCode::UNAUTHORIZED);
    287     
    288     let resp = cli.put(format!("/api/group?id={}&name=", group.id)).send().await;
    289     resp.assert_status(StatusCode::BAD_REQUEST);
    290 
    291     let resp = cli.put("/api/group?id=12&name=test2").send().await;
    292     resp.assert_status(StatusCode::NOT_FOUND);
    293 
    294     let resp = cli.put(format!("/api/group?id={}&name=test2", group.id)).send().await;
    295     resp.assert_status_is_ok();
    296 
    297     let group = find_group(&cli, group.id).await;
    298     assert_eq!(group.name, String::from("test2"));
    299 }
    300 
    301 #[tokio::test]
    302 /// TODO non exhaustive
    303 async fn del_group() {
    304     let (cli, _user) = setup_user_auth().await;
    305     let group = make_group(&cli, "test").await;
    306 
    307     let resp = cli.delete(format!("/api/group?id={}", group.id))
    308         .header::<&str, &str>("Authorization", "").send().await;
    309     resp.assert_status(StatusCode::UNAUTHORIZED);
    310 
    311     let resp = cli.delete("/api/group?id=12").send().await;
    312     resp.assert_status(StatusCode::NOT_FOUND);
    313 
    314     let resp = cli.delete(format!("/api/group?id={}", group.id)).send().await;
    315     resp.assert_status_is_ok();
    316 
    317     let resp = cli.get(format!("/api/group?id={}", group.id)).send().await;
    318     resp.assert_status(StatusCode::NOT_FOUND);
    319     let resp = cli.get(format!("/api/channel?id={}", group.channels[0])).send().await;
    320     resp.assert_status(StatusCode::NOT_FOUND);
    321 
    322     let resp = cli.get("/api/user/groups").send().await;
    323     resp.assert_status_is_ok();
    324     let groups = resp.json().await.value().deserialize::<Vec<Group>>();
    325     assert!(!groups.contains(&group));
    326 }
    327 
    328 // #[tokio::test]
    329 // async fn get_group_members() {
    330 //     let (cli, user) = setup_user_auth().await;
    331 //     let group = make_group(&cli, auth.clone(), "test").await;
    332 //     add_group_member
    333 // }
    334 
    335 #[tokio::test]
    336 /// TODO non exhaustive
    337 async fn put_group_members() {
    338     let (cli, user) = setup_user_auth().await;
    339     let group = make_group(&cli, "test").await;
    340     let user2 = make_user(&cli, "testeroo", "test2@example.com", "123456").await;
    341     
    342     let resp = cli.put(format!("/api/group/members?gid={}&uid={}", group.id, user2.id))
    343         .header::<&str, &str>("Authorization", "").send().await;
    344     resp.assert_status(StatusCode::UNAUTHORIZED);
    345 
    346     let resp = cli.put(format!("/api/group/members?gid={}&uid=", group.id)).send().await;
    347     resp.assert_status(StatusCode::BAD_REQUEST);
    348 
    349     let resp = cli.put(format!("/api/group/members?gid=12&uid={}", user.id)).send().await;
    350     resp.assert_status(StatusCode::NOT_FOUND);
    351 
    352     let resp = cli.put(format!("/api/group/members?gid={}&uid={}", group.id, user2.id)).send().await;
    353     resp.assert_status_is_ok();
    354     
    355     assert!(find_group(&cli, group.id).await.members.contains(&user2.id));
    356 }
    357 #[test]
    358 /// Test if gen_id() gives unique IDs on successive calls
    359 /// and if it can be called from multiple threads without error
    360 fn test_id_gen() {
    361     let a = gen_id();
    362     std::thread::sleep(std::time::Duration::from_secs(1));
    363     let b = gen_id();
    364     assert_ge!(b, a);
    365     let threads: Vec<_> = (0..100).map(|i| std::thread::spawn(move || gen_id())).collect();
    366     for handle in threads {
    367         handle.join().unwrap();
    368     }
    369 }
    370 
    371 #[tokio::test]
    372 async fn get_channel() {
    373     let (cli, _user) = setup_user_auth().await;
    374     let group = make_group(&cli, "test").await;
    375     let chan = make_channel(&cli, group.id, "random").await;
    376     let resp = cli.get(format!("/api/channel?id={}", chan.id)).send().await;
    377     resp.assert_status_is_ok();
    378     let recv_chan = resp.json().await.value().deserialize::<Channel>();
    379     assert_eq!(chan, recv_chan);
    380 }
    381 
    382 
    383 #[tokio::test]
    384 async fn post_channel_whitebox() {
    385     let (cli, _user) = setup_user_auth().await;
    386     let group = make_group(&cli, "test").await;
    387     let chan = make_channel(&cli, group.id, "random").await;
    388     
    389     let db = Cassandra::new("test");
    390     assert_eq!(db.get_channel(chan.id).unwrap(), chan);
    391     assert!(db.get_group_channels(group.id).unwrap().contains(&chan.id));
    392 }
    393 
    394 
    395 // FIXME non exhaustive
    396 #[tokio::test]
    397 async fn get_channels() {
    398     let (cli, _user) = setup_user_auth().await;
    399     let group = make_group(&cli, "test").await;
    400     let chan1 = make_channel(&cli, group.id, "random").await;
    401     let chan2 = make_channel(&cli, group.id, "random").await;
    402     let chan3 = make_channel(&cli, group.id, "random").await;
    403     let resp = cli.get(format!("/api/group/channels?gid={}", group.id)).send().await;
    404     resp.assert_status_is_ok();
    405     let channels = resp.json().await.value().deserialize::<Vec<Channel>>();
    406 
    407     assert!(contents_eq(
    408         channels,
    409         vec![find_channel(&cli, group.channels[0]).await, chan1, chan2, chan3]
    410     ));
    411 }
    412 
    413 #[tokio::test]
    414 async fn get_group() {
    415     let (cli, _user) = setup_user_auth().await;
    416     let (user2, auth2) = user_auth(&cli, "wehee", "who@cares.com", "12").await;
    417     let group = make_group(&cli, "test1").await;
    418     let group2 = make_group(&cli, "test2").await;
    419     add_group_member(&cli, group2.id, user2.id).await;
    420     
    421     let resp = cli.get(format!("/api/group?id={}", group.id)).send().await;
    422     resp.assert_status_is_ok();
    423     let recv_group = resp.json().await.value().deserialize::<Group>();
    424     assert_eq!(group, recv_group);
    425 
    426     let resp = cli.get(format!("/api/group?id={}", group.id))
    427         .header::<&str, &str>("Authorization", &auth2).send().await;
    428     resp.assert_status(StatusCode::NOT_FOUND);
    429 }
    430 
    431 #[tokio::test]
    432 async fn get_groups() {
    433     let (cli, _user) = setup_user_auth().await;
    434     let (user2, auth2) = user_auth(&cli, "wehee", "who@cares.com", "12").await;
    435     let group = make_group(&cli, "test1").await;
    436     add_group_member(&cli, group.id, user2.id).await;
    437     let group = find_group(&cli, group.id).await;
    438     let group2 = make_group(&cli, "test2").await;
    439     let group3 = make_group(&cli, "test3").await;
    440     
    441     let resp = cli.get("/api/user/groups").send().await;
    442     resp.assert_status_is_ok();
    443     let groups = resp.json().await.value().deserialize::<Vec<Group>>();
    444     assert!(contents_eq(groups, vec![group.clone(), group2, group3]));
    445 
    446     let resp = cli.get("/api/user/groups")
    447         .header::<&str, &str>("Authorization", &auth2).send().await;
    448     resp.assert_status_is_ok();
    449     let groups = resp.json().await.value().deserialize::<Vec<Group>>();
    450     assert!(contents_eq(groups, vec![group]));
    451 }
    452 
    453 #[tokio::test]
    454 async fn get_dms() {
    455     let (cli, _user) = setup_user_auth().await;
    456     let (user2, auth2) = user_auth(&cli, "wehee", "who@cares.com", "12").await;
    457     let (user3, auth3) = user_auth(&cli, "whoo", "why@ask.com", "11").await;
    458     let dm1 = make_dm(&cli, user2.id).await;
    459     add_group_member(&cli, dm1.id, user3.id).await;
    460     let dm2 = make_dm(&cli, user3.id).await;
    461     let dm1 = find_group(&cli, dm1.id).await;
    462     let dm2 = find_group(&cli, dm2.id).await;
    463         
    464     let resp = cli.get("/api/user/dms").send().await;
    465     resp.assert_status_is_ok();
    466     let dms = resp.json().await.value().deserialize::<Vec<Group>>();
    467     assert!(contents_eq(dms, vec![dm1.clone(), dm2.clone()]));
    468     
    469     let resp = cli.get("/api/user/dms")
    470         .header::<&str, &str>("Authorization", &auth2).send().await;
    471     resp.assert_status_is_ok();
    472     let dms = resp.json().await.value().deserialize::<Vec<Group>>();
    473     assert!(contents_eq(dms, vec![dm1.clone()]));
    474 
    475     let resp = cli.get("/api/user/dms")
    476         .header::<&str, &str>("Authorization", &auth3).send().await;
    477     resp.assert_status_is_ok();
    478     let dms = resp.json().await.value().deserialize::<Vec<Group>>();
    479     assert!(contents_eq(dms, vec![dm1.clone(), dm2.clone()]));
    480 }
    481 
    482 #[tokio::test]
    483 async fn leave_group() {
    484     let (cli, user) = setup_user_auth().await;
    485     let (user2, auth2) = user_auth(&cli, "wehee", "who@cares.com", "12").await;
    486     let group = make_group(&cli, "test1").await;
    487     add_group_member(&cli, group.id, user2.id).await;
    488 
    489     let resp = cli.delete(format!("/api/user/groups?gid={}", group.id))
    490         .header::<&str, &str>("Authorization", &auth2).send().await;    
    491     resp.assert_status_is_ok();
    492 
    493     let members = find_group(&cli, group.id).await.members;
    494     assert!(contents_eq(members, vec![user.id]));
    495 }