dce-session 1.0.0

A session lib with user binding and renewable.
Documentation
use std::collections::BTreeSet;
use redis::{cmd, Value};
use redis_test::{MockCmd, MockRedisConnection};
use serde::{Deserialize, Serialize};
use tokio::test;
use dce_session::redis::RedisSession;
use dce_session::session::{Meta, Session};
use dce_session::user::{UidGetter, User};
use crate::common::redis;

mod common;

#[test]
async fn login() {
    let (sid_pool, commands, user) = commends();
    let redis = redis(commands);

    let mut session = RedisSession::<_, Member>::new_with_id(sid_pool).unwrap().with(redis);
    session.login(user.clone(), 10080).await.unwrap();
    let u = session.user().await.unwrap();

    assert_eq!(u, &user);
    assert_eq!(u.id, user.id);
    assert_eq!(u.id.clone(), session.uid().await.unwrap());
}

#[test]
async fn sync() {
    let user_new = Member{
        id: 10000,
        nick: "Drunk".to_string(),
        gender: Gender::Male,
        role_id: 100,
    };
    let user_new_string = serde_json::to_string::<Member>(&user_new).unwrap();
    let (sid_pool1, mut commands1, user1) = commends();
    commands1.push(MockCmd::new(cmd("HGET").arg(RedisSession::<MockRedisConnection, Member>::gen_key("dcesid", &sid_pool1[1])).arg("$user"), Ok(user_new_string.clone())));
    let redis1 = redis(commands1);
    let (sid_pool2, mut commands2, user2) = commends();
    commands2.push(MockCmd::new(cmd("HGET").arg(RedisSession::<MockRedisConnection, Member>::gen_key("dcesid", &sid_pool2[1])).arg("$user"), Ok(user_new_string.clone())));
    let redis2 = redis(commands2);

    let mut session1 = RedisSession::<_, Member>::new_with_id(sid_pool1.clone()).unwrap().with(redis1);
    session1.login(user1.clone(), 10080).await.unwrap();
    let mut session2 = RedisSession::<_, Member>::new_with_id(sid_pool2.clone()).unwrap().with(redis2);
    session2.login(user1.clone(), 10080).await.unwrap();
    let u1 = session1.user().await.unwrap().clone();
    let u2 = session2.user().await.unwrap().clone();

    let umapped_sids = [&sid_pool1[1], &sid_pool2[1]].into_iter().collect::<BTreeSet<_>>().into_iter().collect::<Vec<_>>();
    let usids_value = umapped_sids.iter().map(|id| Value::Data(id.as_bytes().into())).collect::<Vec<_>>();
    let ukey = RedisSession::<MockRedisConnection, Member>::gen_user_key("dceusmap", u1.id);
    let manager_sid_pool = (0..1).map(|_| Meta::gen_id(60).unwrap().0).collect::<Vec<_>>();
    let manager_redis = redis(vec![
        MockCmd::new(cmd("SMEMBERS").arg(ukey), Ok(Value::Bulk(usids_value))),
        MockCmd::new(cmd("EXISTS").arg(RedisSession::<MockRedisConnection, Member>::gen_key("dcesid", &umapped_sids[0])), Ok("1")),
        MockCmd::new(cmd("EXISTS").arg(RedisSession::<MockRedisConnection, Member>::gen_key("dcesid", &umapped_sids[1])), Ok("1")),
        MockCmd::new(cmd("HSET").arg(RedisSession::<MockRedisConnection, Member>::gen_key("dcesid", &umapped_sids[0])).arg("$user").arg(&user_new_string), Ok("1")),
        MockCmd::new(cmd("HSET").arg(RedisSession::<MockRedisConnection, Member>::gen_key("dcesid", &umapped_sids[1])).arg("$user").arg(&user_new_string), Ok("1")),
    ]);

    let mut manager_session = RedisSession::<_, Member>::new_with_id(manager_sid_pool).unwrap().with(manager_redis);
    manager_session.sync(&user_new).await.unwrap();

    let u1_new = session1.get::<Member>("$user").await.unwrap();
    let u2_new = session2.get::<Member>("$user").await.unwrap();

    assert_eq!(u1, u2);
    assert_eq!(u1_new, u2_new);
    assert_eq!(u1, user2);
    assert_ne!(u1, u1_new);
    assert_eq!(u1.role_id, 1);
    assert_eq!(u1_new.role_id, 100);
}

fn commends() -> (Vec<String>, Vec<MockCmd>, Member) {
    let sid_pool = (0..2).map(|_| Meta::gen_id(60).unwrap().0).collect::<Vec<_>>();
    let skey = RedisSession::<MockRedisConnection, Member>::gen_key("dcesid", &sid_pool[0]);
    let skey2 = RedisSession::<MockRedisConnection, Member>::gen_key("dcesid", &sid_pool[1]);
    let user = Member {
        id: 10000,
        nick: "Dce".to_string(),
        gender: Gender::Male,
        role_id: 1,
    };
    let ukey = RedisSession::<MockRedisConnection, Member>::gen_user_key("dceusmap", user.id);
    let user_string = serde_json::to_string::<Member>(&user).unwrap();
    let commands = vec![
        MockCmd::new(cmd("HGETALL").arg(skey.as_str()), Ok(Value::Bulk(vec![]))),
        MockCmd::new(cmd("HMSET").arg(skey2.as_str()).arg("$user").arg(user_string.as_str()), Ok("1")),
        MockCmd::new(cmd("EXPIRE").arg(skey2.as_str()).arg("604800"), Ok("1")),
        MockCmd::new(cmd("HGET").arg(skey2.as_str()).arg("$user"), Ok(user_string)),
        MockCmd::new(cmd("SADD").arg(ukey.as_str()).arg(&sid_pool[1]), Ok("1")),
        MockCmd::new(cmd("EXPIRE").arg(ukey.as_str()).arg("604800"), Ok("1")),
        MockCmd::new(cmd("DEL").arg(skey.as_str()), Ok("1")),
    ];
    (sid_pool, commands, user)
}

#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
struct Member {
    id: u64,
    nick: String,
    gender: Gender,
    role_id: u16,
}

#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
enum Gender {
    Male,
    Female,
}

impl UidGetter for Member {
    fn id(&self) -> u64 {
        self.id
    }
}