Removed old code.
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 1s

This commit is contained in:
Jeff Baskin 2025-12-24 16:56:43 -05:00
parent 97df1a8ece
commit 9df6c4db42
8 changed files with 0 additions and 1947 deletions

View File

@ -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());
}
}

View File

@ -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");
}
}

View File

@ -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());
}
}

View File

@ -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"),
}
}
}

View File

@ -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(_) => {}
}
}
}

View File

@ -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());
}
}

View File

@ -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(_) => {}
}
}
}

View File

@ -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
);
}
}
}