1use super::*;
2use crate::test_both_dbs;
3use language::proto::{self, serialize_version};
4use text::Buffer;
5
6test_both_dbs!(
7 test_channel_buffers,
8 test_channel_buffers_postgres,
9 test_channel_buffers_sqlite
10);
11
12async fn test_channel_buffers(db: &Arc<Database>) {
13 let a_id = db
14 .create_user(
15 "user_a@example.com",
16 None,
17 false,
18 NewUserParams {
19 github_login: "user_a".into(),
20 github_user_id: 101,
21 },
22 )
23 .await
24 .unwrap()
25 .user_id;
26 let b_id = db
27 .create_user(
28 "user_b@example.com",
29 None,
30 false,
31 NewUserParams {
32 github_login: "user_b".into(),
33 github_user_id: 102,
34 },
35 )
36 .await
37 .unwrap()
38 .user_id;
39
40 // This user will not be a part of the channel
41 let c_id = db
42 .create_user(
43 "user_c@example.com",
44 None,
45 false,
46 NewUserParams {
47 github_login: "user_c".into(),
48 github_user_id: 103,
49 },
50 )
51 .await
52 .unwrap()
53 .user_id;
54
55 let owner_id = db.create_server("production").await.unwrap().0 as u32;
56
57 let zed_id = db.create_root_channel("zed", a_id).await.unwrap();
58
59 db.invite_channel_member(zed_id, b_id, a_id, ChannelRole::Member)
60 .await
61 .unwrap();
62
63 db.respond_to_channel_invite(zed_id, b_id, true)
64 .await
65 .unwrap();
66
67 let connection_id_a = ConnectionId { owner_id, id: 1 };
68 let _ = db
69 .join_channel_buffer(zed_id, a_id, connection_id_a)
70 .await
71 .unwrap();
72
73 let mut buffer_a = Buffer::new(0, text::BufferId::new(1).unwrap(), "".to_string());
74 let operations = vec![
75 buffer_a.edit([(0..0, "hello world")]),
76 buffer_a.edit([(5..5, ", cruel")]),
77 buffer_a.edit([(0..5, "goodbye")]),
78 buffer_a.undo().unwrap().1,
79 ];
80 assert_eq!(buffer_a.text(), "hello, cruel world");
81
82 let operations = operations
83 .into_iter()
84 .map(|op| proto::serialize_operation(&language::Operation::Buffer(op)))
85 .collect::<Vec<_>>();
86
87 db.update_channel_buffer(zed_id, a_id, &operations)
88 .await
89 .unwrap();
90
91 let connection_id_b = ConnectionId { owner_id, id: 2 };
92 let buffer_response_b = db
93 .join_channel_buffer(zed_id, b_id, connection_id_b)
94 .await
95 .unwrap();
96
97 let mut buffer_b = Buffer::new(
98 0,
99 text::BufferId::new(1).unwrap(),
100 buffer_response_b.base_text,
101 );
102 buffer_b.apply_ops(buffer_response_b.operations.into_iter().map(|operation| {
103 let operation = proto::deserialize_operation(operation).unwrap();
104 if let language::Operation::Buffer(operation) = operation {
105 operation
106 } else {
107 unreachable!()
108 }
109 }));
110
111 assert_eq!(buffer_b.text(), "hello, cruel world");
112
113 // Ensure that C fails to open the buffer
114 assert!(
115 db.join_channel_buffer(zed_id, c_id, ConnectionId { owner_id, id: 3 })
116 .await
117 .is_err()
118 );
119
120 // Ensure that both collaborators have shown up
121 assert_eq!(
122 buffer_response_b.collaborators,
123 &[
124 rpc::proto::Collaborator {
125 user_id: a_id.to_proto(),
126 peer_id: Some(rpc::proto::PeerId { id: 1, owner_id }),
127 replica_id: 0,
128 is_host: false,
129 committer_name: None,
130 committer_email: None,
131 },
132 rpc::proto::Collaborator {
133 user_id: b_id.to_proto(),
134 peer_id: Some(rpc::proto::PeerId { id: 2, owner_id }),
135 replica_id: 1,
136 is_host: false,
137 committer_name: None,
138 committer_email: None,
139 }
140 ]
141 );
142
143 // Ensure that get_channel_buffer_collaborators works
144 let zed_collaborats = db.get_channel_buffer_collaborators(zed_id).await.unwrap();
145 assert_eq!(zed_collaborats, &[a_id, b_id]);
146
147 let left_buffer = db
148 .leave_channel_buffer(zed_id, connection_id_b)
149 .await
150 .unwrap();
151
152 assert_eq!(left_buffer.connections, &[connection_id_a],);
153
154 let cargo_id = db.create_root_channel("cargo", a_id).await.unwrap();
155 let _ = db
156 .join_channel_buffer(cargo_id, a_id, connection_id_a)
157 .await
158 .unwrap();
159
160 db.leave_channel_buffers(connection_id_a).await.unwrap();
161
162 let zed_collaborators = db.get_channel_buffer_collaborators(zed_id).await.unwrap();
163 let cargo_collaborators = db.get_channel_buffer_collaborators(cargo_id).await.unwrap();
164 assert_eq!(zed_collaborators, &[]);
165 assert_eq!(cargo_collaborators, &[]);
166
167 // When everyone has left the channel, the operations are collapsed into
168 // a new base text.
169 let buffer_response_b = db
170 .join_channel_buffer(zed_id, b_id, connection_id_b)
171 .await
172 .unwrap();
173 assert_eq!(buffer_response_b.base_text, "hello, cruel world");
174 assert_eq!(buffer_response_b.operations, &[]);
175}
176
177test_both_dbs!(
178 test_channel_buffers_last_operations,
179 test_channel_buffers_last_operations_postgres,
180 test_channel_buffers_last_operations_sqlite
181);
182
183async fn test_channel_buffers_last_operations(db: &Database) {
184 let user_id = db
185 .create_user(
186 "user_a@example.com",
187 None,
188 false,
189 NewUserParams {
190 github_login: "user_a".into(),
191 github_user_id: 101,
192 },
193 )
194 .await
195 .unwrap()
196 .user_id;
197 let observer_id = db
198 .create_user(
199 "user_b@example.com",
200 None,
201 false,
202 NewUserParams {
203 github_login: "user_b".into(),
204 github_user_id: 102,
205 },
206 )
207 .await
208 .unwrap()
209 .user_id;
210 let owner_id = db.create_server("production").await.unwrap().0 as u32;
211 let connection_id = ConnectionId {
212 owner_id,
213 id: user_id.0 as u32,
214 };
215
216 let mut buffers = Vec::new();
217 let mut text_buffers = Vec::new();
218 for i in 0..3 {
219 let channel = db
220 .create_root_channel(&format!("channel-{i}"), user_id)
221 .await
222 .unwrap();
223
224 db.invite_channel_member(channel, observer_id, user_id, ChannelRole::Member)
225 .await
226 .unwrap();
227 db.respond_to_channel_invite(channel, observer_id, true)
228 .await
229 .unwrap();
230
231 db.join_channel_buffer(channel, user_id, connection_id)
232 .await
233 .unwrap();
234
235 buffers.push(
236 db.transaction(|tx| async move { db.get_channel_buffer(channel, &tx).await })
237 .await
238 .unwrap(),
239 );
240
241 text_buffers.push(Buffer::new(
242 0,
243 text::BufferId::new(1).unwrap(),
244 "".to_string(),
245 ));
246 }
247
248 update_buffer(
249 buffers[0].channel_id,
250 user_id,
251 db,
252 vec![
253 text_buffers[0].edit([(0..0, "a")]),
254 text_buffers[0].edit([(0..0, "b")]),
255 text_buffers[0].edit([(0..0, "c")]),
256 ],
257 )
258 .await;
259
260 update_buffer(
261 buffers[1].channel_id,
262 user_id,
263 db,
264 vec![
265 text_buffers[1].edit([(0..0, "d")]),
266 text_buffers[1].edit([(1..1, "e")]),
267 text_buffers[1].edit([(2..2, "f")]),
268 ],
269 )
270 .await;
271
272 // cause buffer 1's epoch to increment.
273 db.leave_channel_buffer(buffers[1].channel_id, connection_id)
274 .await
275 .unwrap();
276 db.join_channel_buffer(buffers[1].channel_id, user_id, connection_id)
277 .await
278 .unwrap();
279 text_buffers[1] = Buffer::new(1, text::BufferId::new(1).unwrap(), "def".to_string());
280 update_buffer(
281 buffers[1].channel_id,
282 user_id,
283 db,
284 vec![
285 text_buffers[1].edit([(0..0, "g")]),
286 text_buffers[1].edit([(0..0, "h")]),
287 ],
288 )
289 .await;
290
291 update_buffer(
292 buffers[2].channel_id,
293 user_id,
294 db,
295 vec![text_buffers[2].edit([(0..0, "i")])],
296 )
297 .await;
298
299 let channels_for_user = db.get_channels_for_user(user_id).await.unwrap();
300
301 pretty_assertions::assert_eq!(
302 channels_for_user.latest_buffer_versions,
303 [
304 rpc::proto::ChannelBufferVersion {
305 channel_id: buffers[0].channel_id.to_proto(),
306 epoch: 0,
307 version: serialize_version(&text_buffers[0].version()),
308 },
309 rpc::proto::ChannelBufferVersion {
310 channel_id: buffers[1].channel_id.to_proto(),
311 epoch: 1,
312 version: serialize_version(&text_buffers[1].version())
313 .into_iter()
314 .filter(|vector| vector.replica_id == text_buffers[1].replica_id() as u32)
315 .collect::<Vec<_>>(),
316 },
317 rpc::proto::ChannelBufferVersion {
318 channel_id: buffers[2].channel_id.to_proto(),
319 epoch: 0,
320 version: serialize_version(&text_buffers[2].version()),
321 },
322 ]
323 );
324}
325
326async fn update_buffer(
327 channel_id: ChannelId,
328 user_id: UserId,
329 db: &Database,
330 operations: Vec<text::Operation>,
331) {
332 let operations = operations
333 .into_iter()
334 .map(|op| proto::serialize_operation(&language::Operation::Buffer(op)))
335 .collect::<Vec<_>>();
336 db.update_channel_buffer(channel_id, user_id, &operations)
337 .await
338 .unwrap();
339}