Skip to content

Commit 545e9d8

Browse files
committed
Add tests to search splits contained in time range
1 parent e42f8d4 commit 545e9d8

File tree

3 files changed

+147
-3
lines changed

3 files changed

+147
-3
lines changed

quickwit/quickwit-indexing/src/test_utils.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
// limitations under the License.
1414

1515
use std::num::NonZeroUsize;
16+
use std::ops::RangeInclusive;
1617
use std::str::FromStr;
1718
use std::sync::Arc;
1819
use std::sync::atomic::{AtomicUsize, Ordering};
@@ -251,8 +252,16 @@ pub struct MockSplitBuilder {
251252

252253
impl MockSplitBuilder {
253254
pub fn new(split_id: &str) -> Self {
255+
Self::new_with_time_range(split_id, Some(121000..=130198))
256+
}
257+
258+
pub fn new_with_time_range(split_id: &str, time_range: Option<RangeInclusive<i64>>) -> Self {
254259
Self {
255-
split_metadata: mock_split_meta(split_id, &IndexUid::for_test("test-index", 0)),
260+
split_metadata: mock_split_meta(
261+
split_id,
262+
&IndexUid::for_test("test-index", 0),
263+
time_range,
264+
),
256265
}
257266
}
258267

@@ -277,14 +286,18 @@ pub fn mock_split(split_id: &str) -> Split {
277286
}
278287

279288
/// Mock split meta helper.
280-
pub fn mock_split_meta(split_id: &str, index_uid: &IndexUid) -> SplitMetadata {
289+
pub fn mock_split_meta(
290+
split_id: &str,
291+
index_uid: &IndexUid,
292+
time_range: Option<RangeInclusive<i64>>,
293+
) -> SplitMetadata {
281294
SplitMetadata {
282295
index_uid: index_uid.clone(),
283296
split_id: split_id.to_string(),
284297
partition_id: 13u64,
285298
num_docs: if split_id == "split1" { 1_000_000 } else { 10 },
286299
uncompressed_docs_size_in_bytes: 256,
287-
time_range: Some(121000..=130198),
300+
time_range,
288301
create_timestamp: 0,
289302
footer_offsets: 700..800,
290303
..Default::default()

quickwit/quickwit-search/src/root.rs

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5059,4 +5059,111 @@ mod tests {
50595059
assert_eq!(search_response.failed_splits.len(), 1);
50605060
Ok(())
50615061
}
5062+
5063+
#[tokio::test]
5064+
async fn test_count_from_metastore_in_contained_time_range() -> anyhow::Result<()> {
5065+
let search_request = quickwit_proto::search::SearchRequest {
5066+
start_timestamp: Some(122_000),
5067+
end_timestamp: Some(129_000),
5068+
index_id_patterns: vec!["test-index".to_string()],
5069+
query_ast: serde_json::to_string(&QueryAst::MatchAll)
5070+
.expect("MatchAll should be JSON serializable."),
5071+
max_hits: 0,
5072+
..Default::default()
5073+
};
5074+
5075+
let index_metadata = IndexMetadata::for_test("test-index", "ram:///test-index");
5076+
let index_uid = index_metadata.index_uid.clone();
5077+
5078+
let mut mock_metastore = MockMetastoreService::new();
5079+
mock_metastore
5080+
.expect_list_indexes_metadata()
5081+
.returning(move |_q| {
5082+
Ok(ListIndexesMetadataResponse::for_test(vec![
5083+
index_metadata.clone(),
5084+
]))
5085+
});
5086+
mock_metastore.expect_list_splits().returning(move |_req| {
5087+
let splits = vec![
5088+
MockSplitBuilder::new_with_time_range("split_before", Some(100_000..=110_000))
5089+
.with_index_uid(&index_uid)
5090+
.build(),
5091+
MockSplitBuilder::new_with_time_range(
5092+
"split_overlap_start",
5093+
Some(120_000..=123_000),
5094+
)
5095+
.with_index_uid(&index_uid)
5096+
.build(),
5097+
MockSplitBuilder::new_with_time_range("split_overlap_end", Some(128_000..=140_000))
5098+
.with_index_uid(&index_uid)
5099+
.build(),
5100+
MockSplitBuilder::new_with_time_range(
5101+
"split_covering_whole",
5102+
Some(100_000..=200_000),
5103+
)
5104+
.with_index_uid(&index_uid)
5105+
.build(),
5106+
MockSplitBuilder::new_with_time_range("split_inside", Some(124_000..=126_000))
5107+
.with_index_uid(&index_uid)
5108+
.build(),
5109+
];
5110+
let resp = ListSplitsResponse::try_from_splits(splits).unwrap();
5111+
Ok(ServiceStream::from(vec![Ok(resp)]))
5112+
});
5113+
5114+
let mut mock_search = MockSearchService::new();
5115+
mock_search
5116+
.expect_leaf_search()
5117+
.withf(|leaf_search_req| {
5118+
let mut expected = HashSet::new();
5119+
5120+
// Notice split_inside is not included.
5121+
expected.insert("split_before");
5122+
expected.insert("split_covering_whole");
5123+
expected.insert("split_overlap_end");
5124+
expected.insert("split_overlap_start");
5125+
5126+
leaf_search_req.leaf_requests.len() == 1
5127+
&& leaf_search_req.leaf_requests[0]
5128+
.split_offsets
5129+
.iter()
5130+
.map(|s| s.split_id.as_str())
5131+
.collect::<HashSet<&str>>()
5132+
== expected
5133+
})
5134+
.times(1)
5135+
.returning(|_| {
5136+
Ok(quickwit_proto::search::LeafSearchResponse {
5137+
num_hits: 5,
5138+
partial_hits: vec![],
5139+
failed_splits: Vec::new(),
5140+
num_attempted_splits: 0,
5141+
..Default::default()
5142+
})
5143+
});
5144+
mock_search.expect_fetch_docs().returning(|fetch_req| {
5145+
Ok(quickwit_proto::search::FetchDocsResponse {
5146+
hits: get_doc_for_fetch_req(fetch_req),
5147+
})
5148+
});
5149+
5150+
let searcher_pool = searcher_pool_for_test([("127.0.0.1:1001", mock_search)]);
5151+
let search_job_placer = SearchJobPlacer::new(searcher_pool);
5152+
let cluster_client = ClusterClient::new(search_job_placer);
5153+
5154+
let ctx = SearcherContext::for_test();
5155+
let resp = root_search(
5156+
&ctx,
5157+
search_request,
5158+
MetastoreServiceClient::from_mock(mock_metastore),
5159+
&cluster_client,
5160+
)
5161+
.await?;
5162+
5163+
assert_eq!(resp.num_hits, 15);
5164+
assert_eq!(resp.hits.len(), 0);
5165+
assert_eq!(resp.num_successful_splits, 1);
5166+
5167+
Ok(())
5168+
}
50625169
}

quickwit/rest-api-tests/scenarii/qw_search_api/0001_ts_range.yaml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,27 @@ params:
3434
query: "ts:>=1684993002 AND ts:<1684993004"
3535
expected:
3636
num_hits: 2
37+
---
38+
endpoint: simple/search
39+
params:
40+
query: "*"
41+
start_timestamp: 1684993000
42+
end_timestamp: 1684993004
43+
expected:
44+
num_hits: 3
45+
---
46+
endpoint: simple/search
47+
params:
48+
query: "*"
49+
start_timestamp: 1684993001
50+
end_timestamp: 1684993005
51+
expected:
52+
num_hits: 4
53+
---
54+
endpoint: simple/search
55+
params:
56+
query: "*"
57+
start_timestamp: 1684992999
58+
end_timestamp: 1684993003
59+
expected:
60+
num_hits: 3

0 commit comments

Comments
 (0)