This is an automated email from the ASF dual-hosted git repository.
alamb pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-rs-object-store.git
The following commit(s) were added to refs/heads/main by this push:
new 19264b8 Implement tests for range and partial content responses (#619)
19264b8 is described below
commit 19264b856396f76c9cf31029d6c800feeeb53714
Author: Victor Ordaz <[email protected]>
AuthorDate: Tue Feb 3 10:09:06 2026 -0800
Implement tests for range and partial content responses (#619)
* Implement tests for range and partial content responses
Added tests for handling partial content responses and retries for
incomplete response bodies.
* Add CONNECTION header import in get.rs
* Clean up whitespace in get.rs
Removed unnecessary empty lines in the get.rs file.
---
src/client/get.rs | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 78 insertions(+), 1 deletion(-)
diff --git a/src/client/get.rs b/src/client/get.rs
index cefb07b..5a5ec37 100644
--- a/src/client/get.rs
+++ b/src/client/get.rs
@@ -490,7 +490,7 @@ mod http_tests {
use crate::{ClientOptions, ObjectStoreExt, RetryConfig};
use bytes::Bytes;
use futures::FutureExt;
- use http::header::{CONTENT_LENGTH, CONTENT_RANGE, ETAG, RANGE};
+ use http::header::{CONNECTION, CONTENT_LENGTH, CONTENT_RANGE, ETAG, RANGE};
use http::{Response, StatusCode};
use hyper::body::Frame;
use std::pin::Pin;
@@ -579,6 +579,83 @@ mod http_tests {
let b = store.get(&path).await.unwrap().bytes().await.unwrap();
assert_eq!(b.as_ref(), b"Hello World");
+ // Test basic with range
+ let resp = Response::builder()
+ .status(StatusCode::PARTIAL_CONTENT)
+ .header(CONTENT_LENGTH, 4)
+ .header(ETAG, "123")
+ .header(CONTENT_RANGE, "bytes 1-4/11")
+ .body("ello".to_string())
+ .unwrap();
+
+ mock.push(resp);
+
+ let b = store.get_range(&path, 1..5).await.unwrap();
+ assert_eq!(b.as_ref(), b"ello");
+
+ // NOTE: if debug_assertions is true, hyper panics with response
content length header
+ // value does not match the length of response body.
+ if !cfg!(debug_assertions) {
+ // Test retry if a response body is incomplete.
+ mock.push(
+ Response::builder()
+ .header(CONTENT_LENGTH, 12)
+ .header(ETAG, "123")
+ // connection: close disables keep alive
+ .header(CONNECTION, "close")
+ .body("Hello".to_string())
+ .unwrap(),
+ );
+
+ mock.push_fn(|req| {
+ assert_eq!(
+ req.headers().get(RANGE).unwrap().to_str().unwrap(),
+ "bytes=5-11"
+ );
+
+ Response::builder()
+ .status(StatusCode::PARTIAL_CONTENT)
+ .header(CONTENT_LENGTH, 7)
+ .header(ETAG, "123")
+ .header(CONTENT_RANGE, "bytes 5-11/12")
+ .body(" World!".to_string())
+ .unwrap()
+ });
+
+ let ret = store.get(&path).await.unwrap().bytes().await.unwrap();
+ assert_eq!(ret.as_ref(), b"Hello World!");
+
+ // Test retry if a get range response body is incomplete.
+ mock.push(
+ Response::builder()
+ .status(StatusCode::PARTIAL_CONTENT)
+ .header(CONTENT_LENGTH, 5)
+ .header(CONNECTION, "close")
+ .header(ETAG, "123")
+ .header(CONTENT_RANGE, "bytes 6-10/12")
+ .body("Wo".to_string())
+ .unwrap(),
+ );
+
+ mock.push_fn(|req| {
+ assert_eq!(
+ req.headers().get(RANGE).unwrap().to_str().unwrap(),
+ "bytes=8-10"
+ );
+
+ Response::builder()
+ .status(StatusCode::PARTIAL_CONTENT)
+ .header(CONTENT_LENGTH, 3)
+ .header(ETAG, "123")
+ .header(CONTENT_RANGE, "bytes 8-10/12")
+ .body("rld".to_string())
+ .unwrap()
+ });
+
+ let ret = store.get_range(&path, 6..11).await.unwrap();
+ assert_eq!(ret.as_ref(), b"World");
+ }
+
// Should retry with range
mock.push(
Response::builder()