mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
test(search): track author-only FTS skip drift
Co-authored-by: npub1t2tgm7d8f995uqvmnm8h88sg3wnpp9a5xysjf6dg3tjmgt3ltulqdp8ehr <5a968df9a7494b4e019b9ecf739e088ba61097b4312124e9a88ae5b42e3f5f3e@sprout-oss.stage.blox.sqprod.co> Signed-off-by: npub1t2tgm7d8f995uqvmnm8h88sg3wnpp9a5xysjf6dg3tjmgt3ltulqdp8ehr <5a968df9a7494b4e019b9ecf739e088ba61097b4312124e9a88ae5b42e3f5f3e@sprout-oss.stage.blox.sqprod.co>
This commit is contained in:
parent
4c51a8119f
commit
46ba39e45a
@@ -6,7 +6,7 @@
|
|||||||
//! migration into it, exercises a scenario, and drops it. Tests are
|
//! migration into it, exercises a scenario, and drops it. Tests are
|
||||||
//! parallel-safe.
|
//! parallel-safe.
|
||||||
|
|
||||||
use buzz_core::CommunityId;
|
use buzz_core::{kind::AUTHOR_ONLY_KINDS, CommunityId};
|
||||||
use buzz_search::{ChannelScope, SearchQuery, SearchService};
|
use buzz_search::{ChannelScope, SearchQuery, SearchService};
|
||||||
use sqlx::{postgres::PgPoolOptions, Executor, PgPool};
|
use sqlx::{postgres::PgPoolOptions, Executor, PgPool};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
@@ -910,3 +910,87 @@ async fn excluded_kinds_are_storage_level_unsearchable() {
|
|||||||
|
|
||||||
teardown(pool, &schema).await;
|
teardown(pool, &schema).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Tripwire: every Rust-side author-only kind MUST be excluded from
|
||||||
|
/// `search_tsv` at the storage layer.
|
||||||
|
///
|
||||||
|
/// The schema generated column hard-codes the privacy skip-set, while
|
||||||
|
/// `AUTHOR_ONLY_KINDS` is a Rust const. If a future author-only kind is added
|
||||||
|
/// without the matching schema migration, search would still spend FTS budget on
|
||||||
|
/// those private hits before the relay post-filter rejects them. Catch that
|
||||||
|
/// drift here by inserting one row per author-only kind and proving only the
|
||||||
|
/// public kind:9 control is searchable.
|
||||||
|
#[tokio::test]
|
||||||
|
#[ignore = "requires Postgres"]
|
||||||
|
async fn author_only_kinds_are_storage_level_unsearchable() {
|
||||||
|
let (pool, schema) = setup().await;
|
||||||
|
|
||||||
|
let c = mk_community(&pool, "author-only-tripwire.example").await;
|
||||||
|
let token = "authoronly_tripwire_marker_qwerty";
|
||||||
|
|
||||||
|
insert_event(
|
||||||
|
&pool,
|
||||||
|
c,
|
||||||
|
rand_bytes32(),
|
||||||
|
rand_bytes32(),
|
||||||
|
9,
|
||||||
|
&format!("public control — {token}"),
|
||||||
|
None,
|
||||||
|
1_700_000_000,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
for (i, &kind) in AUTHOR_ONLY_KINDS.iter().enumerate() {
|
||||||
|
insert_event(
|
||||||
|
&pool,
|
||||||
|
c,
|
||||||
|
rand_bytes32(),
|
||||||
|
rand_bytes32(),
|
||||||
|
kind as i32,
|
||||||
|
&format!("author-only kind:{kind} — {token}"),
|
||||||
|
None,
|
||||||
|
1_700_000_100 + i as i64,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
let svc = SearchService::new(pool.clone());
|
||||||
|
let result = svc
|
||||||
|
.search(&SearchQuery {
|
||||||
|
community: c,
|
||||||
|
q: token.into(),
|
||||||
|
channel_scope: ChannelScope::Any,
|
||||||
|
kinds: None,
|
||||||
|
authors: None,
|
||||||
|
since: None,
|
||||||
|
until: None,
|
||||||
|
page: 1,
|
||||||
|
per_page: 100,
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.expect("search ok");
|
||||||
|
|
||||||
|
let kinds: Vec<i32> = result.hits.iter().map(|h| h.kind).collect();
|
||||||
|
assert!(
|
||||||
|
kinds.contains(&9),
|
||||||
|
"kind:9 control row MUST be searchable, got kinds={kinds:?}",
|
||||||
|
);
|
||||||
|
|
||||||
|
for &kind in AUTHOR_ONLY_KINDS {
|
||||||
|
assert!(
|
||||||
|
!kinds.contains(&(kind as i32)),
|
||||||
|
"AUTHOR_ONLY kind:{kind} MUST NOT be searchable — \
|
||||||
|
schema skip-set is missing this kind. AUTHOR_ONLY_KINDS={AUTHOR_ONLY_KINDS:?}, \
|
||||||
|
hits={kinds:?}",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
result.hits.len(),
|
||||||
|
1,
|
||||||
|
"expected exactly 1 hit (the kind:9 control), got {} (kinds={kinds:?})",
|
||||||
|
result.hits.len(),
|
||||||
|
);
|
||||||
|
|
||||||
|
teardown(pool, &schema).await;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user