1use agent::SharedThread;
2use gpui::{BackgroundExecutor, TestAppContext};
3use rpc::proto;
4use uuid::Uuid;
5
6use crate::tests::TestServer;
7
8#[gpui::test]
9async fn test_share_and_retrieve_thread(
10 executor: BackgroundExecutor,
11 cx_a: &mut TestAppContext,
12 cx_b: &mut TestAppContext,
13) {
14 let mut server = TestServer::start(executor.clone()).await;
15 let client_a = server.create_client(cx_a, "user_a").await;
16 let client_b = server.create_client(cx_b, "user_b").await;
17
18 executor.run_until_parked();
19
20 let session_id = Uuid::new_v4().to_string();
21
22 let original_thread = SharedThread {
23 title: "Shared Test Thread".into(),
24 messages: vec![],
25 updated_at: chrono::Utc::now(),
26 model: None,
27 completion_mode: None,
28 version: SharedThread::VERSION.to_string(),
29 };
30
31 let thread_data = original_thread
32 .to_bytes()
33 .expect("Failed to serialize thread");
34
35 client_a
36 .client()
37 .request(proto::ShareAgentThread {
38 session_id: session_id.clone(),
39 title: original_thread.title.to_string(),
40 thread_data,
41 })
42 .await
43 .expect("Failed to share thread");
44
45 let get_response = client_b
46 .client()
47 .request(proto::GetSharedAgentThread {
48 session_id: session_id.clone(),
49 })
50 .await
51 .expect("Failed to get shared thread");
52
53 let imported_shared_thread =
54 SharedThread::from_bytes(&get_response.thread_data).expect("Failed to deserialize thread");
55
56 assert_eq!(imported_shared_thread.title, original_thread.title);
57 assert_eq!(imported_shared_thread.version, SharedThread::VERSION);
58
59 let db_thread = imported_shared_thread.to_db_thread();
60
61 assert!(
62 db_thread.title.starts_with("🔗"),
63 "Imported thread title should have link prefix"
64 );
65 assert!(
66 db_thread.title.contains("Shared Test Thread"),
67 "Imported thread should preserve original title"
68 );
69}
70
71#[gpui::test]
72async fn test_reshare_updates_existing_thread(
73 executor: BackgroundExecutor,
74 cx_a: &mut TestAppContext,
75 cx_b: &mut TestAppContext,
76) {
77 let mut server = TestServer::start(executor.clone()).await;
78 let client_a = server.create_client(cx_a, "user_a").await;
79 let client_b = server.create_client(cx_b, "user_b").await;
80
81 executor.run_until_parked();
82
83 let session_id = Uuid::new_v4().to_string();
84
85 client_a
86 .client()
87 .request(proto::ShareAgentThread {
88 session_id: session_id.clone(),
89 title: "Original Title".to_string(),
90 thread_data: b"original data".to_vec(),
91 })
92 .await
93 .expect("Failed to share thread");
94
95 client_a
96 .client()
97 .request(proto::ShareAgentThread {
98 session_id: session_id.clone(),
99 title: "Updated Title".to_string(),
100 thread_data: b"updated data".to_vec(),
101 })
102 .await
103 .expect("Failed to re-share thread");
104
105 let get_response = client_b
106 .client()
107 .request(proto::GetSharedAgentThread {
108 session_id: session_id.clone(),
109 })
110 .await
111 .expect("Failed to get shared thread");
112
113 assert_eq!(get_response.title, "Updated Title");
114 assert_eq!(get_response.thread_data, b"updated data".to_vec());
115}
116
117#[gpui::test]
118async fn test_get_nonexistent_thread(executor: BackgroundExecutor, cx: &mut TestAppContext) {
119 let mut server = TestServer::start(executor.clone()).await;
120 let client = server.create_client(cx, "user_a").await;
121
122 executor.run_until_parked();
123
124 let nonexistent_session_id = Uuid::new_v4().to_string();
125
126 let result = client
127 .client()
128 .request(proto::GetSharedAgentThread {
129 session_id: nonexistent_session_id,
130 })
131 .await;
132
133 assert!(result.is_err(), "Should fail for nonexistent thread");
134}
135
136#[gpui::test]
137async fn test_sync_imported_thread(
138 executor: BackgroundExecutor,
139 cx_a: &mut TestAppContext,
140 cx_b: &mut TestAppContext,
141) {
142 let mut server = TestServer::start(executor.clone()).await;
143 let client_a = server.create_client(cx_a, "user_a").await;
144 let client_b = server.create_client(cx_b, "user_b").await;
145
146 executor.run_until_parked();
147
148 let session_id = Uuid::new_v4().to_string();
149
150 // User A shares a thread with initial content.
151 let initial_thread = SharedThread {
152 title: "Initial Title".into(),
153 messages: vec![],
154 updated_at: chrono::Utc::now(),
155 model: None,
156 completion_mode: None,
157 version: SharedThread::VERSION.to_string(),
158 };
159
160 client_a
161 .client()
162 .request(proto::ShareAgentThread {
163 session_id: session_id.clone(),
164 title: initial_thread.title.to_string(),
165 thread_data: initial_thread.to_bytes().expect("Failed to serialize"),
166 })
167 .await
168 .expect("Failed to share thread");
169
170 // User B imports the thread.
171 let initial_response = client_b
172 .client()
173 .request(proto::GetSharedAgentThread {
174 session_id: session_id.clone(),
175 })
176 .await
177 .expect("Failed to get shared thread");
178
179 let initial_imported =
180 SharedThread::from_bytes(&initial_response.thread_data).expect("Failed to deserialize");
181 assert_eq!(initial_imported.title.as_ref(), "Initial Title");
182
183 // User A updates the shared thread.
184 let updated_thread = SharedThread {
185 title: "Updated Title".into(),
186 messages: vec![],
187 updated_at: chrono::Utc::now(),
188 model: None,
189 completion_mode: None,
190 version: SharedThread::VERSION.to_string(),
191 };
192
193 client_a
194 .client()
195 .request(proto::ShareAgentThread {
196 session_id: session_id.clone(),
197 title: updated_thread.title.to_string(),
198 thread_data: updated_thread.to_bytes().expect("Failed to serialize"),
199 })
200 .await
201 .expect("Failed to re-share thread");
202
203 // User B syncs the imported thread (fetches the latest version).
204 let synced_response = client_b
205 .client()
206 .request(proto::GetSharedAgentThread {
207 session_id: session_id.clone(),
208 })
209 .await
210 .expect("Failed to sync shared thread");
211
212 let synced_thread =
213 SharedThread::from_bytes(&synced_response.thread_data).expect("Failed to deserialize");
214
215 // The synced thread should have the updated title.
216 assert_eq!(synced_thread.title.as_ref(), "Updated Title");
217}