feat(sync): include history in snapshots

This commit is contained in:
2026-05-16 07:03:59 -04:00
parent b550360a47
commit 80729083eb
9 changed files with 270 additions and 3 deletions
+1
View File
@@ -32,6 +32,7 @@ mod splits;
mod sync; mod sync;
mod sync_apply; mod sync_apply;
mod sync_context; mod sync_context;
mod sync_history;
mod sync_notes; mod sync_notes;
mod sync_profiles; mod sync_profiles;
mod sync_reading_list; mod sync_reading_list;
@@ -31,6 +31,9 @@ impl BrowserCore {
for record in body.site_permissions { for record in body.site_permissions {
self.apply_site_permission_sync_record(record, &mut summary, &context)?; self.apply_site_permission_sync_record(record, &mut summary, &context)?;
} }
for record in body.history {
self.apply_history_sync_record(record, &mut summary, &context)?;
}
Ok(summary) Ok(summary)
} }
} }
@@ -0,0 +1,90 @@
use std::{
num::NonZeroU32,
time::{Duration, UNIX_EPOCH},
};
use ely_domain::{HistoryEntry, SyncObjectKind, SyncObjectPolicy, TabId, UrlText};
use ely_sync_client::SyncClientError;
use super::{BrowserCore, sync::snapshot_schema_error, sync_context::SyncSnapshotApplyContext};
use crate::{sync_engine::SyncSnapshotApplySummary, sync_records::HistorySyncRecord};
impl BrowserCore {
pub(crate) fn visible_history_for_sync(&self) -> Vec<&HistoryEntry> {
if self.sync_object_policy(SyncObjectKind::History) == SyncObjectPolicy::Paused {
return Vec::new();
}
self.history_entries
.iter()
.filter(|entry| self.profile_allows_cloud_sync(entry.profile_id()))
.collect()
}
pub(super) fn apply_history_sync_record(
&mut self,
record: HistorySyncRecord,
summary: &mut SyncSnapshotApplySummary,
context: &SyncSnapshotApplyContext,
) -> Result<(), SyncClientError> {
let profile_id = self.sync_profile_id(&record.profile_id, context)?;
let space_id = self.sync_space_id(&record.space_id, record.space_name.as_deref())?;
let url = UrlText::parse(&record.url).map_err(snapshot_schema_error)?;
let source_tab_id = self.resolve_history_source_tab_id(
&record.source_tab_id,
&profile_id,
&space_id,
&url,
)?;
let visited_at = UNIX_EPOCH + Duration::from_secs(record.visited_at_secs);
let visit_count = NonZeroU32::new(record.visit_count).ok_or_else(|| {
snapshot_schema_error("history visit_count must be greater than zero")
})?;
let existing_index = self.history_entries.iter().position(|entry| {
entry.profile_id() == &profile_id
&& entry.space_id() == &space_id
&& entry.url() == &url
});
let entry = HistoryEntry::new(
profile_id,
space_id,
source_tab_id,
record.title,
url,
record.favicon_key,
visited_at,
);
let entry = HistoryEntry::restore(entry, visit_count);
match existing_index {
Some(index) if self.history_entries[index] == entry => summary.record_skipped(),
Some(index) => {
self.history_entries[index] = entry;
summary.record_updated();
}
None => {
self.history_entries.push(entry);
summary.record_imported();
}
}
Ok(())
}
fn resolve_history_source_tab_id(
&self,
raw: &str,
profile_id: &ely_domain::ProfileId,
space_id: &ely_domain::SpaceId,
url: &UrlText,
) -> Result<TabId, SyncClientError> {
let remote_tab_id = TabId::parse(raw).map_err(snapshot_schema_error)?;
if self.tabs.iter().any(|tab| tab.id() == &remote_tab_id) {
return Ok(remote_tab_id);
}
if let Some(tab) = self.tabs.iter().find(|tab| {
tab.profile_id() == profile_id && tab.space_id() == space_id && tab.url() == url
}) {
return Ok(tab.id().clone());
}
Ok(remote_tab_id)
}
}
+43 -2
View File
@@ -1,8 +1,9 @@
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::{SystemTime, UNIX_EPOCH};
use ely_domain::{ use ely_domain::{
ArchivePolicy, BookmarkEntry, BrowserTab, NoteEntry, NoteTarget, Profile, ProfileKind, ArchivePolicy, BookmarkEntry, BrowserTab, HistoryEntry, NoteEntry, NoteTarget, Profile,
ProfileSyncPolicy, ReadingListEntry, ReadingProgress, SitePermissionEntry, Space, TabFlags, ProfileKind, ProfileSyncPolicy, ReadingListEntry, ReadingProgress, SitePermissionEntry, Space,
TabFlags,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -26,6 +27,8 @@ pub(crate) struct SyncSnapshotBody {
pub(crate) reading_list: Vec<ReadingListSyncRecord>, pub(crate) reading_list: Vec<ReadingListSyncRecord>,
#[serde(default)] #[serde(default)]
pub(crate) site_permissions: Vec<SitePermissionSyncRecord>, pub(crate) site_permissions: Vec<SitePermissionSyncRecord>,
#[serde(default)]
pub(crate) history: Vec<HistorySyncRecord>,
} }
impl SyncSnapshotBody { impl SyncSnapshotBody {
@@ -81,6 +84,13 @@ impl SyncSnapshotBody {
.into_iter() .into_iter()
.map(SitePermissionSyncRecord::from_entry) .map(SitePermissionSyncRecord::from_entry)
.collect(), .collect(),
history: core
.visible_history_for_sync()
.into_iter()
.map(|entry| {
HistorySyncRecord::from_entry(entry, core.sync_space_name_for(entry.space_id()))
})
.collect(),
} }
} }
} }
@@ -399,6 +409,37 @@ impl SitePermissionSyncRecord {
} }
} }
#[derive(Clone, Debug, Serialize, Deserialize)]
pub(crate) struct HistorySyncRecord {
pub(crate) profile_id: String,
pub(crate) space_id: String,
#[serde(default)]
pub(crate) space_name: Option<String>,
pub(crate) source_tab_id: String,
pub(crate) title: String,
pub(crate) url: String,
#[serde(default)]
pub(crate) favicon_key: Option<String>,
pub(crate) visited_at_secs: u64,
pub(crate) visit_count: u32,
}
impl HistorySyncRecord {
fn from_entry(entry: &HistoryEntry, space_name: Option<String>) -> Self {
Self {
profile_id: entry.profile_id().as_str().to_string(),
space_id: entry.space_id().as_str().to_string(),
space_name,
source_tab_id: entry.source_tab_id().as_str().to_string(),
title: entry.title().to_string(),
url: entry.url().as_str().to_string(),
favicon_key: entry.favicon_key().map(str::to_string),
visited_at_secs: system_time_secs(entry.visited_at()),
visit_count: entry.visit_count(),
}
}
}
fn default_sync_enabled() -> bool { fn default_sync_enabled() -> bool {
true true
} }
+15
View File
@@ -98,6 +98,7 @@ fn sync_snapshot_imports_remote_bookmarks_into_active_scope() -> Result<(), Box<
source.set_bookmark_collection_name(&bookmark_id, "Research")?; source.set_bookmark_collection_name(&bookmark_id, "Research")?;
source.set_bookmark_tags(&bookmark_id, vec!["rust".to_string(), "gpui".to_string()])?; source.set_bookmark_tags(&bookmark_id, vec!["rust".to_string(), "gpui".to_string()])?;
source.set_bookmark_note(&bookmark_id, "Read later")?; source.set_bookmark_note(&bookmark_id, "Read later")?;
pause_history_sync(&mut source);
let bytes = source.build_sync_snapshot_bytes()?; let bytes = source.build_sync_snapshot_bytes()?;
let mut target = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?; let mut target = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
@@ -129,6 +130,7 @@ fn sync_snapshot_imports_remote_tabs_into_active_scope() -> Result<(), Box<dyn E
source.toggle_active_tab_pinned()?; source.toggle_active_tab_pinned()?;
source.toggle_active_tab_favorite()?; source.toggle_active_tab_favorite()?;
source.set_active_tab_zoom_percent(125)?; source.set_active_tab_zoom_percent(125)?;
pause_history_sync(&mut source);
let bytes = source.build_sync_snapshot_bytes()?; let bytes = source.build_sync_snapshot_bytes()?;
let mut target = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?; let mut target = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
@@ -166,6 +168,7 @@ fn sync_snapshot_imports_remote_spaces_before_tabs() -> Result<(), Box<dyn Error
let research_home_tab_id = source.snapshot()?.active_tab_id; let research_home_tab_id = source.snapshot()?.active_tab_id;
source.set_tab_sync_enabled(&research_home_tab_id, false)?; source.set_tab_sync_enabled(&research_home_tab_id, false)?;
source.open_tab(UrlText::parse("https://example.com/research")?); source.open_tab(UrlText::parse("https://example.com/research")?);
pause_history_sync(&mut source);
let bytes = source.build_sync_snapshot_bytes()?; let bytes = source.build_sync_snapshot_bytes()?;
let mut target = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?; let mut target = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
@@ -203,6 +206,7 @@ fn sync_snapshot_updates_existing_tab_metadata() -> Result<(), Box<dyn Error>> {
let source_tab_id = source.open_tab(UrlText::parse("https://example.com/research")?); let source_tab_id = source.open_tab(UrlText::parse("https://example.com/research")?);
source.set_tab_title(&source_tab_id, "Research Brief")?; source.set_tab_title(&source_tab_id, "Research Brief")?;
source.set_tab_favicon_key(&source_tab_id, "https://example.com/favicon.ico")?; source.set_tab_favicon_key(&source_tab_id, "https://example.com/favicon.ico")?;
pause_history_sync(&mut source);
let bytes = source.build_sync_snapshot_bytes()?; let bytes = source.build_sync_snapshot_bytes()?;
let mut target = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?; let mut target = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
@@ -226,6 +230,7 @@ fn sync_snapshot_omits_paused_tabs() -> Result<(), Box<dyn Error>> {
let mut source = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?; let mut source = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
source.open_tab(UrlText::parse("https://example.com/research")?); source.open_tab(UrlText::parse("https://example.com/research")?);
source.set_sync_object_policy(SyncObjectKind::Tabs, SyncObjectPolicy::Paused); source.set_sync_object_policy(SyncObjectKind::Tabs, SyncObjectPolicy::Paused);
pause_history_sync(&mut source);
let bytes = source.build_sync_snapshot_bytes()?; let bytes = source.build_sync_snapshot_bytes()?;
let mut target = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?; let mut target = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
@@ -250,6 +255,7 @@ fn sync_snapshot_updates_existing_bookmark_metadata() -> Result<(), Box<dyn Erro
source.set_bookmark_collection_name(&source_bookmark_id, "Research")?; source.set_bookmark_collection_name(&source_bookmark_id, "Research")?;
source.set_bookmark_tags(&source_bookmark_id, vec!["servo".to_string()])?; source.set_bookmark_tags(&source_bookmark_id, vec!["servo".to_string()])?;
source.set_bookmark_note(&source_bookmark_id, "Canonical")?; source.set_bookmark_note(&source_bookmark_id, "Canonical")?;
pause_history_sync(&mut source);
let bytes = source.build_sync_snapshot_bytes()?; let bytes = source.build_sync_snapshot_bytes()?;
let mut target = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?; let mut target = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
@@ -279,6 +285,7 @@ fn sync_snapshot_omits_paused_bookmarks() -> Result<(), Box<dyn Error>> {
source.set_tab_sync_enabled(&source_tab_id, false)?; source.set_tab_sync_enabled(&source_tab_id, false)?;
source.bookmark_active_tab()?; source.bookmark_active_tab()?;
source.set_sync_object_policy(SyncObjectKind::Bookmarks, SyncObjectPolicy::Paused); source.set_sync_object_policy(SyncObjectKind::Bookmarks, SyncObjectPolicy::Paused);
pause_history_sync(&mut source);
let bytes = source.build_sync_snapshot_bytes()?; let bytes = source.build_sync_snapshot_bytes()?;
let mut target = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?; let mut target = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
@@ -301,6 +308,7 @@ fn sync_snapshot_imports_remote_url_notes_into_active_scope() -> Result<(), Box<
source.set_tab_sync_enabled(&source_tab_id, false)?; source.set_tab_sync_enabled(&source_tab_id, false)?;
source.set_tab_title(&source_tab_id, "Research Brief")?; source.set_tab_title(&source_tab_id, "Research Brief")?;
source.save_active_url_note(" # Finding\r\n- one ")?; source.save_active_url_note(" # Finding\r\n- one ")?;
pause_history_sync(&mut source);
let bytes = source.build_sync_snapshot_bytes()?; let bytes = source.build_sync_snapshot_bytes()?;
let mut target = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?; let mut target = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
@@ -332,6 +340,7 @@ fn sync_snapshot_imports_remote_tab_notes_after_tabs() -> Result<(), Box<dyn Err
let source_tab_id = source.open_tab(UrlText::parse("https://example.com/research")?); let source_tab_id = source.open_tab(UrlText::parse("https://example.com/research")?);
source.set_tab_title(&source_tab_id, "Research Brief")?; source.set_tab_title(&source_tab_id, "Research Brief")?;
source.save_active_tab_note("pinned tab context")?; source.save_active_tab_note("pinned tab context")?;
pause_history_sync(&mut source);
let bytes = source.build_sync_snapshot_bytes()?; let bytes = source.build_sync_snapshot_bytes()?;
let mut target = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?; let mut target = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
@@ -365,6 +374,7 @@ fn sync_snapshot_updates_existing_note_body() -> Result<(), Box<dyn Error>> {
source.set_tab_sync_enabled(&source_tab_id, false)?; source.set_tab_sync_enabled(&source_tab_id, false)?;
source.set_tab_title(&source_tab_id, "Research Brief")?; source.set_tab_title(&source_tab_id, "Research Brief")?;
source.save_active_url_note("canonical note")?; source.save_active_url_note("canonical note")?;
pause_history_sync(&mut source);
let bytes = source.build_sync_snapshot_bytes()?; let bytes = source.build_sync_snapshot_bytes()?;
let mut target = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?; let mut target = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
@@ -395,6 +405,7 @@ fn sync_snapshot_omits_paused_notes() -> Result<(), Box<dyn Error>> {
source.set_tab_sync_enabled(&source_tab_id, false)?; source.set_tab_sync_enabled(&source_tab_id, false)?;
source.save_active_url_note("local only")?; source.save_active_url_note("local only")?;
source.set_sync_object_policy(SyncObjectKind::Notes, SyncObjectPolicy::Paused); source.set_sync_object_policy(SyncObjectKind::Notes, SyncObjectPolicy::Paused);
pause_history_sync(&mut source);
let bytes = source.build_sync_snapshot_bytes()?; let bytes = source.build_sync_snapshot_bytes()?;
let mut target = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?; let mut target = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
@@ -420,3 +431,7 @@ fn sync_snapshot_rejects_unknown_schema_rev() -> Result<(), Box<dyn Error>> {
assert!(error.to_string().contains("unsupported schema_rev 999")); assert!(error.to_string().contains("unsupported schema_rev 999"));
Ok(()) Ok(())
} }
fn pause_history_sync(core: &mut BrowserCore) {
core.set_sync_object_policy(SyncObjectKind::History, SyncObjectPolicy::Paused);
}
@@ -0,0 +1,95 @@
use std::error::Error;
use ely_browser_core::{BrowserCore, InitialBrowserConfig};
use ely_domain::{SyncObjectKind, SyncObjectPolicy, UrlText};
#[test]
fn sync_snapshot_imports_remote_history_into_active_scope() -> Result<(), Box<dyn Error>> {
let mut source = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
let source_home_tab_id = source.snapshot()?.active_tab_id;
source.set_tab_sync_enabled(&source_home_tab_id, false)?;
let source_tab_id = source.open_tab(UrlText::parse("https://example.com/research")?);
source.set_tab_sync_enabled(&source_tab_id, false)?;
source.set_tab_title(&source_tab_id, "Research Brief")?;
source.set_tab_favicon_key(&source_tab_id, "favicons/example.ico")?;
let bytes = source.build_sync_snapshot_bytes()?;
let mut target = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
let target_profile_id = target.snapshot()?.active_profile_id;
let target_space_id = target.snapshot()?.active_space_id;
let summary = target.apply_sync_snapshot_bytes(&bytes)?;
let snapshot = target.snapshot()?;
let [entry] = snapshot.history_entries.as_slice() else {
return Err(
format!("expected 1 history entry, got {}", snapshot.history_entries.len()).into()
);
};
assert_eq!(summary.imported(), 1);
assert_eq!(summary.updated(), 0);
assert_eq!(summary.skipped(), 0);
assert_eq!(entry.profile_id(), &target_profile_id);
assert_eq!(entry.space_id(), &target_space_id);
assert_eq!(entry.source_tab_id(), &source_tab_id);
assert_eq!(entry.title(), "Research Brief");
assert_eq!(entry.url().as_str(), "https://example.com/research");
assert_eq!(entry.favicon_key(), Some("favicons/example.ico"));
assert_eq!(entry.visit_count(), 1);
Ok(())
}
#[test]
fn sync_snapshot_updates_existing_history_entry() -> Result<(), Box<dyn Error>> {
let mut source = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
let source_home_tab_id = source.snapshot()?.active_tab_id;
source.set_tab_sync_enabled(&source_home_tab_id, false)?;
let first_source_tab_id = source.open_tab(UrlText::parse("https://example.com/research")?);
source.set_tab_sync_enabled(&first_source_tab_id, false)?;
let latest_source_tab_id = source.open_tab(UrlText::parse("https://example.com/research")?);
source.set_tab_sync_enabled(&latest_source_tab_id, false)?;
source.set_tab_title(&latest_source_tab_id, "Canonical Research")?;
source.set_tab_favicon_key(&latest_source_tab_id, "favicons/canonical.ico")?;
let bytes = source.build_sync_snapshot_bytes()?;
let mut target = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
let target_tab_id = target.open_tab(UrlText::parse("https://example.com/research")?);
target.set_tab_title(&target_tab_id, "Old Research")?;
target.set_tab_favicon_key(&target_tab_id, "favicons/old.ico")?;
let summary = target.apply_sync_snapshot_bytes(&bytes)?;
let snapshot = target.snapshot()?;
let [entry] = snapshot.history_entries.as_slice() else {
return Err(
format!("expected 1 history entry, got {}", snapshot.history_entries.len()).into()
);
};
assert_eq!(summary.imported(), 0);
assert_eq!(summary.updated(), 1);
assert_eq!(summary.skipped(), 0);
assert_eq!(entry.source_tab_id(), &target_tab_id);
assert_eq!(entry.title(), "Canonical Research");
assert_eq!(entry.favicon_key(), Some("favicons/canonical.ico"));
assert_eq!(entry.visit_count(), 2);
Ok(())
}
#[test]
fn sync_snapshot_omits_paused_history() -> Result<(), Box<dyn Error>> {
let mut source = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
let source_home_tab_id = source.snapshot()?.active_tab_id;
source.set_tab_sync_enabled(&source_home_tab_id, false)?;
let source_tab_id = source.open_tab(UrlText::parse("https://example.com/research")?);
source.set_tab_sync_enabled(&source_tab_id, false)?;
source.set_sync_object_policy(SyncObjectKind::History, SyncObjectPolicy::Paused);
let bytes = source.build_sync_snapshot_bytes()?;
let mut target = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
let summary = target.apply_sync_snapshot_bytes(&bytes)?;
let snapshot = target.snapshot()?;
assert_eq!(summary.imported(), 0);
assert_eq!(summary.updated(), 0);
assert_eq!(summary.skipped(), 0);
assert!(snapshot.history_entries.is_empty());
Ok(())
}
@@ -94,6 +94,13 @@ fn paused_profile_data_is_omitted_from_sync_snapshots() -> Result<(), Box<dyn Er
assert_eq!(summary.updated(), 0); assert_eq!(summary.updated(), 0);
assert_eq!(summary.skipped(), 0); assert_eq!(summary.skipped(), 0);
assert!(snapshot.profiles.iter().any(|profile| profile.name() == "Research")); assert!(snapshot.profiles.iter().any(|profile| profile.name() == "Research"));
let imported_profile_id = snapshot
.profiles
.iter()
.find(|profile| profile.name() == "Research")
.ok_or("missing imported profile")?
.id()
.clone();
assert!( assert!(
snapshot.tabs.iter().all(|tab| tab.url().as_str() != "https://example.com/paused-profile") snapshot.tabs.iter().all(|tab| tab.url().as_str() != "https://example.com/paused-profile")
); );
@@ -101,5 +108,7 @@ fn paused_profile_data_is_omitted_from_sync_snapshots() -> Result<(), Box<dyn Er
assert!(snapshot.notes.is_empty()); assert!(snapshot.notes.is_empty());
assert!(snapshot.reading_list.is_empty()); assert!(snapshot.reading_list.is_empty());
assert!(snapshot.site_permissions.is_empty()); assert!(snapshot.site_permissions.is_empty());
target.select_profile(&imported_profile_id)?;
assert!(target.snapshot()?.history_entries.is_empty());
Ok(()) Ok(())
} }
@@ -18,6 +18,7 @@ fn sync_snapshot_imports_remote_reading_list_into_active_scope() -> Result<(), B
&entry_id, &entry_id,
ReadingProgress::InProgress(ReadingProgressPercent::new(42)?), ReadingProgress::InProgress(ReadingProgressPercent::new(42)?),
)?; )?;
pause_history_sync(&mut source);
let bytes = source.build_sync_snapshot_bytes()?; let bytes = source.build_sync_snapshot_bytes()?;
let mut target = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?; let mut target = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
@@ -52,6 +53,7 @@ fn sync_snapshot_updates_existing_reading_list_entry() -> Result<(), Box<dyn Err
source.set_tab_title(&source_tab_id, "Canonical Long Read")?; source.set_tab_title(&source_tab_id, "Canonical Long Read")?;
let source_entry_id = source.save_active_tab_to_reading_list()?; let source_entry_id = source.save_active_tab_to_reading_list()?;
source.set_reading_list_progress(&source_entry_id, ReadingProgress::Finished)?; source.set_reading_list_progress(&source_entry_id, ReadingProgress::Finished)?;
pause_history_sync(&mut source);
let bytes = source.build_sync_snapshot_bytes()?; let bytes = source.build_sync_snapshot_bytes()?;
let mut target = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?; let mut target = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
@@ -84,6 +86,7 @@ fn sync_snapshot_omits_paused_reading_list() -> Result<(), Box<dyn Error>> {
source.set_tab_sync_enabled(&source_tab_id, false)?; source.set_tab_sync_enabled(&source_tab_id, false)?;
source.save_active_tab_to_reading_list()?; source.save_active_tab_to_reading_list()?;
source.set_sync_object_policy(SyncObjectKind::ReadingList, SyncObjectPolicy::Paused); source.set_sync_object_policy(SyncObjectKind::ReadingList, SyncObjectPolicy::Paused);
pause_history_sync(&mut source);
let bytes = source.build_sync_snapshot_bytes()?; let bytes = source.build_sync_snapshot_bytes()?;
let mut target = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?; let mut target = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
@@ -96,3 +99,7 @@ fn sync_snapshot_omits_paused_reading_list() -> Result<(), Box<dyn Error>> {
assert!(snapshot.reading_list.is_empty()); assert!(snapshot.reading_list.is_empty());
Ok(()) Ok(())
} }
fn pause_history_sync(core: &mut BrowserCore) {
core.set_sync_object_policy(SyncObjectKind::History, SyncObjectPolicy::Paused);
}
+7 -1
View File
@@ -1,4 +1,4 @@
use std::time::SystemTime; use std::{num::NonZeroU32, time::SystemTime};
use crate::{ProfileId, SpaceId, TabId, UrlText}; use crate::{ProfileId, SpaceId, TabId, UrlText};
@@ -53,6 +53,12 @@ impl HistoryEntry {
self.visit_count = self.visit_count.saturating_add(1); self.visit_count = self.visit_count.saturating_add(1);
} }
#[must_use]
pub fn restore(mut entry: Self, visit_count: NonZeroU32) -> Self {
entry.visit_count = visit_count.get();
entry
}
#[must_use] #[must_use]
pub fn profile_id(&self) -> &ProfileId { pub fn profile_id(&self) -> &ProfileId {
&self.profile_id &self.profile_id