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