#[macro_use] extern crate lazy_static; use seshat::{ CheckpointDirection, CrawlerCheckpoint, Database, Event, EventType, LoadConfig, LoadDirection, Profile, SearchConfig, }; #[cfg(feature = "encryption")] use seshat::Config; use std::path::Path; use tempfile::tempdir; use fake::{faker::internet::raw::*, locales::*, Fake}; pub static EVENT_SOURCE: &str = "{ content: { body: Test message, msgtype: m.text }, event_id: $15163622445EBvZJ:localhost, origin_server_ts: 1516362244026, sender: @example2:localhost, type: m.room.message, unsigned: {age: 43289803095}, user_id: @example2:localhost, age: 43289803095 }"; pub static TOPIC_EVENT_SOURCE: &str = "{ content: { topic: Test topic }, event_id: $15163622448EBvZJ:localhost, origin_server_ts: 1516362244050, sender: @example2:localhost, type: m.room.topic, unsigned: {age: 43289803098}, user_id: @example2:localhost, age: 43289803098 }"; pub static FILE_SOURCE: &str = "{ content: { body: Test File, msgtype: m.file, }, event_id: $15163622445EBvZJ:localhost, origin_server_ts: 1516362244026, sender: @example2:localhost, type: m.room.message, unsigned: {age: 43289803095}, user_id: @example2:localhost, age: 43289803095 }"; pub static IMAGE_SOURCE: &str = "{ content: { body: Test image, msgtype: m.image, }, event_id: $15163622445EBvZJ:localhost, origin_server_ts: 1516362244026, sender: @example2:localhost, type: m.room.message, unsigned: {age: 43289803095}, user_id: @example2:localhost, age: 43289803095 }"; pub static VIDEO_SOURCE: &str = "{ content: { body: Test video, msgtype: m.video, }, event_id: $15163622449Ebeoj:localhost, origin_server_ts: 1516362244100, sender: @example2:localhost, type: m.room.message, unsigned: {age: 43289803095}, user_id: @example2:localhost, age: 43289803095 }"; lazy_static! { pub static ref EVENT: Event = Event::new( EventType::Message, "Test message", Some("m.text"), "$15163622445EBvZJ:localhost", "@example2:localhost", 151636_2244026, "!test_room:localhost", EVENT_SOURCE, ); } lazy_static! { pub static ref FILE_EVENT: Event = Event::new( EventType::Message, "Test file", Some("m.file"), "$15163622468file:localhost", "@example2:localhost", 151636_2244000, "!test_room:localhost", FILE_SOURCE, ); } lazy_static! { pub static ref IMAGE_EVENT: Event = Event::new( EventType::Message, "Test image", Some("m.image"), "$15163622471image:localhost", "@example2:localhost", 151636_2244050, "!test_room:localhost", IMAGE_SOURCE, ); } lazy_static! { pub static ref VIDEO_EVENT: Event = Event::new( EventType::Message, "Test video", Some("m.video"), "$15163622449video:localhost", "@example2:localhost", 151636_2244100, "!test_room:localhost", VIDEO_SOURCE, ); } lazy_static! { pub static ref TOPIC_EVENT: Event = Event::new( EventType::Topic, "Test topic", None, "$15163622445EBvZE:localhost", "@example2:localhost", 151636_2244038, "!test_room:localhost", TOPIC_EVENT_SOURCE, ); } fn fake_event() -> Event { let domain: String = FreeEmailProvider(EN).fake(); Event::new( EventType::Message, "Hello world", Some("m.text"), &format!("${}:{}", (0..10).fake::(), &domain), &format!( "@{}:{}", Username(EN).fake::(), FreeEmailProvider(EN).fake::() ), 151636_2244026, "!test_room:localhost", EVENT_SOURCE, ) } #[test] fn create_db() { let tmpdir = tempdir().unwrap(); let _db = Database::new(tmpdir.path()).unwrap(); } #[test] fn save_and_search() { let tmpdir = tempdir().unwrap(); let mut db = Database::new(tmpdir.path()).unwrap(); let profile = Profile::new("Alice", ""); db.add_event(EVENT.clone(), profile); db.force_commit().unwrap(); db.reload().unwrap(); let result = db.search("Test", &Default::default()).unwrap().results; assert!(!result.is_empty()); assert_eq!(result[0].event_source, EVENT.source); } #[test] fn search_with_room() { let tmpdir = tempdir().unwrap(); let mut db = Database::new(tmpdir.path()).unwrap(); let profile = Profile::new("Alice", ""); db.add_event(EVENT.clone(), profile); db.force_commit().unwrap(); db.reload().unwrap(); let cases = [ ("\"Test message\"", true), ("Test message", true), ("Test anything", true), ("anything message", true), ("Test", true), ("message", true), ("massage", false), ("\"Test massage\"", false), ]; for (phrase, should_match) in cases.iter() { let result = db .search(phrase, SearchConfig::new().for_room("!test_room:localhost")) .unwrap() .results; assert!( should_match == &!result.is_empty(), "searching for '{}' should not return a result, but found {}", phrase, result[0].event_source ); if *should_match { assert_eq!(result[0].event_source, EVENT.source); } } } #[test] fn duplicate_events() { let tmpdir = tempdir().unwrap(); let mut db = Database::new(tmpdir.path()).unwrap(); let profile = Profile::new("Alice", ""); db.add_event(EVENT.clone(), profile.clone()); db.add_event(EVENT.clone(), profile); db.force_commit().unwrap(); db.reload().unwrap(); let searcher = db.get_searcher(); let result = searcher .search("Test", &Default::default()) .unwrap() .results; assert_eq!(result.len(), 1); } #[test] fn save_and_search_historic_events() { let tmpdir = tempdir().unwrap(); let db = Database::new(tmpdir.path()).unwrap(); let profile = Profile::new("Alice", ""); let mut events = Vec::new(); for i in 1..6 { let mut event: Event = fake_event(); event.server_ts = EVENT.server_ts - i; event.source = format!("Hello before event {}", i); events.push((event, profile.clone())); } let checkpoint = CrawlerCheckpoint { room_id: "!test:room".to_string(), token: "1234".to_string(), full_crawl: false, direction: CheckpointDirection::Backwards, }; let receiver = db.add_historic_events(events, Some(checkpoint.clone()), None); let ret = receiver.recv().unwrap(); assert!(ret.is_ok()); let connection = db.get_connection().unwrap(); let checkpoints = connection.load_checkpoints().unwrap(); assert!(checkpoints.contains(&checkpoint)); } #[test] fn get_size() { let tmpdir = tempdir().unwrap(); let mut db = Database::new(tmpdir.path()).unwrap(); let profile = Profile::new("Alice", ""); db.add_event(EVENT.clone(), profile.clone()); let mut before_event = None; for i in 1..6 { let mut event: Event = fake_event(); event.server_ts = EVENT.server_ts - i; event.source = format!("Hello before event {}", i); if before_event.is_none() { before_event = Some(event.clone()); } db.add_event(event, profile.clone()); } db.force_commit().unwrap(); assert!(db.get_size().unwrap() > 0); } #[test] fn add_differing_events() { let tmpdir = tempdir().unwrap(); let mut db = Database::new(tmpdir.path()).unwrap(); let profile = Profile::new("Alice", ""); db.add_event(EVENT.clone(), profile.clone()); db.add_event(TOPIC_EVENT.clone(), profile); db.force_commit().unwrap(); db.reload().unwrap(); let searcher = db.get_searcher(); let result = searcher .search("Test", &SearchConfig::new()) .unwrap() .results; assert_eq!(result.len(), 2); } #[test] fn search_with_specific_key() { let tmpdir = tempdir().unwrap(); let mut db = Database::new(tmpdir.path()).unwrap(); let profile = Profile::new("Alice", ""); let searcher = db.get_searcher(); db.add_event(EVENT.clone(), profile.clone()); db.force_commit().unwrap(); db.reload().unwrap(); let result = searcher .search("Test", SearchConfig::new().with_key(EventType::Topic)) .unwrap() .results; assert!(result.is_empty()); db.add_event(TOPIC_EVENT.clone(), profile); db.force_commit().unwrap(); db.reload().unwrap(); let searcher = db.get_searcher(); let result = searcher .search("Test", SearchConfig::new().with_key(EventType::Topic)) .unwrap() .results; assert_eq!(result.len(), 1); assert_eq!(result[0].event_source, TOPIC_EVENT.source) } #[test] fn delete() { let tmpdir = tempdir().unwrap(); let path: &Path = tmpdir.path(); assert!(path.exists()); let db = Database::new(tmpdir.path()).unwrap(); db.delete().unwrap(); assert!(!path.exists()); } #[cfg(feature = "encryption")] #[test] fn encrypted_save_and_search() { let tmpdir = tempdir().unwrap(); let db_config = Config::new().set_passphrase("wordpass"); let mut db = Database::new_with_config(tmpdir.path(), &db_config).unwrap(); let profile = Profile::new("Alice", ""); db.add_event(EVENT.clone(), profile); db.force_commit().unwrap(); db.reload().unwrap(); let result = db.search("Test", &Default::default()).unwrap().results; assert!(!result.is_empty()); assert_eq!(result[0].event_source, EVENT.source); } #[test] fn load_file_events() { let tmpdir = tempdir().unwrap(); let mut db = Database::new(tmpdir.path()).unwrap(); let profile = Profile::new("Alice", ""); db.add_event(EVENT.clone(), profile.clone()); db.add_event(FILE_EVENT.clone(), profile.clone()); db.add_event(IMAGE_EVENT.clone(), profile); db.force_commit().unwrap(); db.reload().unwrap(); let connection = db.get_connection().unwrap(); let mut config = LoadConfig::new(&FILE_EVENT.room_id).limit(10); let result = connection .load_file_events(&config) .expect("Can't load file events"); assert!(!result.is_empty()); assert!(result.len() == 2); assert_eq!(result[0].0, IMAGE_EVENT.source); assert!(result.len() == 2); assert_eq!(result[1].0, FILE_EVENT.source); config = config.limit(1); let result = connection .load_file_events(&config) .expect("Can't load file events"); assert!(!result.is_empty()); assert!(result.len() == 1); assert_eq!(result[0].0, IMAGE_EVENT.source); config = config.from_event(&IMAGE_EVENT.event_id); let result = connection .load_file_events(&config) .expect("Can't load file events with token"); assert!(!result.is_empty()); assert!(result.len() == 1); assert_eq!(result[0].0, FILE_EVENT.source); } #[test] fn load_file_events_directions() { let tmpdir = tempdir().unwrap(); let mut db = Database::new(tmpdir.path()).unwrap(); let profile = Profile::new("Alice", ""); db.add_event(EVENT.clone(), profile.clone()); db.add_event(FILE_EVENT.clone(), profile.clone()); db.add_event(IMAGE_EVENT.clone(), profile.clone()); db.add_event(VIDEO_EVENT.clone(), profile); db.force_commit().unwrap(); db.reload().unwrap(); let connection = db.get_connection().unwrap(); // Get the newest event. let mut config = LoadConfig::new(&FILE_EVENT.room_id).limit(1); let result = connection.load_file_events(&config).unwrap(); assert_eq!(result.len(), 1); assert_eq!(result[0].0, VIDEO_EVENT.source); // Get the next two. config = config.from_event(&VIDEO_EVENT.event_id).limit(10); let result = connection.load_file_events(&config).unwrap(); assert_eq!(result.len(), 2); assert_eq!(result[0].0, IMAGE_EVENT.source); assert_eq!(result[1].0, FILE_EVENT.source); // Try to get a newer one than the last one. config = config.direction(LoadDirection::Forwards); let result = connection.load_file_events(&config).unwrap(); assert!(result.is_empty()); // Get the two newer events than the last one. config = config.from_event(&FILE_EVENT.event_id); let result = connection.load_file_events(&config).unwrap(); assert_eq!(result.len(), 2); assert_eq!(result[0].0, IMAGE_EVENT.source); assert_eq!(result[1].0, VIDEO_EVENT.source); } #[test] fn delete_events() { let tmpdir = tempdir().unwrap(); let mut db = Database::new(tmpdir.path()).unwrap(); let profile = Profile::new("Alice", ""); db.add_event(EVENT.clone(), profile.clone()); db.add_event(TOPIC_EVENT.clone(), profile); db.force_commit().unwrap(); db.reload().unwrap(); let searcher = db.get_searcher(); let result = searcher .search("Test", &SearchConfig::new()) .unwrap() .results; assert_eq!(result.len(), 2); let receiver = db.delete_event(&EVENT.event_id); let result = receiver.recv().unwrap(); result.unwrap(); db.force_commit().unwrap(); db.reload().unwrap(); let result = searcher .search("Test", &SearchConfig::new()) .unwrap() .results; assert_eq!(result.len(), 1); assert_eq!(result[0].event_source, TOPIC_EVENT.source); }