Removed old code.
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 1s
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 1s
This commit is contained in:
parent
97df1a8ece
commit
9df6c4db42
178
src/client.rs
178
src/client.rs
@ -1,178 +0,0 @@
|
||||
use crate::queue::{Message, MsgType, Queue};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
sync::{
|
||||
mpsc::{channel, Receiver, Sender},
|
||||
Arc, Mutex,
|
||||
},
|
||||
thread::spawn,
|
||||
};
|
||||
use uuid::Uuid;
|
||||
|
||||
const RESPONS_TO: [MsgType; 4] = [
|
||||
MsgType::ActionOk,
|
||||
MsgType::Document,
|
||||
MsgType::Error,
|
||||
MsgType::SessionValidated,
|
||||
];
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ClientChannel {
|
||||
queue: Queue,
|
||||
registry: Arc<Mutex<HashMap<Uuid, Sender<Message>>>>,
|
||||
}
|
||||
|
||||
impl ClientChannel {
|
||||
fn new(queue: Queue) -> Self {
|
||||
Self {
|
||||
queue: queue,
|
||||
registry: Arc::new(Mutex::new(HashMap::new())),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send(&self, mut msg: Message) -> Receiver<Message> {
|
||||
let mut reg = self.registry.lock().unwrap();
|
||||
while reg.contains_key(&msg.get_id()) {
|
||||
msg.reset_id();
|
||||
}
|
||||
let (tx, rx) = channel();
|
||||
reg.insert(msg.get_id(), tx);
|
||||
self.queue.send(msg).unwrap();
|
||||
rx
|
||||
}
|
||||
|
||||
fn reply(&self, msg: Message) {
|
||||
let mut reg = self.registry.lock().unwrap();
|
||||
match reg.remove(&msg.get_id()) {
|
||||
Some(tx) => tx.send(msg).unwrap(),
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod client_channels {
|
||||
use super::*;
|
||||
use std::time::Duration;
|
||||
|
||||
static TIMEOUT: Duration = Duration::from_millis(500);
|
||||
|
||||
#[test]
|
||||
fn fowards_message() {
|
||||
let msg_type = MsgType::Document;
|
||||
let reply_type = MsgType::Time;
|
||||
let queue = Queue::new();
|
||||
let (tx, rx) = channel();
|
||||
queue.add(tx, [msg_type.clone()].to_vec());
|
||||
let chan = ClientChannel::new(queue);
|
||||
let msg = Message::new(msg_type.clone());
|
||||
let client_rx = chan.send(msg.clone());
|
||||
let reply = rx.recv_timeout(TIMEOUT).unwrap();
|
||||
assert_eq!(reply.get_id(), msg.get_id());
|
||||
assert_eq!(reply.get_msg_type().clone(), msg_type);
|
||||
let client_reply = reply.reply(MsgType::Time);
|
||||
chan.reply(client_reply);
|
||||
let client_msg = client_rx.recv_timeout(TIMEOUT).unwrap();
|
||||
assert_eq!(client_msg.get_id(), msg.get_id());
|
||||
assert_eq!(client_msg.get_msg_type().clone(), reply_type);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_duplicate_ids() {
|
||||
let (tx, rx) = channel();
|
||||
let queue = Queue::new();
|
||||
queue.add(tx, [MsgType::Time].to_vec());
|
||||
let chan = ClientChannel::new(queue);
|
||||
let msg1 = Message::new(MsgType::Time);
|
||||
let msg2 = msg1.reply(MsgType::Time);
|
||||
let rx1 = chan.send(msg1);
|
||||
let rx2 = chan.send(msg2);
|
||||
let queue1 = rx.recv_timeout(TIMEOUT).unwrap();
|
||||
let queue2 = rx.recv_timeout(TIMEOUT).unwrap();
|
||||
assert_ne!(queue1.get_id(), queue2.get_id());
|
||||
chan.reply(queue1.reply(MsgType::Document));
|
||||
chan.reply(queue2.reply(MsgType::Document));
|
||||
let reply1 = rx1.recv_timeout(TIMEOUT).unwrap();
|
||||
let reply2 = rx2.recv_timeout(TIMEOUT).unwrap();
|
||||
assert_eq!(reply1.get_id(), queue1.get_id());
|
||||
assert_eq!(reply2.get_id(), queue2.get_id());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ignore_unrequested() {
|
||||
let queue = Queue::new();
|
||||
let chan = ClientChannel::new(queue);
|
||||
chan.reply(Message::new(MsgType::Document));
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Client {
|
||||
channel: ClientChannel,
|
||||
rx: Receiver<Message>,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
fn new(chan: ClientChannel, rx: Receiver<Message>) -> Self {
|
||||
Self {
|
||||
channel: chan,
|
||||
rx: rx,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start(queue: Queue) -> ClientChannel {
|
||||
let (tx, rx) = channel();
|
||||
queue.add(tx.clone(), RESPONS_TO.to_vec());
|
||||
let chan = ClientChannel::new(queue.clone());
|
||||
let client = Client::new(chan.clone(), rx);
|
||||
spawn(move || {
|
||||
client.listen();
|
||||
});
|
||||
chan
|
||||
}
|
||||
|
||||
fn listen(&self) {
|
||||
loop {
|
||||
let msg = self.rx.recv().unwrap();
|
||||
self.channel.reply(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod clients {
|
||||
use super::*;
|
||||
use crate::session::sessions::create_validated_reply;
|
||||
use std::time::Duration;
|
||||
|
||||
static TIMEOUT: Duration = Duration::from_millis(500);
|
||||
|
||||
#[test]
|
||||
fn session_validated() {
|
||||
let queue = Queue::new();
|
||||
let (queue_tx, queue_rx) = channel();
|
||||
queue.add(queue_tx, [MsgType::SessionValidate].to_vec());
|
||||
let chan = Client::start(queue.clone());
|
||||
let chan_rx = chan.send(Message::new(MsgType::SessionValidate));
|
||||
let msg = queue_rx.recv_timeout(TIMEOUT).unwrap();
|
||||
let expected = create_validated_reply(msg);
|
||||
queue.send(expected.clone()).unwrap();
|
||||
let result = chan_rx.recv_timeout(TIMEOUT).unwrap();
|
||||
assert_eq!(result.get_id(), expected.get_id());
|
||||
assert_eq!(result.get_msg_type(), expected.get_msg_type());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn document_return() {
|
||||
let queue = Queue::new();
|
||||
let (queue_tx, queue_rx) = channel();
|
||||
queue.add(queue_tx, [MsgType::DocumentRequest].to_vec());
|
||||
let chan = Client::start(queue.clone());
|
||||
let chan_rx = chan.send(Message::new(MsgType::DocumentRequest));
|
||||
let msg = queue_rx.recv_timeout(TIMEOUT).unwrap();
|
||||
let expected = msg.reply(MsgType::Document);
|
||||
queue.send(expected.clone()).unwrap();
|
||||
let result = chan_rx.recv_timeout(TIMEOUT).unwrap();
|
||||
assert_eq!(result.get_id(), expected.get_id());
|
||||
assert_eq!(result.get_msg_type(), expected.get_msg_type());
|
||||
}
|
||||
}
|
||||
91
src/clock.rs
91
src/clock.rs
@ -1,91 +0,0 @@
|
||||
use crate::queue::{Message, MsgType, Queue};
|
||||
use chrono::prelude::*;
|
||||
use std::{
|
||||
thread::{sleep, spawn},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
const SLEEP_FOR: Duration = Duration::from_secs(1);
|
||||
|
||||
pub struct Clock {
|
||||
queue: Queue,
|
||||
}
|
||||
|
||||
impl Clock {
|
||||
fn new(queue: Queue) -> Self {
|
||||
Self { queue: queue }
|
||||
}
|
||||
|
||||
pub fn start(queue: Queue) {
|
||||
let clock = Clock::new(queue);
|
||||
spawn(move || {
|
||||
clock.listen();
|
||||
});
|
||||
}
|
||||
|
||||
fn listen(&self) {
|
||||
loop {
|
||||
let mut msg = Message::new(MsgType::Time);
|
||||
msg.add_data("time", Utc::now());
|
||||
match self.queue.send(msg) {
|
||||
Ok(_) => {}
|
||||
Err(_) => {}
|
||||
};
|
||||
sleep(SLEEP_FOR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod clocks {
|
||||
use super::*;
|
||||
use std::{
|
||||
sync::mpsc::{channel, Receiver},
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
static TIMEOUT: Duration = Duration::from_millis(500);
|
||||
|
||||
fn start_clock(listen_for: Vec<MsgType>) -> Receiver<Message> {
|
||||
let queue = Queue::new();
|
||||
let (tx, rx) = channel();
|
||||
queue.add(tx, listen_for);
|
||||
Clock::start(queue);
|
||||
rx
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sends_timestamp() {
|
||||
let rx = start_clock([MsgType::Time].to_vec());
|
||||
let msg = rx.recv_timeout(TIMEOUT).unwrap();
|
||||
match msg.get_msg_type() {
|
||||
MsgType::Time => {
|
||||
msg.get_data("time").unwrap().to_datetime().unwrap();
|
||||
}
|
||||
_ => unreachable!("should have been a time message"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn continues_to_send_time() {
|
||||
let start = Instant::now();
|
||||
let rx = start_clock([MsgType::Time].to_vec());
|
||||
let msg1 = rx.recv_timeout(TIMEOUT).unwrap();
|
||||
let msg2 = rx.recv().unwrap();
|
||||
assert!(
|
||||
start.elapsed() >= SLEEP_FOR,
|
||||
"did not pause long enough between sends"
|
||||
);
|
||||
assert!(
|
||||
msg2.get_data("time").unwrap().to_datetime().unwrap()
|
||||
>= msg1.get_data("time").unwrap().to_datetime().unwrap() + SLEEP_FOR,
|
||||
"should present the latest time"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn does_not_panic_without_listeners() {
|
||||
let rx = start_clock([MsgType::SessionValidate].to_vec());
|
||||
assert!(rx.recv_timeout(TIMEOUT).is_err(), "should timeout");
|
||||
}
|
||||
}
|
||||
@ -1,48 +0,0 @@
|
||||
use crate::queue::{Message, MsgType, Queue};
|
||||
use std::{
|
||||
sync::mpsc::{channel, Receiver},
|
||||
thread::spawn,
|
||||
};
|
||||
|
||||
const RESPONDS_TO: [MsgType; 0] = [];
|
||||
|
||||
/// Definition of the document type.
|
||||
struct DocType {
|
||||
queue: Queue,
|
||||
rx: Receiver<Message>,
|
||||
}
|
||||
|
||||
impl DocType {
|
||||
fn new(queue: Queue, rx: Receiver<Message>) -> Self {
|
||||
Self {
|
||||
queue: queue,
|
||||
rx: rx,
|
||||
}
|
||||
}
|
||||
|
||||
fn start(queue: Queue) {
|
||||
let (tx, rx) = channel();
|
||||
let mut doctype = DocType::new(queue, rx);
|
||||
doctype.queue.add(tx, RESPONDS_TO.to_vec());
|
||||
spawn(move || {
|
||||
doctype.listen();
|
||||
});
|
||||
}
|
||||
|
||||
fn listen(&self) {
|
||||
loop {
|
||||
self.rx.recv().unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod doctypes {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn create_empty() {
|
||||
let queue = Queue::new();
|
||||
DocType::start(queue.clone());
|
||||
}
|
||||
}
|
||||
348
src/document.rs
348
src/document.rs
@ -1,348 +0,0 @@
|
||||
use crate::{
|
||||
queue::{Message, MsgType, Queue},
|
||||
ActionType, ErrorType,
|
||||
};
|
||||
use serde_json::Value;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
sync::mpsc::{channel, Receiver},
|
||||
thread::spawn,
|
||||
};
|
||||
|
||||
const RESPONDS_TO: [MsgType; 1] = [MsgType::DocumentRequest];
|
||||
|
||||
struct Table;
|
||||
|
||||
impl Table {
|
||||
fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
|
||||
fn add_column(&self) {}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tables {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn create_table() {
|
||||
let tbl = Table::new();
|
||||
tbl.add_column();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Document {
|
||||
data: HashMap<String, String>,
|
||||
queue: Queue,
|
||||
rx: Receiver<Message>,
|
||||
}
|
||||
|
||||
impl Document {
|
||||
fn new(queue: Queue, rx: Receiver<Message>) -> Self {
|
||||
let mut data = HashMap::new();
|
||||
data.insert("root".to_string(), "Something goes here.".to_string());
|
||||
Self {
|
||||
data: data,
|
||||
queue: queue,
|
||||
rx: rx,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start(queue: Queue) {
|
||||
let (tx, rx) = channel();
|
||||
let mut document = Document::new(queue, rx);
|
||||
document.queue.add(tx, RESPONDS_TO.to_vec());
|
||||
spawn(move || {
|
||||
document.listen();
|
||||
});
|
||||
}
|
||||
|
||||
fn listen(&mut self) {
|
||||
loop {
|
||||
let msg = self.rx.recv().unwrap();
|
||||
match msg.get_data("action") {
|
||||
Some(action_field) => {
|
||||
let action = action_field.to_action().unwrap();
|
||||
match action {
|
||||
ActionType::Add | ActionType::Update => self.add(action, msg),
|
||||
_ => self.get(msg),
|
||||
}
|
||||
}
|
||||
None => self.get(msg),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add(&mut self, action: ActionType, msg: Message) {
|
||||
let name = msg.get_data("name").unwrap().to_string();
|
||||
match self.data.get(&name) {
|
||||
Some(_) => match action {
|
||||
ActionType::Add => {
|
||||
self.queue
|
||||
.send(msg.reply_with_error(ErrorType::DocumentAlreadyExists))
|
||||
.unwrap();
|
||||
return;
|
||||
}
|
||||
ActionType::Update => {}
|
||||
_ => unreachable!("listen should prevent anything else"),
|
||||
},
|
||||
None => match action {
|
||||
ActionType::Add => {}
|
||||
ActionType::Update => {
|
||||
self.queue
|
||||
.send(msg.reply_with_error(ErrorType::DocumentNotFound))
|
||||
.unwrap();
|
||||
return;
|
||||
}
|
||||
_ => unreachable!("listen should prevent anything else"),
|
||||
},
|
||||
}
|
||||
let doc: Value = match serde_json::from_str(&msg.get_data("doc").unwrap().to_string()) {
|
||||
Ok(value) => value,
|
||||
Err(_) => {
|
||||
self.queue
|
||||
.send(msg.reply_with_error(ErrorType::DocumentInvalidRequest))
|
||||
.unwrap();
|
||||
return;
|
||||
}
|
||||
};
|
||||
let reply = match doc["template"].as_str() {
|
||||
Some(content) => {
|
||||
self.data.insert(name, content.to_string());
|
||||
msg.reply(MsgType::ActionOk)
|
||||
}
|
||||
None => msg.reply_with_error(ErrorType::DocumentInvalidRequest),
|
||||
};
|
||||
self.queue.send(reply).unwrap();
|
||||
}
|
||||
|
||||
fn get(&self, msg: Message) {
|
||||
let name = match msg.get_data("name") {
|
||||
Some(doc) => doc.to_string(),
|
||||
None => "root".to_string(),
|
||||
};
|
||||
let reply = match self.data.get(&name) {
|
||||
Some(data) => {
|
||||
let mut holder = msg.reply(MsgType::Document);
|
||||
holder.add_data("doc", data.clone());
|
||||
holder
|
||||
}
|
||||
None => msg.reply_with_error(ErrorType::DocumentNotFound),
|
||||
};
|
||||
self.queue.send(reply).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod documents {
|
||||
use super::*;
|
||||
use serde_json::json;
|
||||
use std::time::Duration;
|
||||
use uuid::Uuid;
|
||||
|
||||
const TIMEOUT: Duration = Duration::from_millis(500);
|
||||
|
||||
fn setup_document() -> (Queue, Receiver<Message>) {
|
||||
let queue = Queue::new();
|
||||
let (tx, rx) = channel();
|
||||
queue.add(
|
||||
tx,
|
||||
[MsgType::ActionOk, MsgType::Document, MsgType::Error].to_vec(),
|
||||
);
|
||||
Document::start(queue.clone());
|
||||
(queue, rx)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn start_service() {
|
||||
let (queue, rx) = setup_document();
|
||||
let id = Uuid::new_v4();
|
||||
let mut msg = Message::new(MsgType::DocumentRequest);
|
||||
msg.add_data("sess_id", id.clone());
|
||||
queue.send(msg.clone()).unwrap();
|
||||
let reply = rx.recv_timeout(TIMEOUT).unwrap();
|
||||
assert_eq!(reply.get_id(), msg.get_id());
|
||||
match reply.get_msg_type() {
|
||||
MsgType::Document => {}
|
||||
_ => unreachable!("got {:?} should have gotten document", msg.get_msg_type()),
|
||||
}
|
||||
assert!(reply.get_data("doc").is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_existing_document() {
|
||||
let (queue, rx) = setup_document();
|
||||
let name = format!("name-{}", Uuid::new_v4());
|
||||
let mut msg = Message::new(MsgType::DocumentRequest);
|
||||
msg.add_data("name", name.clone());
|
||||
queue.send(msg.clone()).unwrap();
|
||||
let reply = rx.recv_timeout(TIMEOUT).unwrap();
|
||||
assert_eq!(reply.get_id(), msg.get_id());
|
||||
match reply.get_msg_type() {
|
||||
MsgType::Error => {}
|
||||
_ => unreachable!("got {:?}: shoud have been error", reply.get_msg_type()),
|
||||
}
|
||||
match reply.get_data("error_type") {
|
||||
Some(err) => match err.to_error_type().unwrap() {
|
||||
ErrorType::DocumentNotFound => {}
|
||||
_ => unreachable!("got {:?}: should have been document not found'", err),
|
||||
},
|
||||
None => unreachable!("should contain error type"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn root_always_exists() {
|
||||
let (queue, rx) = setup_document();
|
||||
let mut msg = Message::new(MsgType::DocumentRequest);
|
||||
msg.add_data("name", "root");
|
||||
queue.send(msg).unwrap();
|
||||
let reply = rx.recv_timeout(TIMEOUT).unwrap();
|
||||
match reply.get_msg_type() {
|
||||
MsgType::Document => {}
|
||||
_ => unreachable!(
|
||||
"Got '{:?}': should have been a document",
|
||||
reply.get_msg_type()
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_new_document() {
|
||||
let (queue, rx) = setup_document();
|
||||
let name = format!("name-{}", Uuid::new_v4());
|
||||
let content = format!("content-{}", Uuid::new_v4());
|
||||
let input = json!({
|
||||
"template": content.clone()
|
||||
});
|
||||
let mut msg1 = Message::new(MsgType::DocumentRequest);
|
||||
msg1.add_data("name", name.clone());
|
||||
msg1.add_data("action", ActionType::Add);
|
||||
msg1.add_data("doc", input.to_string());
|
||||
queue.send(msg1.clone()).unwrap();
|
||||
let reply1 = rx.recv_timeout(TIMEOUT).unwrap();
|
||||
assert_eq!(reply1.get_id(), msg1.get_id());
|
||||
match reply1.get_msg_type() {
|
||||
MsgType::ActionOk => {}
|
||||
_ => unreachable!(
|
||||
"got {:?}: should have received action ok",
|
||||
reply1.get_msg_type()
|
||||
),
|
||||
}
|
||||
let mut msg2 = Message::new(MsgType::DocumentRequest);
|
||||
msg2.add_data("name", name.clone());
|
||||
msg2.add_data("action", ActionType::Get);
|
||||
queue.send(msg2.clone()).unwrap();
|
||||
let reply2 = rx.recv_timeout(TIMEOUT).unwrap();
|
||||
assert_eq!(reply2.get_id(), msg2.get_id());
|
||||
match reply2.get_msg_type() {
|
||||
MsgType::Document => {}
|
||||
_ => unreachable!(
|
||||
"got {:?}: should have received document",
|
||||
reply2.get_msg_type()
|
||||
),
|
||||
}
|
||||
assert_eq!(reply2.get_data("doc").unwrap().to_string(), content);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_does_not_overwrite_existing() {
|
||||
let (queue, rx) = setup_document();
|
||||
let mut holder = Message::new(MsgType::DocumentRequest);
|
||||
holder.add_data("name", "root");
|
||||
holder.add_data("action", ActionType::Get);
|
||||
queue.send(holder.clone()).unwrap();
|
||||
let binding = rx.recv_timeout(TIMEOUT).unwrap();
|
||||
let expected = binding.get_data("doc").unwrap();
|
||||
let input = json!({
|
||||
"template": format!("content-{}", Uuid::new_v4())
|
||||
});
|
||||
let mut msg = Message::new(MsgType::DocumentRequest);
|
||||
msg.add_data("name", "root");
|
||||
msg.add_data("action", ActionType::Add);
|
||||
msg.add_data("doc", input.to_string());
|
||||
queue.send(msg.clone()).unwrap();
|
||||
let reply = rx.recv_timeout(TIMEOUT).unwrap();
|
||||
assert_eq!(reply.get_id(), msg.get_id());
|
||||
match reply.get_msg_type() {
|
||||
MsgType::Error => {}
|
||||
_ => unreachable!(
|
||||
"got '{:?}': should have received document",
|
||||
reply.get_msg_type()
|
||||
),
|
||||
}
|
||||
match reply.get_data("error_type") {
|
||||
Some(err) => match err.to_error_type().unwrap() {
|
||||
ErrorType::DocumentAlreadyExists => {}
|
||||
_ => unreachable!("got {:?}: should have been document not found'", err),
|
||||
},
|
||||
None => unreachable!("should contain error type"),
|
||||
}
|
||||
queue.send(holder).unwrap();
|
||||
let binding = rx.recv_timeout(TIMEOUT).unwrap();
|
||||
let result = binding.get_data("doc").unwrap();
|
||||
assert_eq!(result.to_string(), expected.to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_json() {
|
||||
let inputs = ["Invalid json request.", "{}"];
|
||||
let (queue, rx) = setup_document();
|
||||
for input in inputs.into_iter() {
|
||||
let mut msg = Message::new(MsgType::DocumentRequest);
|
||||
msg.add_data("action", ActionType::Add);
|
||||
msg.add_data("name", "doc");
|
||||
msg.add_data("doc", input);
|
||||
queue.send(msg.clone()).unwrap();
|
||||
let reply = match rx.recv_timeout(TIMEOUT) {
|
||||
Ok(data) => data,
|
||||
Err(err) => {
|
||||
assert!(false, "got '{}' with the following json: '{}'", err, input);
|
||||
Message::new(MsgType::Error)
|
||||
}
|
||||
};
|
||||
assert_eq!(reply.get_id(), msg.get_id());
|
||||
match reply.get_msg_type() {
|
||||
MsgType::Error => {}
|
||||
_ => unreachable!(
|
||||
"got '{:?}': should have received document",
|
||||
reply.get_msg_type()
|
||||
),
|
||||
}
|
||||
match reply.get_data("error_type") {
|
||||
Some(err) => match err.to_error_type().unwrap() {
|
||||
ErrorType::DocumentInvalidRequest => {}
|
||||
_ => unreachable!("got {:?}: should have been bad request'", err),
|
||||
},
|
||||
None => unreachable!("should contain error type"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn patch_nonexistant_page() {
|
||||
let (queue, rx) = setup_document();
|
||||
let input = json!({
|
||||
"template": "Sothing here"
|
||||
});
|
||||
let mut msg = Message::new(MsgType::DocumentRequest);
|
||||
msg.add_data("action", ActionType::Update);
|
||||
msg.add_data("name", "something");
|
||||
msg.add_data("doc", input.to_string());
|
||||
queue.send(msg.clone()).unwrap();
|
||||
let reply = rx.recv_timeout(TIMEOUT).unwrap();
|
||||
assert_eq!(reply.get_id(), msg.get_id());
|
||||
match reply.get_msg_type() {
|
||||
MsgType::Error => {}
|
||||
_ => unreachable!("got {:?}: shoud have been error", reply.get_msg_type()),
|
||||
}
|
||||
match reply.get_data("error_type") {
|
||||
Some(err) => match err.to_error_type().unwrap() {
|
||||
ErrorType::DocumentNotFound => {}
|
||||
_ => unreachable!("got {:?}: should have been document not found'", err),
|
||||
},
|
||||
None => unreachable!("should contain error type"),
|
||||
}
|
||||
}
|
||||
}
|
||||
350
src/field.rs
350
src/field.rs
@ -1,350 +0,0 @@
|
||||
use crate::{ActionType, ErrorType};
|
||||
use chrono::prelude::*;
|
||||
use isolang::Language;
|
||||
use std::fmt;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
enum FieldType {
|
||||
Action,
|
||||
DateTime,
|
||||
Error,
|
||||
StaticString,
|
||||
Uuid,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Field {
|
||||
Action(ActionType),
|
||||
DateTime(DateTime<Utc>),
|
||||
ErrorType(ErrorType),
|
||||
Lang(Language),
|
||||
Static(String),
|
||||
Uuid(Uuid),
|
||||
}
|
||||
|
||||
impl Field {
|
||||
pub fn to_action(&self) -> Result<ActionType, String> {
|
||||
match self {
|
||||
Field::Action(data) => Ok(data.clone()),
|
||||
_ => Err("not an action".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_uuid(&self) -> Result<Uuid, String> {
|
||||
match self {
|
||||
Field::Uuid(data) => Ok(data.clone()),
|
||||
_ => Err("not a uuid".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_datetime(&self) -> Result<DateTime<Utc>, String> {
|
||||
match self {
|
||||
Field::DateTime(data) => Ok(data.clone()),
|
||||
_ => Err("not a datetime".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_error_type(&self) -> Result<ErrorType, String> {
|
||||
match self {
|
||||
Field::ErrorType(data) => Ok(data.clone()),
|
||||
_ => Err("not an error type".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_language(&self) -> Result<Language, String> {
|
||||
match self {
|
||||
Field::Lang(data) => Ok(data.clone()),
|
||||
_ => Err("not an error type".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for Field {
|
||||
fn from(value: String) -> Self {
|
||||
match Uuid::try_from(value.as_str()) {
|
||||
Ok(data) => return Field::Uuid(data),
|
||||
Err(_) => {}
|
||||
}
|
||||
Field::Static(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for Field {
|
||||
fn from(value: &str) -> Self {
|
||||
match Uuid::try_from(value) {
|
||||
Ok(data) => return Field::Uuid(data),
|
||||
Err(_) => {}
|
||||
}
|
||||
Field::Static(value.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ActionType> for Field {
|
||||
fn from(value: ActionType) -> Self {
|
||||
Field::Action(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Uuid> for Field {
|
||||
fn from(value: Uuid) -> Self {
|
||||
Field::Uuid(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DateTime<Utc>> for Field {
|
||||
fn from(value: DateTime<Utc>) -> Self {
|
||||
Field::DateTime(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ErrorType> for Field {
|
||||
fn from(value: ErrorType) -> Self {
|
||||
Field::ErrorType(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Language> for Field {
|
||||
fn from(value: Language) -> Self {
|
||||
Field::Lang(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Field {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Field::DateTime(data) => write!(f, "{}", data),
|
||||
Field::Static(data) => write!(f, "{}", data),
|
||||
Field::Uuid(data) => write!(f, "{}", data),
|
||||
_ => write!(f, ""),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod fields {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn string_to_field() {
|
||||
let entries = ["test1".to_string(), "test2".to_string()];
|
||||
for data in entries {
|
||||
match data.clone().into() {
|
||||
Field::Static(result) => assert_eq!(result, data),
|
||||
_ => unreachable!("shouuld have been a static field"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn str_to_field() {
|
||||
let entries = ["test1", "test2"];
|
||||
for data in entries {
|
||||
match data.into() {
|
||||
Field::Static(result) => assert_eq!(result, data),
|
||||
_ => unreachable!("shouuld have been a static field"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uuid_to_field() {
|
||||
let id = Uuid::new_v4();
|
||||
match id.into() {
|
||||
Field::Uuid(result) => assert_eq!(result, id),
|
||||
_ => unreachable!("should have been a uuid field"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uuid_string_to_field() {
|
||||
let id = Uuid::new_v4();
|
||||
let id_string = id.to_string();
|
||||
match id_string.into() {
|
||||
Field::Uuid(result) => assert_eq!(result, id),
|
||||
_ => unreachable!("should have been a uuid field"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uuid_str_to_field() {
|
||||
let id = Uuid::new_v4();
|
||||
let id_string = id.to_string();
|
||||
let id_str = id_string.as_str();
|
||||
match id_str.into() {
|
||||
Field::Uuid(result) => assert_eq!(result, id),
|
||||
_ => unreachable!("should have been a uuid field"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uuid_field_to_string() {
|
||||
let id = Uuid::new_v4();
|
||||
let result = id.to_string();
|
||||
let input = Field::Uuid(id);
|
||||
assert_eq!(input.to_string(), result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn str_field_to_string() {
|
||||
let result = "Something goes here";
|
||||
let input: Field = result.into();
|
||||
assert_eq!(input.to_string(), result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn string_field_to_string() {
|
||||
let result = "Another string".to_string();
|
||||
let input: Field = result.clone().into();
|
||||
assert_eq!(input.to_string(), result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn field_to_uuid() {
|
||||
let id = Uuid::new_v4();
|
||||
let field: Field = id.into();
|
||||
match field.to_uuid() {
|
||||
Ok(result) => assert_eq!(result, id),
|
||||
Err(_) => unreachable!("did not convert to uuid"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_uuid_field_to_uuid() {
|
||||
let text = "Not a uuid.";
|
||||
let field: Field = text.into();
|
||||
match field.to_uuid() {
|
||||
Ok(_) => unreachable!("should return an error"),
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn use_date_to_field() {
|
||||
let expected = Utc::now();
|
||||
let field: Field = expected.into();
|
||||
match field {
|
||||
Field::DateTime(result) => assert_eq!(result, expected),
|
||||
_ => unreachable!("should have been date time"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_datetime_field_to_string() {
|
||||
let now = Utc::now();
|
||||
let expected = now.to_string();
|
||||
let field: Field = now.into();
|
||||
assert_eq!(field.to_string(), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_field_to_datetime() {
|
||||
let now = Utc::now();
|
||||
let field: Field = now.into();
|
||||
assert_eq!(field.to_datetime().unwrap(), now);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_static_field_to_datatime() {
|
||||
let txt = "Not gonna work.";
|
||||
let field: Field = txt.into();
|
||||
assert!(field.to_datetime().is_err(), "should not return a value");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_error_to_field() {
|
||||
let err = ErrorType::DocumentNotFound;
|
||||
let field: Field = err.into();
|
||||
match field {
|
||||
Field::ErrorType(data) => match data {
|
||||
ErrorType::DocumentNotFound => {}
|
||||
_ => unreachable!("got {:?}: should have been Document not found", data),
|
||||
},
|
||||
_ => unreachable!("should have been an error type"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_field_to_error_type_error() {
|
||||
let field: Field = Uuid::new_v4().into();
|
||||
assert!(field.to_error_type().is_err(), "should generate an error");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_field_to_error_type() {
|
||||
let err = ErrorType::DocumentNotFound;
|
||||
let field: Field = err.into();
|
||||
let result = field.to_error_type().unwrap();
|
||||
match result {
|
||||
ErrorType::DocumentNotFound => {}
|
||||
_ => unreachable!("got {:?}: should have been document not found", result),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_action_to_field() {
|
||||
let actions = [ActionType::Add, ActionType::Get, ActionType::Update];
|
||||
for action in actions.into_iter() {
|
||||
let result: Field = action.clone().into();
|
||||
match result {
|
||||
Field::Action(data) => assert_eq!(format!("{:?}", data), format!("{:?}", action)),
|
||||
_ => unreachable!("should have been an action"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_field_to_action() {
|
||||
let actions = [ActionType::Add, ActionType::Get, ActionType::Update];
|
||||
for action in actions.into_iter() {
|
||||
let field: Field = action.clone().into();
|
||||
let result = field.to_action().unwrap();
|
||||
assert_eq!(format!("{:?}", result), format!("{:?}", action));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_uuid_to_action() {
|
||||
let field: Field = Uuid::new_v4().into();
|
||||
match field.to_action() {
|
||||
Ok(_) => unreachable!("should have returned an error"),
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_lang_to_field() {
|
||||
let langs = [
|
||||
Language::from_639_1("en").unwrap(),
|
||||
Language::from_639_1("ja").unwrap(),
|
||||
];
|
||||
for lang in langs.into_iter() {
|
||||
let field: Field = lang.into();
|
||||
match field {
|
||||
Field::Lang(data) => assert_eq!(data, lang),
|
||||
_ => unreachable!("should identify language"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_field_to_lang() {
|
||||
let langs = [
|
||||
Language::from_639_1("en").unwrap(),
|
||||
Language::from_639_1("ja").unwrap(),
|
||||
];
|
||||
for lang in langs.into_iter() {
|
||||
let field: Field = lang.into();
|
||||
assert_eq!(field.to_language().unwrap(), lang);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrong_field_to_lang() {
|
||||
let field: Field = Uuid::nil().into();
|
||||
match field.to_language() {
|
||||
Ok(_) => unreachable!("should have produced an error"),
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
202
src/lib.rs-old
202
src/lib.rs-old
@ -1,202 +0,0 @@
|
||||
mod client;
|
||||
mod clock;
|
||||
mod doctype;
|
||||
mod document;
|
||||
mod field;
|
||||
mod message;
|
||||
mod queue;
|
||||
mod session;
|
||||
|
||||
use client::{Client, ClientChannel};
|
||||
use clock::Clock;
|
||||
use document::Document;
|
||||
use field::Field;
|
||||
use queue::{Message, MsgType, Queue};
|
||||
use session::Session;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum ActionType {
|
||||
Get,
|
||||
Add,
|
||||
Update,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum ErrorType {
|
||||
DocumentAlreadyExists,
|
||||
DocumentInvalidRequest,
|
||||
DocumentNotFound,
|
||||
}
|
||||
|
||||
pub struct MTTReply {
|
||||
document: String,
|
||||
error_type: Option<ErrorType>,
|
||||
}
|
||||
|
||||
impl MTTReply {
|
||||
fn new(msg: Message) -> Self {
|
||||
Self {
|
||||
document: match msg.get_data("doc") {
|
||||
Some(doc) => doc.to_string(),
|
||||
None => "".to_string(),
|
||||
},
|
||||
error_type: match msg.get_data("error_type") {
|
||||
Some(err) => Some(err.to_error_type().unwrap()),
|
||||
None => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_document(&self) -> String {
|
||||
self.document.clone()
|
||||
}
|
||||
|
||||
pub fn get_error(&self) -> Option<ErrorType> {
|
||||
self.error_type.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod mtt_replies {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn create_reply_with_no_error() {
|
||||
let mut msg = Message::new(MsgType::Document);
|
||||
let content = format!("content-{}", Uuid::new_v4());
|
||||
msg.add_data("doc", content.to_string());
|
||||
let reply = MTTReply::new(msg);
|
||||
assert!(reply.get_error().is_none());
|
||||
assert_eq!(reply.get_document(), content);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_reply_with_error() {
|
||||
let mut msg = Message::new(MsgType::Error);
|
||||
msg.add_data("error_type", ErrorType::DocumentNotFound);
|
||||
let reply = MTTReply::new(msg);
|
||||
match reply.get_error() {
|
||||
Some(err) => match err {
|
||||
ErrorType::DocumentNotFound => {}
|
||||
_ => unreachable!("got {:?}: should have been document not found", err),
|
||||
},
|
||||
None => unreachable!("should return an error type"),
|
||||
}
|
||||
assert_eq!(reply.get_document(), "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_error() {
|
||||
let msg = Message::new(MsgType::Document);
|
||||
let reply = MTTReply::new(msg);
|
||||
assert!(reply.get_error().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn some_error() {
|
||||
let mut msg = Message::new(MsgType::Error);
|
||||
msg.add_data("error_type", ErrorType::DocumentNotFound);
|
||||
let reply = MTTReply::new(msg);
|
||||
match reply.get_error() {
|
||||
Some(err) => match err {
|
||||
ErrorType::DocumentNotFound => {}
|
||||
_ => unreachable!("got {:?}: should have been document not found", err),
|
||||
},
|
||||
None => unreachable!("should return an error type"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct MoreThanText {
|
||||
client_channel: ClientChannel,
|
||||
}
|
||||
|
||||
impl MoreThanText {
|
||||
pub fn new() -> Self {
|
||||
let queue = Queue::new();
|
||||
Clock::start(queue.clone());
|
||||
Document::start(queue.clone());
|
||||
Session::start(queue.clone());
|
||||
Self {
|
||||
client_channel: Client::start(queue.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn validate_session<F>(&mut self, session: Option<F>) -> Uuid
|
||||
where
|
||||
F: Into<Field>,
|
||||
{
|
||||
let mut msg = Message::new(MsgType::SessionValidate);
|
||||
match session {
|
||||
Some(id) => msg.add_data("sess_id", id.into()),
|
||||
None => {}
|
||||
}
|
||||
let rx = self.client_channel.send(msg);
|
||||
let reply = rx.recv().unwrap();
|
||||
reply.get_data("sess_id").unwrap().to_uuid().unwrap()
|
||||
}
|
||||
|
||||
pub fn get_document<S>(
|
||||
&self,
|
||||
sess_id: Uuid,
|
||||
action: ActionType,
|
||||
doc_name: S,
|
||||
data: String,
|
||||
) -> MTTReply
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
let mut msg = Message::new(MsgType::DocumentRequest);
|
||||
msg.add_data("sess_id", sess_id);
|
||||
msg.add_data("action", action);
|
||||
msg.add_data("name", doc_name.into());
|
||||
msg.add_data("doc", data);
|
||||
let rx = self.client_channel.send(msg);
|
||||
let reply = rx.recv().unwrap();
|
||||
MTTReply::new(reply)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod mtt {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn session_id_is_unique() {
|
||||
let mut mtt = MoreThanText::new();
|
||||
let input: Option<String> = None;
|
||||
let mut ids: Vec<Uuid> = Vec::new();
|
||||
for _ in 0..10 {
|
||||
let id = mtt.validate_session(input.clone());
|
||||
assert!(!ids.contains(&id));
|
||||
ids.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reuse_existing_session() {
|
||||
let mut mtt = MoreThanText::new();
|
||||
let initial: Option<String> = None;
|
||||
let id = mtt.validate_session(initial);
|
||||
let output = mtt.validate_session(Some(id.clone()));
|
||||
assert_eq!(output, id);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_root_document_with_str() {
|
||||
let mut mtt = MoreThanText::new();
|
||||
let id = mtt.validate_session(Some(Uuid::new_v4()));
|
||||
let output = mtt.get_document(id, ActionType::Get, "root", "".to_string());
|
||||
assert!(output.get_error().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_root_document_with_string() {
|
||||
let mut mtt = MoreThanText::new();
|
||||
let id = mtt.validate_session(Some(Uuid::new_v4()));
|
||||
let output = mtt.get_document(id, ActionType::Get, "root".to_string(), "".to_string());
|
||||
assert!(output.get_error().is_none());
|
||||
}
|
||||
}
|
||||
346
src/queue.rs
346
src/queue.rs
@ -1,346 +0,0 @@
|
||||
use crate::{field::Field, ErrorType};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
sync::{mpsc::Sender, Arc, RwLock},
|
||||
};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
pub enum MsgType {
|
||||
ActionOk,
|
||||
Document,
|
||||
DocumentRequest,
|
||||
Error,
|
||||
Session,
|
||||
SessionGet,
|
||||
SessionValidate,
|
||||
SessionValidated,
|
||||
Time,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Message {
|
||||
id: Uuid,
|
||||
msg_type: MsgType,
|
||||
data: HashMap<String, Field>,
|
||||
}
|
||||
|
||||
impl Message {
|
||||
pub fn new(msg_type: MsgType) -> Self {
|
||||
Self {
|
||||
id: Uuid::new_v4(),
|
||||
msg_type: msg_type,
|
||||
data: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reply(&self, data: MsgType) -> Message {
|
||||
Self {
|
||||
id: self.id.clone(),
|
||||
msg_type: data,
|
||||
data: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reply_with_data(&self, msg_type: MsgType) -> Message {
|
||||
Self {
|
||||
id: self.id.clone(),
|
||||
msg_type: msg_type,
|
||||
data: self.data.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reply_with_error(&self, error: ErrorType) -> Self {
|
||||
let mut reply = self.reply(MsgType::Error);
|
||||
reply.add_data("error_type", error);
|
||||
reply
|
||||
}
|
||||
|
||||
pub fn get_msg_type(&self) -> &MsgType {
|
||||
&self.msg_type
|
||||
}
|
||||
|
||||
pub fn add_data<S, F>(&mut self, name: S, data: F)
|
||||
where
|
||||
S: Into<String>,
|
||||
F: Into<Field>,
|
||||
{
|
||||
self.data.insert(name.into(), data.into());
|
||||
}
|
||||
|
||||
pub fn get_data<S>(&self, name: S) -> Option<&Field>
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
let field_name = name.into();
|
||||
self.data.get(&field_name)
|
||||
}
|
||||
|
||||
pub fn get_id(&self) -> Uuid {
|
||||
self.id.clone()
|
||||
}
|
||||
|
||||
pub fn reset_id(&mut self) {
|
||||
self.id = Uuid::new_v4();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod messages {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn new_message() {
|
||||
let msg = Message::new(MsgType::SessionValidate);
|
||||
match msg.msg_type {
|
||||
MsgType::SessionValidate => (),
|
||||
_ => unreachable!("new defaults to noop"),
|
||||
}
|
||||
assert!(msg.data.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn message_ids_are_random() {
|
||||
let mut ids: Vec<Uuid> = Vec::new();
|
||||
for _ in 0..10 {
|
||||
let msg = Message::new(MsgType::SessionValidate);
|
||||
let id = msg.id.clone();
|
||||
assert!(!ids.contains(&id), "{} is a duplicate", id);
|
||||
ids.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_reply() {
|
||||
let id = Uuid::new_v4();
|
||||
let mut msg = Message::new(MsgType::SessionValidate);
|
||||
msg.id = id.clone();
|
||||
msg.add_data("test", "test");
|
||||
let data = MsgType::SessionValidate;
|
||||
let result = msg.reply(data);
|
||||
assert_eq!(result.id, id);
|
||||
match result.msg_type {
|
||||
MsgType::SessionValidate => {}
|
||||
_ => unreachable!("should have been a registration request"),
|
||||
}
|
||||
assert!(result.data.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_message_type() {
|
||||
let msg = Message::new(MsgType::SessionValidate);
|
||||
match msg.get_msg_type() {
|
||||
MsgType::SessionValidate => {}
|
||||
_ => unreachable!("should have bneen noopn"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_data() {
|
||||
let mut msg = Message::new(MsgType::SessionValidate);
|
||||
let one = "one";
|
||||
let two = "two".to_string();
|
||||
msg.add_data(one, one);
|
||||
msg.add_data(two.clone(), two.clone());
|
||||
assert_eq!(msg.get_data(one).unwrap().to_string(), one);
|
||||
assert_eq!(msg.get_data(&two).unwrap().to_string(), two);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_data_into_string() {
|
||||
let id = Uuid::new_v4();
|
||||
let mut msg = Message::new(MsgType::SessionValidate);
|
||||
msg.add_data(id, id);
|
||||
assert_eq!(msg.get_data(id).unwrap().to_uuid().unwrap(), id);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn copy_data_with_reply() {
|
||||
let id = Uuid::new_v4();
|
||||
let reply_type = MsgType::SessionValidated;
|
||||
let mut msg = Message::new(MsgType::SessionValidate);
|
||||
msg.add_data(id, id);
|
||||
let reply = msg.reply_with_data(reply_type.clone());
|
||||
assert_eq!(reply.id, msg.id);
|
||||
match reply.get_msg_type() {
|
||||
MsgType::SessionValidated => {}
|
||||
_ => unreachable!(
|
||||
"Got {:?} should have been {:?}",
|
||||
msg.get_msg_type(),
|
||||
reply_type
|
||||
),
|
||||
}
|
||||
assert_eq!(reply.data.len(), msg.data.len());
|
||||
let output = reply.get_data(&id.to_string()).unwrap().to_uuid().unwrap();
|
||||
let expected = msg.get_data(&id.to_string()).unwrap().to_uuid().unwrap();
|
||||
assert_eq!(output, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_message_id() {
|
||||
let msg = Message::new(MsgType::SessionValidated);
|
||||
assert_eq!(msg.get_id(), msg.id);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reset_msg_id() {
|
||||
let mut msg = Message::new(MsgType::Time);
|
||||
let id = msg.get_id();
|
||||
msg.reset_id();
|
||||
assert_ne!(msg.get_id(), id);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_reply() {
|
||||
let msg = Message::new(MsgType::Time);
|
||||
let errors = [
|
||||
ErrorType::DocumentAlreadyExists,
|
||||
ErrorType::DocumentInvalidRequest,
|
||||
];
|
||||
for error in errors.into_iter() {
|
||||
let reply = msg.reply_with_error(error.clone());
|
||||
assert_eq!(reply.get_id(), msg.get_id());
|
||||
assert_eq!(
|
||||
format!("{:?}", reply.get_msg_type()),
|
||||
format!("{:?}", MsgType::Error)
|
||||
);
|
||||
assert_eq!(
|
||||
format!(
|
||||
"{:?}",
|
||||
reply
|
||||
.get_data("error_type")
|
||||
.unwrap()
|
||||
.to_error_type()
|
||||
.unwrap()
|
||||
),
|
||||
format!("{:?}", error)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Queue {
|
||||
store: Arc<RwLock<HashMap<MsgType, Vec<Sender<Message>>>>>,
|
||||
}
|
||||
|
||||
impl Queue {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
store: Arc::new(RwLock::new(HashMap::new())),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(&self, tx: Sender<Message>, msg_types: Vec<MsgType>) {
|
||||
let mut store = self.store.write().unwrap();
|
||||
for msg_type in msg_types.into_iter() {
|
||||
if !store.contains_key(&msg_type) {
|
||||
store.insert(msg_type.clone(), Vec::new());
|
||||
}
|
||||
let senders = store.get_mut(&msg_type).unwrap();
|
||||
senders.push(tx.clone());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send(&self, msg: Message) -> Result<(), String> {
|
||||
let store = self.store.read().unwrap();
|
||||
match store.get(&msg.get_msg_type()) {
|
||||
Some(senders) => {
|
||||
for sender in senders.into_iter() {
|
||||
sender.send(msg.clone()).unwrap();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
None => Err(format!("no listeners for {:?}", msg.get_msg_type())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod queues {
|
||||
use super::*;
|
||||
use std::{
|
||||
sync::mpsc::{channel, RecvTimeoutError},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
static TIMEOUT: Duration = Duration::from_millis(500);
|
||||
|
||||
#[test]
|
||||
fn create_queue() {
|
||||
let queue = Queue::new();
|
||||
let (tx1, rx1) = channel();
|
||||
let (tx2, rx2) = channel();
|
||||
queue.add(tx1, [MsgType::SessionValidate].to_vec());
|
||||
queue.add(tx2, [MsgType::SessionValidate].to_vec());
|
||||
queue.send(Message::new(MsgType::SessionValidate)).unwrap();
|
||||
rx1.recv().unwrap();
|
||||
rx2.recv().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn messages_are_routed() {
|
||||
let queue = Queue::new();
|
||||
let (tx1, rx1) = channel();
|
||||
let (tx2, rx2) = channel();
|
||||
queue.add(tx1, [MsgType::SessionValidate].to_vec());
|
||||
queue.add(tx2, [MsgType::SessionValidated].to_vec());
|
||||
queue.send(Message::new(MsgType::SessionValidate)).unwrap();
|
||||
let result = rx1.recv().unwrap();
|
||||
match result.get_msg_type() {
|
||||
MsgType::SessionValidate => {}
|
||||
_ => unreachable!(
|
||||
"received {:?}, should have been session vvalidate",
|
||||
result.get_msg_type()
|
||||
),
|
||||
}
|
||||
match rx2.recv_timeout(TIMEOUT) {
|
||||
Ok(_) => unreachable!("should not have received anything"),
|
||||
Err(err) => match err {
|
||||
RecvTimeoutError::Timeout => {}
|
||||
_ => unreachable!("{:?}", err),
|
||||
},
|
||||
}
|
||||
queue.send(Message::new(MsgType::SessionValidated)).unwrap();
|
||||
let result = rx2.recv().unwrap();
|
||||
match result.get_msg_type() {
|
||||
MsgType::SessionValidated => {}
|
||||
_ => unreachable!(
|
||||
"received {:?}, should have been session vvalidate",
|
||||
result.get_msg_type()
|
||||
),
|
||||
}
|
||||
match rx1.recv_timeout(TIMEOUT) {
|
||||
Ok(_) => unreachable!("should not have received anything"),
|
||||
Err(err) => match err {
|
||||
RecvTimeoutError::Timeout => {}
|
||||
_ => unreachable!("{:?}", err),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn assign_sender_multiple_message_types() {
|
||||
let queue = Queue::new();
|
||||
let (tx, rx) = channel();
|
||||
queue.add(
|
||||
tx,
|
||||
[MsgType::SessionValidated, MsgType::SessionValidate].to_vec(),
|
||||
);
|
||||
queue.send(Message::new(MsgType::SessionValidate)).unwrap();
|
||||
let msg = rx.recv().unwrap();
|
||||
assert_eq!(msg.get_msg_type(), &MsgType::SessionValidate);
|
||||
queue.send(Message::new(MsgType::SessionValidated)).unwrap();
|
||||
let msg = rx.recv().unwrap();
|
||||
assert_eq!(msg.get_msg_type(), &MsgType::SessionValidated);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unassigned_message_should_return_error() {
|
||||
let queue = Queue::new();
|
||||
match queue.send(Message::new(MsgType::SessionValidated)) {
|
||||
Ok(_) => unreachable!("should return error"),
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
384
src/session.rs
384
src/session.rs
@ -1,384 +0,0 @@
|
||||
use crate::{
|
||||
field::Field,
|
||||
queue::{Message, MsgType, Queue},
|
||||
};
|
||||
use chrono::prelude::*;
|
||||
use isolang::Language;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
sync::mpsc::{channel, Receiver},
|
||||
thread::spawn,
|
||||
time::Duration,
|
||||
};
|
||||
use uuid::Uuid;
|
||||
|
||||
const EXPIRE_IN: Duration = Duration::from_secs(60 * 60);
|
||||
const RESPONDS_TO: [MsgType; 3] = [MsgType::SessionGet, MsgType::SessionValidate, MsgType::Time];
|
||||
const DEFAULT_LANG: Language = Language::Eng;
|
||||
|
||||
struct SessionData {
|
||||
expire_on: DateTime<Utc>,
|
||||
language: Language,
|
||||
}
|
||||
|
||||
impl SessionData {
|
||||
fn new(lang: Option<Language>) -> Self {
|
||||
let session_lang = match lang {
|
||||
Some(data) => data.clone(),
|
||||
None => DEFAULT_LANG,
|
||||
};
|
||||
Self {
|
||||
expire_on: Utc::now() + EXPIRE_IN,
|
||||
language: session_lang,
|
||||
}
|
||||
}
|
||||
|
||||
fn extend(&mut self) {
|
||||
self.expire_on = Utc::now() + EXPIRE_IN;
|
||||
}
|
||||
|
||||
fn is_expired(&self, now: &DateTime<Utc>) -> bool {
|
||||
now > &self.expire_on
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod sessiondatas {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn create_session_data() {
|
||||
let expire = Utc::now() + EXPIRE_IN;
|
||||
let data = SessionData::new(None);
|
||||
assert!(
|
||||
data.expire_on > expire,
|
||||
"{:?} should be greater than {:?}",
|
||||
data.expire_on,
|
||||
expire
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn extend_usage_time() {
|
||||
let mut data = SessionData::new(None);
|
||||
let expire = Utc::now() + EXPIRE_IN;
|
||||
data.extend();
|
||||
assert!(
|
||||
data.expire_on > expire,
|
||||
"{:?} should be greater than {:?}",
|
||||
data.expire_on,
|
||||
expire
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_expired() {
|
||||
let data = SessionData::new(None);
|
||||
let expire = Utc::now() + EXPIRE_IN;
|
||||
assert!(data.is_expired(&expire), "should be expired");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_not_expired() {
|
||||
let expire = Utc::now() + EXPIRE_IN;
|
||||
let data = SessionData::new(None);
|
||||
assert!(!data.is_expired(&expire), "should be not expired");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn english_is_the_default_language() {
|
||||
let data = SessionData::new(None);
|
||||
assert_eq!(data.language, DEFAULT_LANG);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn assign_language() {
|
||||
let langs = [Language::Jpn, Language::Deu];
|
||||
for lang in langs.into_iter() {
|
||||
let data = SessionData::new(Some(lang.clone()));
|
||||
assert_eq!(data.language, lang);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Session {
|
||||
data: HashMap<Uuid, SessionData>,
|
||||
queue: Queue,
|
||||
rx: Receiver<Message>,
|
||||
}
|
||||
|
||||
impl Session {
|
||||
fn new(queue: Queue, rx: Receiver<Message>) -> Self {
|
||||
Self {
|
||||
data: HashMap::new(),
|
||||
queue: queue,
|
||||
rx: rx,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start(queue: Queue) {
|
||||
let (tx, rx) = channel();
|
||||
let mut session = Session::new(queue, rx);
|
||||
session.queue.add(tx, RESPONDS_TO.to_vec());
|
||||
spawn(move || {
|
||||
session.listen();
|
||||
});
|
||||
}
|
||||
|
||||
fn listen(&mut self) {
|
||||
loop {
|
||||
let msg = self.rx.recv().unwrap();
|
||||
match msg.get_msg_type() {
|
||||
MsgType::SessionGet => self.get(msg),
|
||||
MsgType::SessionValidate => self.validate(msg),
|
||||
MsgType::Time => self.expire(msg),
|
||||
_ => unreachable!("received unknown message"),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn validate(&mut self, msg: Message) {
|
||||
match msg.get_data("sess_id") {
|
||||
Some(sid) => match sid {
|
||||
Field::Uuid(sess_id) => match self.data.get_mut(&sess_id) {
|
||||
Some(sess_data) => {
|
||||
sess_data.extend();
|
||||
let reply = msg.reply_with_data(MsgType::SessionValidated);
|
||||
self.queue.send(reply).unwrap();
|
||||
}
|
||||
None => self.new_session(msg),
|
||||
},
|
||||
_ => self.new_session(msg),
|
||||
},
|
||||
None => self.new_session(msg),
|
||||
}
|
||||
}
|
||||
|
||||
fn new_session(&mut self, msg: Message) {
|
||||
let mut id = Uuid::new_v4();
|
||||
while self.data.contains_key(&id) {
|
||||
id = Uuid::new_v4();
|
||||
}
|
||||
let req_lang = match msg.get_data("language") {
|
||||
Some(data) => Some(data.to_language().unwrap().clone()),
|
||||
None => None,
|
||||
};
|
||||
self.data.insert(id.clone(), SessionData::new(req_lang));
|
||||
let mut reply = msg.reply_with_data(MsgType::SessionValidated);
|
||||
reply.add_data("sess_id", id);
|
||||
self.queue.send(reply).unwrap();
|
||||
}
|
||||
|
||||
fn expire(&mut self, msg: Message) {
|
||||
let now = msg.get_data("time").unwrap().to_datetime().unwrap();
|
||||
let mut expired: Vec<Uuid> = Vec::new();
|
||||
for (id, data) in self.data.iter() {
|
||||
if data.is_expired(&now) {
|
||||
expired.push(id.clone());
|
||||
}
|
||||
}
|
||||
for id in expired.iter() {
|
||||
self.data.remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
fn get(&self, msg: Message) {
|
||||
let sess_id = msg.get_data("sess_id").unwrap().to_uuid().unwrap();
|
||||
let sess_data = self.data.get(&sess_id).unwrap();
|
||||
let mut reply = msg.reply(MsgType::Session);
|
||||
reply.add_data("language", sess_data.language.clone());
|
||||
self.queue.send(reply);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod sessions {
|
||||
use super::*;
|
||||
use crate::queue::{Message, MsgType};
|
||||
use std::{sync::mpsc::channel, time::Duration};
|
||||
|
||||
static TIMEOUT: Duration = Duration::from_millis(500);
|
||||
|
||||
pub fn create_validated_reply(msg: Message) -> Message {
|
||||
let mut reply = msg.reply(MsgType::SessionValidated);
|
||||
reply.add_data("sess_id", Uuid::new_v4());
|
||||
reply
|
||||
}
|
||||
|
||||
fn setup_session() -> (Queue, Receiver<Message>) {
|
||||
let queue = Queue::new();
|
||||
let (tx, rx) = channel();
|
||||
let listen_for = [MsgType::Session, MsgType::SessionValidated].to_vec();
|
||||
queue.add(tx, listen_for);
|
||||
Session::start(queue.clone());
|
||||
(queue, rx)
|
||||
}
|
||||
|
||||
fn create_session(queue: &Queue, rx: &Receiver<Message>, lang: Option<Language>) -> Uuid {
|
||||
let mut msg = Message::new(MsgType::SessionValidate);
|
||||
match lang {
|
||||
Some(data) => msg.add_data("language", data.clone()),
|
||||
None => {}
|
||||
}
|
||||
queue.send(msg.clone()).unwrap();
|
||||
let holder = rx.recv_timeout(TIMEOUT).unwrap();
|
||||
holder.get_data("sess_id").unwrap().to_uuid().unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_new_session() {
|
||||
let id = Uuid::new_v4();
|
||||
let (queue, rx) = setup_session();
|
||||
let mut msg = Message::new(MsgType::SessionValidate);
|
||||
msg.add_data(id, id);
|
||||
queue.send(msg.clone()).unwrap();
|
||||
let result = rx.recv_timeout(TIMEOUT).unwrap();
|
||||
match result.get_msg_type() {
|
||||
MsgType::SessionValidated => {}
|
||||
_ => unreachable!(
|
||||
"received {:?}, should have been a session",
|
||||
result.get_msg_type()
|
||||
),
|
||||
}
|
||||
assert_eq!(result.get_id(), msg.get_id());
|
||||
assert_eq!(result.get_data(id).unwrap().to_uuid().unwrap(), id);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn session_id_is_unique() {
|
||||
let (queue, rx) = setup_session();
|
||||
let msg = Message::new(MsgType::SessionValidate);
|
||||
let mut ids: Vec<Uuid> = Vec::new();
|
||||
for _ in 0..10 {
|
||||
queue.send(msg.clone()).unwrap();
|
||||
let result = rx.recv_timeout(TIMEOUT).unwrap();
|
||||
let id = result.get_data("sess_id").unwrap().to_uuid().unwrap();
|
||||
assert!(!ids.contains(&id), "{} is a duplicate id", id);
|
||||
ids.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn existing_id_is_returned() {
|
||||
let add_data = Uuid::new_v4();
|
||||
let (queue, rx) = setup_session();
|
||||
let id = create_session(&queue, &rx, None);
|
||||
let mut msg = Message::new(MsgType::SessionValidate);
|
||||
msg.add_data("sess_id", id.clone());
|
||||
msg.add_data(add_data, add_data);
|
||||
queue.send(msg).unwrap();
|
||||
let result = rx.recv_timeout(TIMEOUT).unwrap();
|
||||
let output = result.get_data("sess_id").unwrap().to_uuid().unwrap();
|
||||
assert_eq!(output, id);
|
||||
assert_eq!(
|
||||
result.get_data(add_data).unwrap().to_uuid().unwrap(),
|
||||
add_data
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn issue_new_if_validated_doe_not_exist() {
|
||||
let id = Uuid::new_v4();
|
||||
let (queue, rx) = setup_session();
|
||||
let mut msg = Message::new(MsgType::SessionValidate);
|
||||
msg.add_data("sess_id", id.clone());
|
||||
queue.send(msg).unwrap();
|
||||
let result = rx.recv_timeout(TIMEOUT).unwrap();
|
||||
let output = result.get_data("sess_id").unwrap().to_uuid().unwrap();
|
||||
assert_ne!(output, id);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_for_bad_uuid() {
|
||||
let id = "bad uuid";
|
||||
let (queue, rx) = setup_session();
|
||||
let mut msg = Message::new(MsgType::SessionValidate);
|
||||
msg.add_data("sess_id", id);
|
||||
queue.send(msg).unwrap();
|
||||
let result = rx.recv_timeout(TIMEOUT).unwrap();
|
||||
let output = result.get_data("sess_id").unwrap().to_string();
|
||||
assert_ne!(output, id);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn timer_does_nothing_to_unexpired() {
|
||||
let expire = Utc::now() + EXPIRE_IN;
|
||||
let (queue, rx) = setup_session();
|
||||
let id = create_session(&queue, &rx, None);
|
||||
let mut time_msg = Message::new(MsgType::Time);
|
||||
time_msg.add_data("time", expire);
|
||||
queue.send(time_msg).unwrap();
|
||||
let mut validate_msg = Message::new(MsgType::SessionValidate);
|
||||
validate_msg.add_data("sess_id", id.clone());
|
||||
queue.send(validate_msg).unwrap();
|
||||
let result = rx.recv_timeout(TIMEOUT).unwrap();
|
||||
assert_eq!(result.get_data("sess_id").unwrap().to_uuid().unwrap(), id);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn timer_removes_expired() {
|
||||
let (queue, rx) = setup_session();
|
||||
let id = create_session(&queue, &rx, None);
|
||||
let expire = Utc::now() + EXPIRE_IN;
|
||||
let mut time_msg = Message::new(MsgType::Time);
|
||||
time_msg.add_data("time", expire);
|
||||
queue.send(time_msg).unwrap();
|
||||
let mut validate_msg = Message::new(MsgType::SessionValidate);
|
||||
validate_msg.add_data("sess_id", id.clone());
|
||||
queue.send(validate_msg).unwrap();
|
||||
let result = rx.recv_timeout(TIMEOUT).unwrap();
|
||||
assert_ne!(result.get_data("sess_id").unwrap().to_uuid().unwrap(), id);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validate_extends_session() {
|
||||
let (queue, rx) = setup_session();
|
||||
let id = create_session(&queue, &rx, None);
|
||||
let mut validate_msg = Message::new(MsgType::SessionValidate);
|
||||
validate_msg.add_data("sess_id", id.clone());
|
||||
let expire = Utc::now() + EXPIRE_IN;
|
||||
let mut time_msg = Message::new(MsgType::Time);
|
||||
time_msg.add_data("time", expire);
|
||||
queue.send(validate_msg.clone()).unwrap();
|
||||
queue.send(time_msg).unwrap();
|
||||
queue.send(validate_msg).unwrap();
|
||||
rx.recv_timeout(TIMEOUT).unwrap();
|
||||
let result = rx.recv_timeout(TIMEOUT).unwrap();
|
||||
assert_eq!(result.get_data("sess_id").unwrap().to_uuid().unwrap(), id);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_session_information() {
|
||||
let (queue, rx) = setup_session();
|
||||
let id = create_session(&queue, &rx, None);
|
||||
let mut msg = Message::new(MsgType::SessionGet);
|
||||
msg.add_data("sess_id", id.clone());
|
||||
queue.send(msg.clone());
|
||||
let reply = rx.recv_timeout(TIMEOUT).unwrap();
|
||||
assert_eq!(reply.get_id(), msg.get_id());
|
||||
assert_eq!(reply.get_msg_type(), &MsgType::Session);
|
||||
assert_eq!(
|
||||
reply.get_data("language").unwrap().to_language().unwrap(),
|
||||
DEFAULT_LANG
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_requested_langaages() {
|
||||
let langs = [Language::Jpn, Language::Deu];
|
||||
let (queue, rx) = setup_session();
|
||||
for lang in langs.into_iter() {
|
||||
let id = create_session(&queue, &rx, Some(lang.clone()));
|
||||
let mut msg = Message::new(MsgType::SessionGet);
|
||||
msg.add_data("sess_id", id.clone());
|
||||
queue.send(msg.clone());
|
||||
let reply = rx.recv_timeout(TIMEOUT).unwrap();
|
||||
assert_eq!(reply.get_id(), msg.get_id());
|
||||
assert_eq!(reply.get_msg_type(), &MsgType::Session);
|
||||
assert_eq!(
|
||||
reply.get_data("language").unwrap().to_language().unwrap(),
|
||||
lang
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user