2023-09-07 18:16:51 +00:00
|
|
|
use crate::channel_chat::ChannelChatEvent;
|
|
|
|
|
2023-08-01 01:00:14 +00:00
|
|
|
use super::*;
|
2023-09-07 18:16:51 +00:00
|
|
|
use client::{test::FakeServer, Client, UserStore};
|
|
|
|
use gpui::{AppContext, ModelHandle, TestAppContext};
|
2023-10-13 17:34:13 +00:00
|
|
|
use rpc::proto::{self};
|
2023-09-08 01:06:05 +00:00
|
|
|
use settings::SettingsStore;
|
2023-08-09 20:43:16 +00:00
|
|
|
use util::http::FakeHttpClient;
|
2023-08-01 01:00:14 +00:00
|
|
|
|
|
|
|
#[gpui::test]
|
|
|
|
fn test_update_channels(cx: &mut AppContext) {
|
2023-09-08 01:06:05 +00:00
|
|
|
let channel_store = init_test(cx);
|
2023-08-01 01:00:14 +00:00
|
|
|
|
|
|
|
update_channels(
|
|
|
|
&channel_store,
|
|
|
|
proto::UpdateChannels {
|
|
|
|
channels: vec![
|
|
|
|
proto::Channel {
|
|
|
|
id: 1,
|
|
|
|
name: "b".to_string(),
|
2023-10-17 16:15:20 +00:00
|
|
|
visibility: proto::ChannelVisibility::Members as i32,
|
2023-10-18 12:28:05 +00:00
|
|
|
role: proto::ChannelRole::Admin.into(),
|
2023-10-24 15:28:03 +00:00
|
|
|
parent_path: Vec::new(),
|
2023-08-01 01:00:14 +00:00
|
|
|
},
|
|
|
|
proto::Channel {
|
|
|
|
id: 2,
|
|
|
|
name: "a".to_string(),
|
2023-10-17 16:15:20 +00:00
|
|
|
visibility: proto::ChannelVisibility::Members as i32,
|
2023-10-18 12:28:05 +00:00
|
|
|
role: proto::ChannelRole::Member.into(),
|
2023-10-24 15:28:03 +00:00
|
|
|
parent_path: Vec::new(),
|
2023-08-01 01:00:14 +00:00
|
|
|
},
|
|
|
|
],
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
cx,
|
|
|
|
);
|
|
|
|
assert_channels(
|
|
|
|
&channel_store,
|
|
|
|
&[
|
|
|
|
//
|
2023-10-19 01:27:00 +00:00
|
|
|
(0, "a".to_string(), proto::ChannelRole::Member),
|
|
|
|
(0, "b".to_string(), proto::ChannelRole::Admin),
|
2023-08-01 01:00:14 +00:00
|
|
|
],
|
|
|
|
cx,
|
|
|
|
);
|
|
|
|
|
|
|
|
update_channels(
|
|
|
|
&channel_store,
|
|
|
|
proto::UpdateChannels {
|
|
|
|
channels: vec![
|
|
|
|
proto::Channel {
|
|
|
|
id: 3,
|
|
|
|
name: "x".to_string(),
|
2023-10-17 16:15:20 +00:00
|
|
|
visibility: proto::ChannelVisibility::Members as i32,
|
2023-10-19 01:27:00 +00:00
|
|
|
role: proto::ChannelRole::Admin.into(),
|
2023-10-25 07:22:06 +00:00
|
|
|
parent_path: vec![1],
|
2023-08-01 01:00:14 +00:00
|
|
|
},
|
|
|
|
proto::Channel {
|
|
|
|
id: 4,
|
|
|
|
name: "y".to_string(),
|
2023-10-17 16:15:20 +00:00
|
|
|
visibility: proto::ChannelVisibility::Members as i32,
|
2023-10-18 12:28:05 +00:00
|
|
|
role: proto::ChannelRole::Member.into(),
|
2023-10-25 07:22:06 +00:00
|
|
|
parent_path: vec![2],
|
2023-08-01 01:00:14 +00:00
|
|
|
},
|
|
|
|
],
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
cx,
|
|
|
|
);
|
|
|
|
assert_channels(
|
|
|
|
&channel_store,
|
|
|
|
&[
|
2023-10-19 01:27:00 +00:00
|
|
|
(0, "a".to_string(), proto::ChannelRole::Member),
|
|
|
|
(1, "y".to_string(), proto::ChannelRole::Member),
|
|
|
|
(0, "b".to_string(), proto::ChannelRole::Admin),
|
|
|
|
(1, "x".to_string(), proto::ChannelRole::Admin),
|
2023-08-01 01:00:14 +00:00
|
|
|
],
|
|
|
|
cx,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-08-14 23:27:35 +00:00
|
|
|
#[gpui::test]
|
|
|
|
fn test_dangling_channel_paths(cx: &mut AppContext) {
|
2023-09-08 01:06:05 +00:00
|
|
|
let channel_store = init_test(cx);
|
2023-08-14 23:27:35 +00:00
|
|
|
|
|
|
|
update_channels(
|
|
|
|
&channel_store,
|
|
|
|
proto::UpdateChannels {
|
|
|
|
channels: vec![
|
|
|
|
proto::Channel {
|
|
|
|
id: 0,
|
|
|
|
name: "a".to_string(),
|
2023-10-17 16:15:20 +00:00
|
|
|
visibility: proto::ChannelVisibility::Members as i32,
|
2023-10-18 12:28:05 +00:00
|
|
|
role: proto::ChannelRole::Admin.into(),
|
2023-10-25 07:22:06 +00:00
|
|
|
parent_path: vec![],
|
2023-08-14 23:27:35 +00:00
|
|
|
},
|
|
|
|
proto::Channel {
|
|
|
|
id: 1,
|
|
|
|
name: "b".to_string(),
|
2023-10-17 16:15:20 +00:00
|
|
|
visibility: proto::ChannelVisibility::Members as i32,
|
2023-10-18 12:28:05 +00:00
|
|
|
role: proto::ChannelRole::Admin.into(),
|
2023-10-25 07:22:06 +00:00
|
|
|
parent_path: vec![0],
|
2023-08-14 23:27:35 +00:00
|
|
|
},
|
|
|
|
proto::Channel {
|
|
|
|
id: 2,
|
|
|
|
name: "c".to_string(),
|
2023-10-17 16:15:20 +00:00
|
|
|
visibility: proto::ChannelVisibility::Members as i32,
|
2023-10-18 12:28:05 +00:00
|
|
|
role: proto::ChannelRole::Admin.into(),
|
2023-10-25 07:22:06 +00:00
|
|
|
parent_path: vec![0, 1],
|
2023-08-14 23:27:35 +00:00
|
|
|
},
|
|
|
|
],
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
cx,
|
|
|
|
);
|
|
|
|
// Sanity check
|
|
|
|
assert_channels(
|
|
|
|
&channel_store,
|
|
|
|
&[
|
|
|
|
//
|
2023-10-19 01:27:00 +00:00
|
|
|
(0, "a".to_string(), proto::ChannelRole::Admin),
|
|
|
|
(1, "b".to_string(), proto::ChannelRole::Admin),
|
|
|
|
(2, "c".to_string(), proto::ChannelRole::Admin),
|
2023-08-14 23:27:35 +00:00
|
|
|
],
|
|
|
|
cx,
|
|
|
|
);
|
|
|
|
|
|
|
|
update_channels(
|
|
|
|
&channel_store,
|
|
|
|
proto::UpdateChannels {
|
2023-09-08 18:38:00 +00:00
|
|
|
delete_channels: vec![1, 2],
|
2023-08-14 23:27:35 +00:00
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
cx,
|
|
|
|
);
|
|
|
|
|
|
|
|
// Make sure that the 1/2/3 path is gone
|
2023-10-19 01:27:00 +00:00
|
|
|
assert_channels(
|
|
|
|
&channel_store,
|
|
|
|
&[(0, "a".to_string(), proto::ChannelRole::Admin)],
|
|
|
|
cx,
|
|
|
|
);
|
2023-08-14 23:27:35 +00:00
|
|
|
}
|
|
|
|
|
2023-09-07 18:16:51 +00:00
|
|
|
#[gpui::test]
|
|
|
|
async fn test_channel_messages(cx: &mut TestAppContext) {
|
|
|
|
let user_id = 5;
|
|
|
|
let channel_id = 5;
|
2023-09-08 01:06:05 +00:00
|
|
|
let channel_store = cx.update(init_test);
|
|
|
|
let client = channel_store.read_with(cx, |s, _| s.client());
|
|
|
|
let server = FakeServer::for_client(user_id, &client, cx).await;
|
2023-09-07 18:16:51 +00:00
|
|
|
|
|
|
|
// Get the available channels.
|
|
|
|
server.send(proto::UpdateChannels {
|
|
|
|
channels: vec![proto::Channel {
|
|
|
|
id: channel_id,
|
|
|
|
name: "the-channel".to_string(),
|
2023-10-17 16:15:20 +00:00
|
|
|
visibility: proto::ChannelVisibility::Members as i32,
|
2023-10-19 01:27:00 +00:00
|
|
|
role: proto::ChannelRole::Member.into(),
|
2023-10-24 15:28:03 +00:00
|
|
|
parent_path: vec![],
|
2023-09-07 18:16:51 +00:00
|
|
|
}],
|
|
|
|
..Default::default()
|
|
|
|
});
|
2023-09-08 01:06:05 +00:00
|
|
|
cx.foreground().run_until_parked();
|
2023-09-07 18:16:51 +00:00
|
|
|
cx.read(|cx| {
|
2023-10-19 01:27:00 +00:00
|
|
|
assert_channels(
|
|
|
|
&channel_store,
|
|
|
|
&[(0, "the-channel".to_string(), proto::ChannelRole::Member)],
|
|
|
|
cx,
|
|
|
|
);
|
2023-09-07 18:16:51 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
let get_users = server.receive::<proto::GetUsers>().await.unwrap();
|
|
|
|
assert_eq!(get_users.payload.user_ids, vec![5]);
|
2023-09-08 01:06:05 +00:00
|
|
|
server.respond(
|
|
|
|
get_users.receipt(),
|
|
|
|
proto::UsersResponse {
|
|
|
|
users: vec![proto::User {
|
|
|
|
id: 5,
|
|
|
|
github_login: "nathansobo".into(),
|
|
|
|
avatar_url: "http://avatar.com/nathansobo".into(),
|
|
|
|
}],
|
|
|
|
},
|
|
|
|
);
|
2023-09-07 18:16:51 +00:00
|
|
|
|
|
|
|
// Join a channel and populate its existing messages.
|
2023-09-08 01:06:05 +00:00
|
|
|
let channel = channel_store.update(cx, |store, cx| {
|
2023-10-24 15:28:03 +00:00
|
|
|
let channel_id = store.ordered_channels().next().unwrap().1.id;
|
2023-09-08 01:06:05 +00:00
|
|
|
store.open_channel_chat(channel_id, cx)
|
|
|
|
});
|
2023-09-07 18:16:51 +00:00
|
|
|
let join_channel = server.receive::<proto::JoinChannelChat>().await.unwrap();
|
2023-09-08 01:06:05 +00:00
|
|
|
server.respond(
|
|
|
|
join_channel.receipt(),
|
|
|
|
proto::JoinChannelChatResponse {
|
|
|
|
messages: vec![
|
|
|
|
proto::ChannelMessage {
|
|
|
|
id: 10,
|
|
|
|
body: "a".into(),
|
|
|
|
timestamp: 1000,
|
|
|
|
sender_id: 5,
|
2023-10-18 23:56:03 +00:00
|
|
|
mentions: vec![],
|
2023-09-08 01:06:05 +00:00
|
|
|
nonce: Some(1.into()),
|
|
|
|
},
|
|
|
|
proto::ChannelMessage {
|
|
|
|
id: 11,
|
|
|
|
body: "b".into(),
|
|
|
|
timestamp: 1001,
|
|
|
|
sender_id: 6,
|
2023-10-18 23:56:03 +00:00
|
|
|
mentions: vec![],
|
2023-09-08 01:06:05 +00:00
|
|
|
nonce: Some(2.into()),
|
|
|
|
},
|
|
|
|
],
|
|
|
|
done: false,
|
|
|
|
},
|
|
|
|
);
|
|
|
|
|
|
|
|
cx.foreground().start_waiting();
|
2023-09-07 18:16:51 +00:00
|
|
|
|
|
|
|
// Client requests all users for the received messages
|
|
|
|
let mut get_users = server.receive::<proto::GetUsers>().await.unwrap();
|
|
|
|
get_users.payload.user_ids.sort();
|
|
|
|
assert_eq!(get_users.payload.user_ids, vec![6]);
|
2023-09-08 01:06:05 +00:00
|
|
|
server.respond(
|
|
|
|
get_users.receipt(),
|
|
|
|
proto::UsersResponse {
|
|
|
|
users: vec![proto::User {
|
|
|
|
id: 6,
|
|
|
|
github_login: "maxbrunsfeld".into(),
|
|
|
|
avatar_url: "http://avatar.com/maxbrunsfeld".into(),
|
|
|
|
}],
|
|
|
|
},
|
2023-09-07 18:16:51 +00:00
|
|
|
);
|
2023-09-08 01:06:05 +00:00
|
|
|
|
|
|
|
let channel = channel.await.unwrap();
|
2023-09-07 18:16:51 +00:00
|
|
|
channel.read_with(cx, |channel, _| {
|
|
|
|
assert_eq!(
|
|
|
|
channel
|
|
|
|
.messages_in_range(0..2)
|
|
|
|
.map(|message| (message.sender.github_login.clone(), message.body.clone()))
|
|
|
|
.collect::<Vec<_>>(),
|
|
|
|
&[
|
|
|
|
("nathansobo".into(), "a".into()),
|
|
|
|
("maxbrunsfeld".into(), "b".into())
|
|
|
|
]
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Receive a new message.
|
|
|
|
server.send(proto::ChannelMessageSent {
|
|
|
|
channel_id,
|
|
|
|
message: Some(proto::ChannelMessage {
|
|
|
|
id: 12,
|
|
|
|
body: "c".into(),
|
|
|
|
timestamp: 1002,
|
|
|
|
sender_id: 7,
|
2023-10-18 23:56:03 +00:00
|
|
|
mentions: vec![],
|
2023-09-07 18:16:51 +00:00
|
|
|
nonce: Some(3.into()),
|
|
|
|
}),
|
|
|
|
});
|
|
|
|
|
|
|
|
// Client requests user for message since they haven't seen them yet
|
|
|
|
let get_users = server.receive::<proto::GetUsers>().await.unwrap();
|
|
|
|
assert_eq!(get_users.payload.user_ids, vec![7]);
|
2023-09-08 01:06:05 +00:00
|
|
|
server.respond(
|
|
|
|
get_users.receipt(),
|
|
|
|
proto::UsersResponse {
|
|
|
|
users: vec![proto::User {
|
|
|
|
id: 7,
|
|
|
|
github_login: "as-cii".into(),
|
|
|
|
avatar_url: "http://avatar.com/as-cii".into(),
|
|
|
|
}],
|
|
|
|
},
|
|
|
|
);
|
2023-09-07 18:16:51 +00:00
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
channel.next_event(cx).await,
|
|
|
|
ChannelChatEvent::MessagesUpdated {
|
|
|
|
old_range: 2..2,
|
|
|
|
new_count: 1,
|
|
|
|
}
|
|
|
|
);
|
|
|
|
channel.read_with(cx, |channel, _| {
|
|
|
|
assert_eq!(
|
|
|
|
channel
|
|
|
|
.messages_in_range(2..3)
|
|
|
|
.map(|message| (message.sender.github_login.clone(), message.body.clone()))
|
|
|
|
.collect::<Vec<_>>(),
|
|
|
|
&[("as-cii".into(), "c".into())]
|
|
|
|
)
|
|
|
|
});
|
|
|
|
|
|
|
|
// Scroll up to view older messages.
|
|
|
|
channel.update(cx, |channel, cx| {
|
2023-10-19 19:31:45 +00:00
|
|
|
channel.load_more_messages(cx).unwrap().detach();
|
2023-09-07 18:16:51 +00:00
|
|
|
});
|
|
|
|
let get_messages = server.receive::<proto::GetChannelMessages>().await.unwrap();
|
|
|
|
assert_eq!(get_messages.payload.channel_id, 5);
|
|
|
|
assert_eq!(get_messages.payload.before_message_id, 10);
|
2023-09-08 01:06:05 +00:00
|
|
|
server.respond(
|
|
|
|
get_messages.receipt(),
|
|
|
|
proto::GetChannelMessagesResponse {
|
|
|
|
done: true,
|
|
|
|
messages: vec![
|
|
|
|
proto::ChannelMessage {
|
|
|
|
id: 8,
|
|
|
|
body: "y".into(),
|
|
|
|
timestamp: 998,
|
|
|
|
sender_id: 5,
|
|
|
|
nonce: Some(4.into()),
|
2023-10-18 23:56:03 +00:00
|
|
|
mentions: vec![],
|
2023-09-08 01:06:05 +00:00
|
|
|
},
|
|
|
|
proto::ChannelMessage {
|
|
|
|
id: 9,
|
|
|
|
body: "z".into(),
|
|
|
|
timestamp: 999,
|
|
|
|
sender_id: 6,
|
|
|
|
nonce: Some(5.into()),
|
2023-10-18 23:56:03 +00:00
|
|
|
mentions: vec![],
|
2023-09-08 01:06:05 +00:00
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
);
|
2023-09-07 18:16:51 +00:00
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
channel.next_event(cx).await,
|
|
|
|
ChannelChatEvent::MessagesUpdated {
|
|
|
|
old_range: 0..0,
|
|
|
|
new_count: 2,
|
|
|
|
}
|
|
|
|
);
|
|
|
|
channel.read_with(cx, |channel, _| {
|
|
|
|
assert_eq!(
|
|
|
|
channel
|
|
|
|
.messages_in_range(0..2)
|
|
|
|
.map(|message| (message.sender.github_login.clone(), message.body.clone()))
|
|
|
|
.collect::<Vec<_>>(),
|
|
|
|
&[
|
|
|
|
("nathansobo".into(), "y".into()),
|
|
|
|
("maxbrunsfeld".into(), "z".into())
|
|
|
|
]
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-09-08 01:06:05 +00:00
|
|
|
fn init_test(cx: &mut AppContext) -> ModelHandle<ChannelStore> {
|
|
|
|
let http = FakeHttpClient::with_404_response();
|
|
|
|
let client = Client::new(http.clone(), cx);
|
|
|
|
let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http, cx));
|
|
|
|
|
|
|
|
cx.foreground().forbid_parking();
|
|
|
|
cx.set_global(SettingsStore::test(cx));
|
|
|
|
client::init(&client, cx);
|
2023-10-06 21:16:08 +00:00
|
|
|
crate::init(&client, user_store, cx);
|
2023-09-08 01:06:05 +00:00
|
|
|
|
2023-10-06 21:16:08 +00:00
|
|
|
ChannelStore::global(cx)
|
2023-09-08 01:06:05 +00:00
|
|
|
}
|
|
|
|
|
2023-08-01 01:00:14 +00:00
|
|
|
fn update_channels(
|
|
|
|
channel_store: &ModelHandle<ChannelStore>,
|
|
|
|
message: proto::UpdateChannels,
|
|
|
|
cx: &mut AppContext,
|
|
|
|
) {
|
2023-08-15 00:36:35 +00:00
|
|
|
let task = channel_store.update(cx, |store, cx| store.update_channels(message, cx));
|
|
|
|
assert!(task.is_none());
|
2023-08-01 01:00:14 +00:00
|
|
|
}
|
|
|
|
|
2023-08-08 17:03:55 +00:00
|
|
|
#[track_caller]
|
2023-08-01 01:00:14 +00:00
|
|
|
fn assert_channels(
|
|
|
|
channel_store: &ModelHandle<ChannelStore>,
|
2023-10-19 01:27:00 +00:00
|
|
|
expected_channels: &[(usize, String, proto::ChannelRole)],
|
2023-08-01 01:00:14 +00:00
|
|
|
cx: &AppContext,
|
|
|
|
) {
|
2023-08-14 23:27:35 +00:00
|
|
|
let actual = channel_store.read_with(cx, |store, _| {
|
|
|
|
store
|
2023-10-24 15:28:03 +00:00
|
|
|
.ordered_channels()
|
2023-10-19 01:27:00 +00:00
|
|
|
.map(|(depth, channel)| (depth, channel.name.to_string(), channel.role))
|
2023-08-14 23:27:35 +00:00
|
|
|
.collect::<Vec<_>>()
|
2023-08-01 01:00:14 +00:00
|
|
|
});
|
2023-08-14 23:27:35 +00:00
|
|
|
assert_eq!(actual, expected_channels);
|
2023-08-01 01:00:14 +00:00
|
|
|
}
|