Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions lib/src/db/ai_chat_migration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -379,3 +379,55 @@ async fn migrating_an_ai_chat_shrinks_the_store() {
);
assert!(after < before, "{before} -> {after}");
}

/// A server opens its store before it loads its agent. Opening a store with an
/// old AI chat must migrate it without a default agent (node1 crashed on
/// "No agent set" here).
#[tokio::test]
async fn opening_a_store_without_an_agent_migrates_ai_chats() {
let w = world("ai_chat_migration_open").await;
let chat = old_chat(&w).await;
let first = old_ai_message(&w, &chat, "user", "first", 0).await;
let second = old_ai_message(&w, &chat, "assistant", "second", 1).await;
set_list(&w.db, &chat, MESSAGES, &[first.clone(), second.clone()]).await;
// As a store from before: not marked done.
w.db.kv.remove(Tree::PluginMeta, AI_DONE_KEY).unwrap();
w.db.kv.flush().unwrap();
drop(w);

let path = std::path::Path::new(".temp/db/ai_chat_migration_open");
let uploads = std::path::Path::new(".temp/db/ai_chat_migration_open/uploads");
let mut reopened = None;
let mut last_err = String::new();
// The file lock can outlive the drop by a moment.
for _ in 0..50 {
match Db::init_redb_file(path, Some("https://localhost".into()), uploads).await {
Ok(db) => {
reopened = Some(db);
break;
}
Err(e) => {
last_err = e.to_string();
// Only the file lock is worth waiting for.
assert!(
!last_err.contains("No agent set"),
"opening needs no agent: {last_err}"
);
tokio::time::sleep(std::time::Duration::from_millis(200)).await
}
}
}
let db = reopened.unwrap_or_else(|| panic!("the store reopens: {last_err}"));
assert!(db.get_default_agent().is_err(), "opened without an agent");
assert!(!db.ai_chat_migration_pending().unwrap());
let found = pages_of(&db, &chat).await;
assert_eq!(found.iter().map(|(_, e)| e.len()).sum::<usize>(), 2);
assert!(!exists(&db, &first).await);
assert!(!exists(&db, &second).await);
assert!(db
.get_resource(&chat.as_str().into())
.await
.unwrap()
.get(MESSAGES)
.is_err());
}
6 changes: 3 additions & 3 deletions lib/src/resources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1312,8 +1312,8 @@ impl Resource {
&mut self,
store: &impl Storelike,
commit: crate::Commit,
agent: &crate::agents::Agent,
) -> AtomicResult<CommitResponse> {
let agent = store.get_default_agent()?;
let opts = CommitOpts {
validate_schema: true,
validate_constraints: true,
Expand Down Expand Up @@ -1400,7 +1400,7 @@ impl Resource {
if should_post {
crate::client::post_commit(&commit, store).await?;
}
self.apply_signed_commit(store, commit).await
self.apply_signed_commit(store, commit, agent).await
}

/// Saves the resource (with all the changes) to the store by creating a Commit.
Expand All @@ -1420,7 +1420,7 @@ impl Resource {
.clone()
.sign(&agent, store, self)
.await?;
self.apply_signed_commit(store, commit).await
self.apply_signed_commit(store, commit, &agent).await
}

/// Saves the resource as a new DID-native resource.
Expand Down
Loading