agent_sharing_tests.rs

  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}