mod common;
use common::{delete_remote_db, fresh_remote_db};
use rouchdb::{Database, GetOptions};
#[tokio::test]
#[ignore]
async fn conflict_both_sides_modify_same_doc() {
let url = fresh_remote_db("conflict_both").await;
let local = Database::memory("local");
let remote = Database::http(&url);
let r1 = local
.put("doc1", serde_json::json!({"v": "original"}))
.await
.unwrap();
let original_rev = r1.rev.unwrap();
local.replicate_to(&remote).await.unwrap();
let remote_doc = remote.get("doc1").await.unwrap();
assert_eq!(remote_doc.rev.unwrap().to_string(), original_rev);
local
.update(
"doc1",
&original_rev,
serde_json::json!({"v": "local_edit"}),
)
.await
.unwrap();
remote
.update(
"doc1",
&original_rev,
serde_json::json!({"v": "remote_edit"}),
)
.await
.unwrap();
let (push, pull) = local.sync(&remote).await.unwrap();
assert!(push.ok);
assert!(pull.ok);
let local_doc = local
.get_with_opts(
"doc1",
GetOptions {
conflicts: true,
..Default::default()
},
)
.await
.unwrap();
let remote_doc = remote
.get_with_opts(
"doc1",
GetOptions {
conflicts: true,
..Default::default()
},
)
.await
.unwrap();
assert_eq!(
local_doc.rev.as_ref().unwrap().to_string(),
remote_doc.rev.as_ref().unwrap().to_string(),
"Winning revision must be the same on both sides"
);
assert!(
local_doc.data.get("_conflicts").is_some(),
"Local should have _conflicts"
);
assert!(
remote_doc.data.get("_conflicts").is_some(),
"Remote should have _conflicts"
);
delete_remote_db(&url).await;
}
#[tokio::test]
#[ignore]
async fn conflict_local_delete_remote_update() {
let url = fresh_remote_db("conflict_delupd").await;
let local = Database::memory("local");
let remote = Database::http(&url);
let r1 = local
.put("doc1", serde_json::json!({"v": 1}))
.await
.unwrap();
let rev = r1.rev.unwrap();
local.replicate_to(&remote).await.unwrap();
local.remove("doc1", &rev).await.unwrap();
remote
.update("doc1", &rev, serde_json::json!({"v": 2}))
.await
.unwrap();
local.sync(&remote).await.unwrap();
let remote_doc = remote.get("doc1").await.unwrap();
assert_eq!(remote_doc.data["v"], 2, "Non-deleted revision should win");
let local_doc = local.get("doc1").await.unwrap();
assert_eq!(
local_doc.data["v"], 2,
"Local should agree with remote winner"
);
delete_remote_db(&url).await;
}
#[tokio::test]
#[ignore]
async fn conflict_remote_delete_local_update() {
let url = fresh_remote_db("conflict_updel").await;
let local = Database::memory("local");
let remote = Database::http(&url);
let r1 = local
.put("doc1", serde_json::json!({"v": 1}))
.await
.unwrap();
let rev = r1.rev.unwrap();
local.replicate_to(&remote).await.unwrap();
remote.remove("doc1", &rev).await.unwrap();
local
.update("doc1", &rev, serde_json::json!({"v": 2}))
.await
.unwrap();
local.sync(&remote).await.unwrap();
let local_doc = local.get("doc1").await.unwrap();
assert_eq!(local_doc.data["v"], 2);
let remote_doc = remote.get("doc1").await.unwrap();
assert_eq!(remote_doc.data["v"], 2);
delete_remote_db(&url).await;
}
#[tokio::test]
#[ignore]
async fn conflict_three_way() {
let url = fresh_remote_db("conflict_3way").await;
let local1 = Database::memory("local1");
let local2 = Database::memory("local2");
let remote = Database::http(&url);
let r1 = local1
.put("doc1", serde_json::json!({"v": "original"}))
.await
.unwrap();
let rev = r1.rev.unwrap();
local1.replicate_to(&remote).await.unwrap();
local2.replicate_from(&remote).await.unwrap();
local1
.update("doc1", &rev, serde_json::json!({"v": "local1_edit"}))
.await
.unwrap();
local2
.update("doc1", &rev, serde_json::json!({"v": "local2_edit"}))
.await
.unwrap();
remote
.update("doc1", &rev, serde_json::json!({"v": "remote_edit"}))
.await
.unwrap();
local1.sync(&remote).await.unwrap();
local2.sync(&remote).await.unwrap();
local1.sync(&remote).await.unwrap();
let d1 = local1.get("doc1").await.unwrap();
let d2 = local2.get("doc1").await.unwrap();
let dr = remote.get("doc1").await.unwrap();
let rev1 = d1.rev.as_ref().unwrap().to_string();
let rev2 = d2.rev.as_ref().unwrap().to_string();
let revr = dr.rev.as_ref().unwrap().to_string();
assert_eq!(rev1, rev2, "local1 and local2 must agree on winner");
assert_eq!(rev2, revr, "local2 and remote must agree on winner");
assert_eq!(d1.data["v"], d2.data["v"]);
assert_eq!(d2.data["v"], dr.data["v"]);
delete_remote_db(&url).await;
}
#[tokio::test]
#[ignore]
async fn conflict_resolve_by_update() {
let url = fresh_remote_db("conflict_resolve").await;
let local = Database::memory("local");
let remote = Database::http(&url);
let r1 = local
.put("doc1", serde_json::json!({"v": 1}))
.await
.unwrap();
let rev = r1.rev.unwrap();
local.replicate_to(&remote).await.unwrap();
local
.update("doc1", &rev, serde_json::json!({"v": "local"}))
.await
.unwrap();
remote
.update("doc1", &rev, serde_json::json!({"v": "remote"}))
.await
.unwrap();
local.sync(&remote).await.unwrap();
let doc = local
.get_with_opts(
"doc1",
GetOptions {
conflicts: true,
..Default::default()
},
)
.await
.unwrap();
let conflicts = doc
.data
.get("_conflicts")
.and_then(|c| c.as_array())
.expect("Should have conflicts");
assert!(!conflicts.is_empty());
let winner_rev = doc.rev.unwrap().to_string();
local
.update("doc1", &winner_rev, serde_json::json!({"v": "resolved"}))
.await
.unwrap();
local.sync(&remote).await.unwrap();
let local_doc = local.get("doc1").await.unwrap();
let remote_doc = remote.get("doc1").await.unwrap();
assert_eq!(local_doc.data["v"], "resolved");
assert_eq!(remote_doc.data["v"], "resolved");
delete_remote_db(&url).await;
}