atagen

macltok

public
Star0
Watch0
fa9114fcf75f7bdf1a7cec3b3367d604cf7de472
3
ssh://brewery@pls.lobotomise.me:33/atagen/macltok.git
tests/state.rsRust171 lines5.7 KB
1
use std::time::Duration;
2
3
use macltok::{
4
    Command, ConnectionState, Engine, EngineConfig, EngineError, Event, LifecycleCommand,
5
    RoomMembership,
6
};
7
use matrix_sdk::{
8
    ruma::{api::client::sync::sync_events::v5, room_id},
9
    test_utils::mocks::MatrixMockServer,
10
};
11
use tokio::sync::watch;
12
13
#[tokio::test]
14
async fn rooms_changed_invalidates_room_summaries() {
15
    let server = MatrixMockServer::new().await;
16
    server
17
        .mock_sliding_sync()
18
        .ok(v5::Response::new("1".to_owned()))
19
        .mount()
20
        .await;
21
    let client = server.client_builder().build().await;
22
    let room_id = room_id!("!state:localhost");
23
    server.mock_room_state_encryption().plain().mount().await;
24
    server.sync_joined_room(&client, room_id).await;
25
    let config = EngineConfig::default().with_initial_history_limit(0);
26
    let (engine, handle, mut events) = Engine::from_client(client, config).await.unwrap();
27
    let running = tokio::spawn(engine.run());
28
29
    receive_until(&mut events, |event| matches!(event, Event::RoomsChanged)).await;
30
    let rooms = handle.rooms().await;
31
    let summary = rooms
32
        .iter()
33
        .find(|summary| summary.room_id == room_id)
34
        .expect("synced room was absent from the room summaries");
35
    assert_eq!(summary.membership, RoomMembership::Joined);
36
    assert!(!summary.name.is_empty());
37
38
    handle
39
        .send(Command::Lifecycle(LifecycleCommand::Shutdown))
40
        .await
41
        .unwrap();
42
    receive_until(&mut events, |event| matches!(event, Event::Stopped)).await;
43
    running.await.unwrap().unwrap();
44
}
45
46
#[tokio::test]
47
async fn connection_watch_tracks_the_engine_lifecycle() {
48
    let server = MatrixMockServer::new().await;
49
    server
50
        .mock_sliding_sync()
51
        .ok(v5::Response::new("1".to_owned()))
52
        .mount()
53
        .await;
54
    let client = server.client_builder().build().await;
55
    let config = EngineConfig::default().with_initial_history_limit(0);
56
    let (engine, handle, mut events) = Engine::from_client(client, config).await.unwrap();
57
    let mut connection = handle.connection_state();
58
    let connection_peer = connection.clone();
59
    assert_eq!(*connection.borrow(), ConnectionState::Idle);
60
    assert_eq!(*connection_peer.borrow(), ConnectionState::Idle);
61
62
    let running = tokio::spawn(engine.run());
63
    receive_until(&mut events, |event| {
64
        matches!(event, Event::ConnectionChanged(ConnectionState::Connecting))
65
    })
66
    .await;
67
    assert_ne!(*connection.borrow(), ConnectionState::Idle);
68
    receive_until(&mut events, |event| {
69
        matches!(event, Event::ConnectionChanged(ConnectionState::Online))
70
    })
71
    .await;
72
    wait_for_connection(&mut connection, ConnectionState::Online).await;
73
    assert_eq!(*connection_peer.borrow(), ConnectionState::Online);
74
75
    handle
76
        .send(Command::Lifecycle(LifecycleCommand::Shutdown))
77
        .await
78
        .unwrap();
79
    receive_until(&mut events, |event| matches!(event, Event::Stopped)).await;
80
    running.await.unwrap().unwrap();
81
    wait_for_connection(&mut connection, ConnectionState::Stopped).await;
82
    assert_eq!(*connection_peer.borrow(), ConnectionState::Stopped);
83
}
84
85
#[tokio::test]
86
async fn soft_logout_says_so_and_stops_the_engine() {
87
    let server = MatrixMockServer::new().await;
88
    server
89
        .mock_sliding_sync()
90
        .error_unknown_token(true)
91
        .mount()
92
        .await;
93
    let client = server.client_builder().build().await;
94
    let (engine, _handle, mut events) = Engine::from_client(
95
        client,
96
        EngineConfig::default().with_initial_history_limit(0),
97
    )
98
    .await
99
    .unwrap();
100
    let running = tokio::spawn(engine.run());
101
    receive_until(&mut events, |event| {
102
        matches!(event, Event::SessionAccessRejected { soft_logout: true })
103
    })
104
    .await;
105
    receive_until(&mut events, |event| matches!(event, Event::Stopped)).await;
106
    running.await.unwrap().unwrap();
107
}
108
109
#[tokio::test]
110
async fn closing_the_event_stream_stops_an_idle_engine() {
111
    let server = MatrixMockServer::new().await;
112
    server
113
        .mock_sliding_sync()
114
        .ok(v5::Response::new("1".to_owned()))
115
        .mount()
116
        .await;
117
    let client = server.client_builder().build().await;
118
    let (engine, handle, mut events) = Engine::from_client(
119
        client,
120
        EngineConfig::default().with_initial_history_limit(0),
121
    )
122
    .await
123
    .unwrap();
124
    let running = tokio::spawn(engine.run());
125
    receive_until(&mut events, |event| {
126
        matches!(event, Event::ConnectionChanged(ConnectionState::Online))
127
    })
128
    .await;
129
    drop(events);
130
    let result = tokio::time::timeout(Duration::from_secs(2), running)
131
        .await
132
        .expect("engine did not stop after its event receiver closed")
133
        .unwrap();
134
    assert!(matches!(result, Err(EngineError::EventReceiverClosed)));
135
    drop(handle);
136
}
137
138
async fn wait_for_connection(
139
    connection: &mut watch::Receiver<ConnectionState>,
140
    expected: ConnectionState,
141
) {
142
    tokio::time::timeout(Duration::from_secs(2), async {
143
        loop {
144
            if *connection.borrow_and_update() == expected {
145
                return;
146
            }
147
            connection
148
                .changed()
149
                .await
150
                .expect("connection watch closed before the expected state");
151
        }
152
    })
153
    .await
154
    .expect("expected connection state did not arrive");
155
}
156
157
async fn receive_until(
158
    events: &mut macltok::EventStream,
159
    predicate: impl Fn(&Event) -> bool,
160
) -> Event {
161
    tokio::time::timeout(Duration::from_secs(2), async {
162
        while let Some(event) = events.recv().await {
163
            if predicate(&event) {
164
                return event;
165
            }
166
        }
167
        panic!("event stream closed before the expected event");
168
    })
169
    .await
170
    .expect("expected event did not arrive")
171
}