move store tests into separate reusable macro, too

This commit is contained in:
Benjamin Kampmann
2021-12-01 11:49:01 +01:00
parent c7a9fc6c8e
commit 9d5c1fc14c
5 changed files with 319 additions and 680 deletions
@@ -508,7 +508,7 @@ impl IndexeddbStore {
if let Some((old_event, _)) = room_user_receipts
.get(&key)?
.await?
.map(|f| self.deserialize_event::<(EventId, Receipt)>(f).ok())
.map(|f| self.deserialize_event::<(Box<EventId>, Receipt)>(f).ok())
.flatten()
{
room_event_receipts.delete(&JsValue::from_str(&format!(
@@ -625,33 +625,27 @@ impl IndexeddbStore {
pub async fn get_user_ids_stream(
&self,
room_id: &RoomId,
) -> Result<impl Stream<Item = Result<UserId>>> {
) -> Result<Vec<Box<UserId>>> {
let range = make_range(room_id.as_str().to_owned())?;
let skip = room_id.as_str().len() + 1;
let entries = self
Ok(self
.inner
.transaction_on_one_with_mode(KEYS::MEMBERS, IdbTransactionMode::Readonly)?
.object_store(KEYS::MEMBERS)?
.get_all_keys_with_key(&range)?
.await?
.iter()
.map(|key| {
if let Some(k) = key.as_string() {
UserId::try_from(k[skip..].to_owned())
.map_err(|e| StoreError::Codec(e.to_string()))
} else {
Err(StoreError::Codec(format!("{:?}", key)))
}
.filter_map(|key| match key.as_string() {
Some(k) => Box::<UserId>::try_from(&k[skip..]).ok(),
_ => None
})
.collect::<Vec<_>>();
Ok(stream::iter(entries))
.collect::<Vec<_>>())
}
pub async fn get_invited_user_ids(
&self,
room_id: &RoomId,
) -> Result<impl Stream<Item = Result<UserId>>> {
) -> Result<Vec<Box<UserId>>> {
let range = make_range(room_id.as_str().to_owned())?;
let entries = self
.inner
@@ -660,31 +654,29 @@ impl IndexeddbStore {
.get_all_with_key(&range)?
.await?
.iter()
.map(|f| self.deserialize_event(f).map_err::<StoreError, _>(|e| e.into()))
.filter_map(|f| self.deserialize_event::<Box<UserId>>(f).ok())
.collect::<Vec<_>>();
Ok(stream::iter(entries))
Ok(entries)
}
pub async fn get_joined_user_ids(
&self,
room_id: &RoomId,
) -> Result<impl Stream<Item = Result<UserId>>> {
) -> Result<Vec<Box<UserId>>> {
let range = make_range(room_id.as_str().to_owned())?;
let entries = self
Ok(self
.inner
.transaction_on_one_with_mode(KEYS::JOINED_USER_IDS, IdbTransactionMode::Readonly)?
.object_store(KEYS::JOINED_USER_IDS)?
.get_all_with_key(&range)?
.await?
.iter()
.map(|f| self.deserialize_event(f).map_err::<StoreError, _>(|e| e.into()))
.collect::<Vec<_>>();
Ok(stream::iter(entries))
.filter_map(|f| self.deserialize_event::<Box<UserId>>(f).ok())
.collect::<Vec<_>>())
}
pub async fn get_room_infos(&self) -> Result<impl Stream<Item = Result<RoomInfo>>> {
pub async fn get_room_infos(&self) -> Result<Vec<RoomInfo>> {
let entries: Vec<_> = self
.inner
.transaction_on_one_with_mode(KEYS::ROOM_INFOS, IdbTransactionMode::Readonly)?
@@ -692,13 +684,13 @@ impl IndexeddbStore {
.get_all()?
.await?
.iter()
.map(|f| self.deserialize_event(f).map_err::<StoreError, _>(|e| e.into()))
.filter_map(|f| self.deserialize_event::<RoomInfo>(f).ok())
.collect();
Ok(stream::iter(entries))
Ok(entries)
}
pub async fn get_stripped_room_infos(&self) -> Result<impl Stream<Item = Result<RoomInfo>>> {
pub async fn get_stripped_room_infos(&self) -> Result<Vec<RoomInfo>> {
let entries = self
.inner
.transaction_on_one_with_mode(KEYS::STRIPPED_ROOM_INFO, IdbTransactionMode::Readonly)?
@@ -706,17 +698,17 @@ impl IndexeddbStore {
.get_all()?
.await?
.iter()
.map(|f| self.deserialize_event(f).map_err::<StoreError, _>(|e| e.into()))
.filter_map(|f| self.deserialize_event(f).ok())
.collect::<Vec<_>>();
Ok(stream::iter(entries))
Ok(entries)
}
pub async fn get_users_with_display_name(
&self,
room_id: &RoomId,
display_name: &str,
) -> Result<BTreeSet<UserId>> {
) -> Result<BTreeSet<Box<UserId>>> {
let range = make_range(format!("{}:{}", room_id.as_str(), display_name))?;
Ok(self
.inner
@@ -725,7 +717,7 @@ impl IndexeddbStore {
.get_all_with_key(&range)?
.await?
.iter()
.filter_map(|f| self.deserialize_event::<UserId>(f).ok())
.filter_map(|f| self.deserialize_event::<Box<UserId>>(f).ok())
.collect::<BTreeSet<_>>())
}
@@ -763,7 +755,7 @@ impl IndexeddbStore {
room_id: &RoomId,
receipt_type: ReceiptType,
user_id: &UserId,
) -> Result<Option<(EventId, Receipt)>> {
) -> Result<Option<(Box<EventId>, Receipt)>> {
Ok(self
.inner
.transaction_on_one_with_mode(KEYS::ROOM_USER_RECEIPTS, IdbTransactionMode::Readonly)?
@@ -784,7 +776,7 @@ impl IndexeddbStore {
room_id: &RoomId,
receipt_type: ReceiptType,
event_id: &EventId,
) -> Result<Vec<(UserId, Receipt)>> {
) -> Result<Vec<(Box<UserId>, Receipt)>> {
let key = format!("{}:{}:{}", room_id.as_str(), receipt_type.as_ref(), event_id.as_str());
let prefix_len = key.len() + 1;
let range = make_range(key)?;
@@ -800,8 +792,8 @@ impl IndexeddbStore {
let res =
store.get(&k)?.await?.ok_or(StoreError::Codec(format!("no data at {:?}", k)))?;
let u = if let Some(k_str) = k.as_string() {
UserId::try_from(k_str[prefix_len..].to_owned())
.map_err(|e| StoreError::Codec(e.to_string()))?
Box::<UserId>::try_from(&k_str[prefix_len..])
.map_err(|e| StoreError::Codec(format!("{:?}", e)))?
} else {
return Err(StoreError::Codec(format!("{:?}", k)));
};
@@ -961,31 +953,31 @@ impl StateStore for IndexeddbStore {
self.get_member_event(room_id, state_key).await
}
async fn get_user_ids(&self, room_id: &RoomId) -> Result<Vec<UserId>> {
self.get_user_ids_stream(room_id).await?.try_collect().await
async fn get_user_ids(&self, room_id: &RoomId) -> Result<Vec<Box<UserId>>> {
self.get_user_ids_stream(room_id).await
}
async fn get_invited_user_ids(&self, room_id: &RoomId) -> Result<Vec<UserId>> {
self.get_invited_user_ids(room_id).await?.try_collect().await
async fn get_invited_user_ids(&self, room_id: &RoomId) -> Result<Vec<Box<UserId>>> {
self.get_invited_user_ids(room_id).await
}
async fn get_joined_user_ids(&self, room_id: &RoomId) -> Result<Vec<UserId>> {
self.get_joined_user_ids(room_id).await?.try_collect().await
async fn get_joined_user_ids(&self, room_id: &RoomId) -> Result<Vec<Box<UserId>>> {
self.get_joined_user_ids(room_id).await
}
async fn get_room_infos(&self) -> Result<Vec<RoomInfo>> {
self.get_room_infos().await?.try_collect().await
self.get_room_infos().await
}
async fn get_stripped_room_infos(&self) -> Result<Vec<RoomInfo>> {
self.get_stripped_room_infos().await?.try_collect().await
self.get_stripped_room_infos().await
}
async fn get_users_with_display_name(
&self,
room_id: &RoomId,
display_name: &str,
) -> Result<BTreeSet<UserId>> {
) -> Result<BTreeSet<Box<UserId>>> {
self.get_users_with_display_name(room_id, display_name).await
}
@@ -1009,7 +1001,7 @@ impl StateStore for IndexeddbStore {
room_id: &RoomId,
receipt_type: ReceiptType,
user_id: &UserId,
) -> Result<Option<(EventId, Receipt)>> {
) -> Result<Option<(Box<EventId>, Receipt)>> {
self.get_user_room_receipt_event(room_id, receipt_type, user_id).await
}
@@ -1018,7 +1010,7 @@ impl StateStore for IndexeddbStore {
room_id: &RoomId,
receipt_type: ReceiptType,
event_id: &EventId,
) -> Result<Vec<(UserId, Receipt)>> {
) -> Result<Vec<(Box<UserId>, Receipt)>> {
self.get_event_room_receipt_events(room_id, receipt_type, event_id).await
}
@@ -1054,254 +1046,11 @@ mod test {
#[cfg(target_arch = "wasm32")]
wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
use std::convert::TryFrom;
use super::{IndexeddbStore, Result};
use matrix_sdk_test::async_test;
use ruma::{
api::client::r0::media::get_content_thumbnail::Method,
event_id,
events::{
room::{
member::{MembershipState, RoomMemberEventContent},
power_levels::RoomPowerLevelsEventContent,
},
AnySyncStateEvent, EventType, Unsigned,
},
mxc_uri,
receipt::ReceiptType,
room_id,
serde::Raw,
uint, user_id, EventId, MilliSecondsSinceUnixEpoch, UserId,
};
use serde_json::json;
use super::{IndexeddbStore, StateChanges};
use crate::{
deserialized_responses::MemberEvent,
media::{MediaFormat, MediaRequest, MediaThumbnailSize, MediaType},
store::StateStore,
};
fn user_id() -> UserId {
user_id!("@example:localhost")
async fn get_store() -> Result<IndexeddbStore> {
IndexeddbStore::open().await
}
fn power_level_event() -> Raw<AnySyncStateEvent> {
let content = RoomPowerLevelsEventContent::default();
let event = json!({
"event_id": EventId::try_from("$h29iv0s8:example.com").unwrap(),
"content": content,
"sender": user_id(),
"type": "m.room.power_levels",
"origin_server_ts": 0u64,
"state_key": "",
"unsigned": Unsigned::default(),
});
serde_json::from_value(event).unwrap()
}
fn membership_event() -> MemberEvent {
MemberEvent {
event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(),
content: RoomMemberEventContent::new(MembershipState::Join),
sender: user_id(),
origin_server_ts: MilliSecondsSinceUnixEpoch(198u32.into()),
state_key: user_id(),
prev_content: None,
unsigned: Unsigned::default(),
}
}
#[async_test]
async fn test_member_saving() {
let store = IndexeddbStore::open().await.unwrap();
let room_id = room_id!("!test:localhost");
let user_id = user_id();
assert!(store.get_member_event(&room_id, &user_id).await.unwrap().is_none());
let mut changes = StateChanges::default();
changes
.members
.entry(room_id.clone())
.or_default()
.insert(user_id.clone(), membership_event());
store.save_changes(&changes).await.unwrap();
assert!(store.get_member_event(&room_id, &user_id).await.unwrap().is_some());
let members = store.get_user_ids(&room_id).await.unwrap();
assert!(!members.is_empty())
}
#[async_test]
async fn test_power_level_saving() {
let store = IndexeddbStore::open().await.unwrap();
let room_id = room_id!("!test:localhost");
let raw_event = power_level_event();
let event = raw_event.deserialize().unwrap();
assert!(store
.get_state_event(&room_id, EventType::RoomPowerLevels, "")
.await
.unwrap()
.is_none());
let mut changes = StateChanges::default();
changes.add_state_event(&room_id, event, raw_event);
store.save_changes(&changes).await.unwrap();
assert!(store
.get_state_event(&room_id, EventType::RoomPowerLevels, "")
.await
.unwrap()
.is_some());
}
#[async_test]
async fn test_receipts_saving() {
let store = IndexeddbStore::open().await.unwrap();
let room_id = room_id!("!test:localhost");
let first_event_id = event_id!("$1435641916114394fHBLK:matrix.org");
let second_event_id = event_id!("$fHBLK1435641916114394:matrix.org");
let first_receipt_event = serde_json::from_value(json!({
first_event_id.clone(): {
"m.read": {
user_id(): {
"ts": 1436451550453u64
}
}
}
}))
.unwrap();
let second_receipt_event = serde_json::from_value(json!({
second_event_id.clone(): {
"m.read": {
user_id(): {
"ts": 1436451551453u64
}
}
}
}))
.unwrap();
assert!(store
.get_user_room_receipt_event(&room_id, ReceiptType::Read, &user_id())
.await
.unwrap()
.is_none());
assert!(store
.get_event_room_receipt_events(&room_id, ReceiptType::Read, &first_event_id)
.await
.unwrap()
.is_empty());
assert!(store
.get_event_room_receipt_events(&room_id, ReceiptType::Read, &second_event_id)
.await
.unwrap()
.is_empty());
let mut changes = StateChanges::default();
changes.add_receipts(&room_id, first_receipt_event);
store.save_changes(&changes).await.unwrap();
assert!(store
.get_user_room_receipt_event(&room_id, ReceiptType::Read, &user_id())
.await
.unwrap()
.is_some(),);
assert_eq!(
store
.get_event_room_receipt_events(&room_id, ReceiptType::Read, &first_event_id)
.await
.unwrap()
.len(),
1
);
assert!(store
.get_event_room_receipt_events(&room_id, ReceiptType::Read, &second_event_id)
.await
.unwrap()
.is_empty());
let mut changes = StateChanges::default();
changes.add_receipts(&room_id, second_receipt_event);
store.save_changes(&changes).await.unwrap();
assert!(store
.get_user_room_receipt_event(&room_id, ReceiptType::Read, &user_id())
.await
.unwrap()
.is_some());
assert!(store
.get_event_room_receipt_events(&room_id, ReceiptType::Read, &first_event_id)
.await
.unwrap()
.is_empty());
assert_eq!(
store
.get_event_room_receipt_events(&room_id, ReceiptType::Read, &second_event_id)
.await
.unwrap()
.len(),
1
);
}
#[async_test]
async fn test_media_content() {
let store = IndexeddbStore::open().await.unwrap();
let uri = mxc_uri!("mxc://localhost/media");
let content: Vec<u8> = "somebinarydata".into();
let request_file =
MediaRequest { media_type: MediaType::Uri(uri.clone()), format: MediaFormat::File };
let request_thumbnail = MediaRequest {
media_type: MediaType::Uri(uri.clone()),
format: MediaFormat::Thumbnail(MediaThumbnailSize {
method: Method::Crop,
width: uint!(100),
height: uint!(100),
}),
};
assert!(store.get_media_content(&request_file).await.unwrap().is_none());
assert!(store.get_media_content(&request_thumbnail).await.unwrap().is_none());
store.add_media_content(&request_file, content.clone()).await.unwrap();
assert!(store.get_media_content(&request_file).await.unwrap().is_some());
store.remove_media_content(&request_file).await.unwrap();
assert!(store.get_media_content(&request_file).await.unwrap().is_none());
store.add_media_content(&request_file, content.clone()).await.unwrap();
assert!(store.get_media_content(&request_file).await.unwrap().is_some());
store.add_media_content(&request_thumbnail, content.clone()).await.unwrap();
assert!(store.get_media_content(&request_thumbnail).await.unwrap().is_some());
store.remove_media_content_for_uri(&uri).await.unwrap();
assert!(store.get_media_content(&request_file).await.unwrap().is_none());
assert!(store.get_media_content(&request_thumbnail).await.unwrap().is_none());
}
#[async_test]
async fn test_custom_storage() {
let key = "my_key";
let value = &[0, 1, 2, 3];
let store = IndexeddbStore::open().await.unwrap();
store.set_custom_value(key.as_bytes(), value.to_vec()).await.unwrap();
let read = store.get_custom_value(key.as_bytes()).await.unwrap();
assert_eq!(Some(value.as_ref()), read.as_deref());
}
statestore_integration_tests! { integration }
}
@@ -0,0 +1,266 @@
#[allow(unused_macros)]
macro_rules! statestore_integration_tests {
($($name:ident)*) => {
$(
mod $name {
use matrix_sdk_test::async_test;
use ruma::{
api::client::r0::media::get_content_thumbnail::Method,
event_id,
events::{
room::{
member::{MembershipState, RoomMemberEventContent},
power_levels::RoomPowerLevelsEventContent,
},
AnySyncStateEvent, EventType, Unsigned,
},
mxc_uri,
receipt::ReceiptType,
room_id,
serde::Raw,
uint, user_id, MilliSecondsSinceUnixEpoch, UserId,
};
use serde_json::json;
use crate::{
deserialized_responses::MemberEvent,
media::{MediaFormat, MediaRequest, MediaThumbnailSize, MediaType},
store::{
StateStore,
Result,
StateChanges
}
};
use super::get_store;
fn user_id() -> &'static UserId {
user_id!("@example:localhost")
}
fn power_level_event() -> Raw<AnySyncStateEvent> {
let content = RoomPowerLevelsEventContent::default();
let event = json!({
"event_id": "$h29iv0s8:example.com",
"content": content,
"sender": user_id(),
"type": "m.room.power_levels",
"origin_server_ts": 0u64,
"state_key": "",
"unsigned": Unsigned::default(),
});
serde_json::from_value(event).unwrap()
}
fn membership_event() -> MemberEvent {
MemberEvent {
event_id: event_id!("$h29iv0s8:example.com").to_owned(),
content: RoomMemberEventContent::new(MembershipState::Join),
sender: user_id().to_owned(),
origin_server_ts: MilliSecondsSinceUnixEpoch(198u32.into()),
state_key: user_id().to_owned(),
prev_content: None,
unsigned: Unsigned::default(),
}
}
#[async_test]
async fn test_member_saving() {
let store = get_store().await.unwrap();
let room_id = room_id!("!test:localhost");
let user_id = user_id();
assert!(store.get_member_event(room_id, user_id).await.unwrap().is_none());
let mut changes = StateChanges::default();
changes
.members
.entry(room_id.to_owned())
.or_default()
.insert(user_id.to_owned(), membership_event());
store.save_changes(&changes).await.unwrap();
assert!(store.get_member_event(room_id, user_id).await.unwrap().is_some());
let members = store.get_user_ids(room_id).await.unwrap();
assert!(!members.is_empty())
}
#[async_test]
async fn test_power_level_saving() {
let store = get_store().await.unwrap();
let room_id = room_id!("!test:localhost");
let raw_event = power_level_event();
let event = raw_event.deserialize().unwrap();
assert!(store
.get_state_event(room_id, EventType::RoomPowerLevels, "")
.await
.unwrap()
.is_none());
let mut changes = StateChanges::default();
changes.add_state_event(room_id, event, raw_event);
store.save_changes(&changes).await.unwrap();
assert!(store
.get_state_event(room_id, EventType::RoomPowerLevels, "")
.await
.unwrap()
.is_some());
}
#[async_test]
async fn test_receipts_saving() {
let store = get_store().await.unwrap();
let room_id = room_id!("!test:localhost");
let first_event_id = event_id!("$1435641916114394fHBLK:matrix.org").to_owned();
let second_event_id = event_id!("$fHBLK1435641916114394:matrix.org").to_owned();
let first_receipt_event = serde_json::from_value(json!({
first_event_id.clone(): {
"m.read": {
user_id().to_owned(): {
"ts": 1436451550453u64
}
}
}
}))
.unwrap();
let second_receipt_event = serde_json::from_value(json!({
second_event_id.clone(): {
"m.read": {
user_id().to_owned(): {
"ts": 1436451551453u64
}
}
}
}))
.unwrap();
assert!(store
.get_user_room_receipt_event(room_id, ReceiptType::Read, user_id())
.await
.unwrap()
.is_none());
assert!(store
.get_event_room_receipt_events(room_id, ReceiptType::Read, &first_event_id)
.await
.unwrap()
.is_empty());
assert!(store
.get_event_room_receipt_events(room_id, ReceiptType::Read, &second_event_id)
.await
.unwrap()
.is_empty());
let mut changes = StateChanges::default();
changes.add_receipts(room_id, first_receipt_event);
store.save_changes(&changes).await.unwrap();
assert!(store
.get_user_room_receipt_event(room_id, ReceiptType::Read, user_id())
.await
.unwrap()
.is_some(),);
assert_eq!(
store
.get_event_room_receipt_events(room_id, ReceiptType::Read, &first_event_id)
.await
.unwrap()
.len(),
1
);
assert!(store
.get_event_room_receipt_events(room_id, ReceiptType::Read, &second_event_id)
.await
.unwrap()
.is_empty());
let mut changes = StateChanges::default();
changes.add_receipts(room_id, second_receipt_event);
store.save_changes(&changes).await.unwrap();
assert!(store
.get_user_room_receipt_event(room_id, ReceiptType::Read, user_id())
.await
.unwrap()
.is_some());
assert!(store
.get_event_room_receipt_events(room_id, ReceiptType::Read, &first_event_id)
.await
.unwrap()
.is_empty());
assert_eq!(
store
.get_event_room_receipt_events(room_id, ReceiptType::Read, &second_event_id)
.await
.unwrap()
.len(),
1
);
}
#[async_test]
async fn test_media_content() {
let store = get_store().await.unwrap();
let uri = mxc_uri!("mxc://localhost/media");
let content: Vec<u8> = "somebinarydata".into();
let request_file =
MediaRequest { media_type: MediaType::Uri(uri.to_owned()), format: MediaFormat::File };
let request_thumbnail = MediaRequest {
media_type: MediaType::Uri(uri.to_owned()),
format: MediaFormat::Thumbnail(MediaThumbnailSize {
method: Method::Crop,
width: uint!(100),
height: uint!(100),
}),
};
assert!(store.get_media_content(&request_file).await.unwrap().is_none());
assert!(store.get_media_content(&request_thumbnail).await.unwrap().is_none());
store.add_media_content(&request_file, content.clone()).await.unwrap();
assert!(store.get_media_content(&request_file).await.unwrap().is_some());
store.remove_media_content(&request_file).await.unwrap();
assert!(store.get_media_content(&request_file).await.unwrap().is_none());
store.add_media_content(&request_file, content.clone()).await.unwrap();
assert!(store.get_media_content(&request_file).await.unwrap().is_some());
store.add_media_content(&request_thumbnail, content.clone()).await.unwrap();
assert!(store.get_media_content(&request_thumbnail).await.unwrap().is_some());
store.remove_media_content_for_uri(uri).await.unwrap();
assert!(store.get_media_content(&request_file).await.unwrap().is_none());
assert!(store.get_media_content(&request_thumbnail).await.unwrap().is_none());
}
#[async_test]
async fn test_custom_storage() -> Result<()> {
let key = "my_key";
let value = &[0, 1, 2, 3];
let store = get_store().await?;
store.set_custom_value(key.as_bytes(), value.to_vec()).await?;
let read = store.get_custom_value(key.as_bytes()).await?;
assert_eq!(Some(value.as_ref()), read.as_deref());
Ok(())
}
}
)*
}
}
@@ -592,150 +592,12 @@ impl StateStore for MemoryStore {
#[cfg(test)]
mod test {
use matrix_sdk_test::async_test;
use ruma::{
api::client::r0::media::get_content_thumbnail::Method, event_id, mxc_uri,
receipt::ReceiptType, room_id, uint, user_id, UserId,
};
use serde_json::json;
use super::{MemoryStore, StateChanges};
use crate::media::{MediaFormat, MediaRequest, MediaThumbnailSize, MediaType};
use super::{MemoryStore, StateStore, Result};
fn user_id() -> &'static UserId {
user_id!("@example:localhost")
async fn get_store() -> Result<impl StateStore> {
Ok(MemoryStore::new())
}
#[async_test]
async fn test_receipts_saving() {
let store = MemoryStore::new();
let room_id = room_id!("!test:localhost");
let first_event_id = event_id!("$1435641916114394fHBLK:matrix.org").to_owned();
let second_event_id = event_id!("$fHBLK1435641916114394:matrix.org").to_owned();
let first_receipt_event = serde_json::from_value(json!({
first_event_id.clone(): {
"m.read": {
user_id().to_owned(): {
"ts": 1436451550453u64
}
}
}
}))
.unwrap();
let second_receipt_event = serde_json::from_value(json!({
second_event_id.clone(): {
"m.read": {
user_id().to_owned(): {
"ts": 1436451551453u64
}
}
}
}))
.unwrap();
assert!(store
.get_user_room_receipt_event(room_id, ReceiptType::Read, user_id())
.await
.unwrap()
.is_none());
assert!(store
.get_event_room_receipt_events(room_id, ReceiptType::Read, &first_event_id)
.await
.unwrap()
.is_empty());
assert!(store
.get_event_room_receipt_events(room_id, ReceiptType::Read, &second_event_id)
.await
.unwrap()
.is_empty());
let mut changes = StateChanges::default();
changes.add_receipts(room_id, first_receipt_event);
store.save_changes(&changes).await.unwrap();
assert!(store
.get_user_room_receipt_event(room_id, ReceiptType::Read, user_id())
.await
.unwrap()
.is_some(),);
assert_eq!(
store
.get_event_room_receipt_events(room_id, ReceiptType::Read, &first_event_id)
.await
.unwrap()
.len(),
1
);
assert!(store
.get_event_room_receipt_events(room_id, ReceiptType::Read, &second_event_id)
.await
.unwrap()
.is_empty());
let mut changes = StateChanges::default();
changes.add_receipts(room_id, second_receipt_event);
store.save_changes(&changes).await.unwrap();
assert!(store
.get_user_room_receipt_event(room_id, ReceiptType::Read, user_id())
.await
.unwrap()
.is_some());
assert!(store
.get_event_room_receipt_events(room_id, ReceiptType::Read, &first_event_id)
.await
.unwrap()
.is_empty());
assert_eq!(
store
.get_event_room_receipt_events(room_id, ReceiptType::Read, &second_event_id)
.await
.unwrap()
.len(),
1
);
}
#[async_test]
async fn test_media_content() {
let store = MemoryStore::new();
let uri = mxc_uri!("mxc://localhost/media");
let content: Vec<u8> = "somebinarydata".into();
let request_file =
MediaRequest { media_type: MediaType::Uri(uri.to_owned()), format: MediaFormat::File };
let request_thumbnail = MediaRequest {
media_type: MediaType::Uri(uri.to_owned()),
format: MediaFormat::Thumbnail(MediaThumbnailSize {
method: Method::Crop,
width: uint!(100),
height: uint!(100),
}),
};
assert!(store.get_media_content(&request_file).await.unwrap().is_none());
assert!(store.get_media_content(&request_thumbnail).await.unwrap().is_none());
store.add_media_content(&request_file, content.clone()).await.unwrap();
assert!(store.get_media_content(&request_file).await.unwrap().is_some());
store.remove_media_content(&request_file).await.unwrap();
assert!(store.get_media_content(&request_file).await.unwrap().is_none());
store.add_media_content(&request_file, content.clone()).await.unwrap();
assert!(store.get_media_content(&request_file).await.unwrap().is_some());
store.add_media_content(&request_thumbnail, content.clone()).await.unwrap();
assert!(store.get_media_content(&request_thumbnail).await.unwrap().is_some());
store.remove_media_content_for_uri(uri).await.unwrap();
assert!(store.get_media_content(&request_file).await.unwrap().is_none());
assert!(store.get_media_content(&request_thumbnail).await.unwrap().is_none());
}
statestore_integration_tests! { integration }
}
+4
View File
@@ -20,6 +20,10 @@ use std::{
sync::Arc,
};
#[cfg(test)]
#[macro_use]
pub mod integration_tests;
use dashmap::DashMap;
use matrix_sdk_common::{async_trait, locks::RwLock, AsyncTraitDeps};
use ruma::{
@@ -989,254 +989,12 @@ impl StateStore for SledStore {
#[cfg(test)]
mod test {
use matrix_sdk_test::async_test;
use ruma::{
api::client::r0::media::get_content_thumbnail::Method,
event_id,
events::{
room::{
member::{MembershipState, RoomMemberEventContent},
power_levels::RoomPowerLevelsEventContent,
},
AnySyncStateEvent, EventType, Unsigned,
},
mxc_uri,
receipt::ReceiptType,
room_id,
serde::Raw,
uint, user_id, MilliSecondsSinceUnixEpoch, UserId,
};
use serde_json::json;
use super::{Result, SledStore, StateChanges};
use crate::{
deserialized_responses::MemberEvent,
media::{MediaFormat, MediaRequest, MediaThumbnailSize, MediaType},
StateStore,
};
use super::{SledStore, Result};
fn user_id() -> &'static UserId {
user_id!("@example:localhost")
async fn get_store() -> Result<SledStore> {
SledStore::open()
}
fn power_level_event() -> Raw<AnySyncStateEvent> {
let content = RoomPowerLevelsEventContent::default();
let event = json!({
"event_id": "$h29iv0s8:example.com",
"content": content,
"sender": user_id(),
"type": "m.room.power_levels",
"origin_server_ts": 0u64,
"state_key": "",
"unsigned": Unsigned::default(),
});
serde_json::from_value(event).unwrap()
}
fn membership_event() -> MemberEvent {
MemberEvent {
event_id: event_id!("$h29iv0s8:example.com").to_owned(),
content: RoomMemberEventContent::new(MembershipState::Join),
sender: user_id().to_owned(),
origin_server_ts: MilliSecondsSinceUnixEpoch::now(),
state_key: user_id().to_owned(),
prev_content: None,
unsigned: Unsigned::default(),
}
}
#[async_test]
async fn test_member_saving() {
let store = SledStore::open().unwrap();
let room_id = room_id!("!test:localhost");
let user_id = user_id();
assert!(store.get_member_event(room_id, user_id).await.unwrap().is_none());
let mut changes = StateChanges::default();
changes
.members
.entry(room_id.to_owned())
.or_default()
.insert(user_id.to_owned(), membership_event());
store.save_changes(&changes).await.unwrap();
assert!(store.get_member_event(room_id, user_id).await.unwrap().is_some());
let members = store.get_user_ids(room_id).await.unwrap();
assert!(!members.is_empty())
}
#[async_test]
async fn test_power_level_saving() {
let store = SledStore::open().unwrap();
let room_id = room_id!("!test:localhost");
let raw_event = power_level_event();
let event = raw_event.deserialize().unwrap();
assert!(store
.get_state_event(room_id, EventType::RoomPowerLevels, "")
.await
.unwrap()
.is_none());
let mut changes = StateChanges::default();
changes.add_state_event(room_id, event, raw_event);
store.save_changes(&changes).await.unwrap();
assert!(store
.get_state_event(room_id, EventType::RoomPowerLevels, "")
.await
.unwrap()
.is_some());
}
#[async_test]
async fn test_receipts_saving() {
let store = SledStore::open().unwrap();
let room_id = room_id!("!test:localhost");
let first_event_id = event_id!("$1435641916114394fHBLK:matrix.org").to_owned();
let second_event_id = event_id!("$fHBLK1435641916114394:matrix.org").to_owned();
let first_receipt_event = serde_json::from_value(json!({
first_event_id.clone(): {
"m.read": {
user_id().to_owned(): {
"ts": 1436451550453u64
}
}
}
}))
.unwrap();
let second_receipt_event = serde_json::from_value(json!({
second_event_id.clone(): {
"m.read": {
user_id().to_owned(): {
"ts": 1436451551453u64
}
}
}
}))
.unwrap();
assert!(store
.get_user_room_receipt_event(room_id, ReceiptType::Read, user_id())
.await
.unwrap()
.is_none());
assert!(store
.get_event_room_receipt_events(room_id, ReceiptType::Read, &first_event_id)
.await
.unwrap()
.is_empty());
assert!(store
.get_event_room_receipt_events(room_id, ReceiptType::Read, &second_event_id)
.await
.unwrap()
.is_empty());
let mut changes = StateChanges::default();
changes.add_receipts(room_id, first_receipt_event);
store.save_changes(&changes).await.unwrap();
assert!(store
.get_user_room_receipt_event(room_id, ReceiptType::Read, user_id())
.await
.unwrap()
.is_some(),);
assert_eq!(
store
.get_event_room_receipt_events(room_id, ReceiptType::Read, &first_event_id)
.await
.unwrap()
.len(),
1
);
assert!(store
.get_event_room_receipt_events(room_id, ReceiptType::Read, &second_event_id)
.await
.unwrap()
.is_empty());
let mut changes = StateChanges::default();
changes.add_receipts(room_id, second_receipt_event);
store.save_changes(&changes).await.unwrap();
assert!(store
.get_user_room_receipt_event(room_id, ReceiptType::Read, user_id())
.await
.unwrap()
.is_some());
assert!(store
.get_event_room_receipt_events(room_id, ReceiptType::Read, &first_event_id)
.await
.unwrap()
.is_empty());
assert_eq!(
store
.get_event_room_receipt_events(room_id, ReceiptType::Read, &second_event_id)
.await
.unwrap()
.len(),
1
);
}
#[async_test]
async fn test_media_content() {
let store = SledStore::open().unwrap();
let uri = mxc_uri!("mxc://localhost/media");
let content: Vec<u8> = "somebinarydata".into();
let request_file =
MediaRequest { media_type: MediaType::Uri(uri.to_owned()), format: MediaFormat::File };
let request_thumbnail = MediaRequest {
media_type: MediaType::Uri(uri.to_owned()),
format: MediaFormat::Thumbnail(MediaThumbnailSize {
method: Method::Crop,
width: uint!(100),
height: uint!(100),
}),
};
assert!(store.get_media_content(&request_file).await.unwrap().is_none());
assert!(store.get_media_content(&request_thumbnail).await.unwrap().is_none());
store.add_media_content(&request_file, content.clone()).await.unwrap();
assert!(store.get_media_content(&request_file).await.unwrap().is_some());
store.remove_media_content(&request_file).await.unwrap();
assert!(store.get_media_content(&request_file).await.unwrap().is_none());
store.add_media_content(&request_file, content.clone()).await.unwrap();
assert!(store.get_media_content(&request_file).await.unwrap().is_some());
store.add_media_content(&request_thumbnail, content.clone()).await.unwrap();
assert!(store.get_media_content(&request_thumbnail).await.unwrap().is_some());
store.remove_media_content_for_uri(uri).await.unwrap();
assert!(store.get_media_content(&request_file).await.unwrap().is_none());
assert!(store.get_media_content(&request_thumbnail).await.unwrap().is_none());
}
#[async_test]
async fn test_custom_storage() -> Result<()> {
let key = "my_key";
let value = &[0, 1, 2, 3];
let store = SledStore::open()?;
store.set_custom_value(key.as_bytes(), value.to_vec()).await?;
let read = store.get_custom_value(key.as_bytes()).await?;
assert_eq!(Some(value.as_ref()), read.as_deref());
Ok(())
}
statestore_integration_tests! { integration }
}