Skip to content

Commit 7267848

Browse files
dragonfly1033Shrey Patel
authored andcommitted
test(sdk): Add integration test for search
1 parent 8cbdb53 commit 7267848

File tree

13 files changed

+401
-370
lines changed

13 files changed

+401
-370
lines changed

crates/matrix-sdk-search/src/error.rs

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,6 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
//! The event cache is an abstraction layer, sitting between the Rust SDK and a
16-
//! final client, that acts as a global observer of all the rooms, gathering and
17-
//! inferring some extra useful information about each room. In particular, this
18-
//! doesn't require subscribing to a specific room to get access to this
19-
//! information.
20-
//!
21-
//! It's intended to be fast, robust and easy to maintain, having learned from
22-
//! previous endeavours at implementing middle to high level features elsewhere
23-
//! in the SDK, notably in the UI's Timeline object.
24-
//!
25-
//! See the [github issue](https://github.com/matrix-org/matrix-rust-sdk/issues/3058) for more
26-
//! details about the historical reasons that led us to start writing this.
27-
2815
use tantivy::{
2916
directory::error::OpenDirectoryError as TantivyOpenDirectoryError,
3017
query::QueryParserError as TantivyQueryParserError,

crates/matrix-sdk-search/src/index.rs

Lines changed: 30 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,9 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
//! The event cache is an abstraction layer, sitting between the Rust SDK and a
16-
//! final client, that acts as a global observer of all the rooms, gathering and
17-
//! inferring some extra useful information about each room. In particular, this
18-
//! doesn't require subscribing to a specific room to get access to this
19-
//! information.
20-
//!
21-
//! It's intended to be fast, robust and easy to maintain, having learned from
22-
//! previous endeavours at implementing middle to high level features elsewhere
23-
//! in the SDK, notably in the UI's Timeline object.
24-
//!
25-
//! See the [github issue](https://github.com/matrix-org/matrix-rust-sdk/issues/3058) for more
26-
//! details about the historical reasons that led us to start writing this.
27-
2815
use std::{fmt, fs, path::Path, sync::Arc};
2916

30-
use ruma::{OwnedEventId, OwnedRoomId, RoomId, events::AnyMessageLikeEvent};
17+
use ruma::{OwnedEventId, OwnedRoomId, RoomId, events::AnySyncMessageLikeEvent};
3118
use tantivy::{
3219
Index, IndexReader, TantivyDocument,
3320
collector::TopDocs,
@@ -44,6 +31,11 @@ use crate::{
4431
writer::SearchIndexWriter,
4532
};
4633

34+
/// A struct to represent the operations on a [`RoomIndex`]
35+
pub(crate) enum RoomIndexOperation {
36+
Add(TantivyDocument),
37+
}
38+
4739
/// A struct that holds all data pertaining to a particular room's
4840
/// message index.
4941
pub struct RoomIndex {
@@ -91,9 +83,9 @@ impl RoomIndex {
9183
RoomIndex::new_with(index, schema, room_id)
9284
}
9385

94-
/// Create new [`RoomIndex`] which stores the index in RAM.
86+
/// Create new [`RoomIndex`] which stores the index in memory.
9587
/// Intended for testing.
96-
pub fn new_in_ram(room_id: &RoomId) -> Result<RoomIndex, IndexError> {
88+
pub fn new_in_memory(room_id: &RoomId) -> Result<RoomIndex, IndexError> {
9789
let schema = RoomMessageSchema::new();
9890
let index = Index::create_in_ram(schema.as_tantivy_schema());
9991
RoomIndex::new_with(index, schema, room_id)
@@ -130,10 +122,14 @@ impl RoomIndex {
130122
RoomIndex::new_with(index, schema, room_id)
131123
}
132124

133-
/// Add [`AnyMessageLikeEvent`] to [`RoomIndex`]
134-
pub fn add_event(&mut self, event: AnyMessageLikeEvent) -> Result<(), IndexError> {
135-
let doc = self.schema.make_doc(event)?;
136-
self.writer.add_document(doc)?; // TODO: This is blocking. Handle it.
125+
/// Handle [`AnySyncMessageLikeEvent`]
126+
///
127+
/// This which will add/remove/edit an event in the index based on the
128+
/// event type.
129+
pub fn handle_event(&mut self, event: AnySyncMessageLikeEvent) -> Result<(), IndexError> {
130+
match self.schema.handle_event(event)? {
131+
RoomIndexOperation::Add(document) => self.writer.add_document(document)?,
132+
};
137133
Ok(())
138134
}
139135

@@ -198,64 +194,64 @@ mod tests {
198194
use crate::index::RoomIndex;
199195

200196
#[test]
201-
fn test_make_index_in_ram() {
197+
fn test_make_index_in_memory() {
202198
let room_id = room_id!("!room_id:localhost");
203-
let index = RoomIndex::new_in_ram(room_id);
199+
let index = RoomIndex::new_in_memory(room_id);
204200

205201
index.expect("failed to make index in ram: {index:?}");
206202
}
207203

208204
#[test]
209-
fn test_add_event() {
205+
fn test_handle_event() {
210206
let room_id = room_id!("!room_id:localhost");
211207
let mut index =
212-
RoomIndex::new_in_ram(room_id).expect("failed to make index in ram: {index:?}");
208+
RoomIndex::new_in_memory(room_id).expect("failed to make index in ram: {index:?}");
213209

214210
let event = EventFactory::new()
215211
.text_msg("event message")
216212
.event_id(event_id!("$event_id:localhost"))
217213
.room(room_id)
218214
.sender(user_id!("@user_id:localhost"))
219-
.into_any_message_like_event();
215+
.into_any_sync_message_like_event();
220216

221-
index.add_event(event).expect("failed to add event: {res:?}");
217+
index.handle_event(event).expect("failed to add event: {res:?}");
222218
}
223219

224220
#[test]
225221
fn test_search_populated_index() -> Result<(), Box<dyn Error>> {
226222
let room_id = room_id!("!room_id:localhost");
227223
let mut index =
228-
RoomIndex::new_in_ram(room_id).expect("failed to make index in ram: {index:?}");
224+
RoomIndex::new_in_memory(room_id).expect("failed to make index in ram: {index:?}");
229225

230226
let event_id_1 = event_id!("$event_id_1:localhost");
231227
let event_id_2 = event_id!("$event_id_2:localhost");
232228
let event_id_3 = event_id!("$event_id_3:localhost");
233229

234-
index.add_event(
230+
index.handle_event(
235231
EventFactory::new()
236232
.text_msg("This is a sentence")
237233
.event_id(event_id_1)
238234
.room(room_id)
239235
.sender(user_id!("@user_id:localhost"))
240-
.into_any_message_like_event(),
236+
.into_any_sync_message_like_event(),
241237
)?;
242238

243-
index.add_event(
239+
index.handle_event(
244240
EventFactory::new()
245241
.text_msg("All new words")
246242
.event_id(event_id_2)
247243
.room(room_id)
248244
.sender(user_id!("@user_id:localhost"))
249-
.into_any_message_like_event(),
245+
.into_any_sync_message_like_event(),
250246
)?;
251247

252-
index.add_event(
248+
index.handle_event(
253249
EventFactory::new()
254250
.text_msg("A similar sentence")
255251
.event_id(event_id_3)
256252
.room(room_id)
257253
.sender(user_id!("@user_id:localhost"))
258-
.into_any_message_like_event(),
254+
.into_any_sync_message_like_event(),
259255
)?;
260256

261257
index.commit_and_reload()?;
@@ -275,7 +271,7 @@ mod tests {
275271
fn test_search_empty_index() -> Result<(), Box<dyn Error>> {
276272
let room_id = room_id!("!room_id:localhost");
277273
let mut index =
278-
RoomIndex::new_in_ram(room_id).expect("failed to make index in ram: {index:?}");
274+
RoomIndex::new_in_memory(room_id).expect("failed to make index in ram: {index:?}");
279275

280276
index.commit_and_reload()?;
281277

crates/matrix-sdk-search/src/schema.rs

Lines changed: 47 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -12,39 +12,29 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
//! The event cache is an abstraction layer, sitting between the Rust SDK and a
16-
//! final client, that acts as a global observer of all the rooms, gathering and
17-
//! inferring some extra useful information about each room. In particular, this
18-
//! doesn't require subscribing to a specific room to get access to this
19-
//! information.
20-
//!
21-
//! It's intended to be fast, robust and easy to maintain, having learned from
22-
//! previous endeavours at implementing middle to high level features elsewhere
23-
//! in the SDK, notably in the UI's Timeline object.
24-
//!
25-
//! See the [github issue](https://github.com/matrix-org/matrix-rust-sdk/issues/3058) for more
26-
//! details about the historical reasons that led us to start writing this.
27-
28-
use ruma::{
29-
MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedUserId,
30-
events::{
31-
AnyMessageLikeEvent, MessageLikeEvent, MessageLikeEventContent, RedactContent,
32-
RedactedMessageLikeEventContent, room::message::MessageType,
33-
},
15+
use ruma::events::{
16+
AnySyncMessageLikeEvent, MessageLikeEventContent, RedactContent,
17+
RedactedMessageLikeEventContent, SyncMessageLikeEvent, room::message::MessageType,
3418
};
3519
use tantivy::{
3620
DateTime, TantivyDocument, doc,
3721
schema::{DateOptions, DateTimePrecision, Field, INDEXED, STORED, STRING, Schema, TEXT},
3822
};
3923

40-
use crate::error::{IndexError, IndexSchemaError};
24+
use crate::{
25+
error::{IndexError, IndexSchemaError},
26+
index::RoomIndexOperation,
27+
};
4128

4229
pub(crate) trait MatrixSearchIndexSchema {
4330
fn new() -> Self;
4431
fn default_search_fields(&self) -> Vec<Field>;
4532
fn primary_key(&self) -> Field;
4633
fn as_tantivy_schema(&self) -> Schema;
47-
fn make_doc(&self, event: AnyMessageLikeEvent) -> Result<TantivyDocument, IndexError>;
34+
fn handle_event(
35+
&self,
36+
event: AnySyncMessageLikeEvent,
37+
) -> Result<RoomIndexOperation, IndexError>;
4838
}
4939

5040
#[derive(Debug, Clone)]
@@ -58,48 +48,31 @@ pub(crate) struct RoomMessageSchema {
5848
}
5949

6050
impl RoomMessageSchema {
61-
fn parse_event<C: MessageLikeEventContent + RedactContent, F>(
51+
/// Given an [`AnySyncMessageLikeEvent`] and a function to convert the
52+
/// content into a String to be indexed, return a [`TantivyDocument`] to
53+
/// index.
54+
fn make_doc<C: MessageLikeEventContent + RedactContent, F>(
6255
&self,
63-
event: MessageLikeEvent<C>,
64-
get_body: F,
65-
) -> Result<(OwnedEventId, String, MilliSecondsSinceUnixEpoch, OwnedUserId), IndexError>
56+
event: SyncMessageLikeEvent<C>,
57+
get_body_from_content: F,
58+
) -> Result<TantivyDocument, IndexError>
6659
where
6760
<C as RedactContent>::Redacted: RedactedMessageLikeEventContent,
6861
F: FnOnce(&C) -> Result<String, IndexError>,
6962
{
7063
let unredacted = event.as_original().ok_or(IndexError::CannotIndexRedactedMessage)?;
7164

72-
let body = get_body(&unredacted.content)?;
65+
let body = get_body_from_content(&unredacted.content)?;
7366

74-
Ok((
75-
unredacted.event_id.clone(),
76-
body,
77-
unredacted.origin_server_ts,
78-
unredacted.sender.clone(),
67+
Ok(doc!(
68+
self.event_id_field => unredacted.event_id.to_string(),
69+
self.body_field => body,
70+
self.date_field =>
71+
DateTime::from_timestamp_millis(
72+
unredacted.origin_server_ts.get().into()),
73+
self.sender_field => unredacted.sender.to_string(),
7974
))
8075
}
81-
82-
fn parse_any_event(
83-
&self,
84-
event: AnyMessageLikeEvent,
85-
) -> Result<(OwnedEventId, String, MilliSecondsSinceUnixEpoch, OwnedUserId), IndexError> {
86-
match event {
87-
// old m.room.message behaviour
88-
AnyMessageLikeEvent::RoomMessage(event) => {
89-
self.parse_event(event, |content| match &content.msgtype {
90-
MessageType::Text(content) => Ok(content.body.clone()),
91-
_ => Err(IndexError::MessageTypeNotSupported),
92-
})
93-
}
94-
95-
// new m.message behaviour
96-
AnyMessageLikeEvent::Message(event) => self.parse_event(event, |content| {
97-
content.text.find_plain().ok_or(IndexError::EmptyMessage).map(|v| v.to_owned())
98-
}),
99-
100-
_ => Err(IndexError::MessageTypeNotSupported),
101-
}
102-
}
10376
}
10477

10578
impl MatrixSearchIndexSchema for RoomMessageSchema {
@@ -140,17 +113,28 @@ impl MatrixSearchIndexSchema for RoomMessageSchema {
140113
self.inner.clone()
141114
}
142115

143-
fn make_doc(&self, event: AnyMessageLikeEvent) -> Result<TantivyDocument, IndexError> {
144-
let (event_id, body, timestamp, sender) = self.parse_any_event(event)?;
116+
fn handle_event(
117+
&self,
118+
event: AnySyncMessageLikeEvent,
119+
) -> Result<RoomIndexOperation, IndexError> {
120+
match event {
121+
// m.room.message behaviour
122+
AnySyncMessageLikeEvent::RoomMessage(event) => self
123+
.make_doc(event, |content| match &content.msgtype {
124+
MessageType::Text(content) => Ok(content.body.clone()),
125+
_ => Err(IndexError::MessageTypeNotSupported),
126+
})
127+
.map(RoomIndexOperation::Add),
145128

146-
Ok(doc!(
147-
self.event_id_field => event_id.to_string(),
148-
self.body_field => body,
149-
self.date_field =>
150-
DateTime::from_timestamp_millis(
151-
timestamp.get().into()),
152-
self.sender_field => sender.to_string(),
153-
))
129+
// new MSC-1767 m.message behaviour
130+
AnySyncMessageLikeEvent::Message(event) => self
131+
.make_doc(event, |content| {
132+
content.text.find_plain().ok_or(IndexError::EmptyMessage).map(|v| v.to_owned())
133+
})
134+
.map(RoomIndexOperation::Add),
135+
136+
_ => Err(IndexError::MessageTypeNotSupported),
137+
}
154138
}
155139
}
156140

crates/matrix-sdk-search/src/writer.rs

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,6 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
//! The event cache is an abstraction layer, sitting between the Rust SDK and a
16-
//! final client, that acts as a global observer of all the rooms, gathering and
17-
//! inferring some extra useful information about each room. In particular, this
18-
//! doesn't require subscribing to a specific room to get access to this
19-
//! information.
20-
//!
21-
//! It's intended to be fast, robust and easy to maintain, having learned from
22-
//! previous endeavours at implementing middle to high level features elsewhere
23-
//! in the SDK, notably in the UI's Timeline object.
24-
//!
25-
//! See the [github issue](https://github.com/matrix-org/matrix-rust-sdk/issues/3058) for more
26-
//! details about the historical reasons that led us to start writing this.
27-
2815
use tantivy::{IndexWriter, TantivyDocument, TantivyError};
2916

3017
use crate::{OpStamp, error::IndexError};

crates/matrix-sdk/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,9 @@ matrix-sdk-base.workspace = true
9292
matrix-sdk-common.workspace = true
9393
matrix-sdk-ffi-macros = { workspace = true, optional = true }
9494
matrix-sdk-indexeddb = { workspace = true, optional = true }
95+
matrix-sdk-search = { workspace = true, optional = true }
9596
matrix-sdk-sqlite = { workspace = true, optional = true }
9697
matrix-sdk-test = { workspace = true, optional = true }
97-
matrix-sdk-search = { workspace = true, optional = true }
9898
mime.workspace = true
9999
mime2ext = "0.1.53"
100100
oauth2.workspace = true

0 commit comments

Comments
 (0)