atagen

macltok

public
Star0
Watch0
6ed8c0ef3a2a5cab4ea62b9694d6b5fa2c60f3df
3
ssh://brewery@pls.lobotomise.me:33/atagen/macltok.git
tests/state.rsRust235 lines8.0 KB
1
mod support;
2
3
use std::time::Duration;
4
5
use macltok::{
6
    ConnectionState, Engine, EngineConfig, EngineError, Event, PackUsage, Retain, RoomMembership,
7
    Termination,
8
};
9
use matrix_sdk::{
10
    ruma::{api::client::sync::sync_events::v5, events::AnySyncStateEvent, room_id, serde::Raw},
11
    test_utils::mocks::MatrixMockServer,
12
};
13
use matrix_sdk_test::JoinedRoomBuilder;
14
use serde_json::json;
15
use tokio::sync::watch;
16
17
#[tokio::test]
18
async fn rooms_changed_invalidates_room_summaries() {
19
    let server = MatrixMockServer::new().await;
20
    server
21
        .mock_sliding_sync()
22
        .ok(v5::Response::new("1".to_owned()))
23
        .mount()
24
        .await;
25
    let client = server.client_builder().build().await;
26
    let room_id = room_id!("!state:localhost");
27
    server.mock_room_state_encryption().plain().mount().await;
28
    server.sync_joined_room(&client, room_id).await;
29
    let config = EngineConfig::default().with_initial_history_limit(0);
30
    let (engine, handle, mut events) = Engine::from_client(client, config).await.unwrap();
31
    let running = tokio::spawn(engine.run());
32
33
    support::receive_until(&mut events, |event| matches!(event, Event::RoomsChanged)).await;
34
    let rooms = handle.rooms().await;
35
    let summary = rooms
36
        .iter()
37
        .find(|summary| summary.room_id == room_id)
38
        .expect("synced room was absent from the room summaries");
39
    assert_eq!(summary.membership, RoomMembership::Joined);
40
    assert!(!summary.name.is_empty());
41
42
    support::shut_down(&handle, &mut events, running).await;
43
}
44
45
#[tokio::test]
46
async fn connection_watch_tracks_the_engine_lifecycle() {
47
    let server = MatrixMockServer::new().await;
48
    server
49
        .mock_sliding_sync()
50
        .ok(v5::Response::new("1".to_owned()))
51
        .mount()
52
        .await;
53
    let client = server.client_builder().build().await;
54
    let config = EngineConfig::default().with_initial_history_limit(0);
55
    let (engine, handle, mut events) = Engine::from_client(client, config).await.unwrap();
56
    let mut connection = handle.connection_state();
57
    let connection_peer = connection.clone();
58
    assert_eq!(*connection.borrow(), ConnectionState::Idle);
59
    assert_eq!(*connection_peer.borrow(), ConnectionState::Idle);
60
61
    let running = tokio::spawn(engine.run());
62
    support::receive_until(&mut events, |event| {
63
        matches!(event, Event::ConnectionChanged(ConnectionState::Connecting))
64
    })
65
    .await;
66
    assert_ne!(*connection.borrow(), ConnectionState::Idle);
67
    support::receive_until(&mut events, |event| {
68
        matches!(event, Event::ConnectionChanged(ConnectionState::Online))
69
    })
70
    .await;
71
    wait_for_connection(&mut connection, ConnectionState::Online).await;
72
    assert_eq!(*connection_peer.borrow(), ConnectionState::Online);
73
74
    support::shut_down(&handle, &mut events, running).await;
75
    wait_for_connection(&mut connection, ConnectionState::Stopped).await;
76
    assert_eq!(*connection_peer.borrow(), ConnectionState::Stopped);
77
}
78
79
#[tokio::test]
80
async fn soft_logout_says_so_and_stops_the_engine() {
81
    let server = MatrixMockServer::new().await;
82
    server
83
        .mock_sliding_sync()
84
        .error_unknown_token(true)
85
        .mount()
86
        .await;
87
    let client = server.client_builder().build().await;
88
    let (engine, _handle, mut events) = Engine::from_client(
89
        client,
90
        EngineConfig::default().with_initial_history_limit(0),
91
    )
92
    .await
93
    .unwrap();
94
    let running = tokio::spawn(engine.run());
95
    support::receive_until(&mut events, |event| {
96
        matches!(
97
            event,
98
            Event::SessionAccessRejected {
99
                soft_logout: Some(_)
100
            }
101
        )
102
    })
103
    .await;
104
    support::receive_until(&mut events, |event| matches!(event, Event::Stopped)).await;
105
    let termination = running.await.unwrap().unwrap();
106
    assert!(matches!(termination, Termination::SoftLoggedOut { .. }));
107
    assert_eq!(termination.retain(), Retain::Store);
108
}
109
110
#[tokio::test]
111
async fn closing_the_event_stream_stops_an_idle_engine() {
112
    let server = MatrixMockServer::new().await;
113
    server
114
        .mock_sliding_sync()
115
        .ok(v5::Response::new("1".to_owned()))
116
        .mount()
117
        .await;
118
    let client = server.client_builder().build().await;
119
    let (engine, handle, mut events) = Engine::from_client(
120
        client,
121
        EngineConfig::default().with_initial_history_limit(0),
122
    )
123
    .await
124
    .unwrap();
125
    let running = tokio::spawn(engine.run());
126
    support::receive_until(&mut events, |event| {
127
        matches!(event, Event::ConnectionChanged(ConnectionState::Online))
128
    })
129
    .await;
130
    drop(events);
131
    let result = tokio::time::timeout(Duration::from_secs(2), running)
132
        .await
133
        .expect("engine did not stop after its event receiver closed")
134
        .unwrap();
135
    assert!(matches!(result, Err(EngineError::EventReceiverClosed)));
136
    drop(handle);
137
}
138
139
async fn wait_for_connection(
140
    connection: &mut watch::Receiver<ConnectionState>,
141
    expected: ConnectionState,
142
) {
143
    tokio::time::timeout(Duration::from_secs(2), async {
144
        loop {
145
            if *connection.borrow_and_update() == expected {
146
                return;
147
            }
148
            connection
149
                .changed()
150
                .await
151
                .expect("connection watch closed before the expected state");
152
        }
153
    })
154
    .await
155
    .expect("expected connection state did not arrive");
156
}
157
158
#[tokio::test]
159
async fn image_packs_follow_room_state_and_account_data() {
160
    let server = MatrixMockServer::new().await;
161
    server
162
        .mock_sliding_sync()
163
        .ok(v5::Response::new("1".to_owned()))
164
        .mount()
165
        .await;
166
    let client = server.client_builder().build().await;
167
    let room_id = room_id!("!packs:localhost");
168
    server.mock_room_state_encryption().plain().mount().await;
169
    server.sync_joined_room(&client, room_id).await;
170
    let config = EngineConfig::default().with_initial_history_limit(0);
171
    let (engine, handle, mut events) = Engine::from_client(client.clone(), config).await.unwrap();
172
    let running = tokio::spawn(engine.run());
173
174
    let pack: Raw<AnySyncStateEvent> = serde_json::from_value(json!({
175
        "type": "im.ponies.room_emotes",
176
        "state_key": "cats",
177
        "event_id": "$pack",
178
        "sender": "@example:localhost",
179
        "origin_server_ts": 1,
180
        "content": {
181
            "pack": { "display_name": "cats", "usage": ["emoticon"] },
182
            "images": {
183
                "blep": { "url": "mxc://localhost/blep" },
184
                "broken": { "url": "not an mxc" },
185
                "sticker": { "url": "mxc://localhost/sticker", "usage": ["sticker"] },
186
            },
187
        },
188
    }))
189
    .unwrap();
190
    server
191
        .mock_sync()
192
        .ok_and_run(&client, |builder| {
193
            builder.add_joined_room(JoinedRoomBuilder::new(room_id).add_state_event(pack));
194
            builder.add_custom_global_account_data(json!({
195
                "type": "im.ponies.emote_rooms",
196
                "content": { "rooms": { "!packs:localhost": { "cats": {} } } },
197
            }));
198
        })
199
        .await;
200
    support::receive_until(&mut events, |event| {
201
        matches!(event, Event::ImagePacksChanged)
202
    })
203
    .await;
204
205
    let packs = handle.image_packs().await.unwrap();
206
    let offered = packs.for_room(Some(room_id));
207
    assert_eq!(offered.len(), 1, "an enabled room's pack was offered twice");
208
    let pack = offered[0];
209
    assert_eq!(pack.id, "room:!packs:localhost:cats");
210
    assert_eq!(packs.global, vec![pack.clone()]);
211
    let images: Vec<_> = pack
212
        .images
213
        .iter()
214
        .map(|image| {
215
            (
216
                image.shortcode.as_str(),
217
                image.reaction_key.as_str(),
218
                image.usage.clone(),
219
            )
220
        })
221
        .collect();
222
    assert_eq!(
223
        images,
224
        [
225
            ("blep", "mxc://localhost/blep", vec![PackUsage::Emoticon]),
226
            (
227
                "sticker",
228
                "mxc://localhost/sticker",
229
                vec![PackUsage::Sticker]
230
            ),
231
        ]
232
    );
233
234
    support::shut_down(&handle, &mut events, running).await;
235
}