atagen

macltok

public
Star0
Watch0
743123167e2946d124e2863611dea27dfa887e7d
3
ssh://brewery@pls.lobotomise.me:33/atagen/macltok.git
src/search/feed_tests.rsRust252 lines7.2 KB
1
use serde_json::json;
2
3
use super::*;
4
use crate::search::index::{KeywordIndex, provisional_key};
5
6
const ROOM: &str = "!room:x";
7
8
fn message(id: &str, sender: &str, ts: u64, body: &str) -> Value {
9
    json!({
10
        "type": "m.room.message",
11
        "event_id": id,
12
        "sender": sender,
13
        "origin_server_ts": ts,
14
        "content": { "msgtype": "m.text", "body": body },
15
    })
16
}
17
18
fn edit(id: &str, sender: &str, ts: u64, target: &str, body: &str) -> Value {
19
    json!({
20
        "type": "m.room.message",
21
        "event_id": id,
22
        "sender": sender,
23
        "origin_server_ts": ts,
24
        "content": {
25
            "msgtype": "m.text",
26
            "body": format!("* {body}"),
27
            "m.new_content": { "msgtype": "m.text", "body": body },
28
            "m.relates_to": { "rel_type": "m.replace", "event_id": target },
29
        },
30
    })
31
}
32
33
fn redaction(id: &str, target: &str) -> Value {
34
    json!({
35
        "type": "m.room.redaction",
36
        "event_id": id,
37
        "sender": "@a:x",
38
        "origin_server_ts": 99,
39
        "redacts": target,
40
        "content": {},
41
    })
42
}
43
44
fn feed(index: &mut KeywordIndex, redactions: &mut Redactions, value: Value) -> Effect {
45
    apply(index, redactions, ROOM, observe(&value))
46
}
47
48
fn keys(index: &mut KeywordIndex, query: &str) -> Vec<String> {
49
    let (hits, _) = index.search(query, None, None, 10).unwrap();
50
    hits.into_iter().map(|hit| hit.key).collect()
51
}
52
53
/// backfill walks newest first, so an edit routinely lands before what it edits
54
#[test]
55
fn an_edit_before_its_original_keeps_the_edit_and_takes_the_original_timestamp() {
56
    let mut index = KeywordIndex::new(false);
57
    let mut redactions = Redactions::default();
58
    feed(
59
        &mut index,
60
        &mut redactions,
61
        edit("$e", "@a:x", 20, "$o", "fixed words"),
62
    );
63
    let provisional = index.get(&provisional_key("$o", "@a:x")).unwrap();
64
    assert!(provisional.provisional);
65
    assert_eq!(provisional.ts, 20);
66
    assert!(keys(&mut index, "fixed").is_empty());
67
    feed(
68
        &mut index,
69
        &mut redactions,
70
        message("$o", "@a:x", 10, "typo wrds"),
71
    );
72
    let doc = index.get("$o").unwrap();
73
    assert!(!doc.provisional);
74
    assert_eq!((doc.ts, doc.content.as_str()), (10, "$e"));
75
    assert_eq!(keys(&mut index, "fixed"), vec!["$o"]);
76
    assert!(keys(&mut index, "wrds").is_empty());
77
}
78
79
#[test]
80
fn edits_from_someone_else_and_older_edits_lose() {
81
    let mut index = KeywordIndex::new(false);
82
    let mut redactions = Redactions::default();
83
    feed(
84
        &mut index,
85
        &mut redactions,
86
        message("$o", "@a:x", 10, "original"),
87
    );
88
    feed(
89
        &mut index,
90
        &mut redactions,
91
        edit("$e2", "@a:x", 30, "$o", "newest"),
92
    );
93
    assert_eq!(
94
        feed(
95
            &mut index,
96
            &mut redactions,
97
            edit("$e1", "@a:x", 20, "$o", "older")
98
        ),
99
        Effect::Nothing
100
    );
101
    assert_eq!(
102
        feed(
103
            &mut index,
104
            &mut redactions,
105
            edit("$h", "@b:x", 40, "$o", "hijack")
106
        ),
107
        Effect::Nothing
108
    );
109
    assert_eq!(keys(&mut index, "newest"), vec!["$o"]);
110
    assert!(keys(&mut index, "hijack").is_empty());
111
    assert!(keys(&mut index, "original").is_empty());
112
}
113
114
#[test]
115
fn a_provisional_edit_from_someone_else_gives_way_to_the_original() {
116
    let mut index = KeywordIndex::new(false);
117
    let mut redactions = Redactions::default();
118
    feed(
119
        &mut index,
120
        &mut redactions,
121
        edit("$h", "@b:x", 20, "$o", "hijack"),
122
    );
123
    feed(
124
        &mut index,
125
        &mut redactions,
126
        message("$o", "@a:x", 10, "genuine"),
127
    );
128
    assert_eq!(keys(&mut index, "genuine"), vec!["$o"]);
129
    assert!(keys(&mut index, "hijack").is_empty());
130
}
131
132
#[test]
133
fn a_redaction_removes_the_message_and_a_stale_copy_cannot_bring_it_back() {
134
    let mut index = KeywordIndex::new(false);
135
    let mut redactions = Redactions::default();
136
    feed(
137
        &mut index,
138
        &mut redactions,
139
        message("$o", "@a:x", 10, "secret"),
140
    );
141
    assert_eq!(
142
        feed(&mut index, &mut redactions, redaction("$r", "$o")),
143
        Effect::Removed
144
    );
145
    feed(
146
        &mut index,
147
        &mut redactions,
148
        message("$o", "@a:x", 10, "secret"),
149
    );
150
    assert!(keys(&mut index, "secret").is_empty());
151
}
152
153
#[test]
154
fn redacting_the_latest_edit_asks_for_the_original_again() {
155
    let mut index = KeywordIndex::new(false);
156
    let mut redactions = Redactions::default();
157
    feed(
158
        &mut index,
159
        &mut redactions,
160
        message("$o", "@a:x", 10, "first"),
161
    );
162
    feed(
163
        &mut index,
164
        &mut redactions,
165
        edit("$e", "@a:x", 20, "$o", "second"),
166
    );
167
    assert_eq!(
168
        feed(&mut index, &mut redactions, redaction("$r", "$e")),
169
        Effect::Refetch("$o".to_owned())
170
    );
171
    let mut original = message("$o", "@a:x", 10, "first");
172
    original["unsigned"] =
173
        json!({ "m.relations": { "m.replace": edit("$e", "@a:x", 20, "$o", "second") } });
174
    feed(&mut index, &mut redactions, original);
175
    assert_eq!(keys(&mut index, "first"), vec!["$o"]);
176
    assert!(keys(&mut index, "second").is_empty());
177
}
178
179
#[test]
180
fn reply_fallbacks_are_not_indexed() {
181
    let mut index = KeywordIndex::new(false);
182
    let mut redactions = Redactions::default();
183
    let mut reply = message("$r", "@a:x", 10, "> <@b:x> quoted stuff\n\nactual answer");
184
    reply["content"]["m.relates_to"] = json!({ "m.in_reply_to": { "event_id": "$q" } });
185
    feed(&mut index, &mut redactions, reply);
186
    assert_eq!(keys(&mut index, "answer"), vec!["$r"]);
187
    assert!(keys(&mut index, "quoted").is_empty());
188
}
189
190
#[test]
191
fn a_strangers_early_edit_cannot_shut_out_the_author() {
192
    let mut index = KeywordIndex::new(false);
193
    let mut redactions = Redactions::default();
194
    feed(
195
        &mut index,
196
        &mut redactions,
197
        edit("$h", "@b:x", 30, "$o", "hijack"),
198
    );
199
    feed(
200
        &mut index,
201
        &mut redactions,
202
        edit("$e", "@a:x", 20, "$o", "genuine edit"),
203
    );
204
    feed(
205
        &mut index,
206
        &mut redactions,
207
        message("$o", "@a:x", 10, "original"),
208
    );
209
    assert_eq!(keys(&mut index, "genuine"), vec!["$o"]);
210
    assert!(keys(&mut index, "hijack").is_empty());
211
    assert!(index.get(&provisional_key("$o", "@b:x")).is_none());
212
}
213
214
#[test]
215
fn an_edit_of_an_edit_is_ignored() {
216
    let mut index = KeywordIndex::new(false);
217
    let mut redactions = Redactions::default();
218
    feed(
219
        &mut index,
220
        &mut redactions,
221
        message("$o", "@a:x", 10, "original"),
222
    );
223
    feed(
224
        &mut index,
225
        &mut redactions,
226
        edit("$e", "@a:x", 20, "$o", "first"),
227
    );
228
    assert_eq!(
229
        feed(
230
            &mut index,
231
            &mut redactions,
232
            edit("$ee", "@a:x", 30, "$e", "nested")
233
        ),
234
        Effect::Nothing
235
    );
236
    assert!(index.get(&provisional_key("$e", "@a:x")).is_none());
237
}
238
239
#[test]
240
fn an_edit_to_unreadable_content_clears_the_old_text() {
241
    let mut index = KeywordIndex::new(false);
242
    let mut redactions = Redactions::default();
243
    feed(
244
        &mut index,
245
        &mut redactions,
246
        message("$o", "@a:x", 10, "secret plans"),
247
    );
248
    let mut blank = edit("$e", "@a:x", 20, "$o", "x");
249
    blank["content"]["m.new_content"] = json!({ "msgtype": "m.unknown" });
250
    feed(&mut index, &mut redactions, blank);
251
    assert!(keys(&mut index, "secret").is_empty());
252
}