@@ -1151,6 +1151,31 @@ mod tests {
11511151 } )
11521152 }
11531153
1154+ async fn create_object (
1155+ backend : & BigTableBackend ,
1156+ id : & ObjectId ,
1157+ metadata : & Metadata ,
1158+ payload : & [ u8 ] ,
1159+ now : SystemTime ,
1160+ ) -> Result < ( ) > {
1161+ let path = id. as_storage_path ( ) . to_string ( ) . into_bytes ( ) ;
1162+ let mutations = build_write_mutations ( metadata, payload. to_vec ( ) , now) ?;
1163+ backend. mutate ( path, mutations, "test-setup" ) . await ?;
1164+ Ok ( ( ) )
1165+ }
1166+
1167+ async fn create_tombstone (
1168+ backend : & BigTableBackend ,
1169+ id : & ObjectId ,
1170+ tombstone : & Tombstone ,
1171+ now : SystemTime ,
1172+ ) -> Result < ( ) > {
1173+ let path = id. as_storage_path ( ) . to_string ( ) . into_bytes ( ) ;
1174+ let mutations = build_tombstone_mutations ( tombstone, now) ?;
1175+ backend. mutate ( path, mutations, "test-setup" ) . await ?;
1176+ Ok ( ( ) )
1177+ }
1178+
11541179 /// Writes a legacy-format tombstone row directly into Bigtable.
11551180 async fn write_legacy_tombstone (
11561181 backend : & BigTableBackend ,
@@ -1238,7 +1263,7 @@ mod tests {
12381263
12391264 let ( obj_meta, stream) = backend. get_object ( & id) . await ?. unwrap ( ) ;
12401265 let payload = stream:: read_to_vec ( stream) . await ?;
1241- assert_eq ! ( str :: from_utf8 ( & payload) . unwrap ( ) , "hello, world" ) ;
1266+ assert_eq ! ( payload, b "hello, world") ;
12421267 assert_eq ! ( obj_meta. content_type, metadata. content_type) ;
12431268 assert_eq ! ( obj_meta. custom, metadata. custom) ;
12441269
@@ -1271,9 +1296,7 @@ mod tests {
12711296 custom : BTreeMap :: from_iter ( [ ( "invalid" . into ( ) , "invalid" . into ( ) ) ] ) ,
12721297 ..Default :: default ( )
12731298 } ;
1274- backend
1275- . put_object ( & id, & first_metadata, stream:: single ( "hello" ) )
1276- . await ?;
1299+ create_object ( & backend, & id, & first_metadata, b"hello" , SystemTime :: now ( ) ) . await ?;
12771300
12781301 let second_metadata = Metadata {
12791302 custom : BTreeMap :: from_iter ( [ ( "hello" . into ( ) , "world" . into ( ) ) ] ) ,
@@ -1285,7 +1308,7 @@ mod tests {
12851308
12861309 let ( meta, stream) = backend. get_object ( & id) . await ?. unwrap ( ) ;
12871310 let payload = stream:: read_to_vec ( stream) . await ?;
1288- assert_eq ! ( str :: from_utf8 ( & payload) . unwrap ( ) , "world" ) ;
1311+ assert_eq ! ( payload, b "world") ;
12891312 assert_eq ! ( meta. custom, second_metadata. custom) ;
12901313
12911314 Ok ( ( ) )
@@ -1296,9 +1319,8 @@ mod tests {
12961319 let backend = create_test_backend ( ) . await ?;
12971320
12981321 let id = make_id ( ) ;
1299- backend
1300- . put_object ( & id, & Metadata :: default ( ) , stream:: single ( "hello, world" ) )
1301- . await ?;
1322+ let metadata = Metadata :: default ( ) ;
1323+ create_object ( & backend, & id, & metadata, b"hello" , SystemTime :: now ( ) ) . await ?;
13021324 backend. delete_object ( & id) . await ?;
13031325
13041326 assert ! ( backend. get_object( & id) . await ?. is_none( ) ) ;
@@ -1321,19 +1343,13 @@ mod tests {
13211343 ..Default :: default ( )
13221344 } ;
13231345
1324- // Compute a fake `now` such that build_write_mutations produces a stale timestamp
1325- // just inside the bump window: expire_at = fake_now + tti = now - TTI_DEBOUNCE - 60s.
1346+ // Pass a backdated `now` so the written expiry is inside the bump window:
1347+ // expire_at = past_now + tti = now - TTI_DEBOUNCE - 60s (stale but not yet expired) .
13261348 let past_now = SystemTime :: now ( ) - TTI_DEBOUNCE - Duration :: from_secs ( 60 ) ;
13271349
13281350 // Sub-sequence 1: get_object triggers bump (loaded=true path).
13291351 let id1 = make_id ( ) ;
1330- backend
1331- . put_object ( & id1, & metadata, stream:: single ( "hello, world" ) )
1332- . await ?;
1333- let path1 = id1. as_storage_path ( ) . to_string ( ) . into_bytes ( ) ;
1334- let mutations1 =
1335- build_write_mutations ( & metadata, b"hello, world" . to_vec ( ) , past_now) . unwrap ( ) ;
1336- backend. mutate ( path1, mutations1, "test-setup" ) . await ?;
1352+ create_object ( & backend, & id1, & metadata, b"hello, world" , past_now) . await ?;
13371353
13381354 // get_object reads the stale row, triggers bump, and returns the pre-bump metadata.
13391355 let ( pre_obj_meta, _) = backend. get_object ( & id1) . await ?. unwrap ( ) ;
@@ -1349,13 +1365,7 @@ mod tests {
13491365
13501366 // Sub-sequence 2: get_metadata triggers bump (loaded=false path).
13511367 let id2 = make_id ( ) ;
1352- backend
1353- . put_object ( & id2, & metadata, stream:: single ( "hello, world" ) )
1354- . await ?;
1355- let path2 = id2. as_storage_path ( ) . to_string ( ) . into_bytes ( ) ;
1356- let mutations2 =
1357- build_write_mutations ( & metadata, b"hello, world" . to_vec ( ) , past_now) . unwrap ( ) ;
1358- backend. mutate ( path2, mutations2, "test-setup" ) . await ?;
1368+ create_object ( & backend, & id2, & metadata, b"hello, world" , past_now) . await ?;
13591369
13601370 // First get_metadata sees the stale row and triggers a bump.
13611371 let pre_meta = backend. get_metadata ( & id2) . await ?. unwrap ( ) ;
@@ -1369,7 +1379,7 @@ mod tests {
13691379 // Payload must be intact after the loaded=false bump (which re-fetches the payload).
13701380 let ( _, stream) = backend. get_object ( & id2) . await ?. unwrap ( ) ;
13711381 let payload = stream:: read_to_vec ( stream) . await ?;
1372- assert_eq ! ( & payload, b"hello, world" ) ;
1382+ assert_eq ! ( payload, b"hello, world" ) ;
13731383
13741384 Ok ( ( ) )
13751385 }
@@ -1385,9 +1395,7 @@ mod tests {
13851395 expiration_policy : ExpirationPolicy :: TimeToIdle ( tti) ,
13861396 ..Default :: default ( )
13871397 } ;
1388- backend
1389- . put_object ( & id, & metadata, stream:: single ( "hello, world" ) )
1390- . await ?;
1398+ create_object ( & backend, & id, & metadata, b"hello, world" , SystemTime :: now ( ) ) . await ?;
13911399
13921400 // A freshly written object has time_expires ≈ now + 2d, well outside the bump
13931401 // window (now + 2d - 1d = now + 1d). No bump should occur.
@@ -1417,9 +1425,7 @@ mod tests {
14171425 expiration_policy : ExpirationPolicy :: TimeToLive ( Duration :: from_secs ( 0 ) ) ,
14181426 ..Default :: default ( )
14191427 } ;
1420- backend
1421- . put_object ( & id, & metadata, stream:: single ( "hello, world" ) )
1422- . await ?;
1428+ create_object ( & backend, & id, & metadata, b"hello, world" , SystemTime :: now ( ) ) . await ?;
14231429
14241430 assert ! ( backend. get_object( & id) . await ?. is_none( ) ) ;
14251431
@@ -1438,9 +1444,7 @@ mod tests {
14381444 expiration_policy : ExpirationPolicy :: TimeToIdle ( Duration :: from_secs ( 0 ) ) ,
14391445 ..Default :: default ( )
14401446 } ;
1441- backend
1442- . put_object ( & id, & metadata, stream:: single ( "hello, world" ) )
1443- . await ?;
1447+ create_object ( & backend, & id, & metadata, b"hello, world" , SystemTime :: now ( ) ) . await ?;
14441448
14451449 assert ! ( backend. get_object( & id) . await ?. is_none( ) ) ;
14461450
@@ -1477,15 +1481,13 @@ mod tests {
14771481 custom : BTreeMap :: from_iter ( [ ( "k" . into ( ) , "v" . into ( ) ) ] ) ,
14781482 ..Default :: default ( )
14791483 } ;
1480- backend
1481- . put_object ( & id, & put_meta, stream:: single ( "tiered payload" ) )
1482- . await ?;
1484+ create_object ( & backend, & id, & put_meta, b"payload" , SystemTime :: now ( ) ) . await ?;
14831485
14841486 let TieredGet :: Object ( obj_meta, obj_stream) = backend. get_tiered_object ( & id) . await ? else {
14851487 panic ! ( "expected TieredGet::Object" ) ;
14861488 } ;
14871489 let obj_payload = stream:: read_to_vec ( obj_stream) . await ?;
1488- assert_eq ! ( obj_payload, b"tiered payload" ) ;
1490+ assert_eq ! ( obj_payload, b"payload" ) ;
14891491 assert_eq ! ( obj_meta. content_type, put_meta. content_type) ;
14901492 assert_eq ! ( obj_meta. custom, put_meta. custom) ;
14911493
@@ -1498,11 +1500,11 @@ mod tests {
14981500 // tombstone
14991501 let hv_id = make_id ( ) ;
15001502 let lt_id = ObjectId :: random ( hv_id. context ( ) . clone ( ) ) ;
1501- let write = TieredWrite :: Tombstone ( Tombstone {
1503+ let tombstone = Tombstone {
15021504 target : lt_id. clone ( ) ,
15031505 expiration_policy : ExpirationPolicy :: Manual ,
1504- } ) ;
1505- backend . compare_and_write ( & hv_id, None , write ) . await ?;
1506+ } ;
1507+ create_tombstone ( & backend , & hv_id, & tombstone , SystemTime :: now ( ) ) . await ?;
15061508
15071509 match backend. get_tiered_object ( & hv_id) . await ? {
15081510 TieredGet :: Tombstone ( get_t) => assert_eq ! ( get_t. target, lt_id, ) ,
@@ -1527,20 +1529,19 @@ mod tests {
15271529
15281530 // empty: put_non_tombstone on absent row succeeds and makes object readable.
15291531 let id = make_id ( ) ;
1532+ let metadata = Metadata :: default ( ) ;
15301533 let result = backend
1531- . put_non_tombstone ( & id, & Metadata :: default ( ) , Bytes :: from_static ( b"first" ) )
1534+ . put_non_tombstone ( & id, & metadata , Bytes :: from_static ( b"first" ) )
15321535 . await ?;
15331536 assert_eq ! ( result, None , "expected None on empty row" ) ;
15341537 let ( _, stream) = backend. get_object ( & id) . await ?. unwrap ( ) ;
15351538 assert_eq ! ( & stream:: read_to_vec( stream) . await ?, b"first" ) ;
15361539
15371540 // object: put_non_tombstone on existing object replaces payload, returns None.
15381541 let id = make_id ( ) ;
1539- backend
1540- . put_object ( & id, & Metadata :: default ( ) , stream:: single ( "old" ) )
1541- . await ?;
1542+ create_object ( & backend, & id, & metadata, b"old" , SystemTime :: now ( ) ) . await ?;
15421543 let result = backend
1543- . put_non_tombstone ( & id, & Metadata :: default ( ) , Bytes :: from_static ( b"new" ) )
1544+ . put_non_tombstone ( & id, & metadata , Bytes :: from_static ( b"new" ) )
15441545 . await ?;
15451546 assert_eq ! ( result, None , "expected None when overwriting object" ) ;
15461547 let ( _, stream) = backend. get_object ( & id) . await ?. unwrap ( ) ;
@@ -1549,13 +1550,13 @@ mod tests {
15491550 // tombstone: put_non_tombstone returns Some(Tombstone) and leaves tombstone intact.
15501551 let hv_id = make_id ( ) ;
15511552 let lt_id = ObjectId :: random ( hv_id. context ( ) . clone ( ) ) ;
1552- let write = TieredWrite :: Tombstone ( Tombstone {
1553+ let tombstone = Tombstone {
15531554 target : lt_id. clone ( ) ,
15541555 expiration_policy : ExpirationPolicy :: Manual ,
1555- } ) ;
1556- backend . compare_and_write ( & hv_id, None , write ) . await ?;
1556+ } ;
1557+ create_tombstone ( & backend , & hv_id, & tombstone , SystemTime :: now ( ) ) . await ?;
15571558 let result = backend
1558- . put_non_tombstone ( & hv_id, & Metadata :: default ( ) , Bytes :: new ( ) )
1559+ . put_non_tombstone ( & hv_id, & metadata , Bytes :: new ( ) )
15591560 . await ?;
15601561 let returned = result. expect ( "expected Some(Tombstone) when row is a tombstone" ) ;
15611562 assert_eq ! ( returned. target, lt_id) ;
@@ -1588,19 +1589,18 @@ mod tests {
15881589
15891590 // object
15901591 let id = make_id ( ) ;
1591- backend
1592- . put_object ( & id, & Metadata :: default ( ) , stream:: single ( "hello, world" ) )
1593- . await ?;
1592+ let metadata = Metadata :: default ( ) ;
1593+ create_object ( & backend, & id, & metadata, b"hello, world" , SystemTime :: now ( ) ) . await ?;
15941594 assert_eq ! ( backend. delete_non_tombstone( & id) . await ?, None ) ;
15951595 assert ! ( backend. get_object( & id) . await ?. is_none( ) ) ;
15961596
15971597 // tombstone
15981598 let id = make_id ( ) ;
1599- let write = TieredWrite :: Tombstone ( Tombstone {
1599+ let tombstone = Tombstone {
16001600 target : id. clone ( ) ,
16011601 expiration_policy : ExpirationPolicy :: Manual ,
1602- } ) ;
1603- backend . compare_and_write ( & id, None , write ) . await ?;
1602+ } ;
1603+ create_tombstone ( & backend , & id, & tombstone , SystemTime :: now ( ) ) . await ?;
16041604 let tombstone = backend
16051605 . delete_non_tombstone ( & id)
16061606 . await ?
@@ -1678,11 +1678,11 @@ mod tests {
16781678 let wrong_lt_id = ObjectId :: random ( hv_id. context ( ) . clone ( ) ) ;
16791679 let new_lt_id = ObjectId :: random ( hv_id. context ( ) . clone ( ) ) ;
16801680
1681- let write = TieredWrite :: Tombstone ( Tombstone {
1681+ let tombstone = Tombstone {
16821682 target : old_lt_id. clone ( ) ,
16831683 expiration_policy : ExpirationPolicy :: Manual ,
1684- } ) ;
1685- backend . compare_and_write ( & hv_id, None , write ) . await ?;
1684+ } ;
1685+ create_tombstone ( & backend , & hv_id, & tombstone , SystemTime :: now ( ) ) . await ?;
16861686
16871687 // Wrong target: CAS fails, tombstone unchanged.
16881688 let write = TieredWrite :: Tombstone ( Tombstone {
@@ -1724,11 +1724,11 @@ mod tests {
17241724 let lt_id = ObjectId :: random ( id. context ( ) . clone ( ) ) ;
17251725 let wrong_id = ObjectId :: random ( id. context ( ) . clone ( ) ) ;
17261726
1727- let write = TieredWrite :: Tombstone ( Tombstone {
1727+ let tombstone = Tombstone {
17281728 target : lt_id. clone ( ) ,
17291729 expiration_policy : ExpirationPolicy :: Manual ,
1730- } ) ;
1731- backend . compare_and_write ( & id, None , write ) . await ?;
1730+ } ;
1731+ create_tombstone ( & backend , & id, & tombstone , SystemTime :: now ( ) ) . await ?;
17321732
17331733 // Wrong target: CAS fails, tombstone intact.
17341734 let write = TieredWrite :: Object ( Metadata :: default ( ) , Bytes :: new ( ) ) ;
@@ -1783,11 +1783,11 @@ mod tests {
17831783 let lt_id = ObjectId :: random ( id. context ( ) . clone ( ) ) ;
17841784 let wrong_id = ObjectId :: random ( id. context ( ) . clone ( ) ) ;
17851785
1786- let write = TieredWrite :: Tombstone ( Tombstone {
1786+ let tombstone = Tombstone {
17871787 target : lt_id. clone ( ) ,
17881788 expiration_policy : ExpirationPolicy :: Manual ,
1789- } ) ;
1790- backend . compare_and_write ( & id, None , write ) . await ?;
1789+ } ;
1790+ create_tombstone ( & backend , & id, & tombstone , SystemTime :: now ( ) ) . await ?;
17911791
17921792 // Wrong target: fails, row preserved.
17931793 let deleted = backend
@@ -1812,9 +1812,8 @@ mod tests {
18121812 // Regular object: CAS-delete with Some(target) returns false, object preserved.
18131813 let id2 = make_id ( ) ;
18141814 let fake_lt_id = ObjectId :: random ( id2. context ( ) . clone ( ) ) ;
1815- backend
1816- . put_object ( & id2, & Metadata :: default ( ) , stream:: single ( "data" ) )
1817- . await ?;
1815+ let metadata = Metadata :: default ( ) ;
1816+ create_object ( & backend, & id2, & metadata, b"data" , SystemTime :: now ( ) ) . await ?;
18181817 let deleted = backend
18191818 . compare_and_write ( & id2, Some ( & fake_lt_id) , TieredWrite :: Delete )
18201819 . await ?;
0 commit comments