use chrono::{DateTime, Utc}; use isolang::Language; use morethantext::{ action::{Addition, CalcValue, Calculation, Field, FieldType, Operand, Query, Record}, Action, ErrorID, Include, MTTError, MoreThanText, Name, Path, TestMoreThanText, Update, }; use std::time::Duration; use uuid::Uuid; const DELAY: Duration = Duration::from_hours(1); fn doc_name() -> Name { Name::english("session") } fn id_name() -> Name { Name::english("id") } fn expire_name() -> Name { Name::english("expire") } fn lang_name() -> Name { Name::english("language") } fn get_session(mtt: &mut MoreThanText, id: &Uuid) -> Result { let client = mtt.client(); let mut qry = Query::new(doc_name()); let mut calc = Calculation::new(Operand::Equal); calc.add_value(CalcValue::Existing(FieldType::Uuid)) .unwrap(); calc.add_value(id.clone()).unwrap(); qry.add(Name::english("id"), calc.clone()); match client.records(qry) { Ok(data) => Ok(data.iter().last().unwrap()), Err(err) => Err(err), } } #[test] fn are_session_ids_unique() { let mut mtt = MoreThanText::new(); let count = 10; let mut result: Vec = Vec::new(); for _ in 0..count { let id = mtt.client().session_id(); assert!(!result.contains(&id), "found {} in {:?}", id, result); result.push(id); } } #[test] fn bad_session_id_returns_new_id() { let id = "stuff".to_string(); let result = MoreThanText::new().client().session_id(); assert_ne!(result, id); } #[test] fn creates_new_session_if_missing_or_expired() { let id = Uuid::nil().to_string(); let result = MoreThanText::new() .client_with_session(id.clone(), None) .session_id(); assert_ne!(result, id); } #[test] fn returns_same_session_id_when_valid() { let mut mtt = MoreThanText::new(); let expected = mtt.client().session_id(); let result = mtt.client_with_session(expected.clone(), None).session_id(); assert_eq!(result, expected); } #[test] fn is_expiration_date_set_in_the_future() { let mut test_env = TestMoreThanText::new(); let path = Path::new( Include::All, Include::Just(doc_name().into()), Include::Just(Action::OnAddition), ); test_env.register_channel(vec![path]); let start_time = Utc::now() + DELAY; let id = test_env.get_morethantext().client(); let end_time = Utc::now() + DELAY; let result = test_env.get_trigger_records(Action::OnAddition); let rec = result.iter().last().unwrap(); let expire = rec.get(&expire_name()).unwrap(); assert!( expire > start_time.into(), "{:?} should be after {:?}", expire, start_time ); assert!( expire < end_time.into(), "{:?} should be after {:?}", expire, end_time ); } #[test] fn are_session_ids_unique_in_storage() { let mut mtt = MoreThanText::new(); let client = mtt.client(); let id: Uuid = mtt.client().session_id().try_into().unwrap(); let mut addition = Addition::new(doc_name()); addition.add_field(id_name(), id); let mut error = MTTError::new(ErrorID::IndexEntryAlreadyExists(id.into())); error.add_parent(ErrorID::Field(id_name().into())); error.add_parent(ErrorID::Document(doc_name().into())); match client.records(addition) { Ok(data) => unreachable!("got {:?} should have been error", data), Err(err) => assert_eq!(err.to_string(), error.to_string()), } } #[test] fn does_expire_updates_on_query() { let mut test_env = TestMoreThanText::new(); let mut mtt = test_env.get_morethantext(); let id = mtt.client().session_id(); let path = Path::new( Include::All, Include::Just(doc_name().into()), Include::Just(Action::OnUpdate), ); test_env.register_channel(vec![path]); let start_time = Utc::now() + DELAY; mtt.client_with_session(id, None); let result = test_env.get_trigger_records(Action::OnUpdate); let rec = result.iter().last().unwrap(); let expire = rec.get(&expire_name()).unwrap(); assert!( expire > start_time.into(), "{:?} should be after {:?}", expire, start_time ); } #[test] fn are_expired_sessions_removed() { let mut test_env = TestMoreThanText::new(); let client = test_env.get_morethantext().client(); let id: Uuid = test_env .get_morethantext() .client() .session_id() .try_into() .unwrap(); let mut calc = Calculation::new(Operand::Equal); calc.add_value(CalcValue::Existing(FieldType::Uuid)) .unwrap(); calc.add_value(id.clone()).unwrap(); let mut update = Update::new(doc_name()); let expire = Utc::now() - Duration::from_secs(10); update.get_query_mut().add(id_name(), calc.clone()); update.get_values_mut().add_field(expire_name(), expire); client.records(update).unwrap(); let path = Path::new( Include::All, Include::Just(doc_name().into()), Include::Just(Action::OnDelete), ); test_env.register_channel(vec![path]); test_env.send_time_pulse(); let result = test_env.get_trigger_records(Action::OnDelete); assert_eq!(result.len(), 1, "incorrect number of records\n{:?}", result); let rec = result.iter().last().unwrap(); assert_eq!(rec.get(id_name()).unwrap(), id.into()); } #[test] fn is_english_the_default_language() { let lang_name = Name::english("language"); let lang = Language::from_639_1("en").unwrap(); let mut test_env = TestMoreThanText::new(); let mut mtt = test_env.get_morethantext(); let path = Path::new( Include::All, Include::Just(doc_name().into()), Include::Just(Action::OnAddition), ); test_env.register_channel(vec![path]); mtt.client(); let result = test_env.get_trigger_records(Action::OnAddition); assert_eq!(result.len(), 1, "incorrect number of records"); let rec = result.iter().last().unwrap(); assert_eq!(rec.get(&lang_name).unwrap(), lang.into()); } #[test] fn can_language_be_assigned() { let lang_name = Name::english("language"); let lang = Language::from_639_1("ja").unwrap(); let mut test_env = TestMoreThanText::new(); let mut mtt = test_env.get_morethantext(); let path = Path::new( Include::All, Include::Just(doc_name().into()), Include::Just(Action::OnAddition), ); test_env.register_channel(vec![path]); mtt.client_with_language(lang.clone()); let result = test_env.get_trigger_records(Action::OnAddition); assert_eq!(result.len(), 1, "incorrect number of records"); let rec = result.iter().last().unwrap(); assert_eq!(rec.get(&lang_name).unwrap(), lang.into()); } #[test] fn does_not_change_language() { let lang_name = Name::english("language"); let elang = Language::from_639_1("en").unwrap(); let jlang = Language::from_639_1("ja").unwrap(); let mut test_env = TestMoreThanText::new(); let mut mtt = test_env.get_morethantext(); let id = mtt.client_with_language(jlang.clone()).session_id(); let path = Path::new( Include::All, Include::Just(doc_name().into()), Include::Just(Action::OnUpdate), ); test_env.register_channel(vec![path]); mtt.client_with_session(id, Some(elang)); let result = test_env.get_trigger_records(Action::OnUpdate); assert_eq!(result.len(), 1, "incorrect number of records"); let rec = result.iter().last().unwrap(); assert_eq!(rec.get(&lang_name).unwrap(), jlang.into()); }