Skip to content

Commit 9fa6bb9

Browse files
authored
test: add stress test, display test, and multi-index test (#15)
- Add test_high_throughput_writes: 100 concurrent puts + deletes verifying batch system handles load correctly - Add test_notification_display: verify Display impl for all variants - Add test_multiple_secondary_indexes: verify multiple indexes per record - Total: 38 integration tests + 12 unit tests + 1 doctest = 51 tests Signed-off-by: mattisonchao <mattisonchao@gmail.com>
1 parent ac3fc23 commit 9fa6bb9

File tree

1 file changed

+159
-0
lines changed

1 file changed

+159
-0
lines changed

liboxia-native/tests/integration_tests.rs

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)