@@ -1294,3 +1294,162 @@ async fn test_range_scan_with_partition_key() {
12941294 . unwrap ( ) ;
12951295 client. shutdown ( ) . await . unwrap ( ) ;
12961296}
1297+
1298+ // ============================================================
1299+ // Stress / throughput test
1300+ // ============================================================
1301+
1302+ #[ tokio:: test]
1303+ async fn test_high_throughput_writes ( ) {
1304+ let ( _container, address) = start_oxia ( ) . await ;
1305+ let client = new_client ( & address) . await ;
1306+
1307+ let num_ops = 100 ;
1308+ let mut handles = Vec :: new ( ) ;
1309+
1310+ // Flood with concurrent put operations
1311+ for i in 0 ..num_ops {
1312+ let c = client. clone ( ) ;
1313+ handles. push ( tokio:: spawn ( async move {
1314+ c. put (
1315+ format ! ( "stress/{:04}" , i) ,
1316+ format ! ( "val-{}" , i) . into_bytes ( ) ,
1317+ )
1318+ . await
1319+ } ) ) ;
1320+ }
1321+
1322+ let mut success_count = 0 ;
1323+ for handle in handles {
1324+ if handle. await . unwrap ( ) . is_ok ( ) {
1325+ success_count += 1 ;
1326+ }
1327+ }
1328+ assert_eq ! ( success_count, num_ops, "All puts should succeed" ) ;
1329+
1330+ // Verify all keys exist
1331+ let list = client
1332+ . list ( "stress/" . to_string ( ) , "stress/~" . to_string ( ) )
1333+ . await
1334+ . unwrap ( ) ;
1335+ assert_eq ! ( list. keys. len( ) , num_ops) ;
1336+
1337+ // Range scan all
1338+ let scan = client
1339+ . range_scan ( "stress/" . to_string ( ) , "stress/~" . to_string ( ) )
1340+ . await
1341+ . unwrap ( ) ;
1342+ assert_eq ! ( scan. records. len( ) , num_ops) ;
1343+
1344+ // Flood with concurrent delete operations
1345+ let mut del_handles = Vec :: new ( ) ;
1346+ for i in 0 ..num_ops {
1347+ let c = client. clone ( ) ;
1348+ del_handles. push ( tokio:: spawn ( async move {
1349+ c. delete ( format ! ( "stress/{:04}" , i) ) . await
1350+ } ) ) ;
1351+ }
1352+ for handle in del_handles {
1353+ handle. await . unwrap ( ) . unwrap ( ) ;
1354+ }
1355+
1356+ // Verify all keys deleted
1357+ let list = client
1358+ . list ( "stress/" . to_string ( ) , "stress/~" . to_string ( ) )
1359+ . await
1360+ . unwrap ( ) ;
1361+ assert_eq ! ( list. keys. len( ) , 0 ) ;
1362+
1363+ client. shutdown ( ) . await . unwrap ( ) ;
1364+ }
1365+
1366+ // ============================================================
1367+ // Notification Display test
1368+ // ============================================================
1369+
1370+ #[ tokio:: test]
1371+ async fn test_notification_display ( ) {
1372+ let created = Notification :: KeyCreated ( KeyCreated {
1373+ key : "test/key" . to_string ( ) ,
1374+ version_id : Some ( 42 ) ,
1375+ } ) ;
1376+ assert ! ( format!( "{}" , created) . contains( "test/key" ) ) ;
1377+ assert ! ( format!( "{}" , created) . contains( "42" ) ) ;
1378+
1379+ let deleted = Notification :: KeyDeleted ( KeyDeleted {
1380+ key : "test/key" . to_string ( ) ,
1381+ } ) ;
1382+ assert ! ( format!( "{}" , deleted) . contains( "test/key" ) ) ;
1383+
1384+ let modified = Notification :: KeyModified ( KeyModified {
1385+ key : "test/key" . to_string ( ) ,
1386+ version_id : Some ( 43 ) ,
1387+ } ) ;
1388+ assert ! ( format!( "{}" , modified) . contains( "test/key" ) ) ;
1389+
1390+ let unknown = Notification :: Unknown ( ) ;
1391+ assert_eq ! ( format!( "{}" , unknown) , "Unknown" ) ;
1392+ }
1393+
1394+ // ============================================================
1395+ // Multiple secondary indexes per record
1396+ // ============================================================
1397+
1398+ #[ tokio:: test]
1399+ async fn test_multiple_secondary_indexes ( ) {
1400+ let ( _container, address) = start_oxia ( ) . await ;
1401+ let client = new_client ( & address) . await ;
1402+
1403+ // Put a record with multiple secondary indexes
1404+ client
1405+ . put_with_options (
1406+ "multi-idx/record1" . to_string ( ) ,
1407+ b"some-data" . to_vec ( ) ,
1408+ vec ! [ PutOption :: SecondaryIndexes ( vec![
1409+ SecondaryIndex {
1410+ index_name: "by-type" . to_string( ) ,
1411+ secondary_key: "document" . to_string( ) ,
1412+ } ,
1413+ SecondaryIndex {
1414+ index_name: "by-status" . to_string( ) ,
1415+ secondary_key: "active" . to_string( ) ,
1416+ } ,
1417+ ] ) ] ,
1418+ )
1419+ . await
1420+ . unwrap ( ) ;
1421+
1422+ // Query via first secondary index
1423+ let list1 = client
1424+ . list_with_options (
1425+ "d" . to_string ( ) ,
1426+ "e" . to_string ( ) ,
1427+ vec ! [ ListOption :: UseIndex ( "by-type" . to_string( ) ) ] ,
1428+ )
1429+ . await
1430+ . unwrap ( ) ;
1431+ assert ! (
1432+ !list1. keys. is_empty( ) ,
1433+ "Should find record via by-type index"
1434+ ) ;
1435+
1436+ // Query via second secondary index
1437+ let list2 = client
1438+ . list_with_options (
1439+ "a" . to_string ( ) ,
1440+ "b" . to_string ( ) ,
1441+ vec ! [ ListOption :: UseIndex ( "by-status" . to_string( ) ) ] ,
1442+ )
1443+ . await
1444+ . unwrap ( ) ;
1445+ assert ! (
1446+ !list2. keys. is_empty( ) ,
1447+ "Should find record via by-status index"
1448+ ) ;
1449+
1450+ client
1451+ . delete_range ( "multi-idx/" . to_string ( ) , "multi-idx/~" . to_string ( ) )
1452+ . await
1453+ . unwrap ( ) ;
1454+ client. shutdown ( ) . await . unwrap ( ) ;
1455+ }
0 commit comments