From 3df998876b66f7dcc3dfcd144c66d59e18c6f7d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Fri, 8 May 2026 20:37:42 -0400 Subject: [PATCH] Harden PRD live-site smoke --- crates/ely_app/src/services/servo_sidecar.rs | 14 ++++++++++++ .../src/services/servo_sidecar_tests.rs | 18 +++++++-------- .../src/shell/internal_pages/profiles.rs | 12 ++++++++++ crates/ely_browser_core/src/error.rs | 3 +++ crates/ely_browser_core/src/state.rs | 9 ++++++-- crates/ely_browser_core/tests/spaces.rs | 22 +++++++++++++++++++ 6 files changed, 67 insertions(+), 11 deletions(-) diff --git a/crates/ely_app/src/services/servo_sidecar.rs b/crates/ely_app/src/services/servo_sidecar.rs index ccecced..f747b06 100644 --- a/crates/ely_app/src/services/servo_sidecar.rs +++ b/crates/ely_app/src/services/servo_sidecar.rs @@ -248,6 +248,12 @@ pub struct SidecarSnapshot { title: Option, width: u32, height: u32, + #[cfg(test)] + non_white_pixel_count: u64, + #[cfg(test)] + content_pixel_count: u64, + #[cfg(test)] + sample_hash: u64, rgba_bytes: Vec, } @@ -281,6 +287,12 @@ impl SidecarSnapshot { title: report.title, width: report.width, height: report.height, + #[cfg(test)] + non_white_pixel_count: report.non_white_pixel_count, + #[cfg(test)] + content_pixel_count: report.content_pixel_count, + #[cfg(test)] + sample_hash: report.sample_hash, rgba_bytes, }) } @@ -379,6 +391,8 @@ struct SidecarReport { rgba_byte_count: usize, non_white_pixel_count: u64, content_pixel_count: u64, + #[cfg(test)] + sample_hash: u64, } fn default_sidecar_command() -> Result { diff --git a/crates/ely_app/src/services/servo_sidecar_tests.rs b/crates/ely_app/src/services/servo_sidecar_tests.rs index d6460c8..c8ee202 100644 --- a/crates/ely_app/src/services/servo_sidecar_tests.rs +++ b/crates/ely_app/src/services/servo_sidecar_tests.rs @@ -7,6 +7,8 @@ const LIVE_SITE_WIDTH: u32 = 934; #[cfg(feature = "live-site-smoke")] const LIVE_SITE_HEIGHT: u32 = 657; #[cfg(feature = "live-site-smoke")] +const MINIMUM_CONTENT_PIXELS: u64 = 1_000; +#[cfg(feature = "live-site-smoke")] const PRD_TOP_SITE_CASES: &[LiveSiteCase] = &[ LiveSiteCase { url: "https://github.com", title_fragment: "GitHub" }, LiveSiteCase { url: "https://example.com", title_fragment: "Example Domain" }, @@ -90,6 +92,9 @@ fn accepts_loading_report_with_visible_content() -> Result<(), ServoSidecarError assert_eq!(snapshot.title(), Some("Example Domain")); assert_eq!(snapshot.width(), 2); assert_eq!(snapshot.height(), 1); + assert_eq!(snapshot.non_white_pixel_count, 1); + assert_eq!(snapshot.content_pixel_count, 1); + assert_eq!(snapshot.sample_hash, 42); Ok(()) } @@ -147,6 +152,9 @@ fn assert_live_sites_render(cases: &[LiveSiteCase]) -> Result<(), Box assert_eq!(snapshot.height(), LIVE_SITE_HEIGHT, "{}", case.url); assert_loaded_url_contains(&snapshot, case.url)?; assert_title_contains(&snapshot, case.title_fragment)?; + assert!(snapshot.non_white_pixel_count > 0, "{}", case.url); + assert!(snapshot.content_pixel_count >= MINIMUM_CONTENT_PIXELS, "{}", case.url); + assert!(snapshot.sample_hash > 0, "{}", case.url); let rgba_bytes = snapshot.into_rgba_bytes(); assert_eq!( @@ -155,7 +163,6 @@ fn assert_live_sites_render(cases: &[LiveSiteCase]) -> Result<(), Box "{}", case.url ); - assert!(non_white_pixel_count(&rgba_bytes) > 0, "{}", case.url); } Ok(()) } @@ -178,14 +185,6 @@ fn assert_title_contains(snapshot: &SidecarSnapshot, fragment: &str) -> Result<( Ok(()) } -#[cfg(feature = "live-site-smoke")] -fn non_white_pixel_count(rgba_bytes: &[u8]) -> usize { - rgba_bytes - .chunks_exact(4) - .filter(|pixel| pixel[3] > 0 && (pixel[0] != 255 || pixel[1] != 255 || pixel[2] != 255)) - .count() -} - fn report_with_state(state: &str) -> SidecarReport { SidecarReport { requested_url: "https://example.com".to_string(), @@ -197,6 +196,7 @@ fn report_with_state(state: &str) -> SidecarReport { rgba_byte_count: 8, non_white_pixel_count: 1, content_pixel_count: 1, + sample_hash: 42, } } diff --git a/crates/ely_app/src/shell/internal_pages/profiles.rs b/crates/ely_app/src/shell/internal_pages/profiles.rs index 6816c5b..57d941e 100644 --- a/crates/ely_app/src/shell/internal_pages/profiles.rs +++ b/crates/ely_app/src/shell/internal_pages/profiles.rs @@ -143,6 +143,7 @@ fn render_profile_row( .child(render_profile_default_action( index, default_profile_id, + profile.kind() == &ProfileKind::Standard, default_for_active_space, cx, )) @@ -172,6 +173,7 @@ fn profile_color_swatch(color_hex: u32) -> AnyElement { fn render_profile_default_action( index: usize, profile_id: ProfileId, + allows_default: bool, default_for_active_space: bool, cx: &mut Context, ) -> AnyElement { @@ -184,6 +186,16 @@ fn render_profile_default_action( .into_any_element(); } + if !allows_default { + return Button::new(("default-profile", index)) + .ghost() + .xsmall() + .disabled(true) + .label("Private") + .tooltip("Private Profiles stay opt-in") + .into_any_element(); + } + Button::new(("default-profile", index)) .ghost() .xsmall() diff --git a/crates/ely_browser_core/src/error.rs b/crates/ely_browser_core/src/error.rs index 5361b6f..1c8eccf 100644 --- a/crates/ely_browser_core/src/error.rs +++ b/crates/ely_browser_core/src/error.rs @@ -39,6 +39,9 @@ pub enum CoreError { #[error("private profile keeps sync paused: {id}")] PrivateProfileSyncLocked { id: ProfileId }, + #[error("private profile cannot be a space default profile: {id}")] + PrivateProfileDefaultLocked { id: ProfileId }, + #[error("download not found: {id}")] DownloadNotFound { id: DownloadId }, diff --git a/crates/ely_browser_core/src/state.rs b/crates/ely_browser_core/src/state.rs index 9aac232..08de97c 100644 --- a/crates/ely_browser_core/src/state.rs +++ b/crates/ely_browser_core/src/state.rs @@ -289,8 +289,13 @@ impl BrowserCore { space_id: &SpaceId, profile_id: &ProfileId, ) -> Result<(), CoreError> { - if !self.profiles.iter().any(|profile| profile.id() == profile_id) { - return Err(CoreError::ProfileNotFound { id: profile_id.clone() }); + let profile = self + .profiles + .iter() + .find(|profile| profile.id() == profile_id) + .ok_or_else(|| CoreError::ProfileNotFound { id: profile_id.clone() })?; + if profile.kind() == &ProfileKind::Private { + return Err(CoreError::PrivateProfileDefaultLocked { id: profile_id.clone() }); } let space = self diff --git a/crates/ely_browser_core/tests/spaces.rs b/crates/ely_browser_core/tests/spaces.rs index 8a66885..2a88d50 100644 --- a/crates/ely_browser_core/tests/spaces.rs +++ b/crates/ely_browser_core/tests/spaces.rs @@ -233,6 +233,28 @@ fn space_default_profile_updates_with_profile_validation() -> Result<(), Box Result<(), Box> { + let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?; + let snapshot = core.snapshot()?; + let work_space_id = snapshot.active_space_id; + let default_profile_id = snapshot.active_profile_id; + let private_profile_id = core.create_profile("Private", 0x807d72, ProfileKind::Private)?; + + let error = match core.set_space_default_profile(&work_space_id, &private_profile_id) { + Err(error) => error, + Ok(_) => return Err("space default profile accepted a private profile".into()), + }; + + assert_eq!(error, CoreError::PrivateProfileDefaultLocked { id: private_profile_id.clone() }); + let snapshot = core.snapshot()?; + let Some(work_space) = snapshot.spaces.iter().find(|space| space.id() == &work_space_id) else { + return Err("missing work space".into()); + }; + assert_eq!(work_space.default_profile_id(), &default_profile_id); + Ok(()) +} + #[test] fn active_space_default_profile_updates_current_space() -> Result<(), Box> { let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;